This commit is contained in:
2026-01-19 01:06:51 -06:00
parent a199278e7d
commit 86530871e6
19 changed files with 133 additions and 140 deletions

View File

@@ -238,7 +238,7 @@ action.on_input = function(action_id, evt)
// Send all matched actions (only if we found mappings - this means it's a raw input)
if (length(matched_actions) > 0) {
for (var i = 0; i < length(matched_actions); i++) {
// scene.recurse(game.root, 'on_input', matched_actions[i], evt)
// scene.recurse(game.root, 'on_input', [matched_actions[i], evt])
}
}
}

View File

@@ -5,7 +5,7 @@ var cam = {}
letterbox
overscan
stretch
... or simply 'null' for no presentation
.. or simply 'null' for no presentation
*/
function rect_contains_pt(rect, x, y) {

View File

@@ -202,12 +202,9 @@ function build_drawables(node, root_height, parent_abs_x, parent_abs_y, parent_s
}
// Children
for (var child of node.children) {
var child_drawables = build_drawables(child, root_height, vis_x, vis_y, current_scissor, parent_layer + 0.01)
for (var i = 0; i < length(child_drawables); i++) {
drawables.push(child_drawables[i])
}
}
arrfor(node.children, function(child) {
drawables = array(drawables, build_drawables(child, root_height, vis_x, vis_y, current_scissor, parent_layer + 0.01))
})
return drawables
}

View File

