Compare commits

..

2 Commits

Author SHA1 Message Date
John Alanbrook
ce6b0ddb3a rm push/pop 2026-02-26 08:13:27 -06:00
John Alanbrook
ef7e3e6449 fix clay 2026-02-26 00:56:25 -06:00
31 changed files with 375 additions and 294 deletions

View File

@@ -234,7 +234,7 @@ action.on_input = function(action_id, evt)
var matched_actions = [] var matched_actions = []
arrfor(array(this.action_map), mapped_action => { arrfor(array(this.action_map), mapped_action => {
if (find(this.action_map[mapped_action], action_id) != null) { if (find(this.action_map[mapped_action], action_id) != null) {
push(matched_actions, mapped_action) matched_actions[] = mapped_action
if (evt.pressed) if (evt.pressed)
this.down[mapped_action] = true this.down[mapped_action] = true

185
clay.cm
View File

@@ -1,17 +1,21 @@
// clay2.cm - Revised UI layout engine emitting flat drawables // clay.cm - UI layout engine emitting flat drawables with annotated tree
// //
// Changes from clay.cm: // - Uses meme/merge for config chains
// - No __proto__, uses meme/merge
// - Emits flat list of drawables for film2d // - Emits flat list of drawables for film2d
// - Supports scissor clipping // - Supports scissor clipping
// // - Returns annotated tree root with .drawables for clay_input compatibility
// Now returns [drawable, drawable, ...] instead of {type:'group', ...}
var layout = use('layout') var layout = use('layout')
var graphics = use('graphics') var graphics = use('graphics')
var clay = {} var clay = {}
// Unique key objects for tree traversal (used by clay_input)
var CHILDREN = {}
var PARENT = {}
clay.CHILDREN = CHILDREN
clay.PARENT = PARENT
// Layout context // Layout context
var lay_ctx = layout.make_context() var lay_ctx = layout.make_context()
@@ -65,28 +69,49 @@ var config_stack = []
// Rewriting state management for cleaner recursion // Rewriting state management for cleaner recursion
var tree_stack = [] var tree_stack = []
var _next_id = 0
function annotate_tree(node, root_height, parent_node) {
var rect = lay_ctx.get_rect(node.id)
node.boundingbox = {
x: rect.x,
y: root_height - (rect.y + rect.height),
width: rect.width,
height: rect.height
}
node[CHILDREN] = node.children
node[PARENT] = parent_node
arrfor(node.children, function(child) {
annotate_tree(child, root_height, node)
})
}
clay.layout = function(fn, size) { clay.layout = function(fn, size) {
lay_ctx.reset() lay_ctx.reset()
_next_id = 0
var root_id = lay_ctx.item() var root_id = lay_ctx.item()
lay_ctx.set_size(root_id, size) lay_ctx.set_size(root_id, size)
lay_ctx.set_contain(root_id, layout.contain.row) lay_ctx.set_contain(root_id, layout.contain.row)
var root_node = { var root_node = {
id: root_id, id: root_id,
config: meme(base_config, {size: size}), config: meme(base_config, {size: size}),
children: [] children: []
} }
tree_stack = [root_node] tree_stack = [root_node]
fn() // User builds tree fn() // User builds tree
lay_ctx.run() lay_ctx.run()
// Post-layout: build flat drawable list // Annotate tree for clay_input (boundingbox, CHILDREN, PARENT)
return build_drawables(root_node, size.height) annotate_tree(root_node, size.height, null)
// Build flat drawable list and attach to tree root
root_node.drawables = build_drawables(root_node, size.height)
return root_node
} }
function build_drawables(node, root_height, parent, parent_scissor) { function build_drawables(node, root_height, parent, parent_scissor) {
@@ -130,8 +155,10 @@ function build_drawables(node, root_height, parent, parent_scissor) {
// Background // Background
if (node.config.background_image) { if (node.config.background_image) {
_next_id = _next_id + 1
if (node.config.slice) { if (node.config.slice) {
push(drawables, { drawables[] = {
_id: _next_id,
type: 'sprite', type: 'sprite',
image: node.config.background_image, image: node.config.background_image,
pos: {x: vis_x, y: vis_y}, pos: {x: vis_x, y: vis_y},
@@ -139,11 +166,12 @@ function build_drawables(node, root_height, parent, parent_scissor) {
height: rect.height, height: rect.height,
slice: node.config.slice, slice: node.config.slice,
color: node.config.background_color || {r:1, g:1, b:1, a:1}, color: node.config.background_color || {r:1, g:1, b:1, a:1},
layer: p_layer - 0.1, // slightly behind content layer: p_layer - 0.1,
scissor: current_scissor scissor: current_scissor
}) }
} else { } else {
push(drawables, { drawables[] = {
_id: _next_id,
type: 'sprite', type: 'sprite',
image: node.config.background_image, image: node.config.background_image,
pos: {x: vis_x, y: vis_y}, pos: {x: vis_x, y: vis_y},
@@ -152,10 +180,12 @@ function build_drawables(node, root_height, parent, parent_scissor) {
color: node.config.background_color || {r:1, g:1, b:1, a:1}, color: node.config.background_color || {r:1, g:1, b:1, a:1},
layer: p_layer - 0.1, layer: p_layer - 0.1,
scissor: current_scissor scissor: current_scissor
}) }
} }
} else if (node.config.background_color) { } else if (node.config.background_color) {
push(drawables, { _next_id = _next_id + 1
drawables[] = {
_id: _next_id,
type: 'rect', type: 'rect',
pos: {x: vis_x, y: vis_y}, pos: {x: vis_x, y: vis_y},
width: rect.width, width: rect.width,
@@ -163,43 +193,39 @@ function build_drawables(node, root_height, parent, parent_scissor) {
color: node.config.background_color, color: node.config.background_color,
layer: p_layer - 0.1, layer: p_layer - 0.1,
scissor: current_scissor scissor: current_scissor
}) }
} }
// Content (Image/Text) // Content (Image/Text)
if (node.config.image) { if (node.config.image) {
push(drawables, { _next_id = _next_id + 1
drawables[] = {
_id: _next_id,
type: 'sprite', type: 'sprite',
image: node.config.image, image: node.config.image,
pos: {x: vis_x, y: vis_y}, pos: {x: vis_x, y: vis_y},
width: rect.width, width: rect.width,
height: rect.height, height: rect.height,
color: node.config.color, color: node.config.color,
layer: p_layer, layer: p_layer,
scissor: current_scissor scissor: current_scissor
}) }
} }
if (node.config.text) { if (node.config.text) {
push(drawables, { _next_id = _next_id + 1
drawables[] = {
_id: _next_id,
type: 'text', type: 'text',
text: node.config.text, text: node.config.text,
font: node.config.font_path, font: node.config.font_path,
size: node.config.font_size, size: node.config.font_size,
color: node.config.color, color: node.config.color,
pos: {x: vis_x, y: vis_y + rect.height}, // Baseline adjustment pos: {x: vis_x, y: vis_y + rect.height},
anchor_y: 1.0, // Text usually draws from baseline up or top down? anchor_y: 1.0,
// film2d text uses top-left by default unless anchor set.
// Original clay put it at `y + rect.height`.
// Let's assume origin top-left, so we might need anchor adjustment or just position.
// If frame is top-down (0 at top), `abs_y` is top.
// `rect.y` in layout is bottom-up? "rect.y is from bottom" says original comment.
// `abs_y = root_height - (rect.y + rect.height)` -> Top edge of element.
// Text usually wants baseline.
// If we put it at `vis_y + rect.height`, that's bottom of element.
layer: p_layer, layer: p_layer,
scissor: current_scissor scissor: current_scissor
}) }
} }
// Children // Children
@@ -216,6 +242,20 @@ function build_drawables(node, root_height, parent, parent_scissor) {
function process_configs(configs) { function process_configs(configs) {
var cfg = meme(base_config, configs) var cfg = meme(base_config, configs)
// Parse shorthand font string (e.g. 'blackcastle.64') into font_path and font_size
var font_parts = null
var parsed_size = null
if (cfg.font && is_text(cfg.font)) {
font_parts = array(cfg.font, '.')
if (length(font_parts) >= 2) {
parsed_size = number(font_parts[length(font_parts) - 1])
if (parsed_size) {
cfg.font_size = parsed_size
cfg.font_path = font_parts[0]
}
}
}
cfg.color = normalize_color(cfg.color, base_config.color) cfg.color = normalize_color(cfg.color, base_config.color)
if (cfg.background_color) cfg.background_color = normalize_color(cfg.background_color, {r:1,g:1,b:1,a:1}) if (cfg.background_color) cfg.background_color = normalize_color(cfg.background_color, {r:1,g:1,b:1,a:1})
@@ -250,15 +290,15 @@ function push_node(configs, contain_mode) {
// Add to parent // Add to parent
var parent = tree_stack[length(tree_stack)-1] var parent = tree_stack[length(tree_stack)-1]
push(parent.children, node) parent.children[] = node
lay_ctx.insert(parent.id, item) lay_ctx.insert(parent.id, item)
push(tree_stack, node) tree_stack[] = node
return node return node
} }
function pop_node() { function pop_node() {
pop(tree_stack) tree_stack[]
} }
// Generic container // Generic container
@@ -305,34 +345,34 @@ clay.zstack = function(configs, fn) {
} }
// Leaf nodes // Leaf nodes
clay.image = function(path, configs) { clay.image = function(path, configs, extra) {
var img = graphics.texture(path) var img = graphics.texture(path)
var c = [{image: path}] var c = [{image: path}]
var final_config = process_configs(configs) var _configs = configs ? (is_array(configs) ? configs : [configs]) : []
if (extra) _configs = array(_configs, is_array(extra) ? extra : [extra])
var final_config = process_configs(_configs)
if (!final_config.size && !final_config.behave) if (!final_config.size && !final_config.behave)
c.size = {width: img.width, height: img.height} c[] = {size: {width: img.width, height: img.height}}
var _configs = is_array(configs) ? configs : [configs]
push_node(array(c, _configs), null) push_node(array(c, _configs), null)
pop_node() pop_node()
} }
clay.text = function(str, configs) { clay.text = function(str, configs, extra) {
var c = [{text: str}] var c = [{text: str}]
var final_config = process_configs(configs) var _configs = configs ? (is_array(configs) ? configs : [configs]) : []
if (extra) _configs = array(_configs, is_array(extra) ? extra : [extra])
var final_config = process_configs(_configs)
if (!final_config.size && !final_config.behave) { if (!final_config.size && !final_config.behave) {
c.size = {width: 100, height: 20} c[] = {size: {width: 100, height: 20}}
} }
var _configs = is_array(configs) ? configs : [configs]
push_node(array(c, _configs), null) push_node(array(c, _configs), null)
pop_node() pop_node()
} }
clay.rectangle = function(configs) { clay.rectangle = function(configs) {
var _configs = is_array(configs) ? configs : [configs] var _configs = configs ? (is_array(configs) ? configs : [configs]) : [{}]
push_node(_configs, null) push_node(_configs, null)
pop_node() pop_node()
} }
@@ -350,6 +390,47 @@ clay.button = function(str, action, configs) {
}) })
} }
// Spacer — fills available space
clay.spacer = function(config) {
var cfg = config || {}
if (!cfg.behave) cfg.behave = layout.behave.hfill | layout.behave.vfill
push_node([cfg], null)
pop_node()
}
// Convenience draw wrapper — auto-detects call patterns:
// clay.draw(fn) — default 640x360
// clay.draw(fn, size_obj) — fn first, size object second
// clay.draw(size_array, fn) — size array first, fn second
clay.draw = function(arg1, arg2) {
var fn = null
var size = {width: 640, height: 360}
if (is_function(arg1)) {
fn = arg1
if (arg2) {
if (is_array(arg2)) size = {width: arg2[0], height: arg2[1]}
else if (is_object(arg2)) size = arg2
}
} else if (is_array(arg1)) {
size = {width: arg1[0], height: arg1[1]}
fn = arg2
}
return clay.layout(fn, size)
}
// Offset all drawables in an array by a position
clay.offset_drawables = function(drawables, offset) {
var result = []
var i = 0
var d = null
for (i = 0; i < length(drawables); i = i + 1) {
d = meme(drawables[i])
d.pos = {x: d.pos.x + offset.x, y: d.pos.y + offset.y}
result[] = d
}
return result
}
// Constants // Constants
clay.behave = layout.behave clay.behave = layout.behave
clay.contain = layout.contain clay.contain = layout.contain

View File

@@ -34,7 +34,8 @@ function find_path(node, path, pos) {
if (!pointer_enabled(node)) return null if (!pointer_enabled(node)) return null
if (!rect_contains(node, pos)) return null if (!rect_contains(node, pos)) return null
var next_path = array(path, node) var next_path = array(path)
next_path[] = node
var i = 0 var i = 0
var child = null var child = null
var child_path = null var child_path = null
@@ -79,7 +80,7 @@ clay_input.click = function click(tree_root, mousepos, button) {
clay_input.get_actionable = function get_actionable(tree_root) { clay_input.get_actionable = function get_actionable(tree_root) {
var actionable = [] var actionable = []
function walk(node) { function walk(node) {
if (node.config.action) push(actionable, node) if (node.config.action) actionable[] = node
if (node[clay.CHILDREN]) if (node[clay.CHILDREN])
arrfor(node[clay.CHILDREN], walk) arrfor(node[clay.CHILDREN], walk)
} }
@@ -90,7 +91,7 @@ clay_input.get_actionable = function get_actionable(tree_root) {
clay_input.filter = function filter(tree_root, predicate) { clay_input.filter = function filter(tree_root, predicate) {
var results = [] var results = []
function rec(node) { function rec(node) {
if (predicate(node)) push(results, node) if (predicate(node)) results[] = node
if (node[clay.CHILDREN]) if (node[clay.CHILDREN])
arrfor(node[clay.CHILDREN], rec) arrfor(node[clay.CHILDREN], rec)
} }

View File

@@ -73,7 +73,7 @@ collision2d.overlap = function(body, pos, others) {
for (i = 0; i < length(others); i++) { for (i = 0; i < length(others); i++) {
other = others[i] other = others[i]
if (collision2d.test(body, pos, other.body, other.pos)) if (collision2d.test(body, pos, other.body, other.pos))
push(results, other) results[] = other
} }
return results return results
} }
@@ -94,12 +94,12 @@ collision2d.overlap_point = function(point, bodies) {
hw = b.body.width * 0.5 hw = b.body.width * 0.5
hh = b.body.height * 0.5 hh = b.body.height * 0.5
if (abs(point.x - c.x) < hw && abs(point.y - c.y) < hh) if (abs(point.x - c.x) < hw && abs(point.y - c.y) < hh)
push(results, b) results[] = b
} else if (b.body.type == 'circle') { } else if (b.body.type == 'circle') {
dx = point.x - c.x dx = point.x - c.x
dy = point.y - c.y dy = point.y - c.y
if (dx * dx + dy * dy < b.body.radius * b.body.radius) if (dx * dx + dy * dy < b.body.radius * b.body.radius)
push(results, b) results[] = b
} }
} }
return results return results

View File

@@ -23,7 +23,7 @@ compositor.compile = function(config) {
// Clear screen // Clear screen
if (config.clear) if (config.clear)
push(ctx.passes, {type: 'clear', target: 'screen', color: config.clear}) ctx.passes[] = {type: 'clear', target: 'screen', color: config.clear}
// Process each plane (supports both 'planes' and legacy 'layers' key) // Process each plane (supports both 'planes' and legacy 'layers' key)
var planes = config.planes || config.layers || [] var planes = config.planes || config.layers || []
@@ -44,11 +44,11 @@ compositor.compile = function(config) {
} }
function compile_imgui_layer(layer, ctx) { function compile_imgui_layer(layer, ctx) {
push(ctx.passes, { ctx.passes[] = {
type: 'imgui', type: 'imgui',
target: 'screen', target: 'screen',
draw: layer.draw draw: layer.draw
}) }
} }
function compile_plane(plane_config, ctx, group_effects) { function compile_plane(plane_config, ctx, group_effects) {
@@ -75,7 +75,7 @@ function compile_plane(plane_config, ctx, group_effects) {
var di = 0 var di = 0
if (plane_config.drawables) { if (plane_config.drawables) {
for (di = 0; di < length(plane_config.drawables); di++) for (di = 0; di < length(plane_config.drawables); di++)
push(all_sprites, plane_config.drawables[di]) all_sprites[] = plane_config.drawables[di]
} }
// Find which sprites belong to groups with effects // Find which sprites belong to groups with effects
@@ -110,21 +110,21 @@ function compile_plane(plane_config, ctx, group_effects) {
if (group_effects[gname]) { if (group_effects[gname]) {
if (!effect_groups[gname]) if (!effect_groups[gname])
effect_groups[gname] = {sprites: [], effects: group_effects[gname].effects} effect_groups[gname] = {sprites: [], effects: group_effects[gname].effects}
push(effect_groups[gname].sprites, s) effect_groups[gname].sprites[] = s
assigned = true assigned = true
break // Only assign to first matching effect group break // Only assign to first matching effect group
} }
} }
// Add to base sprites if not assigned to effect group and not mask-only // Add to base sprites if not assigned to effect group and not mask-only
if (!assigned && !is_mask_only) push(base_sprites, s) if (!assigned && !is_mask_only) base_sprites[] = s
} }
// Allocate plane target // Allocate plane target
var plane_target = ctx.alloc(res.width, res.height, plane_config.name) var plane_target = ctx.alloc(res.width, res.height, plane_config.name)
// Always clear plane target to prevent stale data between frames // Always clear plane target to prevent stale data between frames
push(ctx.passes, {type: 'clear', target: plane_target, color: plane_config.clear || {r: 0, g: 0, b: 0, a: 0}}) ctx.passes[] = {type: 'clear', target: plane_target, color: plane_config.clear || {r: 0, g: 0, b: 0, a: 0}}
// Render each effect group to temp target, apply effects, composite back // Render each effect group to temp target, apply effects, composite back
arrfor(array(effect_groups), gname => { arrfor(array(effect_groups), gname => {
@@ -134,7 +134,7 @@ function compile_plane(plane_config, ctx, group_effects) {
var group_target = ctx.alloc(res.width, res.height, gname + '_content') var group_target = ctx.alloc(res.width, res.height, gname + '_content')
// Render group content // Render group content
push(ctx.passes, { ctx.passes[] = {
type: 'render', type: 'render',
renderer: 'film2d', renderer: 'film2d',
drawables: eg.sprites, drawables: eg.sprites,
@@ -143,7 +143,7 @@ function compile_plane(plane_config, ctx, group_effects) {
target_size: res, target_size: res,
layer_sort: layer_sort, layer_sort: layer_sort,
clear: {r: 0, g: 0, b: 0, a: 0} clear: {r: 0, g: 0, b: 0, a: 0}
}) }
// Apply effects // Apply effects
var current = group_target var current = group_target
@@ -155,19 +155,19 @@ function compile_plane(plane_config, ctx, group_effects) {
} }
// Composite result to plane // Composite result to plane
push(ctx.passes, { ctx.passes[] = {
type: 'composite', type: 'composite',
source: current, source: current,
dest: plane_target, dest: plane_target,
source_size: res, source_size: res,
dest_size: res, dest_size: res,
blend: 'over' blend: 'over'
}) }
}) })
// Render base sprites (no effects) // Render base sprites (no effects)
if (length(base_sprites) > 0) { if (length(base_sprites) > 0) {
push(ctx.passes, { ctx.passes[] = {
type: 'render', type: 'render',
renderer: 'film2d', renderer: 'film2d',
drawables: base_sprites, drawables: base_sprites,
@@ -176,17 +176,17 @@ function compile_plane(plane_config, ctx, group_effects) {
target_size: res, target_size: res,
layer_sort: layer_sort, layer_sort: layer_sort,
clear: null // Don't clear, blend on top clear: null // Don't clear, blend on top
}) }
} }
// Composite plane to screen // Composite plane to screen
push(ctx.passes, { ctx.passes[] = {
type: 'blit_to_screen', type: 'blit_to_screen',
source: plane_target, source: plane_target,
source_size: res, source_size: res,
dest_size: ctx.screen_size, dest_size: ctx.screen_size,
presentation: plane_config.presentation || 'stretch' presentation: plane_config.presentation || 'stretch'
}) }
} }
function apply_effect(ctx, effect, input, params) { function apply_effect(ctx, effect, input, params) {
@@ -212,25 +212,25 @@ function apply_effect(ctx, effect, input, params) {
blur2 = ctx.alloc(size.width, size.height, hint + '_blur2') blur2 = ctx.alloc(size.width, size.height, hint + '_blur2')
// Threshold // Threshold
push(ctx.passes, { ctx.passes[] = {
type: 'shader_pass', type: 'shader_pass',
shader: 'threshold', shader: 'threshold',
input: input, input: input,
output: bright, output: bright,
uniforms: {threshold: effect.threshold || 0.8, intensity: effect.intensity || 1} uniforms: {threshold: effect.threshold || 0.8, intensity: effect.intensity || 1}
}) }
// Blur passes // Blur passes
blur_passes = effect.blur_passes || 2 blur_passes = effect.blur_passes || 2
blur_in = bright blur_in = bright
for (p = 0; p < blur_passes; p++) { for (p = 0; p < blur_passes; p++) {
push(ctx.passes, {type: 'shader_pass', shader: 'blur', input: blur_in, output: blur1, uniforms: {direction: {x: 1, y: 0}, texel_size: {x: 1/size.width, y: 1/size.height}}}) ctx.passes[] = {type: 'shader_pass', shader: 'blur', input: blur_in, output: blur1, uniforms: {direction: {x: 1, y: 0}, texel_size: {x: 1/size.width, y: 1/size.height}}}
push(ctx.passes, {type: 'shader_pass', shader: 'blur', input: blur1, output: blur2, uniforms: {direction: {x: 0, y: 1}, texel_size: {x: 1/size.width, y: 1/size.height}}}) ctx.passes[] = {type: 'shader_pass', shader: 'blur', input: blur1, output: blur2, uniforms: {direction: {x: 0, y: 1}, texel_size: {x: 1/size.width, y: 1/size.height}}}
blur_in = blur2 blur_in = blur2
} }
// Composite bloom // Composite bloom
push(ctx.passes, {type: 'composite_textures', base: input, overlay: blur2, output: output, mode: 'add'}) ctx.passes[] = {type: 'composite_textures', base: input, overlay: blur2, output: output, mode: 'add'}
} else if (effect.type == 'mask') { } else if (effect.type == 'mask') {
mask_group = effect.mask_group mask_group = effect.mask_group
@@ -241,7 +241,7 @@ function apply_effect(ctx, effect, input, params) {
mask_target = ctx.alloc(size.width, size.height, hint + '_mask') mask_target = ctx.alloc(size.width, size.height, hint + '_mask')
// Render mask // Render mask
push(ctx.passes, { ctx.passes[] = {
type: 'render', type: 'render',
renderer: 'film2d', renderer: 'film2d',
drawables: mask_sprites, drawables: mask_sprites,
@@ -249,24 +249,24 @@ function apply_effect(ctx, effect, input, params) {
target: mask_target, target: mask_target,
target_size: size, target_size: size,
clear: {r: 0, g: 0, b: 0, a: 0} clear: {r: 0, g: 0, b: 0, a: 0}
}) }
// Apply mask // Apply mask
push(ctx.passes, { ctx.passes[] = {
type: 'apply_mask', type: 'apply_mask',
content: input, content: input,
mask: mask_target, mask: mask_target,
output: output, output: output,
mode: effect.channel || 'alpha', mode: effect.channel || 'alpha',
invert: effect.invert || false invert: effect.invert || false
}) }
} else { } else {
// No mask sprites, pass through // No mask sprites, pass through
push(ctx.passes, {type: 'blit', source: input, dest: output}) ctx.passes[] = {type: 'blit', source: input, dest: output}
} }
} else { } else {
// Unknown effect, pass through // Unknown effect, pass through
push(ctx.passes, {type: 'blit', source: input, dest: output}) ctx.passes[] = {type: 'blit', source: input, dest: output}
} }
return output return output
@@ -302,8 +302,8 @@ compositor.execute = function(plan) {
if (pass.type == 'clear') { if (pass.type == 'clear') {
target = resolve(pass.target) target = resolve(pass.target)
push(commands, {cmd: 'begin_render', target: target, clear: pass.color}) commands[] = {cmd: 'begin_render', target: target, clear: pass.color}
push(commands, {cmd: 'end_render'}) commands[] = {cmd: 'end_render'}
} else if (pass.type == 'render') { } else if (pass.type == 'render') {
result = film2d.render({ result = film2d.render({
@@ -315,68 +315,68 @@ compositor.execute = function(plan) {
clear: pass.clear clear: pass.clear
}, backend) }, backend)
for (c = 0; c < length(result.commands); c++) for (c = 0; c < length(result.commands); c++)
push(commands, result.commands[c]) commands[] = result.commands[c]
} else if (pass.type == 'shader_pass') { } else if (pass.type == 'shader_pass') {
push(commands, { commands[] = {
cmd: 'shader_pass', cmd: 'shader_pass',
shader: pass.shader, shader: pass.shader,
input: resolve(pass.input), input: resolve(pass.input),
output: resolve(pass.output), output: resolve(pass.output),
uniforms: pass.uniforms uniforms: pass.uniforms
}) }
} else if (pass.type == 'composite_textures') { } else if (pass.type == 'composite_textures') {
push(commands, { commands[] = {
cmd: 'composite_textures', cmd: 'composite_textures',
base: resolve(pass.base), base: resolve(pass.base),
overlay: resolve(pass.overlay), overlay: resolve(pass.overlay),
output: resolve(pass.output), output: resolve(pass.output),
mode: pass.mode mode: pass.mode
}) }
} else if (pass.type == 'apply_mask') { } else if (pass.type == 'apply_mask') {
push(commands, { commands[] = {
cmd: 'apply_mask', cmd: 'apply_mask',
content_texture: resolve(pass.content), content_texture: resolve(pass.content),
mask_texture: resolve(pass.mask), mask_texture: resolve(pass.mask),
output: resolve(pass.output), output: resolve(pass.output),
mode: pass.mode, mode: pass.mode,
invert: pass.invert invert: pass.invert
}) }
} else if (pass.type == 'composite') { } else if (pass.type == 'composite') {
push(commands, { commands[] = {
cmd: 'blit', cmd: 'blit',
texture: resolve(pass.source), texture: resolve(pass.source),
target: resolve(pass.dest), target: resolve(pass.dest),
dst_rect: {x: 0, y: 0, width: pass.dest_size.width, height: pass.dest_size.height} dst_rect: {x: 0, y: 0, width: pass.dest_size.width, height: pass.dest_size.height}
}) }
} else if (pass.type == 'blit_to_screen') { } else if (pass.type == 'blit_to_screen') {
rect = _calc_presentation(pass.source_size, pass.dest_size, pass.presentation) rect = _calc_presentation(pass.source_size, pass.dest_size, pass.presentation)
push(commands, { commands[] = {
cmd: 'blit', cmd: 'blit',
texture: resolve(pass.source), texture: resolve(pass.source),
target: 'screen', target: 'screen',
dst_rect: rect, dst_rect: rect,
filter: pass.presentation == 'integer_scale' ? 'nearest' : 'linear' filter: pass.presentation == 'integer_scale' ? 'nearest' : 'linear'
}) }
} else if (pass.type == 'blit') { } else if (pass.type == 'blit') {
src = resolve(pass.source) src = resolve(pass.source)
dst = resolve(pass.dest) dst = resolve(pass.dest)
push(commands, { commands[] = {
cmd: 'blit', cmd: 'blit',
texture: src, texture: src,
target: dst, target: dst,
dst_rect: {x: 0, y: 0, width: dst.width, height: dst.height} dst_rect: {x: 0, y: 0, width: dst.width, height: dst.height}
}) }
} else if (pass.type == 'imgui') { } else if (pass.type == 'imgui') {
push(commands, { commands[] = {
cmd: 'imgui', cmd: 'imgui',
target: resolve(pass.target), target: resolve(pass.target),
draw: pass.draw draw: pass.draw
}) }
} }
} }
@@ -425,7 +425,7 @@ compositor.snapshot = function() {
for (i = 0; i < length(_last_plan.passes); i++) { for (i = 0; i < length(_last_plan.passes); i++) {
pass = _last_plan.passes[i] pass = _last_plan.passes[i]
if (pass.type == 'render') { if (pass.type == 'render') {
push(planes, { planes[] = {
drawable_count: length(pass.drawables), drawable_count: length(pass.drawables),
camera: pass.camera ? { camera: pass.camera ? {
pos: pass.camera.pos, pos: pass.camera.pos,
@@ -433,7 +433,7 @@ compositor.snapshot = function() {
height: pass.camera.height height: pass.camera.height
} : null, } : null,
target_size: pass.target_size target_size: pass.target_size
}) }
} }
} }
return { return {

View File

@@ -78,6 +78,9 @@ core.start = function(config) {
// Start main loop // Start main loop
_main_loop() _main_loop()
// Call start callback after the first frame and main loop are established
if (config.start) config.start()
return true return true
} }
@@ -105,7 +108,7 @@ function fps_add_sample(sample) {
var n = length(_fps_samples) var n = length(_fps_samples)
var old = null var old = null
if (n < _fps_sample_count) { if (n < _fps_sample_count) {
push(_fps_samples, sample) _fps_samples[] = sample
_fps_sample_sum += sample _fps_sample_sum += sample
} else { } else {
old = _fps_samples[_fps_sample_pos] old = _fps_samples[_fps_sample_pos]
@@ -225,7 +228,7 @@ function _main_loop() {
// Handle both compositor result ({commands: [...]}) and fx_graph (graph object) // Handle both compositor result ({commands: [...]}) and fx_graph (graph object)
if (render_result.commands) { if (render_result.commands) {
if (_config.imgui || _config.editor) { if (_config.imgui || _config.editor) {
push(render_result.commands, { render_result.commands[] = {
cmd: 'imgui', cmd: 'imgui',
draw: function(ui) { draw: function(ui) {
if (_config.imgui) _config.imgui(ui) if (_config.imgui) _config.imgui(ui)
@@ -235,7 +238,7 @@ function _main_loop() {
} }
}, },
target: 'screen' target: 'screen'
}) }
} }
// Compositor result - execute commands directly // Compositor result - execute commands directly
_backend.execute_commands(render_result.commands, win_size, dbg) _backend.execute_commands(render_result.commands, win_size, dbg)

View File

@@ -144,31 +144,31 @@ function _render_node_summary(imgui, node) {
var info = [] var info = []
if (node.pos) { if (node.pos) {
push(info, "pos:(" + text(round(node.pos.x)) + "," + text(round(node.pos.y)) + ")") info[] = "pos:(" + text(round(node.pos.x)) + "," + text(round(node.pos.y)) + ")"
} }
if (node.width && node.height) { if (node.width && node.height) {
push(info, "size:" + text(node.width) + "x" + text(node.height)) info[] = "size:" + text(node.width) + "x" + text(node.height)
} }
if (node.image) { if (node.image) {
push(info, "img:" + node.image) info[] = "img:" + node.image
} }
var t = null var t = null
if (node.text) { if (node.text) {
t = node.text t = node.text
if (length(t) > 20) t = text(t, 0, 17) + "..." if (length(t) > 20) t = text(t, 0, 17) + "..."
push(info, "\"" + t + "\"") info[] = "\"" + t + "\""
} }
var fx = [] var fx = []
var j = 0 var j = 0
if (node.effects && length(node.effects) > 0) { if (node.effects && length(node.effects) > 0) {
for (j = 0; j < length(node.effects); j++) { for (j = 0; j < length(node.effects); j++) {
push(fx, node.effects[j].type) fx[] = node.effects[j].type
} }
push(info, "fx:[" + text(fx, ",") + "]") info[] = "fx:[" + text(fx, ",") + "]"
} }
if (length(info) > 0) { if (length(info) > 0) {

View File

@@ -36,7 +36,7 @@ effects.register('bloom', {
// Threshold extraction // Threshold extraction
var thresh_target = ctx.alloc_target(size.width, size.height, 'bloom_thresh') var thresh_target = ctx.alloc_target(size.width, size.height, 'bloom_thresh')
push(passes, { passes[] = {
type: 'shader', type: 'shader',
shader: 'threshold', shader: 'threshold',
input: input, input: input,
@@ -45,7 +45,7 @@ effects.register('bloom', {
threshold: params.threshold != null ? params.threshold : 0.8, threshold: params.threshold != null ? params.threshold : 0.8,
intensity: params.intensity != null ? params.intensity : 1.0 intensity: params.intensity != null ? params.intensity : 1.0
} }
}) }
// Blur ping-pong // Blur ping-pong
var blur_a = ctx.alloc_target(size.width, size.height, 'bloom_blur_a') var blur_a = ctx.alloc_target(size.width, size.height, 'bloom_blur_a')
@@ -56,31 +56,31 @@ effects.register('bloom', {
var i = 0 var i = 0
for (i = 0; i < blur_count; i++) { for (i = 0; i < blur_count; i++) {
push(passes, { passes[] = {
type: 'shader', type: 'shader',
shader: 'blur', shader: 'blur',
input: blur_src, input: blur_src,
output: blur_a, output: blur_a,
uniforms: {direction: {x: 2, y: 0}, texel_size: texel} uniforms: {direction: {x: 2, y: 0}, texel_size: texel}
}) }
push(passes, { passes[] = {
type: 'shader', type: 'shader',
shader: 'blur', shader: 'blur',
input: blur_a, input: blur_a,
output: blur_b, output: blur_b,
uniforms: {direction: {x: 0, y: 2}, texel_size: texel} uniforms: {direction: {x: 0, y: 2}, texel_size: texel}
}) }
blur_src = blur_b blur_src = blur_b
} }
// Additive composite // Additive composite
push(passes, { passes[] = {
type: 'composite', type: 'composite',
base: input, base: input,
overlay: blur_src, overlay: blur_src,
output: output, output: output,
blend: 'add' blend: 'add'
}) }
return passes return passes
} }
@@ -125,16 +125,16 @@ effects.register('mask', {
// Render mask source to target // Render mask source to target
var mask_target = ctx.alloc_target(size.width, size.height, 'mask_src') var mask_target = ctx.alloc_target(size.width, size.height, 'mask_src')
push(passes, { passes[] = {
type: 'render_subtree', type: 'render_subtree',
root: mask_source, root: mask_source,
output: mask_target, output: mask_target,
clear: {r: 0, g: 0, b: 0, a: 0}, clear: {r: 0, g: 0, b: 0, a: 0},
space: params.space || 'local' space: params.space || 'local'
}) }
// Apply mask shader // Apply mask shader
push(passes, { passes[] = {
type: 'shader', type: 'shader',
shader: 'mask', shader: 'mask',
inputs: [input, mask_target], inputs: [input, mask_target],
@@ -143,7 +143,7 @@ effects.register('mask', {
channel: params.channel == 'alpha' ? 0 : 1, channel: params.channel == 'alpha' ? 0 : 1,
invert: params.invert ? 1 : 0 invert: params.invert ? 1 : 0
} }
}) }
return passes return passes
} }
@@ -192,25 +192,25 @@ effects.register('blur', {
var i = 0 var i = 0
for (i = 0; i < blur_count; i++) { for (i = 0; i < blur_count; i++) {
push(passes, { passes[] = {
type: 'shader', type: 'shader',
shader: 'blur', shader: 'blur',
input: src, input: src,
output: blur_a, output: blur_a,
uniforms: {direction: {x: 2, y: 0}, texel_size: texel} uniforms: {direction: {x: 2, y: 0}, texel_size: texel}
}) }
push(passes, { passes[] = {
type: 'shader', type: 'shader',
shader: 'blur', shader: 'blur',
input: blur_a, input: blur_a,
output: blur_b, output: blur_b,
uniforms: {direction: {x: 0, y: 2}, texel_size: texel} uniforms: {direction: {x: 0, y: 2}, texel_size: texel}
}) }
src = blur_b src = blur_b
} }
// Final blit to output // Final blit to output
push(passes, {type: 'blit', source: src, dest: output}) passes[] = {type: 'blit', source: src, dest: output}
return passes return passes
} }
}) })

View File

@@ -47,8 +47,8 @@ function add_bunny(x, y) {
anchor_x: 0.5, anchor_y: 0.5, anchor_x: 0.5, anchor_y: 0.5,
plane: 'game' plane: 'game'
}) })
push(bunnies, bunny) bunnies[] = bunny
push(bunny_sprites, s) bunny_sprites[] = s
} }
// Initial bunnies // Initial bunnies

View File

@@ -29,14 +29,14 @@ function init(grid) {
row = [] row = []
for (bx = 0; bx < 8; bx++) { for (bx = 0; bx < 8; bx++) {
col = ((bx + by) & 1) ? dark_color : light_color col = ((bx + by) & 1) ? dark_color : light_color
push(row, shape.rect({ row[] = shape.rect({
pos: {x: bx * S + S / 2, y: by * S + S / 2}, pos: {x: bx * S + S / 2, y: by * S + S / 2},
width: S, height: S, width: S, height: S,
fill: {r: col.r, g: col.g, b: col.b, a: col.a}, fill: {r: col.r, g: col.g, b: col.b, a: col.a},
plane: 'game', layer: 0 plane: 'game', layer: 0
})) })
} }
push(board_shapes, row) board_shapes[] = row
} }
next_id = 0 next_id = 0

View File

@@ -49,7 +49,7 @@ function compute_valid_moves(from) {
dest = grid.at(to) dest = grid.at(to)
if (length(dest) && dest[0].colour == piece.colour) continue if (length(dest) && dest[0].colour == piece.colour) continue
if (rules.canMove(piece, from, to, grid)) if (rules.canMove(piece, from, to, grid))
push(validMoves, to) validMoves[] = to
} }
} }
} }

View File

@@ -77,7 +77,7 @@ function compute_valid_moves(from) {
dest = grid.at(to) dest = grid.at(to)
if (length(dest) && dest[0].colour == piece.colour) continue if (length(dest) && dest[0].colour == piece.colour) continue
if (rules.canMove(piece, from, to, grid)) if (rules.canMove(piece, from, to, grid))
push(validMoves, to) validMoves[] = to
} }
} }
} }

View File

@@ -32,7 +32,7 @@ var grid_prototype = {
// add an entity into a cell // add an entity into a cell
add(entity, pos) { add(entity, pos) {
var cx = px(pos), cy = py(pos); var cx = px(pos), cy = py(pos);
push(this.cell(cx, cy), entity); this.cell(cx, cy)[] = entity;
entity.coord = [cx, cy]; entity.coord = [cx, cy];
}, },

View File

@@ -91,7 +91,7 @@ function compute_valid_moves(from) {
dest = grid.at(to) dest = grid.at(to)
if (length(dest) && dest[0].colour == piece.colour) continue if (length(dest) && dest[0].colour == piece.colour) continue
if (rules.canMove(piece, from, to, grid)) if (rules.canMove(piece, from, to, grid))
push(validMoves, to) validMoves[] = to
} }
} }
} }

View File

@@ -91,12 +91,12 @@ function reset_game() {
var cy = floor(gridH / 2) var cy = floor(gridH / 2)
var wp = null var wp = null
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
push(snake_pos, {x: cx - i, y: cy}) snake_pos[] = {x: cx - i, y: cy}
wp = grid_to_world(cx - i, cy) wp = grid_to_world(cx - i, cy)
push(snake_shapes, shape.rect({ snake_shapes[] = shape.rect({
pos: {x: wp.x, y: wp.y}, width: cellSize - 2, height: cellSize - 2, pos: {x: wp.x, y: wp.y}, width: cellSize - 2, height: cellSize - 2,
fill: {r: 0, g: 1, b: 0.3, a: 1}, plane: 'game' fill: {r: 0, g: 1, b: 0.3, a: 1}, plane: 'game'
})) })
} }
dir = {x: 1, y: 0} dir = {x: 1, y: 0}
@@ -166,7 +166,7 @@ core.start({
var old_wp = grid_to_world(snake_pos[0].x, snake_pos[0].y) var old_wp = grid_to_world(snake_pos[0].x, snake_pos[0].y)
var new_wp = grid_to_world(hx, hy) var new_wp = grid_to_world(hx, hy)
var new_pos = [{x: hx, y: hy}] var new_pos = [{x: hx, y: hy}]
for (i = 0; i < length(snake_pos); i++) push(new_pos, snake_pos[i]) for (i = 0; i < length(snake_pos); i++) new_pos[] = snake_pos[i]
snake_pos = new_pos snake_pos = new_pos
var head = shape.rect({ var head = shape.rect({
pos: {x: old_wp.x, y: old_wp.y}, width: cellSize - 2, height: cellSize - 2, pos: {x: old_wp.x, y: old_wp.y}, width: cellSize - 2, height: cellSize - 2,
@@ -175,7 +175,7 @@ core.start({
// Smooth tween from old position to new position // Smooth tween from old position to new position
tw.tween(head.pos).to({x: new_wp.x, y: new_wp.y}, move_interval).ease(ease.linear) tw.tween(head.pos).to({x: new_wp.x, y: new_wp.y}, move_interval).ease(ease.linear)
var new_shapes = [head] var new_shapes = [head]
for (i = 0; i < length(snake_shapes); i++) push(new_shapes, snake_shapes[i]) for (i = 0; i < length(snake_shapes); i++) new_shapes[] = snake_shapes[i]
snake_shapes = new_shapes snake_shapes = new_shapes
// Eat apple? // Eat apple?
@@ -185,9 +185,9 @@ core.start({
spawn_apple() spawn_apple()
} else { } else {
// Remove tail // Remove tail
tail = pop(snake_shapes) tail = snake_shapes[]
tail.destroy() tail.destroy()
pop(snake_pos) snake_pos[]
} }
}, },

View File

@@ -50,16 +50,16 @@ function init_board() {
row = [] row = []
srow = [] srow = []
for (c = 0; c < COLS; c++) { for (c = 0; c < COLS; c++) {
push(row, null) row[] = null
push(srow, shape.rect({ srow[] = shape.rect({
pos: {x: c * TILE + TILE / 2, y: r * TILE + TILE / 2}, pos: {x: c * TILE + TILE / 2, y: r * TILE + TILE / 2},
width: TILE - 1, height: TILE - 1, width: TILE - 1, height: TILE - 1,
fill: {r: 0.5, g: 0.5, b: 0.5, a: 1}, fill: {r: 0.5, g: 0.5, b: 0.5, a: 1},
plane: 'game', layer: 0, visible: false plane: 'game', layer: 0, visible: false
})) })
} }
push(board, row) board[] = row
push(board_shapes, srow) board_shapes[] = srow
} }
} }
@@ -104,10 +104,10 @@ var next_label = text2d({
var next_shapes = [] var next_shapes = []
var ns = 0 var ns = 0
for (ns = 0; ns < 4; ns++) { for (ns = 0; ns < 4; ns++) {
push(next_shapes, shape.rect({ next_shapes[] = shape.rect({
pos: {x: 0, y: 0}, width: TILE - 1, height: TILE - 1, pos: {x: 0, y: 0}, width: TILE - 1, height: TILE - 1,
fill: {r: 1, g: 1, b: 1, a: 1}, plane: 'game', layer: 2, visible: false fill: {r: 1, g: 1, b: 1, a: 1}, plane: 'game', layer: 2, visible: false
})) })
} }
function random_shape() { function random_shape() {
@@ -244,10 +244,10 @@ function place_piece() {
// Create 4 shapes for active piece (layer 1 = on top of board) // Create 4 shapes for active piece (layer 1 = on top of board)
var pi = 0 var pi = 0
for (pi = 0; pi < 4; pi++) { for (pi = 0; pi < 4; pi++) {
push(piece_shapes, shape.rect({ piece_shapes[] = shape.rect({
pos: {x: 0, y: 0}, width: TILE - 1, height: TILE - 1, pos: {x: 0, y: 0}, width: TILE - 1, height: TILE - 1,
fill: {r: 1, g: 1, b: 1, a: 1}, plane: 'game', layer: 1, visible: false fill: {r: 1, g: 1, b: 1, a: 1}, plane: 'game', layer: 1, visible: false
})) })
} }
init_board() init_board()

View File

@@ -129,7 +129,7 @@ film2d.register = function(drawable) {
// Index by plane // Index by plane
var plane = drawable.plane || 'default' var plane = drawable.plane || 'default'
if (!plane_index[plane]) plane_index[plane] = [] if (!plane_index[plane]) plane_index[plane] = []
push(plane_index[plane], id) plane_index[plane][] = id
// Index by groups (effect routing only) // Index by groups (effect routing only)
var groups = drawable.groups || [] var groups = drawable.groups || []
@@ -138,7 +138,7 @@ film2d.register = function(drawable) {
for (i = 0; i < length(groups); i++) { for (i = 0; i < length(groups); i++) {
g = groups[i] g = groups[i]
if (!group_index[g]) group_index[g] = [] if (!group_index[g]) group_index[g] = []
push(group_index[g], id) group_index[g][] = id
} }
return id return id
@@ -177,7 +177,7 @@ film2d.unregister = function(id) {
film2d.index_group = function(id, group) { film2d.index_group = function(id, group) {
if (!group_index[group]) group_index[group] = [] if (!group_index[group]) group_index[group] = []
if (search(group_index[group], text(id)) == null) if (search(group_index[group], text(id)) == null)
push(group_index[group], text(id)) group_index[group][] = text(id)
} }
film2d.unindex_group = function(id, group) { film2d.unindex_group = function(id, group) {
@@ -218,9 +218,9 @@ film2d.query = function(selector) {
// If also filtering by group, check membership // If also filtering by group, check membership
if (selector.group) { if (selector.group) {
groups = d.groups || [] groups = d.groups || []
if (search(groups, selector.group) != null) push(result, d) if (search(groups, selector.group) != null) result[] = d
} else { } else {
push(result, d) result[] = d
} }
} }
} }
@@ -232,7 +232,7 @@ film2d.query = function(selector) {
ids = group_index[selector.group] || [] ids = group_index[selector.group] || []
for (i = 0; i < length(ids); i++) { for (i = 0; i < length(ids); i++) {
d = registry[ids[i]] d = registry[ids[i]]
if (d && d.visible != false) push(result, d) if (d && d.visible != false) result[] = d
} }
return result return result
} }
@@ -245,7 +245,7 @@ film2d.query = function(selector) {
if (!seen[ids[i]]) { if (!seen[ids[i]]) {
seen[ids[i]] = true seen[ids[i]] = true
d = registry[ids[i]] d = registry[ids[i]]
if (d && d.visible != false) push(result, d) if (d && d.visible != false) result[] = d
} }
} }
} }
@@ -268,7 +268,7 @@ film2d.get_groups = function(id) {
film2d.all_groups = function() { film2d.all_groups = function() {
var groups = [] var groups = []
arrfor(array(group_index), g => { arrfor(array(group_index), g => {
if (length(group_index[g]) > 0) push(groups, g) if (length(group_index[g]) > 0) groups[] = g
}) })
return groups return groups
} }
@@ -312,7 +312,7 @@ film2d.render = function(params, render_backend) {
b = [] b = []
buckets[layer_key] = b buckets[layer_key] = b
} }
push(b, d) b[] = d
} }
// Sort layers numerically (keys are text) // Sort layers numerically (keys are text)
@@ -339,14 +339,14 @@ film2d.render = function(params, render_backend) {
if (!y_down) b = reverse(b) // y_up => smaller y draws later => reverse if (!y_down) b = reverse(b) // y_up => smaller y draws later => reverse
} }
for (j = 0; j < length(b); j++) push(sorted_drawables, b[j]) for (j = 0; j < length(b); j++) sorted_drawables[] = b[j]
} }
drawables = sorted_drawables drawables = sorted_drawables
var commands = [] var commands = []
push(commands, { cmd: "begin_render", target: target, clear: clear_color, target_size: target_size }) commands[] = { cmd: "begin_render", target: target, clear: clear_color, target_size: target_size }
push(commands, { cmd: "set_camera", camera: camera }) commands[] = { cmd: "set_camera", camera: camera }
var batches = _batch_drawables(drawables) var batches = _batch_drawables(drawables)
var batch = null var batch = null
@@ -354,18 +354,18 @@ film2d.render = function(params, render_backend) {
for (i = 0; i < length(batches); i++) { for (i = 0; i < length(batches); i++) {
batch = batches[i] batch = batches[i]
if (batch.type == "sprite_batch") if (batch.type == "sprite_batch")
push(commands, { cmd: "draw_batch", batch_type: "sprites", geometry: { sprites: batch.sprites }, texture: batch.texture, material: batch.material }) commands[] = { cmd: "draw_batch", batch_type: "sprites", geometry: { sprites: batch.sprites }, texture: batch.texture, material: batch.material }
else if (batch.type == "mesh2d_batch") else if (batch.type == "mesh2d_batch")
push(commands, { cmd: "draw_mesh2d", meshes: batch.meshes, texture: batch.texture, material: batch.material }) commands[] = { cmd: "draw_mesh2d", meshes: batch.meshes, texture: batch.texture, material: batch.material }
else if (batch.type == "text") else if (batch.type == "text")
push(commands, { cmd: "draw_text", drawable: batch.drawable }) commands[] = { cmd: "draw_text", drawable: batch.drawable }
else if (batch.type == "texture_ref") else if (batch.type == "texture_ref")
push(commands, { cmd: "draw_texture_ref", drawable: batch.drawable }) commands[] = { cmd: "draw_texture_ref", drawable: batch.drawable }
else if (batch.type == "shape") else if (batch.type == "shape")
push(commands, { cmd: "draw_shape", drawable: batch.drawable }) commands[] = { cmd: "draw_shape", drawable: batch.drawable }
} }
push(commands, { cmd: "end_render" }) commands[] = { cmd: "end_render" }
return { commands: commands } return { commands: commands }
} }
@@ -408,9 +408,9 @@ function _batch_drawables(drawables) {
mat = d.material || {blend: 'alpha', sampler: d.filter || 'nearest'} mat = d.material || {blend: 'alpha', sampler: d.filter || 'nearest'}
if (current && current.type == 'sprite_batch' && current.texture == tex && _mat_eq(current.material, mat)) { if (current && current.type == 'sprite_batch' && current.texture == tex && _mat_eq(current.material, mat)) {
push(current.sprites, d) current.sprites[] = d
} else { } else {
if (current) push(batches, current) if (current) batches[] = current
current = {type: 'sprite_batch', texture: tex, material: mat, sprites: [d]} current = {type: 'sprite_batch', texture: tex, material: mat, sprites: [d]}
} }
} else if (d.type == 'particles') { } else if (d.type == 'particles') {
@@ -437,9 +437,9 @@ function _batch_drawables(drawables) {
} }
if (current && current.type == 'sprite_batch' && current.texture == tex && _mat_eq(current.material, mat)) { if (current && current.type == 'sprite_batch' && current.texture == tex && _mat_eq(current.material, mat)) {
push(current.sprites, sprite) current.sprites[] = sprite
} else { } else {
if (current) push(batches, current) if (current) batches[] = current
current = {type: 'sprite_batch', texture: tex, material: mat, sprites: [sprite]} current = {type: 'sprite_batch', texture: tex, material: mat, sprites: [sprite]}
} }
} }
@@ -480,9 +480,9 @@ function _batch_drawables(drawables) {
tex = img tex = img
mat = default_mat mat = default_mat
if (current && current.type == 'sprite_batch' && current.texture == tex && _mat_eq(current.material, mat)) { if (current && current.type == 'sprite_batch' && current.texture == tex && _mat_eq(current.material, mat)) {
push(current.sprites, sprite) current.sprites[] = sprite
} else { } else {
if (current) push(batches, current) if (current) batches[] = current
current = {type: 'sprite_batch', texture: tex, material: mat, sprites: [sprite]} current = {type: 'sprite_batch', texture: tex, material: mat, sprites: [sprite]}
} }
} }
@@ -493,28 +493,28 @@ function _batch_drawables(drawables) {
mat = d.material || {blend: d.blend || 'alpha', sampler: d.filter || 'linear'} mat = d.material || {blend: d.blend || 'alpha', sampler: d.filter || 'linear'}
if (current && current.type == 'mesh2d_batch' && current.texture == tex && _mat_eq(current.material, mat)) { if (current && current.type == 'mesh2d_batch' && current.texture == tex && _mat_eq(current.material, mat)) {
push(current.meshes, d) current.meshes[] = d
} else { } else {
if (current) push(batches, current) if (current) batches[] = current
current = {type: 'mesh2d_batch', texture: tex, material: mat, meshes: [d]} current = {type: 'mesh2d_batch', texture: tex, material: mat, meshes: [d]}
} }
} else if (d.type == 'shape') { } else if (d.type == 'shape') {
// Shapes are rendered individually (each has unique SDF params) // Shapes are rendered individually (each has unique SDF params)
if (current) { if (current) {
push(batches, current) batches[] = current
current = null current = null
} }
push(batches, {type: 'shape', drawable: d}) batches[] = {type: 'shape', drawable: d}
} else { } else {
if (current) { if (current) {
push(batches, current) batches[] = current
current = null current = null
} }
push(batches, {type: d.type, drawable: d}) batches[] = {type: d.type, drawable: d}
} }
} }
if (current) push(batches, current) if (current) batches[] = current
return batches return batches
} }
@@ -531,7 +531,7 @@ film2d.snapshot = function() {
for (i = 0; i < length(ids); i++) { for (i = 0; i < length(ids); i++) {
d = registry[ids[i]] d = registry[ids[i]]
if (!d) continue if (!d) continue
push(result, { result[] = {
id: ids[i], id: ids[i],
type: d.type, type: d.type,
pos: d.pos ? {x: d.pos.x, y: d.pos.y} : null, pos: d.pos ? {x: d.pos.x, y: d.pos.y} : null,
@@ -546,7 +546,7 @@ film2d.snapshot = function() {
opacity: d.opacity, opacity: d.opacity,
image: d.image ? (is_text(d.image) ? d.image : '(texture)') : null, image: d.image ? (is_text(d.image) ? d.image : '(texture)') : null,
text: d.text text: d.text
}) }
} }
return result return result
} }

View File

@@ -67,7 +67,7 @@ fx_graph.add_node = function(type, params) {
params: local_params, params: local_params,
output: {node_id: this.next_id - 1, slot: 'output'} output: {node_id: this.next_id - 1, slot: 'output'}
} }
push(this.nodes, node) this.nodes[] = node
return node return node
} }
@@ -203,14 +203,14 @@ NODE_EXECUTORS.composite = function(params, backend) {
// Emit composite_textures command (handled outside render pass) // Emit composite_textures command (handled outside render pass)
var commands = [] var commands = []
push(commands, { commands[] = {
cmd: 'composite_textures', cmd: 'composite_textures',
base: base.target, base: base.target,
overlay: overlay.target, overlay: overlay.target,
output: target, output: target,
mode: mode, mode: mode,
opacity: opacity opacity: opacity
}) }
return {target: target, commands: commands} return {target: target, commands: commands}
} }
@@ -233,14 +233,14 @@ NODE_EXECUTORS.mask = function(params, backend) {
// Emit apply_mask command (handled via shader pass outside render pass) // Emit apply_mask command (handled via shader pass outside render pass)
var commands = [] var commands = []
push(commands, { commands[] = {
cmd: 'apply_mask', cmd: 'apply_mask',
content_texture: content.target, content_texture: content.target,
mask_texture: mask.target, mask_texture: mask.target,
output: target, output: target,
mode: mode, mode: mode,
invert: invert invert: invert
}) }
return {target: target, commands: commands} return {target: target, commands: commands}
} }
@@ -307,13 +307,13 @@ NODE_EXECUTORS.blit = function(params, backend) {
} }
var commands = [] var commands = []
push(commands, { commands[] = {
cmd: 'blit', cmd: 'blit',
texture: src_target, texture: src_target,
target: target, target: target,
dst_rect: dst_rect, dst_rect: dst_rect,
filter: filter filter: filter
}) }
return {target: target, commands: commands} return {target: target, commands: commands}
} }
@@ -323,7 +323,7 @@ NODE_EXECUTORS.present = function(params, backend) {
var input = params.input var input = params.input
var commands = [] var commands = []
push(commands, {cmd: 'present'}) commands[] = {cmd: 'present'}
return {commands: commands} return {commands: commands}
} }
@@ -354,13 +354,13 @@ NODE_EXECUTORS.shader_pass = function(params, backend) {
} }
var commands = [] var commands = []
push(commands, { commands[] = {
cmd: 'shader_pass', cmd: 'shader_pass',
shader: shader, shader: shader,
input: src, input: src,
output: target, output: target,
uniforms: uniforms uniforms: uniforms
}) }
return {target: target, commands: commands} return {target: target, commands: commands}
} }

View File

@@ -21,8 +21,8 @@ graphics.Image = function(surfaceData) {
img.cpu = surfaceData || null; img.cpu = surfaceData || null;
img.texture = 0; img.texture = 0;
img.surface = img.cpu; img.surface = img.cpu;
img.width = surfaceData?.width || 0; img.width = surfaceData.width || 0;
img.height = surfaceData?.height || 0; img.height = surfaceData.height || 0;
img.rect = {x:0, y:0, width:img.width, height:img.height}; img.rect = {x:0, y:0, width:img.width, height:img.height};
img[LOADING] = false; img[LOADING] = false;
img[LASTUSE] = time.number(); img[LASTUSE] = time.number();
@@ -157,7 +157,7 @@ function decode_aseprite(decoded) {
function create_image(path){ function create_image(path){
def bytes = io.slurp(path); def bytes = io.slurp(path);
var ext = pop(array(path, '.')) var ext = array(path, '.')[]
var raw = decode_image(bytes, ext); var raw = decode_image(bytes, ext);
var anims = null var anims = null
var keys = null var keys = null
@@ -367,7 +367,7 @@ graphics.texture = function texture(path) {
} }
graphics.tex_hotreload = function tex_hotreload(file) { graphics.tex_hotreload = function tex_hotreload(file) {
var basename = array(pop(array(file, '/')), '.')[0] var basename = array(array(file, '/')[], '.')[0]
// Check if this basename exists in our cache // Check if this basename exists in our cache
if (!(basename in cache)) return if (!(basename in cache)) return
@@ -479,10 +479,10 @@ graphics.snapshot = function() {
info.frame_count = length(entry.frames) info.frame_count = length(entry.frames)
info.type = 'animation' info.type = 'animation'
} }
push(images, info) images[] = info
}) })
arrfor(array(fontcache), function(k) { arrfor(array(fontcache), function(k) {
push(fonts, k) fonts[] = k
}) })
return {images: images, fonts: fonts} return {images: images, fonts: fonts}
} }

