diff --git a/lib/lume.lua b/lib/lume.lua index 9f7792c..851a23d 100644 --- a/lib/lume.lua +++ b/lib/lume.lua @@ -624,7 +624,7 @@ function lume.wordwrap(str, limit) check = limit end local rtn = {} - local line = "" + local line = str:match("^(%s*)") for word, spaces in str:gmatch("(%S+)(%s*)") do local s = line .. word if check(s) then diff --git a/presentation/commands.fnl b/presentation/commands.fnl index 06121da..2446b9e 100644 --- a/presentation/commands.fnl +++ b/presentation/commands.fnl @@ -1,13 +1,20 @@ +(local util (require :lib.util)) (local core (require :core)) (local command (require :core.command)) (local keymap (require :core.keymap)) (local SlideshowView (require :presentation.engine)) +(fn set-scale [multiplier] + (set _G.SCALE (* (love.graphics.getDPIScale) multiplier)) + (util.hotswap :core.style)) + (command.add nil { "presentation:start" (fn [] (let [node (core.root_view:get_active_node)] - (node:add_view (SlideshowView (require :presentation.slides)))) + (node:add_view (SlideshowView (util.reload :presentation.slides)))) ) + "presentation:scale-up" #(set-scale 2) + "presentation:restore-scale" #(set-scale 1) }) (command.add :presentation.engine { "presentation:next" #(core.active_view:advance) @@ -16,9 +23,9 @@ "presentation:prev-slide" #(core.active_view:prev-slide) }) (keymap.add { - "left" "presentation:prev" - "right" "presentation:next" - "," "presentation:prev-slide" - "." "presentation:next-slide" + "left" "presentation:prev" + "right" "presentation:next" + "ctrl+left" "presentation:prev-slide" + "ctrl+right" "presentation:next-slide" }) diff --git a/presentation/engine.fnl b/presentation/engine.fnl index e72c885..2fcdf01 100644 --- a/presentation/engine.fnl +++ b/presentation/engine.fnl @@ -9,23 +9,25 @@ (icollect [_ slide (ipairs slides)] (icollect [_ elem (ipairs slide)] (match (type elem) - :table (do (set style elem) nil) + (where :table elem.style) (do (set style elem) nil) + :table elem :string (lume.merge style {:text elem}))))) (fn SlideshowView.new [self slides] (SlideshowView.super.new self) (set self.slides slides) + (set self.imagecache {}) (set self.islide 1) (set self.ielem 0) (self:advance)) (fn SlideshowView.next-slide [self] - (set self.islide (if (= self.islide (length self.slides)) 1 (+ self.islide 1))) + (set self.islide (if (>= self.islide (length self.slides)) 1 (+ self.islide 1))) (set self.ielem 0) (self:advance)) (fn SlideshowView.prev-slide [self] - (set self.islide (if (= self.islide 1) (length self.slides) (- self.islide 1))) + (set self.islide (if (<= self.islide 1) (length self.slides) (- self.islide 1))) (set self.ielem (+ 1 (length (. self.slides self.islide)))) (self:back)) @@ -46,18 +48,60 @@ (if ielemNext (set self.ielem ielemNext) (self:prev-slide)))) +(fn SlideshowView.load-image [self {:image filename}] + (when (= (. self.imagecache filename) nil) + (tset self.imagecache filename (love.graphics.newImage filename))) + (. self.imagecache filename)) + +(fn SlideshowView.justify [self element width] + (match element.justify + :center (/ (- self.size.x width) 2) + :right (- self.size.x width style.padding.x) + _ style.padding.x)) + +(fn SlideshowView.this-y [self element y] + (if element.topPadding (+ y element.topPadding) + (+ y style.padding.y))) + +(fn SlideshowView.next-y [self element height y] + (if element.lowerPadding (+ y height element.lowerPadding) + element.overlay y + (+ y height style.padding.y))) + +(fn SlideshowView.word-wrap [self element] + (let [letter-width (element.font:get_width "m") + screen-width (- self.size.x style.padding.x style.padding.x) + max-letters (math.floor (/ screen-width letter-width)) + wrapped (lume.wordwrap element.text max-letters) + lines (icollect [line (string.gmatch wrapped "([^\n]+)")] line)] + lines)) + (fn SlideshowView.render-element [self element y] - (let [x (+ self.position.x - (match element.justify - :center (/ (- self.size.x (element.font:get_width element.text)) 2) - :left style.padding.x))] - (renderer.draw_text element.font element.text x y element.color) - (+ y (* style.padding.y 2) (element.font:get_height)))) + (if element.text + (let [lines (self:word-wrap element) + line-height (element.font:get_height) + full-height (+ (* line-height (length lines)) (* style.padding.y (- (length lines) 1)))] + (each [iline line (ipairs lines)] + (let [width (element.font:get_width line) ;; todo: word-wrapping + x (+ self.position.x (self:justify element width)) + yline (+ y (* (+ (element.font:get_height) style.padding.y) (- iline 1)))] + (renderer.draw_text element.font line x yline element.color))) + (self:next-y element full-height y)) + + element.image + (let [image (self:load-image element) + x (+ self.position.x (self:justify element (image:getWidth)))] + (love.graphics.setColor 1 1 1 element.alpha) + (love.graphics.draw image x y) + (self:next-y element (image:getHeight) y)) + y)) (fn SlideshowView.draw [self] (self:draw_background style.background) - (var y (+ style.padding.y self.position.y)) + (var y self.position.y) (each [ielem element (ipairs (. self.slides self.islide)) :until (> ielem self.ielem)] - (set y (self:render-element element y)))) + (set y (self:render-element element (self:this-y element y))))) + +(fn SlideshowView.get_name [self] "] KFest 2021") SlideshowView diff --git a/presentation/pics/assembly-markup.png b/presentation/pics/assembly-markup.png new file mode 100644 index 0000000..88ae8dc Binary files /dev/null and b/presentation/pics/assembly-markup.png differ diff --git a/presentation/pics/ggj2020.jpeg b/presentation/pics/ggj2020.jpeg new file mode 100644 index 0000000..ce86418 Binary files /dev/null and b/presentation/pics/ggj2020.jpeg differ diff --git a/presentation/pics/pete286.jpeg b/presentation/pics/pete286.jpeg new file mode 100644 index 0000000..99a3397 Binary files /dev/null and b/presentation/pics/pete286.jpeg differ diff --git a/presentation/pics/thinkhard.png b/presentation/pics/thinkhard.png new file mode 100644 index 0000000..be1b5d8 Binary files /dev/null and b/presentation/pics/thinkhard.png differ diff --git a/presentation/slides.fnl b/presentation/slides.fnl index 3b14157..238c27b 100644 --- a/presentation/slides.fnl +++ b/presentation/slides.fnl @@ -1,26 +1,90 @@ (local util (require :lib.util)) +(local lume (require :lib.lume)) (local {: parse} (util.require :presentation.engine)) (local style (require :core.style)) (local h - {:font (renderer.font.load "presentation/font/PrintChar21.ttf" (* 64 SCALE)) + {:style true + :font (renderer.font.load "presentation/font/PrintChar21.ttf" (* 64 SCALE)) :color style.caret - :justify :center}) + :justify :center + :topPadding (* style.padding.y 2) + :lowerPadding 64}) (local ** - {:font (renderer.font.load "presentation/font/PRNumber3.ttf" (* 32 SCALE)) + {:style true + :font (renderer.font.load "presentation/font/PRNumber3.ttf" (* 32 SCALE)) :color style.text :justify :left :pause-after true}) +(fn p [style] (lume.merge style {:pause-after true})) +(fn np [style] (lume.merge style {:pause-after false})) + +(fn bgimg [filename] {:image filename :justify :center :overlay true :alpha 0.3 :topPadding 0}) (parse [ - [h "Some Background" + [h "" "" + "Honeylisp" "" + (np **) "Jeremy Penner" + "https://spindleyq.itch.io/" + "https://blog.information-superhighway.net/" + "https://bitbucket.org/SpindleyQ/honeylisp" + "https://gamemaking.social/@SpindleyQ" + "https://twitter.com/SpindleyQ" + {:pause-after true}] + [(bgimg "presentation/pics/pete286.jpeg") + h "Some Background" ** "In 2019 I built a 16-bit MS-DOS game engine." "* Built on hardware" - "* Using only period software" - "* Powered by Forth"] - [h "Neut Tower" + "* Using only period-appropriate software (Turbo C, NeoPaint)" + "* Powered by Forth" + "* Integrated custom tools" + "* Interactive development via serial terminal"] + [(bgimg "presentation/pics/ggj2020.jpeg") + h "Neut Tower" ** "In 2020, I did the Global Game Jam on my 286." - "Finished the 'Shareware Episode' a couple of months later."] - [h "Then Kansasfest Happened." ** ""] - [h "Oh Dang Bill" - ** "Oh gee oh whiz on toast"] + "Finished 'Shareware Episode 1' a couple of months later."] + [h "The Idea" + ** "What if I took a similar DIY approach with modern tools?" + "* I'd done Forth; what about Lisp?" + "* How far can I push fast iterative development?" + "* Could I integrate an editor?" + "* How can I leverage emulation?"] + [h "Honeylisp" + ** "* Written in Fennel, a Lisp that compiles to Lua" + "* Assembler" + "* Forth-like 'virtual machine' / inner interpreter" + "* 'lite' editor, ported to love2d" + " * Integrated custom editors" + "* MAME integration" + " * Upload new builds directly into RAM" + " * Interactive code injection" + " * Hot code reload" + "* Tape upload" + "* ProDOS disk image generation"] + [h "Assembler" + ** "Represent instructions using Fennel data literals" + " [:lda 0xff]" + "Represent labels with Fennel strings" + " :loop [:bne :loop]" + "Lexical scope with nested blocks" + " [:block :loop (generate-loop-code) [:bne :loop]]"] + [h "Wait WTF Is An Assembler" + ** "It's just converting mnemonics to bytes, right?" + {:image "presentation/pics/assembly-markup.png" :justify :center :pause-after true} + "Whoooops, actually the hard part is converting labels to addresses" + "Zero-page instructions are a different size, which messes up data layout!" + "Initial pass is needed to gather all symbols to determine sizes" + "What about data?" + " [:db 123] [:dw 12345] [:bytes \"HELLO WORLD\"] [:ref :hello]" + "Must be able to line up bytes on page boundaries" + " [:align 0x100]"] + [h "Virtual Machine" + {:image "presentation/pics/thinkhard.png" :justify :center} + ** "Not super keen on writing a complicated compiler" + "I'm already very comfortable with Forth" + "Let's build a stack machine!" + "\"Direct threaded\" inner interpreter" + "\"Immediate words\" can be Fennel functions that generate code!"] + [h "Extensible Assembler??" + ** "How do you turn code into bytes?" + " [:vm 1 2 :+ :.]"] ])