@@ -76,7 +76,7 @@ clay_input.get_actionable = function get_actionable(tree_root) {
function walk(node) {
if (node.config.action) actionable.push(node)
if (node[clay.CHILDREN])
for (var child of node[clay.CHILDREN]) walk(child)
arrfor(node[clay.CHILDREN], walk)
}
walk(tree_root)
return actionable
@@ -87,7 +87,7 @@ clay_input.filter = function filter(tree_root, predicate) {
function rec(node) {
if (predicate(node)) results.push(node)
if (node[clay.CHILDREN])
for (var child of node[clay.CHILDREN]) rec(child)
arrfor(node[clay.CHILDREN], rec)
}
rec(tree_root)
return results
@@ -97,10 +97,10 @@ clay_input.find_by_id = function find_by_id(tree_root, id) {
function rec(node) {
if (node.id == id) return node
if (node[clay.CHILDREN])
for (var child of node[clay.CHILDREN]) {
arrfor(node[clay.CHILDREN], function(child) {
var f = rec(child)
if (f) return f
}
})
return null
}
return rec(tree_root)

View File

@@ -93,11 +93,11 @@ Color.normalize = function (c) {
return n;
};
for (var p of array(c)) {
if (!is_object(c[p])) continue;
arrfor(array(c), function(p) {
if (!is_object(c[p])) return;
if (!is_array(c[p])) {
Color.normalize(c[p]);
continue;
return;
}
// Add alpha channel if not present
@@ -107,12 +107,12 @@ Color.normalize = function (c) {
// Check if any values are > 1 (meaning they're in 0-255 format)
var needs_conversion = false;
for (var color of c[p]) {
arrfor(c[p], function(color) {
if (color > 1) {
needs_conversion = true;
break;
return;
}
}
})
// Convert from 0-255 to 0-1 if needed
if (needs_conversion) {
@@ -120,7 +120,7 @@ Color.normalize = function (c) {
}
c[p].alpha = add_a;
}
})
};
Color.normalize(Color);
@@ -181,22 +181,25 @@ ColorMap.Viridis = ColorMap.makemap({
Color.normalize(ColorMap);
ColorMap.sample = function (t, map = this) {
if (t < 0) return map[0];
if (t > 1) return map[1];
ColorMap.sample = function(t, map = this) {
if (t < 0) return map[0]
if (t > 1) return map[1]
var lastkey = 0;
for (var key of sorted(array(map))) {
var keys = sorted(array(map))
var lastkey = 0
for (var i = 0; i < length(keys); i++) {
var key = keys[i]
if (t < key) {
var b = map[key];
var a = map[lastkey];
var tt = (key - lastkey) * t;
return a.lerp(b, tt);
var b = map[key]
var a = map[lastkey]
var tt = (t - lastkey) / (key - lastkey)
return a.lerp(b, tt)
}
lastkey = key;
lastkey = key
}
return map[1];
};
return map[1]
}
ColorMap.doc = {
sample: "Sample a given colormap at the given percentage (0 to 1).",

View File

@@ -211,27 +211,27 @@ var Player = {
},
mouse_input(type, ...args) {
for (var pawn of reverse([...this.pawns])) {
if (is_function(pawn.inputs?.mouse?.[type])) {
arrfor(array(this.pawns), function(pawn) {
if (is_function(pawn.inputs.mouse[type])) {
call(pawn.inputs.mouse[type], pawn, ...args);
pawn.inputs.post?.call(pawn);
if (!pawn.inputs.fallthru) return;
}
}
}, true)
},
char_input(c) {
for (var pawn of reverse([...this.pawns])) {
if (is_function(pawn.inputs?.char)) {
arrfor(array(this.pawns), function(pawn) {
if (is_function(pawn.inputs.char)) {
call(pawn.inputs.char, pawn, c);
pawn.inputs.post?.call(pawn);
if (!pawn.inputs.fallthru) return;
}
}
}, true)
},
joy_input(name, joystick) {
for (var pawn of reverse([...this.pawns])) {
arrfor(array(this.pawns), function(pawn) {
if (!pawn.inputs) return;
if (!pawn.inputs.joystick) return;
if (!pawn.inputs.joystick[name]) return;
@@ -244,11 +244,11 @@ var Player = {
if (input.keyboard.down(joystick.dy)) y--;
pawn.inputs.joystick[name](x, y);
}
}, true)
},
raw_input(cmd, state, ...args) {
for (var pawn of reverse([...this.pawns])) {
arrfor(array(this.pawns), function(pawn) {
var inputs = pawn.inputs;
if (!inputs[cmd]) {
@@ -281,19 +281,19 @@ var Player = {
if (state == "released") call(inputs.release_post, pawn);
if (inputs.block) return;
if (consumed) return;
}
}, true)
},
obj_controlled(obj) {
for (var p in Player.players) {
if (p.pawns.has(obj)) return true;
if (p.pawns[obj]) return true;
}
return false;
},
print_pawns() {
arrfor(reverse([...this.pawns]), x => log.console(x))
arrfor(array(this.pawns), x => log.console(x), true)
},
create() {

10
core.cm
View File

@@ -100,7 +100,7 @@ function _main_loop() {
// Get input module for auto-ingestion
var input_mod = use('input')
for (var ev of evts) {
arrfor(evts, function(ev) {
if (_config.imgui || _config.editor) {
imgui.process_event(ev)
}
@@ -127,7 +127,7 @@ function _main_loop() {
if (_config.input) {
_config.input(ev_obj)
}
}
})
// Update
if (_config.update) {
@@ -198,11 +198,7 @@ function _main_loop() {
if (length(_fps_samples) > _fps_sample_count) {
_fps_samples.shift()
}
var avg_frame_time = 0
for (var i = 0; i < length(_fps_samples); i++) {
avg_frame_time += _fps_samples[i]
}
avg_frame_time = avg_frame_time / length(_fps_samples)
var avg_frame_time = reduce(_fps_samples, function(a,b) { return a+b }) / length(_fps_samples)
_current_fps = avg_frame_time > 0 ? 1 / avg_frame_time : 0
// Schedule next frame

View File

@@ -86,9 +86,9 @@ action.on_input = function(action_id, action_data)
if (this.prefix_key) {
var full_command = this.prefix_key + " " + emacs_notation
this.prefix_key = null // Reset prefix key
// scene.recurse(game.root, 'on_input', full_command, action_data)
// scene.recurse(game.root, 'on_input', [full_command, action_data])
} else {
// scene.recurse(game.root, 'on_input', emacs_notation, action_data)
// scene.recurse(game.root, 'on_input', [emacs_notation, action_data])
}
}

View File

@@ -31,8 +31,7 @@ this.update = function(dt) {
var currentFPS = 1 / dt
fpsSamples.push(currentFPS)
if (length(fpsSamples) > 60) fpsSamples.shift()
var sum = 0
for (var f of fpsSamples) sum += f
var sum = reduce(fpsSamples, function(a,b) { return a + b })
fpsAvg = sum / length(fpsSamples)
// If left mouse is down, spawn some more bunnies:

View File

@@ -47,10 +47,10 @@ grid.prototype = {
each(fn) {
for (var y = 0; y < this.height; y++) {
for (var x = 0; x < this.width; x++) {
def list = this.cells[y][x];
for (var entity of list) {
def list = this.cells[y][x]
arrfor(list, function(entity) {
fn(entity, entity.coord);
}
})
}
}
},

View File

@@ -81,11 +81,11 @@ fx_graph.execute = function(backend) {
var node_outputs = {}
var all_commands = []
for (var node of sorted) {
arrfor(sorted, function(node) {
var executor = NODE_EXECUTORS[node.type]
if (!executor) {
log.console(`fx_graph: No executor for node type: ${node.type}`)
continue
return
}
var resolved_params = this.resolve_inputs(node.params, node_outputs)
@@ -96,11 +96,9 @@ fx_graph.execute = function(backend) {
// Collect commands from this node
if (result && result.commands) {
for (var cmd of result.commands) {
all_commands.push(cmd)
}
all_commands = array(all_commands, result.commands)
}
}
})
return {commands: all_commands}
}

View File

@@ -61,7 +61,7 @@ gesture.on_input = function(action_id, action) {
if (abs(d) >= this.PINCH_TH) {
var gesture_type = d > 0 ? 'pinch_out' : 'pinch_in'
// scene.recurse(game.root, 'on_input', gesture_type, { delta: d })
// scene.recurse(game.root, 'on_input', [gesture_type, { delta: d }])
this.startDist = currentDist
}
}
@@ -85,7 +85,7 @@ gesture.on_input = function(action_id, action) {
? (dx > 0 ? 'swipe_right' : 'swipe_left')
: (dy > 0 ? 'swipe_down' : 'swipe_up')
audio.play('swipe')
// scene.recurse(game.root, 'on_input', dir, {pressed:true})
// scene.recurse(game.root, 'on_input', [dir, {pressed:true}])
}
}
}

View File

@@ -178,12 +178,12 @@ function create_image(path){
return makeAnim(wrapFrames(raw.frames), !!raw.loop);
def anims = {};
for(def [name, anim] of Object.entries(raw)){
arrfor(Object.entries(raw), function([name, anim]) {
if(anim && is_array(anim.frames))
anims[name] = makeAnim(wrapFrames(anim.frames), !!anim.loop);
else if(anim && anim.surface)
anims[name] = new graphics.Image(anim.surface);
}
})
if(length(array(anims))) return anims;
}

View File

@@ -34,7 +34,7 @@ PlaydateBackend.prototype.get_or_create_target = function(width, height, key) {
this.target_pool[pool_key] = []
// Reuse from pool
for (var target of this.target_pool[pool_key]) {
arrfor(this.target_pool[pool_key], function(target) {
if (!target.in_use) {
target.in_use = true
// Clear bitmap for reuse
@@ -43,7 +43,7 @@ PlaydateBackend.prototype.get_or_create_target = function(width, height, key) {
this.pd.graphics.popContext()
return target
}
}
})
// Create new LCDBitmap
var bitmap = this.pd.graphics.newBitmap(width, height, this.pd.graphics.kColorClear)
@@ -61,10 +61,11 @@ PlaydateBackend.prototype.get_or_create_target = function(width, height, key) {
}
PlaydateBackend.prototype.release_all_targets = function() {
for (var pool_key in this.target_pool) {
for (var target of this.target_pool[pool_key])
arrfor(array(this.target_pool), function(key) {
arrfor(this.target_pool[key], function(target) {
target.in_use = false
}
})
})
}
// ========================================================================
@@ -73,9 +74,9 @@ PlaydateBackend.prototype.release_all_targets = function() {
PlaydateBackend.prototype.execute = function(commands) {
// No command buffer concept - execute immediately
for (var cmd of commands) {
arrfor(commands, function(cmd) {
this.execute_command(cmd)
}
})
this.release_all_targets()
}

View File

@@ -2,9 +2,9 @@ var io = use('cellfs')
function hashify(fn) {
var hash = {}
return function(...args) {
var key = args[0]
if (hash[key] == null) hash[key] = fn(...args)
return function(arg) {
var key = arg
if (hash[key] == null) hash[key] = fn(arg)
return hash[key]
}
}
@@ -52,10 +52,15 @@ function find_in_path(filename, exts = []) {
// Only check extensions if exts is provided and not empty
if (length(exts) > 0) {
for (var ext of exts) {
var cand = null
arrfor(exts, function(ext) {
var candidate = filename + '.' + ext
if (io.exists(candidate) && !io.is_directory(candidate)) return candidate
}
if (io.exists(candidate) && !io.is_directory(candidate)){
cand = candidate
return true
}
}, null, true)
if (cand != null) return cand
} else {
// Fallback to extensionless file only if no extensions are specified
var candidate = filename
@@ -92,11 +97,11 @@ function read_ignore(dir) {
var patterns = []
if (io.exists(path)) {
var lines = array(io.slurp(path), '\n')
for (var line of lines) {
arrfor(lines, function(line) {
line = trim(line)
if (!line || starts_with(line, '#')) continue
if (!line || starts_with(line, '#')) return
patterns.push(line)
}
})
}
return patterns
}
@@ -107,17 +112,17 @@ Resources.getAllFiles = function(dir = "") {
var patterns = read_ignore(dir)
var all = io.globfs(patterns, dir)
var results = []
for (var f of all) {
arrfor(all, function(f) {
var fullPath = dir + '/' + f
try {
var st = io.stat(fullPath)
// skip directories (filesize=0) or unrecognized extension
if (!st.filesize) continue
if (!st.filesize) return
var ext = getExtension(f)
if (!isRecognizedExtension(ext)) continue
if (!isRecognizedExtension(ext)) return
results.push(fullPath)
} catch(e) {}
}
})
return results
}
@@ -126,26 +131,26 @@ Resources.gatherStats = function(filePaths) {
var stats = {
scripts:0, images:0, sounds:0, fonts:0, lib:0, other:0, total:length(filePaths)
}
for (var path of filePaths) {
arrfor(filePaths, function(path) {
var ext = getExtension(path)
if (find(Resources.scripts, ext) != null) {
stats.scripts++
continue
return
}
if (find(Resources.images, ext) != null) {
stats.images++
continue
return
}
if (find(Resources.sounds, ext) != null) {
stats.sounds++
continue
return
}
if (find(Resources.fonts, ext) != null) {
stats.fonts++
continue
return
}
stats.other++
}
})
return stats
}

View File

@@ -782,21 +782,21 @@ sdl_gpu.get_or_create_target = function(width, height, key) {
// Reuse from pool if available
// 1. Check if a target with this exact key already exists
if (key) {
for (var target of _target_pool[pool_key]) {
if (target.key == key) {
target.in_use = true
return target
}
var pool = _target_pool[pool_key]
var idx = find(pool, function(t) { return t.key == key })
if (idx != null) {
pool[idx].in_use = true
return pool[idx]
}
}
// 2. Otherwise prefer most recently used (LIFO) or just first available
for (var target of _target_pool[pool_key]) {
if (!target.in_use) {
target.in_use = true
target.key = key
return target
}
var pool = _target_pool[pool_key]
var idx = find(pool, function(t) { return !t.in_use })
if (idx != null) {
pool[idx].in_use = true
pool[idx].key = key
return pool[idx]
}
// Create new render target texture
@@ -827,10 +827,11 @@ sdl_gpu.get_or_create_target = function(width, height, key) {
}
sdl_gpu.release_all_targets = function() {
for (var pool_key in _target_pool) {
for (var target of _target_pool[pool_key])
arrfor(array(_target_pool), function(pool_key) {
arrfor(_target_pool[pool_key], function(target) {
target.in_use = false
}
})
})
}
// ========================================================================
@@ -1118,13 +1119,12 @@ sdl_gpu.execute_commands = function(commands, window_size, dbg = false) {
function _preload_textures(commands) {
var paths = {}
for (var cmd of commands) {
arrfor(commands, function(cmd) {
if (cmd.cmd == 'draw_batch' && cmd.texture) {
if (is_text(cmd.texture)) {
if (is_text(cmd.texture))
paths[cmd.texture] = true
}
}
}
})
// Load all textures
for (var path in paths) {
@@ -1148,7 +1148,7 @@ function _execute_commands(commands, window_size) {
return _swapchain_tex
}
for (var cmd of commands) {
arrfor(commands, function(cmd) {
switch (cmd.cmd) {
case 'begin_render':
// Flush pending draws
@@ -1352,7 +1352,7 @@ function _execute_commands(commands, window_size) {
// Submit command buffer
break
}
}
})
// Final flush
if (current_pass && length(pending_draws) > 0) {
@@ -1370,7 +1370,7 @@ function _flush_draws(cmd_buffer, pass, draws, camera, target) {
var current_batch = null
// Iterate draws preserving order
for (var draw of draws) {
arrfor(draws, function(draw) {
if (draw.cmd == 'draw_batch') {
// Sprite batch handling
var tex_path = draw.texture || '_white'
@@ -1386,9 +1386,7 @@ function _flush_draws(cmd_buffer, pass, draws, camera, target) {
// Append sprites
if (draw.geometry && draw.geometry.sprites) {
for (var s of draw.geometry.sprites) {
current_batch.sprites.push(s)
}
current_batch.sprites = array(current_batch.sprites, draw.geometry.sprites)
}
} else {
// Flush current batch
@@ -1403,11 +1401,8 @@ function _flush_draws(cmd_buffer, pass, draws, camera, target) {
sprites: []
}
if (draw.geometry && draw.geometry.sprites) {
for (var s of draw.geometry.sprites) {
current_batch.sprites.push(s)
}
}
if (draw.geometry && draw.geometry.sprites)
current_batch.sprites = array(current_batch.sprites, draw.geometry.sprites)
}
} else if (draw.cmd == 'draw_text') {
// Flush current batch
@@ -1438,7 +1433,7 @@ function _flush_draws(cmd_buffer, pass, draws, camera, target) {
// Render mesh2d batch
_render_mesh2d(cmd_buffer, pass, draw, camera, target)
}
}
})
// Flush final batch
if (current_batch) _render_batch(cmd_buffer, pass, current_batch, camera, target)
@@ -1705,10 +1700,10 @@ function _render_mesh2d(cmd_buffer, pass, draw, camera, target) {
// Count total vertices and indices
var total_verts = 0
var total_indices = 0
for (var m of meshes) {
arrfor(meshes, function(m) {
if (m.verts) total_verts += length(m.verts)
if (m.indices) total_indices += length(m.indices)
}
})
if (total_verts == 0 || total_indices == 0) return
@@ -1718,14 +1713,14 @@ function _render_mesh2d(cmd_buffer, pass, draw, camera, target) {
var index_data = blob_mod(total_indices * 2)
var vertex_offset = 0
for (var m of meshes) {
arrfor(meshes, function(m) {
var verts = m.verts || []
var indices = m.indices || []
var opacity = m.opacity != null ? m.opacity : 1
var tint = m.tint || {r: 1, g: 1, b: 1, a: 1}
// Write vertices
for (var v of verts) {
arrfor(verts, function(v) {
vertex_data.wf(v.x)
vertex_data.wf(v.y)
vertex_data.wf(v.u != null ? v.u : 0)
@@ -1738,15 +1733,15 @@ function _render_mesh2d(cmd_buffer, pass, draw, camera, target) {
vertex_data.wf(g)
vertex_data.wf(b)
vertex_data.wf(a)
}
})
// Write indices (offset by current vertex count)
for (var idx of indices) {
arrfor(indices, function(idx) {
index_data.w16(vertex_offset + idx)
}
})
vertex_offset += length(verts)
}
})
// Upload geometry
var vb_size = total_verts * 32
@@ -2223,9 +2218,9 @@ function _do_shader_pass(cmd_buffer, cmd, get_swapchain_tex) {
// Bind samplers
var samplers = [{texture: input.texture, sampler: _sampler_linear}]
if (cmd.extra_inputs) {
for (var extra of cmd.extra_inputs) {
arrfor(cmd.extra_inputs, function(extra) {
samplers.push({texture: extra.texture, sampler: _sampler_linear})
}
})
}
pass.bind_fragment_samplers(0, samplers)

View File

@@ -29,7 +29,7 @@ var Anim = (() => {
}
function current(a){ return a.src.frames[a.idx].image; }
function updateAll(arr, dt){ for(def a of arr) update(a, dt); }
function updateAll(arr, dt){ arrfor(arr, function(a){ update(a, dt); }) }
function draw(a, pos, opt, pipe){
draw2d.image(current(a), pos, 0, [0,0], [0,0], opt, pipe);
}

View File

@@ -55,8 +55,7 @@ function loop()
render.clear([22/255,120/255,194/255,255/255])
render.camera(camera)
for (var sp of sprite.sprites)
draw.image(sp.image, sp.rect)
arrfor(sprite.sprites, sp => draw.image(sp.image, sp.rect))
/* draw.line([[0,0],[100,50]])
draw.point([100,100])

View File

@@ -17,9 +17,9 @@ function make_engine(default_clock) {
if (current_time == null) {
current_time = this.default_clock ? this.default_clock() : time.number()
}
for (var tween of array(this.tweens)) {
arrfor(this.tweens, function(tween) {
tween._update(current_time)
}
})
},
clear() {
this.tweens = []
@@ -198,14 +198,14 @@ var TimelineProto = {
this.engine.update(t)
// Fire any events
for (var ev of this.events) {
arrfor(this.events, function(ev) {
if (!ev.fired && t >= ev.time) {
ev.fn()
ev.fired = true
} else if (ev.fired && t < ev.time) {
ev.fired = false
}
}
})
},
toJSON: function() {