This commit is contained in:
2026-01-21 09:05:02 -06:00
parent 18ca9e14ba
commit f7be9c3344
30 changed files with 237 additions and 246 deletions

View File

@@ -226,7 +226,7 @@ action.on_input = function(action_id, evt)
var matched_actions = []
arrfor(array(this.action_map), mapped_action => {
if (find(this.action_map[mapped_action], action_id) != null) {
matched_actions.push(mapped_action)
push(matched_actions, mapped_action)
if (evt.pressed)
this.down[mapped_action] = true
@@ -256,14 +256,14 @@ action.rebind_action = function(action_name, new_key) {
arrfor(array(this.action_map), act => {
var idx = find(this.action_map[act], new_key)
if (idx != null)
this.action_map[act].splice(idx, 1)
this.action_map[act] = array(array(this.action_map[act], 0, idx), array(this.action_map[act], idx+1))
})
// Clear existing bindings for the current device from the target action
var target_bindings = this.action_map[action_name]
for (var i = length(target_bindings) - 1; i >= 0; i--) {
if (detect_device(target_bindings[i]) == this.current_device)
target_bindings.splice(i, 1)
this.action_map[action_name] = array(array(this.action_map[action_name], 0, i), array(this.action_map[action_name], i+1))
}
// Only insert into the target if it's the right device

16
clay.cm
View File

@@ -130,7 +130,7 @@ function build_drawables(node, root_height, parent_abs_x, parent_abs_y, parent_s
// Background
if (node.config.background_image) {
if (node.config.slice) {
drawables.push({
push(drawables, {
type: 'sprite',
image: node.config.background_image,
pos: {x: vis_x, y: vis_y},
@@ -142,7 +142,7 @@ function build_drawables(node, root_height, parent_abs_x, parent_abs_y, parent_s
scissor: current_scissor
})
} else {
drawables.push({
push(drawables, {
type: 'sprite',
image: node.config.background_image,
pos: {x: vis_x, y: vis_y},
@@ -154,7 +154,7 @@ function build_drawables(node, root_height, parent_abs_x, parent_abs_y, parent_s
})
}
} else if (node.config.background_color) {
drawables.push({
push(drawables, {
type: 'rect',
pos: {x: vis_x, y: vis_y},
width: rect.width,
@@ -167,7 +167,7 @@ function build_drawables(node, root_height, parent_abs_x, parent_abs_y, parent_s
// Content (Image/Text)
if (node.config.image) {
drawables.push({
push(drawables, {
type: 'sprite',
image: node.config.image,
pos: {x: vis_x, y: vis_y},
@@ -180,7 +180,7 @@ function build_drawables(node, root_height, parent_abs_x, parent_abs_y, parent_s
}
if (node.config.text) {
drawables.push({
push(drawables, {
type: 'text',
text: node.config.text,
font: node.config.font_path,
@@ -249,15 +249,15 @@ function push_node(configs, contain_mode) {
// Add to parent
var parent = tree_stack[length(tree_stack)-1]
parent.children.push(node)
push(parent.children, node)
lay_ctx.insert(parent.id, item)
tree_stack.push(node)
push(tree_stack, node)
return node
}
function pop_node() {
tree_stack.pop()
pop(tree_stack)
}
// Generic container

View File

@@ -74,7 +74,7 @@ clay_input.click = function click(tree_root, mousepos, button = 'left') {
clay_input.get_actionable = function get_actionable(tree_root) {
var actionable = []
function walk(node) {
if (node.config.action) actionable.push(node)
if (node.config.action) push(actionable, node)
if (node[clay.CHILDREN])
arrfor(node[clay.CHILDREN], walk)
}
@@ -85,7 +85,7 @@ clay_input.get_actionable = function get_actionable(tree_root) {
clay_input.filter = function filter(tree_root, predicate) {
var results = []
function rec(node) {
if (predicate(node)) results.push(node)
if (predicate(node)) push(results, node)
if (node[clay.CHILDREN])
arrfor(node[clay.CHILDREN], rec)
}

View File

@@ -23,7 +23,7 @@ compositor.compile = function(config) {
// Clear screen
if (config.clear)
ctx.passes.push({type: 'clear', target: 'screen', color: config.clear})
push(ctx.passes, {type: 'clear', target: 'screen', color: config.clear})
// Process each plane (supports both 'planes' and legacy 'layers' key)
var planes = config.planes || config.layers || []
@@ -41,7 +41,7 @@ compositor.compile = function(config) {
}
function compile_imgui_layer(layer, ctx) {
ctx.passes.push({
push(ctx.passes, {
type: 'imgui',
target: 'screen',
draw: layer.draw
@@ -70,7 +70,7 @@ function compile_plane(plane_config, ctx, group_effects) {
// Add manual drawables
if (plane_config.drawables) {
for (var i = 0; i < length(plane_config.drawables); i++)
all_sprites.push(plane_config.drawables[i])
push(all_sprites, plane_config.drawables[i])
}
// Find which sprites belong to groups with effects
@@ -98,14 +98,14 @@ function compile_plane(plane_config, ctx, group_effects) {
if (group_effects[gname]) {
if (!effect_groups[gname])
effect_groups[gname] = {sprites: [], effects: group_effects[gname].effects}
effect_groups[gname].sprites.push(s)
push(effect_groups[gname].sprites, s)
assigned = true
break // Only assign to first matching effect group
}
}
// Add to base sprites if not assigned to effect group and not mask-only
if (!assigned && !is_mask_only) base_sprites.push(s)
if (!assigned && !is_mask_only) push(base_sprites, s)
}
// Allocate plane target
@@ -113,7 +113,7 @@ function compile_plane(plane_config, ctx, group_effects) {
// Clear plane
if (plane_config.clear)
ctx.passes.push({type: 'clear', target: plane_target, color: plane_config.clear})
push(ctx.passes, {type: 'clear', target: plane_target, color: plane_config.clear})
// Render each effect group to temp target, apply effects, composite back
arrfor(array(effect_groups), gname => {
@@ -123,7 +123,7 @@ function compile_plane(plane_config, ctx, group_effects) {
var group_target = ctx.alloc(res.width, res.height, gname + '_content')
// Render group content
ctx.passes.push({
push(ctx.passes, {
type: 'render',
renderer: 'film2d',
drawables: eg.sprites,
@@ -142,7 +142,7 @@ function compile_plane(plane_config, ctx, group_effects) {
}
// Composite result to plane
ctx.passes.push({
push(ctx.passes, {
type: 'composite',
source: current,
dest: plane_target,
@@ -154,7 +154,7 @@ function compile_plane(plane_config, ctx, group_effects) {
// Render base sprites (no effects)
if (length(base_sprites) > 0) {
ctx.passes.push({
push(ctx.passes, {
type: 'render',
renderer: 'film2d',
drawables: base_sprites,
@@ -167,7 +167,7 @@ function compile_plane(plane_config, ctx, group_effects) {
}
// Composite plane to screen
ctx.passes.push({
push(ctx.passes, {
type: 'blit_to_screen',
source: plane_target,
source_size: res,
@@ -185,7 +185,7 @@ function apply_effect(ctx, effect, input, size, camera, hint, current_plane, gro
var blur2 = ctx.alloc(size.width, size.height, hint + '_blur2')
// Threshold
ctx.passes.push({
push(ctx.passes, {
type: 'shader_pass',
shader: 'threshold',
input: input,
@@ -197,13 +197,13 @@ function apply_effect(ctx, effect, input, size, camera, hint, current_plane, gro
var blur_passes = effect.blur_passes || 2
var blur_in = bright
for (var p = 0; p < blur_passes; p++) {
ctx.passes.push({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.push({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}}})
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}}})
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}}})
blur_in = blur2
}
// Composite bloom
ctx.passes.push({type: 'composite_textures', base: input, overlay: blur2, output: output, mode: 'add'})
push(ctx.passes, {type: 'composite_textures', base: input, overlay: blur2, output: output, mode: 'add'})
} else if (effect.type == 'mask') {
var mask_group = effect.mask_group
@@ -214,7 +214,7 @@ function apply_effect(ctx, effect, input, size, camera, hint, current_plane, gro
var mask_target = ctx.alloc(size.width, size.height, hint + '_mask')
// Render mask
ctx.passes.push({
push(ctx.passes, {
type: 'render',
renderer: 'film2d',
drawables: mask_sprites,
@@ -225,7 +225,7 @@ function apply_effect(ctx, effect, input, size, camera, hint, current_plane, gro
})
// Apply mask
ctx.passes.push({
push(ctx.passes, {
type: 'apply_mask',
content: input,
mask: mask_target,
@@ -235,11 +235,11 @@ function apply_effect(ctx, effect, input, size, camera, hint, current_plane, gro
})
} else {
// No mask sprites, pass through
ctx.passes.push({type: 'blit', source: input, dest: output})
push(ctx.passes, {type: 'blit', source: input, dest: output})
}
} else {
// Unknown effect, pass through
ctx.passes.push({type: 'blit', source: input, dest: output})
push(ctx.passes, {type: 'blit', source: input, dest: output})
}
return output
@@ -267,8 +267,8 @@ compositor.execute = function(plan) {
if (pass.type == 'clear') {
var target = resolve(pass.target)
commands.push({cmd: 'begin_render', target: target, clear: pass.color})
commands.push({cmd: 'end_render'})
push(commands, {cmd: 'begin_render', target: target, clear: pass.color})
push(commands, {cmd: 'end_render'})
} else if (pass.type == 'render') {
var result = film2d.render({
@@ -280,10 +280,10 @@ compositor.execute = function(plan) {
clear: pass.clear
}, backend)
for (var c = 0; c < length(result.commands); c++)
commands.push(result.commands[c])
push(commands, result.commands[c])
} else if (pass.type == 'shader_pass') {
commands.push({
push(commands, {
cmd: 'shader_pass',
shader: pass.shader,
input: resolve(pass.input),
@@ -292,7 +292,7 @@ compositor.execute = function(plan) {
})
} else if (pass.type == 'composite_textures') {
commands.push({
push(commands, {
cmd: 'composite_textures',
base: resolve(pass.base),
overlay: resolve(pass.overlay),
@@ -301,7 +301,7 @@ compositor.execute = function(plan) {
})
} else if (pass.type == 'apply_mask') {
commands.push({
push(commands, {
cmd: 'apply_mask',
content_texture: resolve(pass.content),
mask_texture: resolve(pass.mask),
@@ -311,7 +311,7 @@ compositor.execute = function(plan) {
})
} else if (pass.type == 'composite') {
commands.push({
push(commands, {
cmd: 'blit',
texture: resolve(pass.source),
target: resolve(pass.dest),
@@ -320,7 +320,7 @@ compositor.execute = function(plan) {
} else if (pass.type == 'blit_to_screen') {
var rect = _calc_presentation(pass.source_size, pass.dest_size, pass.presentation)
commands.push({
push(commands, {
cmd: 'blit',
texture: resolve(pass.source),
target: 'screen',
@@ -330,14 +330,14 @@ compositor.execute = function(plan) {
} else if (pass.type == 'blit') {
var src = resolve(pass.source)
var dst = resolve(pass.dest)
commands.push({
push(commands, {
cmd: 'blit',
texture: src,
target: dst,
dst_rect: {x: 0, y: 0, width: dst.width, height: dst.height}
})
} else if (pass.type == 'imgui') {
commands.push({
push(commands, {
cmd: 'imgui',
target: resolve(pass.target),
draw: pass.draw

36
core.cm
View File

@@ -78,7 +78,29 @@ core.backend = function() {
}
// FPS tracking
var _fps_samples = []
var _fps_sample_count = 60
var _fps_sample_count = 120
var _fps_sample_sum = 0
var _fps_sample_pos = 0
function fps_add_sample(sample) {
var n = length(_fps_samples)
if (n < _fps_sample_count) {
push(_fps_samples, sample)
_fps_sample_sum += sample
} else {
var old = _fps_samples[_fps_sample_pos]
_fps_samples[_fps_sample_pos] = sample
_fps_sample_sum += sample - old
_fps_sample_pos++
if (_fps_sample_pos >= _fps_sample_count) _fps_sample_pos = 0
}
}
function fps_get_avg() {
var n = length(_fps_samples)
return n ? _fps_sample_sum / n : 0
}
var _current_fps = 0
var _frame_time_ms = 0
@@ -162,7 +184,7 @@ function _main_loop() {
// Handle both compositor result ({commands: [...]}) and fx_graph (graph object)
if (render_result.commands) {
if (_config.imgui || _config.editor) {
render_result.commands.push({
push(render_result.commands, {
cmd: 'imgui',
draw: function(ui) {
if (_config.imgui) _config.imgui(ui)
@@ -188,17 +210,13 @@ function _main_loop() {
}
}
// Measure actual frame work time (excluding delay)
var frame_end = time_mod.number()
var actual_frame_time = frame_end - frame_start
// Track FPS based on actual work time
_frame_time_ms = actual_frame_time * 1000
_fps_samples.push(actual_frame_time)
if (length(_fps_samples) > _fps_sample_count) {
_fps_samples.shift()
}
var avg_frame_time = reduce(_fps_samples, function(a,b) { return a+b }) / length(_fps_samples)
fps_add_sample(actual_frame_time)
var avg_frame_time = fps_get_avg()
_current_fps = avg_frame_time > 0 ? 1 / avg_frame_time : 0
// Schedule next frame

View File

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

View File

@@ -36,7 +36,7 @@ effects.register('bloom', {
// Threshold extraction
var thresh_target = ctx.alloc_target(size.width, size.height, 'bloom_thresh')
passes.push({
push(passes, {
type: 'shader',
shader: 'threshold',
input: input,
@@ -55,14 +55,14 @@ effects.register('bloom', {
var blur_count = params.blur_passes != null ? params.blur_passes : 3
for (var i = 0; i < blur_count; i++) {
passes.push({
push(passes, {
type: 'shader',
shader: 'blur',
input: blur_src,
output: blur_a,
uniforms: {direction: {x: 2, y: 0}, texel_size: texel}
})
passes.push({
push(passes, {
type: 'shader',
shader: 'blur',
input: blur_a,
@@ -73,7 +73,7 @@ effects.register('bloom', {
}
// Additive composite
passes.push({
push(passes, {
type: 'composite',
base: input,
overlay: blur_src,
@@ -124,7 +124,7 @@ effects.register('mask', {
// Render mask source to target
var mask_target = ctx.alloc_target(size.width, size.height, 'mask_src')
passes.push({
push(passes, {
type: 'render_subtree',
root: mask_source,
output: mask_target,
@@ -133,7 +133,7 @@ effects.register('mask', {
})
// Apply mask shader
passes.push({
push(passes, {
type: 'shader',
shader: 'mask',
inputs: [input, mask_target],
@@ -190,14 +190,14 @@ effects.register('blur', {
var blur_count = params.passes != null ? params.passes : 2
for (var i = 0; i < blur_count; i++) {
passes.push({
push(passes, {
type: 'shader',
shader: 'blur',
input: src,
output: blur_a,
uniforms: {direction: {x: 2, y: 0}, texel_size: texel}
})
passes.push({
push(passes, {
type: 'shader',
shader: 'blur',
input: blur_a,
@@ -208,7 +208,7 @@ effects.register('blur', {
}
// Final blit to output
passes.push({type: 'blit', source: src, dest: output})
push(passes, {type: 'blit', source: src, dest: output})
return passes
}
})

View File

@@ -14,7 +14,7 @@ var bunnies = []
// Start with some initial bunnies:
for (var i = 0; i < 100; i++) {
bunnies.push({
push(bunnies, {
x: random.random() * config.width,
y: random.random() * config.height,
vx: (random.random() * 300) - 150,
@@ -22,22 +22,12 @@ for (var i = 0; i < 100; i++) {
})
}
var fpsSamples = []
var fpsAvg = 0
this.update = function(dt) {
// Compute FPS average over the last 60 frames:
var currentFPS = 1 / dt
fpsSamples.push(currentFPS)
if (length(fpsSamples) > 60) fpsSamples.shift()
var sum = reduce(fpsSamples, function(a,b) { return a + b })
fpsAvg = sum / length(fpsSamples)
// If left mouse is down, spawn some more bunnies:
var mouse = input.mousestate()
if (mouse.left)
for (var i = 0; i < 50; i++) {
bunnies.push({
push(bunnies, {
x: mouse.x,
y: mouse.y,
vx: (random.random() * 300) - 150,
@@ -63,7 +53,4 @@ this.update = function(dt) {
this.hud = function() {
draw.images(bunnyTex, bunnies)
var msg = 'FPS: ' + fpsAvg.toFixed(2) + ' Bunnies: ' + length(bunnies)
draw.text(msg, {x:0, y:0, width:config.width, height:40}, null, 0, color.white, 0)
}

View File

@@ -26,15 +26,13 @@ var grid_prototype = {
// add an entity into a cell
add(entity, pos) {
this.cell(pos.x, pos.y).push(entity);
push(this.cell(pos.x, pos.y), entity);
entity.coord = array(pos);
},
// remove an entity from a cell
remove(entity, pos) {
def c = this.cell(pos.x, pos.y);
def i = search(c, entity);
if (i != null) c.splice(i, 1);
this.cells[pos.y][pos.x] = filter(this.cells[pos.y][pos.x], x => x != entity)
},
// bounds check

View File

@@ -1,28 +1,27 @@
/* pieces.js simple data holders + starting layout */
function Piece(kind, colour) {
this.kind = kind; // "pawn" etc.
this.colour = colour; // "white"/"black"
this.sprite = colour + '_' + kind; // for draw2d.image
this.captured = false;
this.coord = [0,0];
var newpiece = { kind, colour}
newpiece.sprite = colour + '_' + kind; // for draw2d.image
newpiece.captured = false;
newpiece.coord = [0,0];
return newpiece
}
Piece.prototype.toString = function () {
return character(this.colour) + upper(character(this.kind));
};
function startingPosition(grid) {
var W = 'white', B = 'black', x;
// pawns
for (x = 0; x < 8; x++) {
grid.add(new Piece('pawn', W), [x, 6]);
grid.add(new Piece('pawn', B), [x, 1]);
grid.add(Piece('pawn', W), [x, 6]);
grid.add(Piece('pawn', B), [x, 1]);
}
// major pieces
var back = ['rook','knight','bishop','queen','king','bishop','knight','rook'];
for (x = 0; x < 8; x++) {
grid.add(new Piece(back[x], W), [x, 7]);
grid.add(new Piece(back[x], B), [x, 0]);
grid.add(Piece(back[x], W), [x, 7]);
grid.add(Piece(back[x], B), [x, 0]);
}
}

View File

@@ -75,7 +75,7 @@ this.update = function(dt) {
// Eat apple?
if (head.x == apple.x && head.y == apple.y) spawnApple()
else snake.pop()
else pop(snake)
}
this.hud = function() {

View File

@@ -58,8 +58,8 @@ function initBoard() {
board = []
for (var r=0; r<ROWS; r++) {
var row = []
for (var c=0; c<COLS; c++) row.push(0)
board.push(row)
for (var c=0; c<COLS; c++) push(row, 0)
push(board, row)
}
}
initBoard()
@@ -119,10 +119,10 @@ function clearLines() {
if (every(board[r], cell => cell)) {
lines++
// remove row
board.splice(r,1)
board = array(array(board, 0, r), array(board, r+1))
// add empty row on top
var newRow = []
for (var c=0; c<COLS; c++) newRow.push(0)
for (var c=0; c<COLS; c++) push(newRow, 0)
board.unshift(newRow)
} else {
r--

View File

@@ -118,14 +118,14 @@ film2d.register = function(drawable) {
// Index by plane
var plane = drawable.plane || 'default'
if (!plane_index[plane]) plane_index[plane] = []
plane_index[plane].push(id)
push(plane_index[plane], id)
// Index by groups (effect routing only)
var groups = drawable.groups || []
for (var i = 0; i < length(groups); i++) {
var g = groups[i]
if (!group_index[g]) group_index[g] = []
group_index[g].push(id)
push(group_index[g], id)
}
return id
@@ -140,7 +140,8 @@ film2d.unregister = function(id) {
var plane = drawable.plane || 'default'
if (plane_index[plane]) {
var idx = find(plane_index[plane], id_str)
if (idx != null) plane_index[plane].splice(idx, 1)
if (idx != null)
plane_index[plane] = array(array(plane_index[plane], 0, idx), array(plane_index[plane], idx+1))
}
// Remove from group indices
@@ -149,7 +150,8 @@ film2d.unregister = function(id) {
var g = groups[i]
if (group_index[g]) {
var idx = find(group_index[g], id_str)
if (idx != null) group_index[g].splice(idx, 1)
if (idx != null)
group_index[g] = array(array(group_index[g], 0, idx), array(group_index[g], idx+1))
}
}
@@ -159,13 +161,14 @@ film2d.unregister = function(id) {
film2d.index_group = function(id, group) {
if (!group_index[group]) group_index[group] = []
if (search(group_index[group], text(id)) == null)
group_index[group].push(text(id))
push(group_index[group], text(id))
}
film2d.unindex_group = function(id, group) {
if (!group_index[group]) return
var idx = search(group_index[group], text(id))
if (idx != null) group_index[group].splice(idx, 1)
if (idx != null)
group_index[group] = array(array(group_index[group], 0, idx), array(group_index[group], idx+1))
}
film2d.reindex = function(id, old_groups, new_groups) {
@@ -192,9 +195,9 @@ film2d.query = function(selector) {
// If also filtering by group, check membership
if (selector.group) {
var groups = d.groups || []
if (search(groups, selector.group) != null) result.push(d)
if (search(groups, selector.group) != null) push(result, d)
} else {
result.push(d)
push(result, d)
}
}
}
@@ -206,7 +209,7 @@ film2d.query = function(selector) {
var ids = group_index[selector.group] || []
for (var i = 0; i < length(ids); i++) {
var d = registry[ids[i]]
if (d && d.visible != false) result.push(d)
if (d && d.visible != false) push(result, d)
}
return result
}
@@ -219,7 +222,7 @@ film2d.query = function(selector) {
if (!seen[ids[i]]) {
seen[ids[i]] = true
var d = registry[ids[i]]
if (d && d.visible != false) result.push(d)
if (d && d.visible != false) push(result, d)
}
}
}
@@ -242,7 +245,7 @@ film2d.get_groups = function(id) {
film2d.all_groups = function() {
var groups = []
arrfor(array(group_index), g => {
if (length(group_index[g]) > 0) groups.push(g)
if (length(group_index[g]) > 0) push(groups, g)
})
return groups
}
@@ -282,7 +285,7 @@ film2d.render = function(params, render_backend) {
b = []
buckets[layer_key] = b
}
b.push(d)
push(b, d)
}
// Sort layers numerically (keys are text)
@@ -305,32 +308,32 @@ film2d.render = function(params, render_backend) {
if (!y_down) b = reverse(b) // y_up => smaller y draws later => reverse
}
for (var j = 0; j < length(b); j++) sorted_drawables.push(b[j])
for (var j = 0; j < length(b); j++) push(sorted_drawables, b[j])
}
drawables = sorted_drawables
var commands = []
commands.push({ cmd: "begin_render", target: target, clear: clear_color, target_size: target_size })
commands.push({ cmd: "set_camera", camera: camera })
push(commands, { cmd: "begin_render", target: target, clear: clear_color, target_size: target_size })
push(commands, { cmd: "set_camera", camera: camera })
var batches = _batch_drawables(drawables)
for (var i = 0; i < length(batches); i++) {
var batch = batches[i]
if (batch.type == "sprite_batch")
commands.push({ cmd: "draw_batch", batch_type: "sprites", geometry: { sprites: batch.sprites }, texture: batch.texture, material: batch.material })
push(commands, { cmd: "draw_batch", batch_type: "sprites", geometry: { sprites: batch.sprites }, texture: batch.texture, material: batch.material })
else if (batch.type == "mesh2d_batch")
commands.push({ cmd: "draw_mesh2d", meshes: batch.meshes, texture: batch.texture, material: batch.material })
push(commands, { cmd: "draw_mesh2d", meshes: batch.meshes, texture: batch.texture, material: batch.material })
else if (batch.type == "text")
commands.push({ cmd: "draw_text", drawable: batch.drawable })
push(commands, { cmd: "draw_text", drawable: batch.drawable })
else if (batch.type == "texture_ref")
commands.push({ cmd: "draw_texture_ref", drawable: batch.drawable })
push(commands, { cmd: "draw_texture_ref", drawable: batch.drawable })
else if (batch.type == "shape")
commands.push({ cmd: "draw_shape", drawable: batch.drawable })
push(commands, { cmd: "draw_shape", drawable: batch.drawable })
}
commands.push({ cmd: "end_render" })
push(commands, { cmd: "end_render" })
return { commands: commands }
}
@@ -350,9 +353,9 @@ function _batch_drawables(drawables) {
var mat = d.material || {blend: 'alpha', sampler: d.filter || 'nearest'}
if (current && current.type == 'sprite_batch' && current.texture == tex && _mat_eq(current.material, mat)) {
current.sprites.push(d)
push(current.sprites, d)
} else {
if (current) batches.push(current)
if (current) push(batches, current)
current = {type: 'sprite_batch', texture: tex, material: mat, sprites: [d]}
}
} else if (d.type == 'particles') {
@@ -379,9 +382,9 @@ function _batch_drawables(drawables) {
}
if (current && current.type == 'sprite_batch' && current.texture == tex && _mat_eq(current.material, mat)) {
current.sprites.push(sprite)
push(current.sprites, sprite)
} else {
if (current) batches.push(current)
if (current) push(batches, current)
current = {type: 'sprite_batch', texture: tex, material: mat, sprites: [sprite]}
}
}
@@ -422,9 +425,9 @@ function _batch_drawables(drawables) {
var tex = img
var mat = default_mat
if (current && current.type == 'sprite_batch' && current.texture == tex && _mat_eq(current.material, mat)) {
current.sprites.push(sprite)
push(current.sprites, sprite)
} else {
if (current) batches.push(current)
if (current) push(batches, current)
current = {type: 'sprite_batch', texture: tex, material: mat, sprites: [sprite]}
}
}
@@ -435,28 +438,28 @@ function _batch_drawables(drawables) {
var 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)) {
current.meshes.push(d)
push(current.meshes, d)
} else {
if (current) batches.push(current)
if (current) push(batches, current)
current = {type: 'mesh2d_batch', texture: tex, material: mat, meshes: [d]}
}
} else if (d.type == 'shape') {
// Shapes are rendered individually (each has unique SDF params)
if (current) {
batches.push(current)
push(batches, current)
current = null
}
batches.push({type: 'shape', drawable: d})
push(batches, {type: 'shape', drawable: d})
} else {
if (current) {
batches.push(current)
push(batches, current)
current = null
}
batches.push({type: d.type, drawable: d})
push(batches, {type: d.type, drawable: d})
}
}
if (current) batches.push(current)
if (current) push(batches, current)
return batches
}

View File

@@ -67,7 +67,7 @@ fx_graph.add_node = function(type, params) {
params: params,
output: {node_id: this.next_id - 1, slot: 'output'}
}
this.nodes.push(node)
push(this.nodes, node)
return node
}
@@ -203,7 +203,7 @@ NODE_EXECUTORS.composite = function(params, backend) {
// Emit composite_textures command (handled outside render pass)
var commands = []
commands.push({
push(commands, {
cmd: 'composite_textures',
base: base.target,
overlay: overlay.target,
@@ -233,7 +233,7 @@ NODE_EXECUTORS.mask = function(params, backend) {
// Emit apply_mask command (handled via shader pass outside render pass)
var commands = []
commands.push({
push(commands, {
cmd: 'apply_mask',
content_texture: content.target,
mask_texture: mask.target,
@@ -264,12 +264,12 @@ NODE_EXECUTORS.clip_rect = function(params, backend) {
}
}
commands.splice(insert_idx, 0, {cmd: 'scissor', rect: rect})
commands = array(array(array(commands, 0, insert_idx), [{cmd: 'scissor', rect: rect}]), array(commands, insert_idx))
// Add scissor reset before end_render
for (var i = length(commands) - 1; i >= 0; i--) {
if (commands[i].cmd == 'end_render') {
commands.splice(i, 0, {cmd: 'scissor', rect: null})
commands = array(array(array(commands, 0, i), [{cmd: 'scissor', rect:null}]) ,array(commands, i+1))
break
}
}
@@ -305,7 +305,7 @@ NODE_EXECUTORS.blit = function(params, backend) {
}
var commands = []
commands.push({
push(commands, {
cmd: 'blit',
texture: src_target,
target: target,
@@ -321,7 +321,7 @@ NODE_EXECUTORS.present = function(params, backend) {
var input = params.input
var commands = []
commands.push({cmd: 'present'})
push(commands, {cmd: 'present'})
return {commands: commands}
}
@@ -350,7 +350,7 @@ NODE_EXECUTORS.shader_pass = function(params, backend) {
}
var commands = []
commands.push({
push(commands, {
cmd: 'shader_pass',
shader: shader,
input: src,

View File

@@ -41,7 +41,7 @@ gesture.on_input = function(action_id, action) {
} else if (touchCount == 2) {
// Two touches - potential pinch
this.gestureState = 'multi'
var fingers = object.values(this.touches)
var fingers = array(array(this.touches), k => this.touches[k])
this.startDist = this.dist(fingers[0], fingers[1])
}
}
@@ -55,7 +55,7 @@ gesture.on_input = function(action_id, action) {
if (touchCount == 2 && this.gestureState == 'multi') {
// Check for pinch gesture
var fingers = object.values(this.touches)
var fingers = array(array(this.touches), k => this.touches[k])
var currentDist = this.dist(fingers[0], fingers[1])
var d = currentDist - this.startDist

View File

@@ -154,7 +154,7 @@ function create_image(path){
try{
def bytes = io.slurp(path);
var ext = array(path, '.').pop()
var ext = pop(array(path, '.'))
var raw = decode_image(bytes, ext);
/* ── Case A: single surface (from make_texture) ────────────── */
@@ -357,7 +357,7 @@ graphics.texture = function texture(path) {
}
graphics.tex_hotreload = function tex_hotreload(file) {
var basename = array(array(file, '/').pop(), '.')[0]
var basename = array(pop(array(file, '/')), '.')[0]
// Check if this basename exists in our cache
if (!(basename in cache)) return

View File

@@ -93,13 +93,13 @@ function create_user(index, config) {
// Push entity onto control stack
push: function(entity) {
this.control_stack.push(entity)
push(this.control_stack, entity)
},
// Pop from control stack
pop: function() {
if (length(this.control_stack) > 1) {
return this.control_stack.pop()
return pop(this.control_stack)
}
return null
},
@@ -166,7 +166,7 @@ function pick_user(canon) {
user.active_device = canon.device_id
if (find(user.paired_devices, canon.device_id) == null) {
user.paired_devices.push(canon.device_id)
push(user.paired_devices, canon.device_id)
}
}
}
@@ -207,7 +207,7 @@ function configure(opts) {
// Create users
_users = []
for (var i = 0; i < _config.max_users; i++) {
_users.push(create_user(i, _config))
push(_users, create_user(i, _config))
}
_initialized = true

View File

@@ -135,7 +135,8 @@ function make(defaults, display_names) {
// Remove from other actions
arrfor(array(this.action_map), act => {
var idx = search(this.action_map[act], new_control)
if (idx >= 0) this.action_map[act].splice(idx, 1)
if (idx >= 0)
this.action_map[act] = array(array(this.action_map[act], 0, idx), array(this.action_map[act], idx+1))
})
// Clear existing bindings for this device kind
@@ -143,9 +144,8 @@ function make(defaults, display_names) {
for (var i = length(target) - 1; i >= 0; i--) {
var existing_kind = starts_with(target[i], 'gamepad_') ? 'gamepad' :
starts_with(target[i], 'swipe_') ? 'touch' : 'keyboard'
if (existing_kind == device_kind) {
target.splice(i, 1)
}
if (existing_kind == device_kind)
this.action_map[action] = array(array(this.action_map[action], 0, i), array(this.action_map[action], i+1))
}
// Add new binding

View File

@@ -40,7 +40,7 @@ function gesture_stage(config) {
// Only process gamepad touchpad events
if (ev.control != 'gamepad_touchpad') {
output.push(ev)
push(output, ev)
continue
}
@@ -72,7 +72,7 @@ function gesture_stage(config) {
var d = currentDist - start_dist
if (Math.abs(d) >= pinch_th / 100) {
output.push({
push(output, {
kind: 'gesture',
device_id: ev.device_id,
control: d > 0 ? 'pinch_out' : 'pinch_in',
@@ -103,7 +103,7 @@ function gesture_stage(config) {
? (dx > 0 ? 'swipe_right' : 'swipe_left')
: (dy > 0 ? 'swipe_down' : 'swipe_up')
output.push({
push(output, {
kind: 'gesture',
device_id: ev.device_id,
control: dir,
@@ -139,18 +139,18 @@ function emacs_stage() {
// Only process keyboard button events
if (ev.device_id != 'kbm' || ev.kind != 'button' || !ev.pressed) {
output.push(ev)
push(output, ev)
continue
}
if (find(valid_emacs_keys, ev.control) == null) {
output.push(ev)
push(output, ev)
continue
}
// Only process if we have modifiers OR waiting for chord
if (!ev.mods?.ctrl && !ev.mods?.alt && !prefix) {
output.push(ev)
push(output, ev)
continue
}
@@ -174,7 +174,7 @@ function emacs_stage() {
if (prefix) {
var chord = prefix + " " + notation
prefix = null
output.push({
push(output, {
kind: 'chord',
device_id: ev.device_id,
control: chord,
@@ -183,7 +183,7 @@ function emacs_stage() {
time: ev.time
})
} else {
output.push({
push(output, {
kind: 'chord',
device_id: ev.device_id,
control: notation,
@@ -213,14 +213,14 @@ function action_stage(bindings) {
// Pass through non-button events
if (ev.kind != 'button' && ev.kind != 'chord' && ev.kind != 'gesture') {
output.push(ev)
push(output, ev)
continue
}
var actions = bindings.get_actions(ev.control)
if (length(actions) == 0) {
output.push(ev)
push(output, ev)
continue
}
@@ -230,7 +230,7 @@ function action_stage(bindings) {
if (ev.pressed) down[action] = true
else if (ev.released) down[action] = false
output.push({
push(output, {
kind: 'action',
device_id: ev.device_id,
control: action,
@@ -277,16 +277,16 @@ function make(user, config) {
var action = null
if (config.gestures != false) {
stages.push(gesture_stage(config))
push(stages, gesture_stage(config))
}
if (config.emacs != false) {
stages.push(emacs_stage())
push(stages, emacs_stage())
}
action = action_stage(user.bindings)
stages.push(action)
stages.push(delivery_stage(user))
push(stages, action)
push(stages, delivery_stage(user))
return {
stages: stages,

View File

@@ -81,9 +81,9 @@ function build_polyline_mesh(line) {
for (var i = 0; i < length(points); i++) {
var p = points[i]
if (points_space == 'local') {
pts.push({x: p.x + pos.x, y: p.y + pos.y})
push(pts, {x: p.x + pos.x, y: p.y + pos.y})
} else {
pts.push({x: p.x, y: p.y})
push(pts, {x: p.x, y: p.y})
}
}
@@ -92,7 +92,7 @@ function build_polyline_mesh(line) {
for (var i = 1; i < length(pts); i++) {
var dx = pts[i].x - pts[i-1].x
var dy = pts[i].y - pts[i-1].y
cumulative.push(cumulative[i-1] + math.sqrt(dx*dx + dy*dy))
push(cumulative, cumulative[i-1] + math.sqrt(dx*dx + dy*dy))
}
var total_length = cumulative[length(cumulative) - 1]
@@ -179,7 +179,7 @@ function build_polyline_mesh(line) {
n.y = dx
}
normals.push(n)
push(normals, n)
}
// Generate vertices (2 per point - left and right of line)
@@ -190,7 +190,7 @@ function build_polyline_mesh(line) {
var u = get_u(i)
// Left vertex (v=0)
verts.push({
push(verts, {
x: p.x + n.x * w,
y: p.y + n.y * w,
u: u,
@@ -199,7 +199,7 @@ function build_polyline_mesh(line) {
})
// Right vertex (v=1)
verts.push({
push(verts, {
x: p.x - n.x * w,
y: p.y - n.y * w,
u: u,
@@ -212,24 +212,24 @@ function build_polyline_mesh(line) {
for (var i = 0; i < length(pts) - 1; i++) {
var base = i * 2
// First triangle
indices.push(base + 0)
indices.push(base + 1)
indices.push(base + 2)
push(indices, base + 0)
push(indices, base + 1)
push(indices, base + 2)
// Second triangle
indices.push(base + 1)
indices.push(base + 3)
indices.push(base + 2)
push(indices, base + 1)
push(indices, base + 3)
push(indices, base + 2)
}
// Handle closed path
if (closed && length(pts) > 2) {
var last = (length(pts) - 1) * 2
indices.push(last + 0)
indices.push(last + 1)
indices.push(0)
indices.push(last + 1)
indices.push(1)
indices.push(0)
push(indices, last + 0)
push(indices, last + 1)
push(indices, 0)
push(indices, last + 1)
push(indices, 1)
push(indices, 0)
}
// Add round caps if requested
@@ -259,7 +259,7 @@ function add_round_cap(verts, indices, p, n, width, u, v_offset, v_scale, is_sta
var dy = is_start ? n.x : -n.x
// Center vertex
verts.push({
push(verts, {
x: p.x,
y: p.y,
u: u,
@@ -274,7 +274,7 @@ function add_round_cap(verts, indices, p, n, width, u, v_offset, v_scale, is_sta
var cx = math.cosine(angle)
var cy = math.sine(angle)
verts.push({
push(verts, {
x: p.x + cx * w,
y: p.y + cy * w,
u: u,
@@ -285,9 +285,9 @@ function add_round_cap(verts, indices, p, n, width, u, v_offset, v_scale, is_sta
// Fan triangles
for (var i = 0; i < segments; i++) {
indices.push(base_idx)
indices.push(base_idx + 1 + i)
indices.push(base_idx + 2 + i)
push(indices, base_idx)
push(indices, base_idx + 1 + i)
push(indices, base_idx + 2 + i)
}
}
@@ -307,17 +307,17 @@ function add_square_cap(verts, indices, p, n, width, u, v_offset, v_scale, is_st
var ey = p.y + dy * ext
// Four corners of the cap
verts.push({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.push({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.push({x: ex + n.x * w, y: ey + n.y * w, u: u, v: v_offset, r: 1, g: 1, b: 1, a: 1})
verts.push({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(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})
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})
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})
indices.push(base_idx + 0)
indices.push(base_idx + 1)
indices.push(base_idx + 2)
indices.push(base_idx + 1)
indices.push(base_idx + 3)
indices.push(base_idx + 2)
push(indices, base_idx + 0)
push(indices, base_idx + 1)
push(indices, base_idx + 2)
push(indices, base_idx + 1)
push(indices, base_idx + 3)
push(indices, base_idx + 2)
}
var defaults = {

View File

@@ -18,7 +18,7 @@ var particles2d_proto = {
var emitters = {
// Spawn a particle for an emitter
spawn: function(emitter) {
emitter.particles.push({
push(emitter.particles, {
pos: {
x: emitter.pos.x + (random() - 0.5) * emitter.spawn_area.width,
y: emitter.pos.y + (random() - 0.5) * emitter.spawn_area.height
@@ -76,17 +76,13 @@ var emitters = {
alpha = 1 - (p.time - p.life * 0.7) / (p.life * 0.3)
}
p.color.a = alpha
// Remove dead particles
if (p.time >= p.life) {
emitter.particles.splice(i, 1)
}
}
emitter.particles = filter(emitter.particles, p => p.time < p.life)
// Sync to film2d if handle provided
if (emitter.handle) {
if (emitter.handle)
emitter.handle.particles = emitter.particles
}
},
// Create an emitter config

View File

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

View File

@@ -91,7 +91,7 @@ rasterize.ellipse = function ellipse(pos, radii, opt) {
within_wedge(dx+1, dy, start, end, full_circle)
if (last || !next_in_ring) {
strips.push({
push(strips, {
x: run_start,
y: y_screen,
width: (cx + dx) - run_start + 1,
@@ -176,7 +176,7 @@ rasterize.round_rect = function round_rect(rect, radius, thickness) {
var w = dx_out - dx_in
if (w <= 0) continue
strips.push(
push(strips,
{ 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_l - dx_out, y:cy_b + dy, width:w, height:1 },
@@ -209,7 +209,7 @@ rasterize.fill_round_rect = function fill_round_rect(rect, radius) {
var dx = floor(math.sqrt(radius * radius - dy * dy))
var w = (dx << 1) + 1
caps.push(
push(caps,
{ 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_l - dx, y:cy_b + dy, width:w, height:1 },

View File

@@ -100,7 +100,7 @@ function read_ignore(dir) {
arrfor(lines, function(line) {
line = trim(line)
if (!line || starts_with(line, '#')) return
patterns.push(line)
push(patterns, line)
})
}
return patterns
@@ -120,7 +120,7 @@ Resources.getAllFiles = function(dir = "") {
if (!st.filesize) return
var ext = getExtension(f)
if (!isRecognizedExtension(ext)) return
results.push(fullPath)
push(results, fullPath)
} catch(e) {}
})
return results

View File

@@ -700,7 +700,7 @@ function _load_image_file(path) {
var decoded
if (!bytes) return null
var ext = lower(array(path, '.').pop())
var ext = lower(pop(array(path, '.')))
var surface = null
switch (ext) {
@@ -822,7 +822,7 @@ sdl_gpu.get_or_create_target = function(width, height, key) {
key: key
}
_target_pool[pool_key].push(target)
push(_target_pool[pool_key], target)
return target
}
@@ -1202,23 +1202,23 @@ function _execute_commands(commands, window_size) {
break
case 'draw_batch':
pending_draws.push(cmd)
push(pending_draws, cmd)
break
case 'draw_text':
pending_draws.push(cmd)
push(pending_draws, cmd)
break
case 'draw_texture_ref':
pending_draws.push(cmd)
push(pending_draws, cmd)
break
case 'draw_shape':
pending_draws.push(cmd)
push(pending_draws, cmd)
break
case 'draw_mesh2d':
pending_draws.push(cmd)
push(pending_draws, cmd)
break
case 'blit':
@@ -2219,7 +2219,7 @@ function _do_shader_pass(cmd_buffer, cmd, get_swapchain_tex) {
var samplers = [{texture: input.texture, sampler: _sampler_linear}]
if (cmd.extra_inputs) {
arrfor(cmd.extra_inputs, function(extra) {
samplers.push({texture: extra.texture, sampler: _sampler_linear})
push(samplers, {texture: extra.texture, sampler: _sampler_linear})
})
}
pass.bind_fragment_samplers(0, samplers)

View File

@@ -87,16 +87,6 @@ function loop()
render.present()
dt = os.now() - now
fps_samples.push(dt)
if (length(fps_samples) > fps_window) fps_samples.shift()
if (now - last_fps_update >= fps_update_period) {
var sum = 0
arrfor(fps_samples, x => sum += x)
prosperon.window.title = `Bunnymark [fps: ${(length(fps_samples)/sum).toFixed(1)}]`;
last_fps_update = now
}
var delay = (1/60) - dt
$delay(loop, delay)
}

View File

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

View File

@@ -2,7 +2,7 @@
var Surface = use('sdl3/surface');
// Test creating a surface
var surf = new Surface({width: 100, height: 100});
var surf = Surface({width: 100, height: 100});
log.console("Created surface:", surf.width, "x", surf.height);
log.console(surf)
@@ -26,12 +26,12 @@ var pixels = surf.pixels();
log.console("Got pixels array buffer, length:", pixels.byteLength);
// Test creating surface with custom format
var surf4 = new Surface({width: 64, height: 64, format: "rgb24"});
var surf4 = Surface({width: 64, height: 64, format: "rgb24"});
log.console("Created RGB24 surface:", surf4.width, "x", surf4.height, "format:", surf4.format);
// Test creating surface from pixels
var pixelData = new ArrayBuffer(32 * 32 * 4); // 32x32 RGBA
var surf5 = new Surface({width: 32, height: 32, pixels: pixelData});
var pixelData = ArrayBuffer(32 * 32 * 4); // 32x32 RGBA
var surf5 = Surface({width: 32, height: 32, pixels: pixelData});
log.console("Created surface from pixels:", surf5.width, "x", surf5.height);
log.console("Surface module test passed!");

View File

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

View File

@@ -8,7 +8,7 @@ function make_engine(default_clock) {
tweens: [],
default_clock: default_clock || null,
add(tween) {
this.tweens.push(tween)
push(this.tweens, tween)
},
remove(tween) {
this.tweens = filter(this.tweens, t => t != tween)
@@ -160,7 +160,7 @@ var TimelineProto = {
engine: null,
add_event: function(time_value, fn) {
this.events.push({ time: time_value, fn, fired: false })
push(this.events, { time: time_value, fn, fired: false })
},
add_tween: function(obj, props, duration, start_time) {