From f389609bd9d3546d3a20dd54b5b35fbe5cdb6cc7 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Mon, 21 Jul 2025 14:42:26 -0500 Subject: [PATCH] improvements --- prosperon/clay.cm | 13 +++++----- prosperon/ease.cm | 24 ++++++++++++++++++ prosperon/prosperon.cm | 56 ++++++++++++++++++++++++++++++++++++------ prosperon/tilemap.cm | 3 ++- prosperon/tween.cm | 32 +++++++++++++++++++++--- scripts/graphics.cm | 2 +- 6 files changed, 110 insertions(+), 20 deletions(-) diff --git a/prosperon/clay.cm b/prosperon/clay.cm index 4ee26c94..881e18d9 100644 --- a/prosperon/clay.cm +++ b/prosperon/clay.cm @@ -77,13 +77,12 @@ clay.draw = function draw(size, fn, config = {}) box.boundingbox = Object.assign({}, box.content); var padding = normalizeSpacing(box.config.padding || 0); - if (padding.l || padding.r || padding.t || padding.b) { - // Adjust the boundingbox to include the padding - box.boundingbox.x -= padding.l; - box.boundingbox.y -= padding.t; - box.boundingbox.width += padding.l + padding.r; - box.boundingbox.height += padding.t + padding.b; - } + + box.boundingbox.x -= padding.l; + box.boundingbox.y -= padding.t; + box.boundingbox.width += padding.l + padding.r; + box.boundingbox.height += padding.t + padding.b; + box.marginbox = Object.assign({}, box.content); var margin = normalizeSpacing(box.config.margin || 0); box.marginbox.x -= margin.l; diff --git a/prosperon/ease.cm b/prosperon/ease.cm index a00376e1..389eb354 100644 --- a/prosperon/ease.cm +++ b/prosperon/ease.cm @@ -121,4 +121,28 @@ Ease.elastic = { Ease.elastic.c4 = (2 * Math.PI) / 3 Ease.elastic.c5 = (2 * Math.PI) / 4.5 +Ease.zoom = { + // Creates a smooth zoom that maintains constant perceptual speed + // ratio is the zoom factor (e.g., 10 for 10x zoom) + smooth(ratio) { + return function(t) { + if (t == 0) return 0 + if (t == 1) return 1 + if (Math.abs(ratio - 1) < 0.001) return t + // Position interpolation formula: (r^t - 1) / (r - 1) + return (Math.pow(ratio, t) - 1) / (ratio - 1) + } + }, + // Exponential interpolation for zoom values + // Interpolates in logarithmic space for smooth visual zoom + exp(startZoom, endZoom) { + return function(t) { + if (t == 0) return startZoom + if (t == 1) return endZoom + // Scale := Exp(LinearInterpolate(Ln(Scale1), Ln(Scale2), t)) + return Math.exp(Math.log(startZoom) + t * (Math.log(endZoom) - Math.log(startZoom))) + } + } +} + return Ease \ No newline at end of file diff --git a/prosperon/prosperon.cm b/prosperon/prosperon.cm index aa93d502..a4f86d93 100644 --- a/prosperon/prosperon.cm +++ b/prosperon/prosperon.cm @@ -199,15 +199,55 @@ function translate_draw_commands(commands) { cmd.rect.width = cmd.rect.width * cmd.scale.x cmd.rect.height = cmd.rect.height * cmd.scale.y cmd.rect = worldToScreenRect(cmd.rect, camera) - - renderer_commands.push({ - op: "texture", - data: { - texture_id: gpu, - dst: cmd.rect, - src: img.rect + + if (cmd.info && (cmd.info.tile_x || cmd.info.tile_y)) { + // Use tiling functionality + var tile_buffer = geometry.tile( + img, + img.rect, // source rect in UV coords + cmd.rect, // destination rect in screen coords + { + repeat_x: cmd.info.tile_x || false, + repeat_y: cmd.info.tile_y || false + } + ) + + if (tile_buffer) { + // Transform XY coordinates using camera matrix + var camera_params = [camera.a, camera.c, camera.e, camera.f] + var transformed_xy = geometry.transform_xy_blob(tile_buffer.xy, camera_params) + + // Create transformed geometry object + var transformed_geom = { + xy: transformed_xy, + xy_stride: tile_buffer.xy_stride, + uv: tile_buffer.uv, + uv_stride: tile_buffer.uv_stride, + color: tile_buffer.color, + color_stride: tile_buffer.color_stride, + indices: tile_buffer.indices, + num_vertices: tile_buffer.num_vertices, + num_indices: tile_buffer.num_indices, + size_indices: tile_buffer.size_indices, + texture_id: gpu + } + + renderer_commands.push({ + op: "geometry_raw", + data: transformed_geom + }) } - }) + } else { + // Normal non-tiled rendering + renderer_commands.push({ + op: "texture", + data: { + texture_id: gpu, + dst: cmd.rect, + src: img.rect + } + }) + } break diff --git a/prosperon/tilemap.cm b/prosperon/tilemap.cm index 05252dfc..b935a256 100644 --- a/prosperon/tilemap.cm +++ b/prosperon/tilemap.cm @@ -158,7 +158,8 @@ tilemap.prototype = this._dirty = false; }, - draw(pos = {x: 0, y: 0}) { + draw() { + var pos = this.pos || {x:0,y:0} // Rebuild cache if dirty or position changed if (this._dirty || Object.keys(this._geometry_cache).length == 0 || this._last_pos?.x != pos.x || this._last_pos?.y != pos.y) { this._build_geometry_cache(pos); diff --git a/prosperon/tween.cm b/prosperon/tween.cm index fe97be46..87e0ff7d 100644 --- a/prosperon/tween.cm +++ b/prosperon/tween.cm @@ -40,8 +40,18 @@ function Tween(obj) { Tween.prototype.to = function(props, duration, start_time) { for (var key in props) { - this.startVals[key] = this.obj[key] - this.endVals[key] = props[key] + var value = props[key] + if (typeof value == 'object' && value != null && !Array.isArray(value)) { + // Handle nested objects by flattening them + for (var subkey in value) { + var flatKey = key + '.' + subkey + this.startVals[flatKey] = this.obj[key] ? this.obj[key][subkey] : undefined + this.endVals[flatKey] = value[subkey] + } + } else { + this.startVals[key] = this.obj[key] + this.endVals[key] = value + } } this.duration = duration @@ -85,7 +95,23 @@ Tween.prototype.seek = function(global_time) { for (var key in this.endVals) { var start = this.startVals[key] var end = this.endVals[key] - this.obj[key] = start + (end - start) * eased + var value = start + (end - start) * eased + + if (key.includes('.')) { + // Handle nested object properties + var parts = key.split('.') + var objKey = parts[0] + var subKey = parts[1] + + // Ensure the nested object exists + if (!this.obj[objKey]) { + this.obj[objKey] = {} + } + + this.obj[objKey][subKey] = value + } else { + this.obj[key] = value + } } if (t == 1 && this.engine) { diff --git a/scripts/graphics.cm b/scripts/graphics.cm index e17725fd..0fcffc41 100644 --- a/scripts/graphics.cm +++ b/scripts/graphics.cm @@ -312,7 +312,7 @@ graphics.texture = function texture(path) { if (!cache[id]) { var ipath = res.find_image(id) if (!ipath) - throw new Error(`unknown image ${id}`) + return graphics.texture('notex') var result = create_image(ipath) cache[id] = result