Fix palette swap backgrounds and timeline drop jitter
This commit is contained in:
parent
26fab9392e
commit
7c49c08bc7
8 changed files with 55 additions and 20 deletions
|
|
@ -243,12 +243,17 @@
|
|||
(assoc op :cx x :cy y :size (* scale (:size op))))
|
||||
op)))
|
||||
|
||||
(defprotocol IActivePalette
|
||||
(active-palette [this]
|
||||
"The palette selected by this resolver's most recently resolved frame."))
|
||||
|
||||
(defn resolver
|
||||
"Resolve an output frame, selecting native content at each symbol boundary.
|
||||
Every instance owns its cursors and buffers. The IResolver queries return
|
||||
native node frames and world matrices for the last rendered output frame."
|
||||
[clip sid store palette opts]
|
||||
(let [context? (and (map? palette) (:palettes palette) (:offsets palette))]
|
||||
(let [context? (and (map? palette) (:palettes palette) (:offsets palette))
|
||||
active-palette-state (atom (:default palette))]
|
||||
(letfn [(channel-value [selection frame]
|
||||
(cond
|
||||
(nil? selection) nil
|
||||
|
|
@ -323,6 +328,9 @@
|
|||
(root-selection-at sym (js/Math.floor f) inherited)
|
||||
inherited)
|
||||
(:default palette))))
|
||||
;; The same decision that maps local drawing slots to
|
||||
;; the active bank also names the clear colour.
|
||||
(when root? (reset! active-palette-state @active))
|
||||
(vreset! entered {})
|
||||
(let [by-id (into {} (map (juxt :node identity))
|
||||
(own (js/Math.floor f) (js/Math.floor pre)))]
|
||||
|
|
@ -409,7 +417,9 @@
|
|||
symbol/IResolver
|
||||
(world-of [_ path] (symbol/world-of r path))
|
||||
(frame-of [_ path] (symbol/frame-of r path))
|
||||
(pre-frame-of [_ path] (symbol/pre-frame-of r path)))))))
|
||||
(pre-frame-of [_ path] (symbol/pre-frame-of r path))
|
||||
IActivePalette
|
||||
(active-palette [_] @active-palette-state))))))
|
||||
|
||||
(defn center
|
||||
"The middle of everything symbol `sid` draws, over all its frames, in its own
|
||||
|
|
|
|||
|
|
@ -109,6 +109,16 @@
|
|||
i (and p (slot-index p value))]
|
||||
(if (some? i) (+ (get offsets id 0) i) 255)))
|
||||
|
||||
(defn background-index
|
||||
"The raster index of slot zero in the resolver's active palette.
|
||||
|
||||
`index-of` remains a supported legacy palette map for domain callers; it has
|
||||
no palette banks or active selection, so its established `:bg` index applies."
|
||||
[palette active]
|
||||
(if (and (:palettes palette) (:offsets palette))
|
||||
(render-index palette active 0)
|
||||
(get palette :bg 0)))
|
||||
|
||||
(defn valid-palette? [{:keys [id name slots]}]
|
||||
(and id (string? name) (seq name) (vector? slots) (pos? (count slots))
|
||||
(<= (count slots) 255)
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
(:refer-clojure :exclude [run!])
|
||||
(:require [arthur.audio.mix :as mix]
|
||||
[arthur.domain.clip :as clip]
|
||||
[arthur.domain.palette :as pal]
|
||||
[arthur.domain.raster :as raster]))
|
||||
|
||||
(defprotocol Exporter
|
||||
|
|
@ -191,8 +192,7 @@
|
|||
;; how.
|
||||
doc (assoc-in clip [:symbols sid] sym)
|
||||
resolve-frame (clip/resolver doc sid store palette nil)
|
||||
ras (raster/make width height)
|
||||
bg (get palette :bg 0)]
|
||||
ras (raster/make width height)]
|
||||
(-> (audio! doc sid store audio-url)
|
||||
(.then (fn [audio]
|
||||
(js/Promise.resolve
|
||||
|
|
@ -210,9 +210,11 @@
|
|||
(fn [chain i]
|
||||
(.then chain
|
||||
(fn [_]
|
||||
(-> ras
|
||||
(raster/clear! bg)
|
||||
(raster/draw-ops! (resolve-frame i)))
|
||||
(let [ops (resolve-frame i)]
|
||||
(-> ras
|
||||
(raster/clear! (pal/background-index palette
|
||||
(clip/active-palette resolve-frame)))
|
||||
(raster/draw-ops! ops)))
|
||||
(-> (js/Promise.resolve (frame! exporter i ras))
|
||||
(.then (fn [_]
|
||||
(when on-progress
|
||||
|
|
|
|||
|
|
@ -194,7 +194,9 @@
|
|||
symbol/IResolver
|
||||
(world-of [_ path] (symbol/world-of resolve path))
|
||||
(frame-of [_ path] (symbol/frame-of resolve path))
|
||||
(pre-frame-of [_ path] (symbol/pre-frame-of resolve path)))))))
|
||||
(pre-frame-of [_ path] (symbol/pre-frame-of resolve path))
|
||||
clip/IActivePalette
|
||||
(active-palette [_] (clip/active-palette resolve)))))))
|
||||
|
||||
(rf/reg-sub
|
||||
::underlay
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@
|
|||
times a second at a 30fps clip on a 60Hz display, not sixty — and it carries
|
||||
no global interceptors."
|
||||
(:require [arthur.clock :as clock]
|
||||
[arthur.domain.clip :as clip]
|
||||
[arthur.domain.palette :as pal]
|
||||
[arthur.domain.pick :as pick]
|
||||
[arthur.domain.raster :as raster]
|
||||
[arthur.events.playback :as pb]
|
||||
|
|
@ -171,10 +173,11 @@
|
|||
;; independent of the footage, so the size the frame is rasterised at comes
|
||||
;; out of the document like everything else.
|
||||
(let [ras (raster-for width height)]
|
||||
(let [ops (resolver f)]
|
||||
(let [ops (resolver f)
|
||||
bg (pal/background-index palette (clip/active-palette resolver))]
|
||||
(swap! state assoc :ops ops)
|
||||
(-> ras
|
||||
(raster/clear! (get palette :bg 0))
|
||||
(raster/clear! bg)
|
||||
(raster/draw-ops! ops)))
|
||||
(js/performance.mark "arthur/blit:start")
|
||||
(canvas/blit! canvas ras ramp)
|
||||
|
|
|
|||
|
|
@ -98,10 +98,11 @@
|
|||
(when (clip/symbol document sid)
|
||||
(let [resolve (clip/resolver document sid store palette {})
|
||||
[w h] (clip/stage document sid)]
|
||||
(-> (raster/make w h)
|
||||
(raster/clear! (get palette :bg 0))
|
||||
(raster/draw-ops! (resolve 0))
|
||||
(canvas/->png ramp))))
|
||||
(let [ops (resolve 0)]
|
||||
(-> (raster/make w h)
|
||||
(raster/clear! (pal/background-index palette (clip/active-palette resolve)))
|
||||
(raster/draw-ops! ops)
|
||||
(canvas/->png ramp)))))
|
||||
(catch :default _ nil)))
|
||||
|
||||
(defn- symbol-thumb
|
||||
|
|
|
|||
|
|
@ -1083,12 +1083,12 @@
|
|||
(if (= drop-lane (:select row))
|
||||
(update row :cels (fnil conj []) lane-ghost)
|
||||
row))))
|
||||
;; The palette track is a permanent master row. An
|
||||
;; untargeted visual drop becomes a new ordinary row and
|
||||
;; therefore previews immediately BELOW it, where the
|
||||
;; committed row will appear—not above the master row.
|
||||
;; An untargeted visual drop becomes a new ordinary row
|
||||
;; at the bottom. Inserting it above the lanes shifts the
|
||||
;; lane under the pointer and makes the browser alternate
|
||||
;; between this ghost and that lane's drop target.
|
||||
(and ghost (not (:sound? drop)))
|
||||
((fn [rows] (into [(first rows) ghost] (rest rows)))))
|
||||
(fn [rows] (conj (vec rows) ghost)))
|
||||
sounds (cond->> (into (vec (filter :sound? picture))
|
||||
(sound-rows clip open expanded))
|
||||
(and ghost (:sound? drop)) (cons ghost))
|
||||
|
|
|
|||
|
|
@ -354,4 +354,11 @@
|
|||
(is (= (pal/render-index context :day 1) (color main 2))
|
||||
"a nil track interval is a real gap and restores the authoring palette")
|
||||
(is (= (pal/render-index context :night 1) (color drawing 0))
|
||||
"the same nested symbol uses its authoring palette when viewed directly")))
|
||||
"the same nested symbol uses its authoring palette when viewed directly")
|
||||
;; The renderer clears with this exact resolver state before rasterising the
|
||||
;; returned ops, so a palette cut changes the stage background as well as
|
||||
;; authored shapes.
|
||||
(main 1)
|
||||
(is (= :night (clip/active-palette main)))
|
||||
(is (= (pal/render-index context :night 0)
|
||||
(pal/background-index context (clip/active-palette main))))))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue