The analysis made every component function a frame root, event handlers (cmp_x_on_delete) too, and every reducer, whether its action is dispatched every frame or once a trip: a component's 'on' handlers are no longer roots, and a dispatch is an edge to its action's reducers, so a reducer counts only when frame code dispatches it. A push into a field declared @max(n) is bounded by the fence's own check and no longer counted. Maroon Lake: frame_allocs 395 -> 337, frame_keeps 188 -> 169. ludic.photo: the roll's order and a page of it are kept lists refilled in place (the pack's page asked for both every frame), its kept lists say @max(256), and a shot's tags, a photograph's fact and a new roll are declared (once per shot, sale or trip). 18 allocs and 9 keeps -> 0 and 0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
105 lines
3.7 KiB
Text
105 lines
3.7 KiB
Text
# roll.ludic - the roll of kept frames, the frame being composed, what has ever been photographed,
|
|
# and the facts
|
|
export const PHOTO_WHY_NONE: int = -1 # no subject: nothing to say
|
|
export const PHOTO_WHY_SIZE: int = 0 # too far off - get closer, or more lens
|
|
export const PHOTO_WHY_FRAME: int = 1 # badly placed in the frame
|
|
export const PHOTO_WHY_LIGHT: int = 2 # the light was wrong
|
|
export const PHOTO_WHY_MOMENT: int = 3 # it was not doing anything
|
|
export const PHOTO_WHY_FINE: int = 4 # nothing to fault
|
|
|
|
export const PHOTO_KEPT: int = 0 # a frame went onto the roll
|
|
export const PHOTO_FULL: int = 1 # the card is full
|
|
export const PHOTO_DELETED: int = 2 # file: the picture to remove
|
|
export const PHOTO_SOLD: int = 3 # v: what it fetched
|
|
|
|
export property PhotoFact {
|
|
what: int = 0
|
|
index: int = -1
|
|
mask: int = 0 # subjects in it, a bit each
|
|
legend: int = 0 # which of them were legends
|
|
firsts: int = 0 # subjects never photographed before this frame
|
|
grade: int = 0
|
|
sign: int = -1 # a sign in the frame, or -1
|
|
stars: bool = false
|
|
file: string = ""
|
|
tags: string = ""
|
|
v: int = 0
|
|
}
|
|
|
|
export state PhotoState {
|
|
pht_sort: int = 0
|
|
pht_page: int = 0
|
|
@max(256) pht_order: []int = new []int # the roll's order, refilled in place (a page asks it every frame)
|
|
@max(8) pht_page_out: []int = new []int # a page of it, the same
|
|
pht_max: int = 40
|
|
pht_n: int = 0
|
|
pht_day: []int = null
|
|
pht_hour: []float = null
|
|
pht_mask: []int = null
|
|
pht_legend: []int = null
|
|
pht_sold: []int = null
|
|
pht_grade: []int = null
|
|
pht_why: []int = null
|
|
@max(256) pht_tags: []string = null
|
|
@max(256) pht_file: []string = null
|
|
pht_best: []int = null # the best grade yet, per subject
|
|
pht_species_shot: int = 0 # every subject ever photographed, sold or deleted
|
|
pht_legend_shot: int = 0
|
|
pht_cover: int = -1 # the one frame a game shows for the whole roll
|
|
pht_pending_tags: string = ""
|
|
pht_pending_mask: int = 0
|
|
pht_pending_legend: int = 0
|
|
pht_pending_grade: int = 0
|
|
pht_pending_why: int = -1
|
|
pht_pending_sign: int = -1
|
|
pht_pending_stars: bool = false
|
|
pht_comp: []float = null # size, framing, light, moment of the last subject scored
|
|
pht_comp_have: bool = false
|
|
pht_fact_q: Queue<PhotoFact> = pht_fact_q__new()
|
|
}
|
|
|
|
|
|
|
|
export function photo_facts(photo_st: PhotoState) -> Queue<PhotoFact> {
|
|
return photo_st.pht_fact_q
|
|
}
|
|
|
|
@alloc_ok("a photograph's fact: one per shot kept, sold or deleted")
|
|
function pht_fact(photo_st: PhotoState, what: int, i: int) -> PhotoFact {
|
|
let f = new PhotoFact
|
|
f.what = what
|
|
f.index = i
|
|
q_push(photo_facts(photo_st), f)
|
|
return f
|
|
}
|
|
|
|
function pht_ints(n: int) -> []int {
|
|
let out = new []int
|
|
for i in 0 .. n { push(out, 0) }
|
|
return out
|
|
}
|
|
|
|
function pht_floats(n: int) -> []float {
|
|
let out = new []float
|
|
for i in 0 .. n { push(out, 0.0) }
|
|
return out
|
|
}
|
|
|
|
# an empty roll of `max` frames
|
|
@alloc_ok("a new roll: once a trip, and when the roll is emptied")
|
|
function pht_blank(photo_st: mut PhotoState) -> void {
|
|
photo_st.pht_n = 0
|
|
photo_st.pht_day = pht_ints(photo_st.pht_max)
|
|
photo_st.pht_hour = pht_floats(photo_st.pht_max)
|
|
photo_st.pht_mask = pht_ints(photo_st.pht_max)
|
|
photo_st.pht_legend = pht_ints(photo_st.pht_max)
|
|
photo_st.pht_sold = pht_ints(photo_st.pht_max)
|
|
photo_st.pht_grade = pht_ints(photo_st.pht_max)
|
|
photo_st.pht_why = pht_ints(photo_st.pht_max)
|
|
photo_st.pht_tags = new []string
|
|
photo_st.pht_file = new []string
|
|
photo_st.pht_best = pht_ints(32)
|
|
photo_st.pht_comp = pht_floats(4)
|
|
photo_st.pht_comp_have = false
|
|
}
|
|
function pht_fact_q__new() -> Queue<PhotoFact> { return queue_new("photo.facts") }
|