View File

@@ -93,13 +93,13 @@ function create_user(index, config) {
// Push entity onto control stack // Push entity onto control stack
push: function(entity) { push: function(entity) {
push(this.control_stack, entity) this.control_stack[] = entity
}, },
// Pop from control stack // Pop from control stack
pop: function() { pop: function() {
if (length(this.control_stack) > 1) { if (length(this.control_stack) > 1) {
return pop(this.control_stack) return this.control_stack[]
} }
return null return null
}, },
@@ -169,7 +169,7 @@ function pick_user(canon) {
picked.active_device = canon.device_id picked.active_device = canon.device_id
if (find(picked.paired_devices, canon.device_id) == null) { if (find(picked.paired_devices, canon.device_id) == null) {
push(picked.paired_devices, canon.device_id) picked.paired_devices[] = canon.device_id
} }
} }
} }
@@ -211,7 +211,7 @@ function configure(o) {
// Create users // Create users
_users = [] _users = []
for (i = 0; i < _config.max_users; i++) { for (i = 0; i < _config.max_users; i++) {
push(_users, create_user(i, _config)) _users[] = create_user(i, _config)
} }
_initialized = true _initialized = true
@@ -268,7 +268,7 @@ function snapshot() {
for (i = 0; i < length(_users); i++) { for (i = 0; i < length(_users); i++) {
u = _users[i] u = _users[i]
target = u.target() target = u.target()
push(users, { users[] = {
index: u.index, index: u.index,
device_kind: u.device_kind(), device_kind: u.device_kind(),
active_device: u.active_device, active_device: u.active_device,
@@ -276,7 +276,7 @@ function snapshot() {
down: u.down(), down: u.down(),
control_stack_depth: length(u.control_stack), control_stack_depth: length(u.control_stack),
target: target ? (target.name || '(entity)') : null target: target ? (target.name || '(entity)') : null
}) }
} }
return { return {
max_users: _config.max_users, max_users: _config.max_users,

View File

@@ -54,7 +54,7 @@ function gesture_stage(cfg) {
// Only process gamepad touchpad events // Only process gamepad touchpad events
if (ev.control != 'gamepad_touchpad') { if (ev.control != 'gamepad_touchpad') {
push(output, ev) output[] = ev
continue continue
} }
@@ -86,7 +86,7 @@ function gesture_stage(cfg) {
d = currentDist - start_dist d = currentDist - start_dist
if (Math.abs(d) >= pinch_th / 100) { if (Math.abs(d) >= pinch_th / 100) {
push(output, { output[] = {
kind: 'gesture', kind: 'gesture',
device_id: ev.device_id, device_id: ev.device_id,
control: d > 0 ? 'pinch_out' : 'pinch_in', control: d > 0 ? 'pinch_out' : 'pinch_in',
@@ -94,7 +94,7 @@ function gesture_stage(cfg) {
released: false, released: false,
delta: d, delta: d,
time: ev.time time: ev.time
}) }
start_dist = currentDist start_dist = currentDist
} }
} }
@@ -118,14 +118,14 @@ function gesture_stage(cfg) {
? (dx > 0 ? 'swipe_right' : 'swipe_left') ? (dx > 0 ? 'swipe_right' : 'swipe_left')
: (dy > 0 ? 'swipe_down' : 'swipe_up') : (dy > 0 ? 'swipe_down' : 'swipe_up')
push(output, { output[] = {
kind: 'gesture', kind: 'gesture',
device_id: ev.device_id, device_id: ev.device_id,
control: dir, control: dir,
pressed: true, pressed: true,
released: false, released: false,
time: ev.time time: ev.time
}) }
} }
} }
} }
@@ -158,18 +158,18 @@ function emacs_stage() {
// Only process keyboard button events // Only process keyboard button events
if (ev.device_id != 'kbm' || ev.kind != 'button' || !ev.pressed) { if (ev.device_id != 'kbm' || ev.kind != 'button' || !ev.pressed) {
push(output, ev) output[] = ev
continue continue
} }
/* if (find(valid_emacs_keys, ev.control) == null) { /* if (find(valid_emacs_keys, ev.control) == null) {
push(output, ev) output[] = ev
continue continue
} }
*/ */
// Only process if we have modifiers OR waiting for chord // Only process if we have modifiers OR waiting for chord
if (!ev.mods?.ctrl && !ev.mods?.alt && !prefix) { if (!ev.mods?.ctrl && !ev.mods?.alt && !prefix) {
push(output, ev) output[] = ev
continue continue
} }
@@ -193,23 +193,23 @@ function emacs_stage() {
if (prefix) { if (prefix) {
chord = prefix + " " + notation chord = prefix + " " + notation
prefix = null prefix = null
push(output, { output[] = {
kind: 'chord', kind: 'chord',
device_id: ev.device_id, device_id: ev.device_id,
control: chord, control: chord,
pressed: true, pressed: true,
released: false, released: false,
time: ev.time time: ev.time
}) }
} else { } else {
push(output, { output[] = {
kind: 'chord', kind: 'chord',
device_id: ev.device_id, device_id: ev.device_id,
control: notation, control: notation,
pressed: true, pressed: true,
released: false, released: false,
time: ev.time time: ev.time
}) }
} }
} }
@@ -237,14 +237,14 @@ function action_stage(bindings) {
// Pass through non-button events // Pass through non-button events
if (ev.kind != 'button' && ev.kind != 'chord' && ev.kind != 'gesture') { if (ev.kind != 'button' && ev.kind != 'chord' && ev.kind != 'gesture') {
push(output, ev) output[] = ev
continue continue
} }
actions = bindings.get_actions(ev.control) actions = bindings.get_actions(ev.control)
if (length(actions) == 0) { if (length(actions) == 0) {
push(output, ev) output[] = ev
continue continue
} }
@@ -254,7 +254,7 @@ function action_stage(bindings) {
if (ev.pressed) down[action] = true if (ev.pressed) down[action] = true
else if (ev.released) down[action] = false else if (ev.released) down[action] = false
push(output, { output[] = {
kind: 'action', kind: 'action',
device_id: ev.device_id, device_id: ev.device_id,
control: action, control: action,
@@ -262,7 +262,7 @@ function action_stage(bindings) {
released: ev.released, released: ev.released,
time: ev.time, time: ev.time,
original: ev original: ev
}) }
} }
} }
@@ -304,16 +304,16 @@ function make(user, cfg) {
var action = null var action = null
if (o.gestures != false) { if (o.gestures != false) {
push(stages, gesture_stage(o)) stages[] = gesture_stage(o)
} }
if (o.emacs != false) { if (o.emacs != false) {
push(stages, emacs_stage()) stages[] = emacs_stage()
} }
action = action_stage(user.bindings) action = action_stage(user.bindings)
push(stages, action) stages[] = action
push(stages, delivery_stage(user)) stages[] = delivery_stage(user)
return { return {
stages: stages, stages: stages,

View File

@@ -86,9 +86,9 @@ function build_polyline_mesh(line) {
for (i = 0; i < length(points); i++) { for (i = 0; i < length(points); i++) {
p = points[i] p = points[i]
if (points_space == 'local') { if (points_space == 'local') {
push(pts, {x: p.x + pos.x, y: p.y + pos.y}) pts[] = {x: p.x + pos.x, y: p.y + pos.y}
} else { } else {
push(pts, {x: p.x, y: p.y}) pts[] = {x: p.x, y: p.y}
} }
} }
@@ -97,7 +97,7 @@ function build_polyline_mesh(line) {
for (i = 1; i < length(pts); i++) { for (i = 1; i < length(pts); i++) {
dx = pts[i].x - pts[i-1].x dx = pts[i].x - pts[i-1].x
dy = pts[i].y - pts[i-1].y dy = pts[i].y - pts[i-1].y
push(cumulative, cumulative[i-1] + math.sqrt(dx*dx + dy*dy)) cumulative[] = cumulative[i-1] + math.sqrt(dx*dx + dy*dy)
} }
var total_length = cumulative[length(cumulative) - 1] var total_length = cumulative[length(cumulative) - 1]
@@ -207,7 +207,7 @@ function build_polyline_mesh(line) {
n.y = dx n.y = dx
} }
push(normals, n) normals[] = n
} }
// Generate vertices (2 per point - left and right of line) // Generate vertices (2 per point - left and right of line)
@@ -220,22 +220,22 @@ function build_polyline_mesh(line) {
u = get_u(i) u = get_u(i)
// Left vertex (v=0) // Left vertex (v=0)
push(verts, { verts[] = {
x: p.x + n.x * w, x: p.x + n.x * w,
y: p.y + n.y * w, y: p.y + n.y * w,
u: u, u: u,
v: v_offset, v: v_offset,
r: 1, g: 1, b: 1, a: 1 r: 1, g: 1, b: 1, a: 1
}) }
// Right vertex (v=1) // Right vertex (v=1)
push(verts, { verts[] = {
x: p.x - n.x * w, x: p.x - n.x * w,
y: p.y - n.y * w, y: p.y - n.y * w,
u: u, u: u,
v: v_scale + v_offset, v: v_scale + v_offset,
r: 1, g: 1, b: 1, a: 1 r: 1, g: 1, b: 1, a: 1
}) }
} }
// Generate indices (triangle strip as triangles) // Generate indices (triangle strip as triangles)
@@ -243,25 +243,25 @@ function build_polyline_mesh(line) {
for (i = 0; i < length(pts) - 1; i++) { for (i = 0; i < length(pts) - 1; i++) {
base = i * 2 base = i * 2
// First triangle // First triangle
push(indices, base + 0) indices[] = base + 0
push(indices, base + 1) indices[] = base + 1
push(indices, base + 2) indices[] = base + 2
// Second triangle // Second triangle
push(indices, base + 1) indices[] = base + 1
push(indices, base + 3) indices[] = base + 3
push(indices, base + 2) indices[] = base + 2
} }
// Handle closed path // Handle closed path
var last = 0 var last = 0
if (closed && length(pts) > 2) { if (closed && length(pts) > 2) {
last = (length(pts) - 1) * 2 last = (length(pts) - 1) * 2
push(indices, last + 0) indices[] = last + 0
push(indices, last + 1) indices[] = last + 1
push(indices, 0) indices[] = 0
push(indices, last + 1) indices[] = last + 1
push(indices, 1) indices[] = 1
push(indices, 0) indices[] = 0
} }
// Add round caps if requested // Add round caps if requested
@@ -301,13 +301,13 @@ function add_round_cap(opts) {
var dy = is_start ? n.x : -n.x var dy = is_start ? n.x : -n.x
// Center vertex // Center vertex
push(verts, { verts[] = {
x: p.x, x: p.x,
y: p.y, y: p.y,
u: u, u: u,
v: 0.5 * v_scale + v_offset, v: 0.5 * v_scale + v_offset,
r: 1, g: 1, b: 1, a: 1 r: 1, g: 1, b: 1, a: 1
}) }
// Arc vertices // Arc vertices
var start_angle = is_start ? math.arc_tangent(n.y, n.x) : math.arc_tangent(-n.y, -n.x) var start_angle = is_start ? math.arc_tangent(n.y, n.x) : math.arc_tangent(-n.y, -n.x)
@@ -320,20 +320,20 @@ function add_round_cap(opts) {
cx = math.cosine(angle) cx = math.cosine(angle)
cy = math.sine(angle) cy = math.sine(angle)
push(verts, { verts[] = {
x: p.x + cx * w, x: p.x + cx * w,
y: p.y + cy * w, y: p.y + cy * w,
u: u, u: u,
v: (0.5 + cy * 0.5) * v_scale + v_offset, v: (0.5 + cy * 0.5) * v_scale + v_offset,
r: 1, g: 1, b: 1, a: 1 r: 1, g: 1, b: 1, a: 1
}) }
} }
// Fan triangles // Fan triangles
for (i = 0; i < segments; i++) { for (i = 0; i < segments; i++) {
push(indices, base_idx) indices[] = base_idx
push(indices, base_idx + 1 + i) indices[] = base_idx + 1 + i
push(indices, base_idx + 2 + i) indices[] = base_idx + 2 + i
} }
} }
@@ -364,17 +364,17 @@ function add_square_cap(opts) {
var ey = p.y + dy * ext var ey = p.y + dy * ext
// Four corners of the cap // Four corners of the cap
push(verts, {x: p.x + n.x * w, y: p.y + n.y * w, u: u, v: v_offset, r: 1, g: 1, b: 1, a: 1}) verts[] = {x: p.x + n.x * w, y: p.y + n.y * w, u: u, v: v_offset, r: 1, g: 1, b: 1, a: 1}
push(verts, {x: p.x - n.x * w, y: p.y - n.y * w, u: u, v: v_scale + v_offset, r: 1, g: 1, b: 1, a: 1}) verts[] = {x: p.x - n.x * w, y: p.y - n.y * w, u: u, v: v_scale + v_offset, r: 1, g: 1, b: 1, a: 1}
push(verts, {x: ex + n.x * w, y: ey + n.y * w, u: u, v: v_offset, r: 1, g: 1, b: 1, a: 1}) verts[] = {x: ex + n.x * w, y: ey + n.y * w, u: u, v: v_offset, r: 1, g: 1, b: 1, a: 1}
push(verts, {x: ex - n.x * w, y: ey - n.y * w, u: u, v: v_scale + v_offset, r: 1, g: 1, b: 1, a: 1}) verts[] = {x: ex - n.x * w, y: ey - n.y * w, u: u, v: v_scale + v_offset, r: 1, g: 1, b: 1, a: 1}
push(indices, base_idx + 0) indices[] = base_idx + 0
push(indices, base_idx + 1) indices[] = base_idx + 1
push(indices, base_idx + 2) indices[] = base_idx + 2
push(indices, base_idx + 1) indices[] = base_idx + 1
push(indices, base_idx + 3) indices[] = base_idx + 3
push(indices, base_idx + 2) indices[] = base_idx + 2
} }
var defaults = { var defaults = {

View File

@@ -18,7 +18,7 @@ var particles2d_proto = {
var emitters = { var emitters = {
// Spawn a particle for an emitter // Spawn a particle for an emitter
spawn: function(emitter) { spawn: function(emitter) {
push(emitter.particles, { emitter.particles[] = {
pos: { pos: {
x: emitter.pos.x + (random() - 0.5) * emitter.spawn_area.width, x: emitter.pos.x + (random() - 0.5) * emitter.spawn_area.width,
y: emitter.pos.y + (random() - 0.5) * emitter.spawn_area.height y: emitter.pos.y + (random() - 0.5) * emitter.spawn_area.height
@@ -37,7 +37,7 @@ var emitters = {
b: emitter.color.b, b: emitter.color.b,
a: 1 a: 1
} }
}) }
}, },
// Update an emitter and its particles // Update an emitter and its particles

View File

@@ -56,7 +56,7 @@ PlaydateBackend.prototype.get_or_create_target = function(width, height, key) {
key: key key: key
} }
push(this.target_pool[pool_key], target) this.target_pool[pool_key][] = target
return target return target
} }

View File

@@ -109,12 +109,12 @@ rasterize.ellipse = function ellipse(pos, radii, opt) {
within_wedge(dx+1, dy, wedge_info) within_wedge(dx+1, dy, wedge_info)
if (last || !next_in_ring) { if (last || !next_in_ring) {
push(strips, { strips[] = {
x: run_start, x: run_start,
y: y_screen, y: y_screen,
width: (cx + dx) - run_start + 1, width: (cx + dx) - run_start + 1,
height: 1 height: 1
}) }
run_start = null run_start = null
} }
} }
@@ -199,12 +199,10 @@ rasterize.round_rect = function round_rect(rect, radius, thickness) {
w = dx_out - dx_in w = dx_out - dx_in
if (w <= 0) continue if (w <= 0) continue
push(strips, strips[] = { x:cx_l - dx_out, y:cy_t - dy, width:w, height:1 },
{ x:cx_l - dx_out, y:cy_t - dy, width:w, height:1 },
{ x:cx_r + dx_in + 1, y:cy_t - dy, width:w, height:1 }, { x:cx_r + dx_in + 1, y:cy_t - dy, width:w, height:1 },
{ x:cx_l - dx_out, y:cy_b + dy, width:w, height:1 }, { x:cx_l - dx_out, y:cy_b + dy, width:w, height:1 },
{ x:cx_r + dx_in + 1, y:cy_b + dy, width:w, height:1 } { x:cx_r + dx_in + 1, y:cy_b + dy, width:w, height:1 }
)
} }
return {type: 'rects', data: array(rects, strips)} return {type: 'rects', data: array(rects, strips)}
@@ -235,12 +233,10 @@ rasterize.fill_round_rect = function fill_round_rect(rect, radius) {
dx = floor(math.sqrt(_radius * _radius - dy * dy)) dx = floor(math.sqrt(_radius * _radius - dy * dy))
w = (dx << 1) + 1 w = (dx << 1) + 1
push(caps, caps[] = { x:cx_l - dx, y:cy_t - dy, width:w, height:1 },
{ x:cx_l - dx, y:cy_t - dy, width:w, height:1 },
{ x:cx_r - dx, y:cy_t - dy, width:w, height:1 }, { x:cx_r - dx, y:cy_t - dy, width:w, height:1 },
{ x:cx_l - dx, y:cy_b + dy, width:w, height:1 }, { x:cx_l - dx, y:cy_b + dy, width:w, height:1 },
{ x:cx_r - dx, y:cy_b + dy, width:w, height:1 } { x:cx_r - dx, y:cy_b + dy, width:w, height:1 }
)
} }
return {type: 'rects', data: array(rects, caps)} return {type: 'rects', data: array(rects, caps)}

