Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
1eed4b9
Merge remote-tracking branch 'origin/ac/vulkan-anim-fix' into osnr/fi…
osnr May 13, 2026
5c5c42a
Makefile: fix tracy build?
osnr May 13, 2026
33119bc
print: Force scaling to none
osnr May 13, 2026
c50acde
gpu/textures: Don't hard crash if we run out of texture slots
osnr May 13, 2026
8e38e4e
prelude: Make Folk Tracy zones reentrant
osnr May 14, 2026
7aeeb11
WIP: rename print (will add mixin next)
osnr May 14, 2026
4c49116
db: Hopefully fix race between matchDestroy and dbMatchInsert
osnr May 15, 2026
b8b00ff
gpu/canvases: Support canvas priority
osnr May 15, 2026
e521fb2
web/db-lib: Support sentinel
osnr May 15, 2026
a36b3aa
WIP: Editor on top of the page itself.
osnr May 15, 2026
e723a3e
db: WIP: Lock current item on kill print (to try to fix UAF)
osnr May 15, 2026
315e1b8
Fix editor canvas layer + layers and options forwarding in general
osnr May 15, 2026
80ca5db
editor: Draw translucent backdrop; draw display canvas on top
osnr May 15, 2026
6c1b6d2
Make tag masking top-level; stabilize editor program
osnr May 15, 2026
efd724c
WIP: Refactoring editor to factor out utils for printing
osnr May 15, 2026
dd5bfd1
WIP: Editor-based printing (emits PDF, no preview yet)
osnr May 19, 2026
66d807b
print-editor: Fix preview
osnr May 19, 2026
a208454
print-editor: Add font
osnr May 19, 2026
74a3aec
WIP: To-scale preview of new printing
osnr May 19, 2026
0e8f6bd
print-editor: Fix font choice and tag rendering
osnr May 19, 2026
d8c5591
WIP: Live print preview to help me debug
osnr May 19, 2026
490ecfc
print-editor: Fix font load
osnr May 19, 2026
3ed35ba
editor: Re-enable text scaling; remove old editor
osnr May 19, 2026
624e2b5
print-editor: Line numbers and text seem to be aligned
osnr May 19, 2026
acfff71
WIP: Editor-based printing works (may break web printing, though)
osnr May 19, 2026
1d73af9
WIP: Factor calibration pdf into separate program
osnr May 20, 2026
7703e0e
prelude: Make fn (lexical) procs local
osnr May 20, 2026
ca12d8a
WIP: Start working on new calibration board
osnr May 20, 2026
8e7041d
calibration-board-pdf: WIP: Portrait board; mark measure edges
osnr May 21, 2026
56ee382
Reasonable new model/calibration page
osnr May 21, 2026
6543517
WIP: Remove interactively-refine. Add UI for new measurements
osnr May 21, 2026
b663b24
Makefile: Disable debuginfod because it was very annoying
osnr May 21, 2026
71e95a7
print: WIP: Make print pdf event for calibration board
osnr May 21, 2026
f3fec9a
print-editor: Cleanup / syntax fix
osnr May 21, 2026
a774cf2
WIP: Print new calibration board; new statements for calib
osnr May 21, 2026
add13f8
print: Force print-scaling=none
osnr May 21, 2026
675cc6e
WIP: Calibrate runs through (but doesn't converge yet)
osnr May 21, 2026
7943e51
WIP: Calibration completes (fixed reliance on old fn-proc behavior)
osnr May 21, 2026
b1685e5
calibrate-page: Move sliders up
osnr May 21, 2026
10ffa8b
WIP: Move to calibration-board.folk, stub for measurement use
osnr May 22, 2026
0a157e1
WIP: Use measurements at print time; print tag to match cal board
osnr May 22, 2026
daa6fc8
jim: Track column numbers (not that well-tested)
osnr May 23, 2026
39f0f90
editor: Wipe old Holds (not that important anyway)
osnr May 25, 2026
019d91b
print: Make tagInset so tag not cut off; emit per-program geometry
osnr May 25, 2026
236d3fd
calibrate-page: Remove example program png step
osnr May 25, 2026
16732ff
print: Handle half-height pages
osnr May 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ debug: folk
if [ "$$(uname)" = "Darwin" ]; then \
lldb -o "process handle -p true -s false SIGUSR1" -- ./folk; \
else \
gdb -ex "handle SIGUSR1 nostop" -ex "handle SIGPIPE nostop" ./folk; \
DEBUGINFOD_URLS="" gdb -ex "handle SIGUSR1 nostop" -ex "handle SIGPIPE nostop" ./folk; \
fi

clean:
Expand Down Expand Up @@ -124,10 +124,10 @@ sync:
rsync --timeout=15 -e "ssh -o StrictHostKeyChecking=no" \
--archive --delete --itemize-changes \
--exclude='/.git' \
--exclude-from='.git/ignores.tmp' \
--exclude='vendor/tracy/public/TracyClient.o' \
--include='vendor/tracy/public/***' \
--exclude='vendor/tracy/*' \
--exclude-from='.git/ignores.tmp' \
./ $(FOLK_REMOTE_NODE):~/folk/

remote-setup:
Expand Down
6 changes: 2 additions & 4 deletions builtin-programs/apriltags.folk
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,7 @@ set entireFrameDetector [makeAprilTagDetector $tagFamily 2.0 1]
set incrementalDetector [makeAprilTagDetector $tagFamily 1.5 1]

# Entire-frame tag detector:
When /nobody/ wishes to calibrate camera /any/ to display /any/ &\
/nobody/ wishes to interactively refine calibration from camera /any/ to display /any/ &\
When /nobody/ wishes to calibrate camera /any/ to display /any/ /...etc/ &\
-serially camera /camera/ has gray frame /frame/ at timestamp /frameTs/ {

tracy zoneBegin
Expand All @@ -141,8 +140,7 @@ When /nobody/ wishes to calibrate camera /any/ to display /any/ &\

# Incremental tag detector (looks at regions where there were tags
# seen recently):
When /nobody/ wishes to calibrate camera /any/ to display /any/ &\
/nobody/ wishes to interactively refine calibration from camera /any/ to display /any/ &\
When /nobody/ wishes to calibrate camera /any/ to display /any/ /...etc/ &\
the image library is /imageLib/ &\
-serially camera /camera/ has gray frame /frame/ at timestamp /frameTs/ {
tracy zoneBegin
Expand Down
317 changes: 47 additions & 270 deletions builtin-programs/calibrate/calibrate-page.folk

Large diffs are not rendered by default.

21 changes: 11 additions & 10 deletions builtin-programs/calibrate/calibrate.folk
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ When camera /camera/ has width /cameraWidth/ height /cameraHeight/ &\
the jpeg library is /jpegLib/ &\
the calibration model library is /modelLib/ &\
the calibration matrix library is /matLib/ &\
the printed calibration tag size is /printedSideLengthMm/ mm &\
/someone/ wishes to calibrate camera /camera/ to display /display/ {
/someone/ wishes to calibrate camera /camera/ to display /display/ \
using tag size /printedSideLengthMm/ mm {

fn makeAprilTagDetector
set calibrationTagDetector [makeAprilTagDetector "tagStandard52h13" 2.0 3]
Expand Down Expand Up @@ -538,7 +538,7 @@ fn setCameraToProjectorExtrinsics {modelLib calibrationVar calibrationPoses} {
# to find the rotation and translation from 3D camera-space to 3D
# projector-space.

upvar $calibrationVar calibration
upvar $calibrationVar cal

# Let's take all the points for which we have a corresponding
# camera frame point and projector frame point.
Expand All @@ -547,12 +547,12 @@ fn setCameraToProjectorExtrinsics {modelLib calibrationVar calibrationPoses} {

for {set i 0} {$i < [llength $calibrationPoses]} {incr i} {
set calibrationPose [lindex $calibrationPoses $i]

set Rc [dict get [lindex [dict get $calibration camera extrinsics] $i] R]
set tc [dict get [lindex [dict get $calibration camera extrinsics] $i] t]

set Rp [dict get [lindex [dict get $calibration projector extrinsics] $i] R]
set tp [dict get [lindex [dict get $calibration projector extrinsics] $i] t]
set Rc [dict get [lindex [dict get $cal camera extrinsics] $i] R]
set tc [dict get [lindex [dict get $cal camera extrinsics] $i] t]

set Rp [dict get [lindex [dict get $cal projector extrinsics] $i] R]
set tp [dict get [lindex [dict get $cal projector extrinsics] $i] t]

# TODO: Try using pose estimation instead?
dict for {id tag} [dict get $calibrationPose model] {
Expand Down Expand Up @@ -594,8 +594,8 @@ fn setCameraToProjectorExtrinsics {modelLib calibrationVar calibrationPoses} {
set t [sub $projectorFramePointsCentroid \
[matmul $R $cameraFramePointsCentroid]]

dict set calibration R_cameraToProjector $R
dict set calibration t_cameraToProjector $t
dict set cal R_cameraToProjector $R
dict set cal t_cameraToProjector $t
}

# End-to-end calibrates a camera-projector pair. calibrationPoses is
Expand Down Expand Up @@ -701,6 +701,7 @@ When the calibration model library is /modelLib/ &\

set calibration [{*}$refineCalibration \
$modelLib $matLib \
[fn setCameraToProjectorExtrinsics] \
$calibrationPoses $calibration]
puts "======== Refined calibration intrinsics ========="

Expand Down
243 changes: 243 additions & 0 deletions builtin-programs/calibrate/calibration-board.folk
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
# Goal of the calibration board is to have the user do four
# measurements:
#
# - paper edge to top margin
#
# - paper edge to bottom margin
#
# - paper edge to left margin
#
# - tag inner width, to account for scaling. (We also want this tag
# inner width to be exactly the same as the tag inner width that we
# use on every printed program, so that if the user measures the tag
# wrong, it still looks OK on the average program.)
#
# Then we can correct for these factors in all future prints, so we
# can print mm-accurate.

# These values are all in points (1/72 of an inch).
set marginTop 48; set marginLeft 48

set measureTop [/ $marginTop 2]; set measureLeft [/ $marginLeft 2]
set tagInnerSideLength 70

When the calibration measurements are /measurements/ {
set m_tag [expr {double([string trimright [dict get $measurements tagSideLength] mm])}]
set m_left [expr {double([string trimright [dict get $measurements left] mm])}]
set m_bottom [expr {double([string trimright [dict get $measurements bottom] mm])}]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the point of using expr {double()} here?


# 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 preamble is "\[$scale 0 0 $scale $tx $ty\] concat"
Claim the calibrated print scale is $scale
}

When the print library is /printLib/ &\
the calibration model library is /modelLib/ &\
the calibration matrix library is /matLib/ {

fn makeCalibrationBoardPs {} {
set model [$modelLib unitModel]

package require linalg
namespace import ::math::linearalgebra::add

set PageWidth 612; set PageHeight 792

set innerToOuter 0.333333

set tagOuterLengthPs [expr {$tagInnerSideLength * 10/6}]

set H_modelToPs [$matLib estimateHomography [subst {
{1 1 $tagInnerSideLength $tagInnerSideLength}
{1 0 $tagInnerSideLength 0}
{0 1 0 $tagInnerSideLength}
{0 0 0 0}
}]]

set ps [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice

gsave
$marginLeft [- $PageHeight [/ $marginTop 2]] translate
0 setgray /Helvetica findfont 14 scalefont setfont
newpath 0 0 moveto (Folk calibration board) show
grestore

/Helvetica findfont 7 scalefont setfont
1 setlinecap
2 setlinewidth 0.67 0.1 0.1 setrgbcolor

% Short red segment at top measure, with arrow up to top edge.
2 setlinewidth
newpath
[expr {$PageWidth/2 - 20}] [- $PageHeight $measureTop] moveto
[expr {$PageWidth/2 + 20}] [- $PageHeight $measureTop] lineto
stroke
1 setlinewidth
newpath
[/ $PageWidth 2] [- $PageHeight $measureTop] moveto
[/ $PageWidth 2] [expr {$PageHeight - 2}] lineto
stroke
newpath
[/ $PageWidth 2] [expr {$PageHeight - 2}] moveto
[expr {$PageWidth/2 - 4}] [expr {$PageHeight - 8}] lineto
stroke
newpath
[/ $PageWidth 2] [expr {$PageHeight - 2}] moveto
[expr {$PageWidth/2 + 4}] [expr {$PageHeight - 8}] lineto
stroke
newpath [expr {$PageWidth/2 + 12}] [expr {$PageHeight - $measureTop/2 - 3}] moveto
(Measure to top edge of paper) show

% Short red segment at bottom measure, with arrow down to bottom edge.
2 setlinewidth
newpath
[expr {$PageWidth/2 - 20}] $measureTop moveto
[expr {$PageWidth/2 + 20}] $measureTop lineto
stroke
1 setlinewidth
newpath
[/ $PageWidth 2] $measureTop moveto
[/ $PageWidth 2] 2 lineto
stroke
newpath
[/ $PageWidth 2] 2 moveto
[expr {$PageWidth/2 - 4}] 8 lineto
stroke
newpath
[/ $PageWidth 2] 2 moveto
[expr {$PageWidth/2 + 4}] 8 lineto
stroke
newpath [expr {$PageWidth/2 + 12}] [expr {$measureTop/2- 3}] moveto
(Measure to bottom edge of paper) show

0.1 0.1 0.67 setrgbcolor

% Short blue segment at left measure, with arrow left to left edge.
2 setlinewidth
newpath
$measureLeft [expr {$PageHeight/2 - 20}] moveto
$measureLeft [expr {$PageHeight/2 + 20}] lineto
stroke
1 setlinewidth
newpath
$measureLeft [/ $PageHeight 2] moveto
2 [/ $PageHeight 2] lineto
stroke
newpath
2 [/ $PageHeight 2] moveto
8 [expr {$PageHeight/2 - 4}] lineto
stroke
newpath
2 [/ $PageHeight 2] moveto
8 [expr {$PageHeight/2 + 4}] lineto
stroke
newpath [/ $measureLeft 4] [expr {$PageHeight/2 - 30}] moveto
(Measure to) show
[/ $measureLeft 4] [expr {$PageHeight/2 - 37}] moveto
(left edge of paper) show

% We should flip the coordinate system to match the model coordinate system,
% so (0, 0) is top-left.
1 -1 scale
$marginLeft [- $marginTop $PageHeight] translate

[set tagIdx -1]
[join [lmap {id modelTag} $model {
if {![$modelLib isPrintedTag $id]} { continue }
incr tagIdx

set modelInnerTopLeft [lindex [dict get $modelTag p] 3]
set modelOuterTopLeft [add $modelInnerTopLeft [list -$innerToOuter -$innerToOuter]]
lassign [$matLib applyHomography $H_modelToPs $modelOuterTopLeft] psX psY
subst {
gsave
$psX [+ $psY $tagOuterLengthPs] translate
$tagOuterLengthPs -$tagOuterLengthPs scale
[$printLib tagPsForId $id]
grestore

% gsave
% 0 setgray /Helvetica findfont 14 scalefont setfont
% 1 0 0 setrgbcolor
% newpath $psX $psY moveto 1 -1 scale ($tagIdx) show
% grestore

% Label the inner side length:
[if {$tagIdx == 1} { subst {
gsave
[expr {$psX + ($tagOuterLengthPs - $tagInnerSideLength)/2}]
[expr {$psY - 15}] translate
1 -1 scale
0.1 0.67 0.1 setrgbcolor 2 setlinewidth
newpath 0 0 moveto $tagInnerSideLength 0 lineto stroke
newpath 0 0 moveto 0 -5 lineto stroke
newpath $tagInnerSideLength 0 moveto $tagInnerSideLength -5 lineto stroke
/Helvetica findfont 7 scalefont setfont
newpath 0 5 moveto (inner side length) show
grestore
} }]
}
}] "\n"]

showpage
}]

return $ps
}
Claim the makeCalibrationBoardPs is [fn makeCalibrationBoardPs]

fn makeCalibrationBoardPdf {} {
set ps [makeCalibrationBoardPs]
set fp [open [list |ps2pdf - - <<$ps] rb]
set pdf [read $fp]; close $fp
return $pdf
}
Claim the makeCalibrationBoardPdf is [fn makeCalibrationBoardPdf]

fn makeCalibrationBoardPng {} {
set ps [makeCalibrationBoardPs]
set psFile [file tempfile].ps
set fp [open $psFile w]; puts $fp $ps; close $fp
set pngFile [file tempfile].png
exec gs -dNOPAUSE -dBATCH -sFONTPATH=vendor/fonts \
-sDEVICE=png16m -r144 \
-sOutputFile=$pngFile $psFile
set fp [open $pngFile rb]
set png [read $fp]; close $fp
return $png
}
Claim the makeCalibrationBoardPng is [fn makeCalibrationBoardPng]

Wish the web server handles route {/calibrate/board.pdf} with hidden true handler {
dict create statusAndHeaders "HTTP/1.1 200 OK
Connection: close
Content-Type: application/pdf

" \
body [makeCalibrationBoardPdf]
}

Wish the web server handles route {/calibrate/board.png} with hidden true handler {
dict create statusAndHeaders "HTTP/1.1 200 OK
Connection: close
Content-Type: image/png

" \
body [makeCalibrationBoardPng]
}

}
Loading