about summary refs log tree commit diff stats
path: root/drawing.lua
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2023-09-15 11:13:04 -0700
committerKartik K. Agaram <vc@akkartik.com>2023-09-15 11:13:04 -0700
commitab5ba3f3e5f4f1f1583d798ace26683cb572ed18 (patch)
tree416b908f23462cf8eb38467eb5b57598f8acafa8 /drawing.lua
parentbafc45b028ad8db3d8be51cf1a09b7f118d75503 (diff)
downloadlines.love-ab5ba3f3e5f4f1f1583d798ace26683cb572ed18.tar.gz
assume starty can be nil in update
This is a backport of a bugfix in pensieve.love. It's not _technically_
a bug here in lines.love, but it seems worth establishing an
architectural invariant (or rather lack of invariant).

LÖVE's standard event loop performs the following sequence of operations
in a single frame:
  * process events
  * update
  * draw

Ideally any mutations to global state happen during the first two
phases, while drawing includes no mutation.

However, there is a special case: `starty`, the top y coordinate for
each each line in the editor. This is used all over the place, and the
cheapest way to compute it is to simply save it while drawing.

However, draw by definition only updates `starty` for lines that are
drawn on screen. To avoid stale data on lines off screen, say after
scrolling, events often clear `starty` for all lines, leaving it to the
next draw phase to repopulate the right lines.

Sandwiched between the above two "however"s, the update phase needs to
gracefully handle `starty` being nil in the occasional frame right after
an event.

I think I've audited all our uses of `starty`, and this commit fixes the
only place that violates this rule.
Diffstat (limited to 'drawing.lua')
-rw-r--r--drawing.lua6
1 files changed, 6 insertions, 0 deletions
diff --git a/drawing.lua b/drawing.lua
index ac4990a..a98f5b2 100644
--- a/drawing.lua
+++ b/drawing.lua
@@ -249,6 +249,12 @@ function Drawing.update(State)
   if State.lines.current_drawing == nil then return end
   local drawing = State.lines.current_drawing
   local line_cache = State.line_cache[State.lines.current_drawing_index]
+  if line_cache.starty == nil then
+    -- some event cleared starty just this frame
+    -- draw in this frame will soon set starty
+    -- just skip this frame
+    return
+  end
   assert(drawing.mode == 'drawing')
   local pmx, pmy = App.mouse_x(), App.mouse_y()
   local mx = Drawing.coord(pmx-State.left, State.width)