diff --git a/prosperon/clay.cm b/prosperon/clay.cm index cd663d16..210d27f2 100644 --- a/prosperon/clay.cm +++ b/prosperon/clay.cm @@ -36,7 +36,7 @@ var clay_base = { spacing:0, padding:0, margin:0, - offset:[0,0], + offset:{x:0, y:0}, size:null, background_color: null }; @@ -54,6 +54,10 @@ clay.draw = function draw(size, fn, config = {}) lay_ctx.reset(); boxes = []; var root = lay_ctx.item(); + // Accept both array and object formats + if (Array.isArray(size)) { + size = {width: size[0], height: size[1]}; + } lay_ctx.set_size(root,size); lay_ctx.set_contain(root,layout.contain.row); root_item = root; @@ -86,9 +90,9 @@ clay.draw = function draw(size, fn, config = {}) box.marginbox.width += margin.l+margin.r; box.marginbox.height += margin.t+margin.b; box.content.y *= -1; - box.content.y += size.y; + box.content.y += size.height; box.boundingbox.y *= -1; - box.boundingbox.y += size.y; + box.boundingbox.y += size.height; box.content.anchor_y = 1; box.boundingbox.anchor_y = 1; } @@ -128,7 +132,7 @@ clay.spacer = create_view_fn({ function image_size(img) { - return [img.rect[2]*img.texture.width, img.rect[3]*img.texture.height]; + return [img.width * (img.rect?.width || 1), img.height * (img.rect?.height || 1)]; } function add_item(config) @@ -163,6 +167,11 @@ function add_item(config) var item = lay_ctx.item(); lay_ctx.set_margins(item, use_config.margin); + use_config.size ??= {width:0, height:0} + // Convert array to object if needed + if (Array.isArray(use_config.size)) { + use_config.size = {width: use_config.size[0], height: use_config.size[1]}; + } lay_ctx.set_size(item,use_config.size); lay_ctx.set_contain(item,use_config.contain); lay_ctx.set_behave(item,use_config.behave); @@ -195,18 +204,18 @@ clay.image = function image(path, ...configs) { var config = rectify_configs(configs); var image = graphics.texture(path); - config.image = image; - config.size ??= [image.texture.width, image.texture.height]; + config.image = path; // Store the path string, not the texture object + config.size ??= {width: image.width, height: image.height}; add_item(config); } clay.text = function text(str, ...configs) { var config = rectify_configs(configs); - config.size ??= [0,0]; + config.size ??= {width:0, height:0}; // config.font = graphics.get_font(config.font) - var tsize = 12; //config.font.text_size(str, 0, 0, config.size.x); - config.size = config.size.map((x,i) => Math.max(x, tsize[i])); + var tsize = {width: 12, height: 12}; //config.font.text_size(str, 0, 0, config.size.width); + config.size = {width: Math.max(config.size.width, tsize.width), height: Math.max(config.size.height, tsize.height)}; config.text = str; add_item(config); } @@ -236,13 +245,17 @@ clay.button = function button(str, action, config = {}) var hovered = null; clay.newframe = function() { hovered = null; } +function point_add(a,b) { + return {x: a.x+b.x, y: a.y+b.y} +} + // mousepos given in hud coordinates -clay.draw_commands = function draw_commands(cmds, pos = [0,0], mousepos = prosperon.camera.screen2hud(input.mouse.screenpos())) +clay.draw_commands = function draw_commands(cmds, pos = {x:0, y:0}, mousepos = {x:0,y:0}) { for (var cmd of cmds) { var config = cmd.config; - var boundingbox = geometry.rect_move(cmd.boundingbox,pos.add(config.offset)); - var content = geometry.rect_move(cmd.content,pos.add(config.offset)); + var boundingbox = geometry.rect_move(cmd.boundingbox,point_add(pos,config.offset)); + var content = geometry.rect_move(cmd.content,point_add(pos, config.offset)); if (config.hovered && geometry.rect_point_inside(boundingbox, mousepos)) { config.hovered.__proto__ = config; @@ -259,7 +272,7 @@ clay.draw_commands = function draw_commands(cmds, pos = [0,0], mousepos = prospe draw.rectangle(boundingbox, config.background_color); if (config.text) - draw.text(config.text, content, config.font, config.font_size, config.color, config.size.x); + draw.text(config.text, content, config.font, config.font_size, config.color, config.size.width); if (config.image) draw.image(config.image, content, 0, config.color); } @@ -270,7 +283,7 @@ clay.debug_colors = dbg_colors; dbg_colors.content = [1,0,0,0.1]; dbg_colors.boundingbox = [0,1,0,0,0.1]; dbg_colors.margin = [0,0,1,0.1]; -clay.draw_debug = function draw_debug(cmds, pos = [0,0]) +clay.draw_debug = function draw_debug(cmds, pos = {x:0, y:0}) { for (var i = 0; i < cmds.length; i++) { var cmd = cmds[i]; diff --git a/prosperon/graphics.cm b/prosperon/graphics.cm index 331268f6..6ea7cc2f 100644 --- a/prosperon/graphics.cm +++ b/prosperon/graphics.cm @@ -6,7 +6,7 @@ Includes both JavaScript and C-implemented routines for creating geometry buffer rectangle packing, etc. ` -var renderer_actor = arg[0] +var renderer_actor = arg?.[0] || null var io = use('io') var time = use('time') @@ -34,7 +34,7 @@ graphics.Image = function(surfaceData) { Object.defineProperties(graphics.Image.prototype, { gpu: { get: function() { - if (!this[GPU] && !this[LOADING]) { + if (!this[GPU] && !this[LOADING] && renderer_actor) { this[LOADING] = true; var self = this; @@ -76,13 +76,13 @@ Object.defineProperties(graphics.Image.prototype, { width: { get: function() { - return this[CPU].width + return this[CPU]?.width || 0 } }, height: { get: function() { - return this[CPU].height + return this[CPU]?.height || 0 } } }); @@ -97,29 +97,44 @@ graphics.Image.prototype.unload_cpu = function() { } function calc_image_size(img) { - if (!img.texture || !img.rect) return - return [img.texture.width * img.rect.width, img.texture.height * img.rect.height] + if (!img.rect) return + if (img.texture) { + return [img.texture.width * img.rect.width, img.texture.height * img.rect.height] + } else if (img[CPU]) { + return [img[CPU].width * img.rect.width, img[CPU].height * img.rect.height] + } + return [0, 0] } function decorate_rect_px(img) { - // needs a GPU texture to measure - if (!img || !img.texture) return - // default UV rect is the whole image if none supplied img.rect ??= {x:0, y:0, width:1, height:1} // [u0,v0,uw,vh] in 0-1 + var width = 0, height = 0; + if (img.texture) { + width = img.texture.width; + height = img.texture.height; + } else if (img[CPU]) { + width = img[CPU].width; + height = img[CPU].height; + } else { + return; + } + // store pixel-space version: [x, y, w, h] in texels img.rect_px = { - x:Math.round(img.rect.x * img.texture.width), - y:Math.round(img.rect.y * img.texture.height), - width:Math.round(img.rect.width * img.texture.width), - height:Math.round(img.rect.height * img.texture.height) + x:Math.round(img.rect.x * width), + y:Math.round(img.rect.y * height), + width:Math.round(img.rect.width * width), + height:Math.round(img.rect.height * height) } } function make_handle(obj) { - return new graphics.Image(obj); + var img = new graphics.Image(obj); + decorate_rect_px(img); + return img; } function wrapSurface(surf, maybeRect){ @@ -189,7 +204,15 @@ function create_image(path){ var image = {} image.dimensions = function() { - return [this.texture.width, this.texture.height].scale([this.rect[2], this.rect[3]]) + var width = 0, height = 0; + if (this.texture) { + width = this.texture.width; + height = this.texture.height; + } else if (this[CPU]) { + width = this[CPU].width; + height = this[CPU].height; + } + return [width, height].scale([this.rect[2], this.rect[3]]) } image.dimensions[cell.DOC] = ` :return: A 2D array [width, height] that is the scaled size of this image (texture size * rect size). @@ -224,7 +247,7 @@ graphics.texture_from_data = function(data) var image = graphics.make_texture(data); var img = make_handle(image) - img.gpu; + if (renderer_actor) img.gpu; return img; } @@ -341,17 +364,19 @@ graphics.get_font = function get_font(path, size) { var font = graphics.make_font(data,size) // Load font texture via renderer actor (async) - send(renderer_actor, { - kind: "renderer", - op: "loadTexture", - data: font.surface - }, function(response) { - if (response.error) { - log.error("Failed to load font texture:", response.error); - } else { - font.texture = response; - } - }); + if (renderer_actor) { + send(renderer_actor, { + kind: "renderer", + op: "loadTexture", + data: font.surface + }, function(response) { + if (response.error) { + log.error("Failed to load font texture:", response.error); + } else { + font.texture = response; + } + }); + } fontcache[fontstr] = font diff --git a/source/jsffi.c b/source/jsffi.c index ae114698..695f381d 100644 --- a/source/jsffi.c +++ b/source/jsffi.c @@ -218,8 +218,6 @@ JSValue __##PROP##__v = JS_GetPropertyStr(JS,VALUE,#ATOM); \ TARGET = js2##TYPE(JS, __##PROP##__v); \ JS_FreeValue(JS,__##PROP##__v); }\ -#define JS_SETATOM(JS, TARGET, ATOM, VALUE, TYPE) JS_SetProperty(JS, TARGET, #ATOM, TYPE##2js(JS, VALUE)); - int JS_GETBOOL(JSContext *js, JSValue v, const char *prop) { JSValue __v = JS_GetPropertyStr(js,v,prop); @@ -429,8 +427,23 @@ JSValue color2js(JSContext *js, colorf color) HMM_Vec2 js2vec2(JSContext *js,JSValue v) { HMM_Vec2 v2; - v2.X = js_getnum_uint32(js,v,0); - v2.Y = js_getnum_uint32(js,v,1); + + // Check if it's an array + if (JS_IsArray(js, v)) { + v2.X = js_getnum_uint32(js,v,0); + v2.Y = js_getnum_uint32(js,v,1); + } else { + // Try to get x,y properties from object + JSValue x_val = JS_GetPropertyStr(js, v, "x"); + JSValue y_val = JS_GetPropertyStr(js, v, "y"); + + v2.X = js2number(js, x_val); + v2.Y = js2number(js, y_val); + + JS_FreeValue(js, x_val); + JS_FreeValue(js, y_val); + } + return v2; } @@ -609,10 +622,10 @@ HMM_Vec2 transform_point(SDL_Renderer *ren, HMM_Vec2 in, HMM_Mat3 *t) JSValue rect2js(JSContext *js,rect rect) { JSValue obj = JS_NewObject(js); - JS_SETATOM(js, obj, x, rect.x, number); - JS_SETATOM(js, obj, y, rect.y, number); - JS_SETATOM(js, obj, width, rect.w, number); - JS_SETATOM(js, obj, height, rect.h, number); + JS_SetPropertyStr(js, obj, "x", number2js(js, rect.x)); + JS_SetPropertyStr(js, obj, "y", number2js(js, rect.y)); + JS_SetPropertyStr(js, obj, "width", number2js(js, rect.w)); + JS_SetPropertyStr(js, obj, "height", number2js(js, rect.h)); return obj; } diff --git a/source/qjs_layout.c b/source/qjs_layout.c index 95c09184..a0ca127b 100644 --- a/source/qjs_layout.c +++ b/source/qjs_layout.c @@ -36,16 +36,35 @@ static JSValue js_layout_set_size(JSContext *js, JSValueConst self, int argc, JS GETLAY GETITEM(id, argv[0]) - double size[2]; - JSValue width_val = JS_GetPropertyUint32(js, argv[1], 0); - JSValue height_val = JS_GetPropertyUint32(js, argv[1], 1); - JS_ToFloat64(js, &size[0], width_val); - JS_ToFloat64(js, &size[1], height_val); - JS_FreeValue(js, width_val); - JS_FreeValue(js, height_val); - if (isnan(size[0])) size[0] = 0; - if (isnan(size[1])) size[1] = 0; - lay_set_size_xy(lay, id, size[0], size[1]); + double width = 0, height = 0; + + // Check if it's an array (for backwards compatibility) + if (JS_IsArray(js, argv[1])) { + JSValue width_val = JS_GetPropertyUint32(js, argv[1], 0); + JSValue height_val = JS_GetPropertyUint32(js, argv[1], 1); + JS_ToFloat64(js, &width, width_val); + JS_ToFloat64(js, &height, height_val); + JS_FreeValue(js, width_val); + JS_FreeValue(js, height_val); + } else { + // Handle object with x,y or width,height properties + JSValue width_val = JS_GetPropertyStr(js, argv[1], "width"); + if (JS_IsNull(width_val)) { + width_val = JS_GetPropertyStr(js, argv[1], "x"); + } + JSValue height_val = JS_GetPropertyStr(js, argv[1], "height"); + if (JS_IsNull(height_val)) { + height_val = JS_GetPropertyStr(js, argv[1], "y"); + } + JS_ToFloat64(js, &width, width_val); + JS_ToFloat64(js, &height, height_val); + JS_FreeValue(js, width_val); + JS_FreeValue(js, height_val); + } + + if (isnan(width)) width = 0; + if (isnan(height)) height = 0; + lay_set_size_xy(lay, id, width, height); return JS_NULL; } diff --git a/source/quickjs.c b/source/quickjs.c index 65b0dd0e..6163c495 100644 --- a/source/quickjs.c +++ b/source/quickjs.c @@ -7129,11 +7129,14 @@ static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj, } else { slow_path: /* ToObject() must be done before ToPropertyKey() */ + atom = JS_ValueToAtom(ctx, prop); if (JS_IsNull(this_obj)) { JS_FreeValue(ctx, prop); - return JS_ThrowTypeError(ctx, "cannot read property of null"); + JSValue ret = JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of null", atom); + JS_FreeAtom(ctx, atom); + return ret; } - atom = JS_ValueToAtom(ctx, prop); + JS_FreeValue(ctx, prop); if (unlikely(atom == JS_ATOM_NULL)) return JS_EXCEPTION;