View File

@@ -94,7 +94,7 @@ function read_ignore(dir) {
arrfor(lines, function(line) { arrfor(lines, function(line) {
var trimmed = trim(line) var trimmed = trim(line)
if (!trimmed || starts_with(trimmed, '#')) return if (!trimmed || starts_with(trimmed, '#')) return
push(patterns, trimmed) patterns[] = trimmed
}) })
} }
return patterns return patterns
@@ -115,7 +115,7 @@ Resources.getAllFiles = function(dir) {
if (!st.filesize) return if (!st.filesize) return
var ext = getExtension(f) var ext = getExtension(f)
if (!isRecognizedExtension(ext)) return if (!isRecognizedExtension(ext)) return
push(results, fullPath) results[] = fullPath
} disruption { } disruption {
// skip files that can't be stat'd // skip files that can't be stat'd
} }

View File

@@ -700,7 +700,7 @@ function _load_image_file(path) {
var decoded = null var decoded = null
if (!bytes) return null if (!bytes) return null
var ext = lower(pop(array(path, '.'))) var ext = lower(array(path, '.')[])
var surface = null var surface = null
if (ext == 'png' || ext == 'jpg' || ext == 'jpeg' || ext == 'bmp') { if (ext == 'png' || ext == 'jpg' || ext == 'jpeg' || ext == 'bmp') {
@@ -814,7 +814,7 @@ sdl_gpu.get_or_create_target = function(width, height, key) {
key: key key: key
} }
push(_target_pool[pool_key], target) _target_pool[pool_key][] = target
return target return target
} }
@@ -1225,7 +1225,7 @@ function _execute_commands(commands, window_size) {
current_camera = cmd.camera current_camera = cmd.camera
} else if (cmd.cmd == 'draw_batch' || cmd.cmd == 'draw_text' || cmd.cmd == 'draw_texture_ref' || cmd.cmd == 'draw_shape' || cmd.cmd == 'draw_mesh2d') { } else if (cmd.cmd == 'draw_batch' || cmd.cmd == 'draw_text' || cmd.cmd == 'draw_texture_ref' || cmd.cmd == 'draw_shape' || cmd.cmd == 'draw_mesh2d') {
push(pending_draws, cmd) pending_draws[] = cmd
} else if (cmd.cmd == 'blit') { } else if (cmd.cmd == 'blit') {
// Flush pending draws first // Flush pending draws first
@@ -1824,8 +1824,8 @@ function _render_text(ctx, drawable) {
if (ax != 0 || ay != 0) { if (ax != 0 || ay != 0) {
dim = font.text_size(drawable.text) dim = font.text_size(drawable.text)
if (dim) { if (dim) {
text_pos.x -= dim.x * ax text_pos.x -= dim[0] * ax
text_pos.y -= dim.y * ay text_pos.y -= dim[1] * ay
} }
} }
@@ -2248,7 +2248,7 @@ function _do_shader_pass(cmd_buffer, cmd, get_swapchain_tex) {
var samplers = [{texture: input.texture, sampler: _sampler_linear}] var samplers = [{texture: input.texture, sampler: _sampler_linear}]
if (cmd.extra_inputs) { if (cmd.extra_inputs) {
arrfor(cmd.extra_inputs, function(extra) { arrfor(cmd.extra_inputs, function(extra) {
push(samplers, {texture: extra.texture, sampler: _sampler_linear}) samplers[] = {texture: extra.texture, sampler: _sampler_linear}
}) })
} }
pass.bind_fragment_samplers(0, samplers) pass.bind_fragment_samplers(0, samplers)

View File

@@ -25,7 +25,7 @@ for (i = 0; i < length(formats); i++) {
if (!colorspaces[fmt.colorspace]) { if (!colorspaces[fmt.colorspace]) {
colorspaces[fmt.colorspace] = []; colorspaces[fmt.colorspace] = [];
} }
push(colorspaces[fmt.colorspace], fmt); colorspaces[fmt.colorspace][] = fmt;
} }
log.console("\nFound colorspaces:"); log.console("\nFound colorspaces:");

View File

@@ -19,10 +19,10 @@ var tilemap = {
var y = pos.y - this.offset_y var y = pos.y - this.offset_y
while (length(this.tiles) <= x) while (length(this.tiles) <= x)
push(this.tiles, []) this.tiles[] = []
while (length(this.tiles[x]) <= y) while (length(this.tiles[x]) <= y)
push(this.tiles[x], null) this.tiles[x][] = null
this.tiles[x][y] = image this.tiles[x][y] = image
}, },

View File

@@ -8,7 +8,7 @@ function make_engine(default_clock) {
tweens: [], tweens: [],
default_clock: default_clock || null, default_clock: default_clock || null,
add(tween) { add(tween) {
push(this.tweens, tween) this.tweens[] = tween
}, },
remove(tween) { remove(tween) {
this.tweens = filter(this.tweens, t => t != tween) this.tweens = filter(this.tweens, t => t != tween)
@@ -164,7 +164,7 @@ var TimelineProto = {
engine: null, engine: null,
add_event: function(time_value, fn) { add_event: function(time_value, fn) {
push(this.events, { time: time_value, fn, fired: false }) this.events[] = { time: time_value, fn, fired: false }
}, },
add_tween: function(obj, props, duration, start_time) { add_tween: function(obj, props, duration, start_time) {
@@ -257,13 +257,13 @@ $delay(() => {
function snapshot() { function snapshot() {
var result = [] var result = []
arrfor(TweenEngine.tweens, function(tw) { arrfor(TweenEngine.tweens, function(tw) {
push(result, { result[] = {
startVals: tw.startVals, startVals: tw.startVals,
endVals: tw.endVals, endVals: tw.endVals,
duration: tw.duration, duration: tw.duration,
startTime: tw.startTime, startTime: tw.startTime,
easing: tw.easing ? (tw.easing.name || 'unknown') : 'none' easing: tw.easing ? (tw.easing.name || 'unknown') : 'none'
}) }
}) })
return {active_count: length(TweenEngine.tweens), tweens: result} return {active_count: length(TweenEngine.tweens), tweens: result}
} }

View File

@@ -73,7 +73,7 @@ world.snapshot = function() {
if (!is_function(e[k])) if (!is_function(e[k]))
snap[k] = e[k] snap[k] = e[k]
}) })
push(result, snap) result[] = snap
}) })
return result return result
} }