From 6a1a06be769f043ede812b998e502c536e013b4e Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Tue, 6 Jun 2023 20:49:55 +0000 Subject: [PATCH] texture scrolling --- source/engine/ffi.c | 6 +- source/engine/script.c | 15 +++++ source/engine/script.h | 2 + source/engine/sprite.c | 40 +++++++------ source/engine/sprite.h | 3 +- source/engine/texture.c | 4 ++ source/engine/texture.h | 2 + source/engine/window.c | 23 ++++---- source/scripts/debug.js | 8 +++ source/scripts/engine.js | 123 +++++++++++++++++++++++++++++++-------- 10 files changed, 170 insertions(+), 56 deletions(-) diff --git a/source/engine/ffi.c b/source/engine/ffi.c index 079a012..8498a34 100644 --- a/source/engine/ffi.c +++ b/source/engine/ffi.c @@ -268,13 +268,11 @@ JSValue duk_cursor_text(JSContext *js, JSValueConst this, int argc, JSValueConst JSValue duk_gui_img(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { const char *img = JS_ToCString(js, argv[0]); - cpVect pos = js2vec2(argv[1]); - gui_draw_img(img, js2hmmv2(argv[1]), js2number(argv[2]), js2number(argv[3])); + gui_draw_img(img, js2hmmv2(argv[1]), js2hmmv2(argv[2]), js2number(argv[3]), js2bool(argv[4]), js2hmmv2(argv[5]), 1.0, js2color(argv[6])); JS_FreeCString(js, img); return JS_NULL; } - struct nk_rect js2nk_rect(JSValue v) { struct nk_rect rect; rect.x = js2number(js_getpropstr(v, "x")); @@ -1620,7 +1618,7 @@ void ffi_load() { DUK_FUNC(gui_text, 6) DUK_FUNC(ui_text, 5) DUK_FUNC(cursor_text, 5) - DUK_FUNC(gui_img, 2) + DUK_FUNC(gui_img, 10) DUK_FUNC(inflate_cpv, 3) diff --git a/source/engine/script.c b/source/engine/script.c index a6f78c3..83dc64c 100644 --- a/source/engine/script.c +++ b/source/engine/script.c @@ -191,6 +191,21 @@ void script_callee(struct callee c, int argc, JSValue *argv) { js_callee_exec(&c, argc, argv); } + + +void send_signal(const char *signal, int argc, JSValue *argv) +{ + JSValue globalThis = JS_GetGlobalObject(js); + JSValue sig = JS_GetPropertyStr(js, globalThis, "Signal"); + JSValue fn = JS_GetPropertyStr(js, sig, "call"); + JSValue args[argc+1]; + args[0] = str2js(signal); + for (int i = 0; i < argc; i++) + args[1+i] = argv[i]; + + JS_Call(js, fn, sig, argc+1, args); +} + static struct callee update_callee; void register_update(struct callee c) { update_callee = c; diff --git a/source/engine/script.h b/source/engine/script.h index 291bc77..b837e3c 100644 --- a/source/engine/script.h +++ b/source/engine/script.h @@ -49,6 +49,8 @@ void call_gui(); void call_nk_gui(); void unregister_obj(JSValue obj); +void send_signal(const char *signal, int argc, JSValue *argv); + void register_physics(struct callee c); void call_physics(double dt); diff --git a/source/engine/sprite.c b/source/engine/sprite.c index 80432d9..5299535 100644 --- a/source/engine/sprite.c +++ b/source/engine/sprite.c @@ -25,7 +25,7 @@ static sg_bindings bind_sprite; struct sprite_vert { HMM_Vec2 pos; - struct uv_n uv; + HMM_Vec2 uv; struct rgba color; }; @@ -159,7 +159,7 @@ void sprite_initialize() { .layout = { .attrs = { [0].format = SG_VERTEXFORMAT_FLOAT2, - [1].format = SG_VERTEXFORMAT_USHORT2N, + [1].format = SG_VERTEXFORMAT_FLOAT2, [2].format = SG_VERTEXFORMAT_UBYTE4N}}, .primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP, .label = "sprite pipeline", @@ -213,7 +213,7 @@ void sprite_initialize() { } /* offset given in texture offset, so -0.5,-0.5 results in it being centered */ -void tex_draw(struct Texture *tex, HMM_Vec2 pos, float angle, HMM_Vec2 size, HMM_Vec2 offset, struct glrect r, struct rgba color) { +void tex_draw(struct Texture *tex, HMM_Vec2 pos, float angle, HMM_Vec2 size, HMM_Vec2 offset, struct glrect r, struct rgba color, int wrap, HMM_Vec2 wrapoffset, float wrapscale) { struct sprite_vert verts[4]; HMM_Vec2 sposes[4] = { @@ -238,15 +238,24 @@ void tex_draw(struct Texture *tex, HMM_Vec2 pos, float angle, HMM_Vec2 size, HMM verts[i].pos = sposes[i]; verts[i].color = color; } + if (!wrap) { + verts[0].uv.X = r.s0; + verts[0].uv.Y = r.t1; + verts[1].uv.X = r.s1; + verts[1].uv.Y = r.t1; + verts[2].uv.X = r.s0; + verts[2].uv.Y = r.t0; + verts[3].uv.X = r.s1; + verts[3].uv.Y = r.t0; + } else { + verts[0].uv = HMM_MulV2((HMM_Vec2){0,0}, size); + verts[1].uv = HMM_MulV2((HMM_Vec2){1,0}, size); + verts[2].uv = HMM_MulV2((HMM_Vec2){0,1}, size); + verts[3].uv = HMM_MulV2((HMM_Vec2){1,1}, size); - verts[0].uv.u = r.s0 * USHRT_MAX; - verts[0].uv.v = r.t1 * USHRT_MAX; - verts[1].uv.u = r.s1 * USHRT_MAX; - verts[1].uv.v = r.t1 * USHRT_MAX; - verts[2].uv.u = r.s0 * USHRT_MAX; - verts[2].uv.v = r.t0 * USHRT_MAX; - verts[3].uv.u = r.s1 * USHRT_MAX; - verts[3].uv.v = r.t0 * USHRT_MAX; + for (int i = 0; i < 4; i++) + verts[i].uv = HMM_AddV2(verts[i].uv, wrapoffset); + } bind_sprite.fs_images[0] = tex->id; sg_append_buffer(bind_sprite.vertex_buffers[0], SG_RANGE_REF(verts)); @@ -263,25 +272,22 @@ void sprite_draw(struct sprite *sprite) { cpVect cpos = cpBodyGetPosition(go->body); HMM_Vec2 pos = {cpos.x, cpos.y}; HMM_Vec2 size = {sprite->size.X * go->scale * go->flipx, sprite->size.Y * go->scale * go->flipy}; - tex_draw(sprite->tex, pos, cpBodyGetAngle(go->body), size, sprite->pos, sprite->frame, sprite->color); + tex_draw(sprite->tex, pos, cpBodyGetAngle(go->body), size, sprite->pos, sprite->frame, sprite->color, 0, pos, 0); } } - - void sprite_setanim(struct sprite *sprite, struct TexAnim *anim, int frame) { if (!sprite) return; sprite->tex = anim->tex; sprite->frame = anim->st_frames[frame]; } -void gui_draw_img(const char *img, HMM_Vec2 pos, float scale, float angle) { +void gui_draw_img(const char *img, HMM_Vec2 pos, HMM_Vec2 scale, float angle, int wrap, HMM_Vec2 wrapoffset, float wrapscale, struct rgba color) { sg_apply_pipeline(pip_sprite); sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(hudproj)); struct Texture *tex = texture_loadfromfile(img); - HMM_Vec2 size = {scale, scale}; HMM_Vec2 offset = {0.f, 0.f}; - tex_draw(tex, pos, 0.f, size, offset, tex_get_rect(tex), color_white); + tex_draw(tex, pos, angle, scale, offset, tex_get_rect(tex), color, wrap, wrapoffset, wrapscale); } void slice9_draw(const char *img, HMM_Vec2 pos, HMM_Vec2 dimensions, struct rgba color) diff --git a/source/engine/sprite.h b/source/engine/sprite.h index aeadb9d..e5c7be1 100644 --- a/source/engine/sprite.h +++ b/source/engine/sprite.h @@ -41,7 +41,6 @@ void sprite_draw_all(); unsigned int incrementAnimFrame(unsigned int interval, struct sprite *sprite); void sprite_flush(); -void gui_draw_img(const char *img, HMM_Vec2 pos, float scale, float angle); - +void gui_draw_img(const char *img, HMM_Vec2 pos, HMM_Vec2 scale, float angle, int wrap, HMM_Vec2 wrapoffset, float wrapscale, struct rgba color); #endif diff --git a/source/engine/texture.c b/source/engine/texture.c index f4be237..bf1f744 100644 --- a/source/engine/texture.c +++ b/source/engine/texture.c @@ -77,6 +77,8 @@ struct Texture *texture_pullfromfile(const char *path) { tex->opts.sprite = 1; tex->opts.mips = 0; tex->opts.gamma = 0; + tex->opts.wrapx = 1; + tex->opts.wrapy = 1; int n; unsigned char *data = stbi_load(path, &tex->width, &tex->height, &n, 4); @@ -133,6 +135,8 @@ struct Texture *texture_pullfromfile(const char *path) { .min_filter = SG_FILTER_NEAREST_MIPMAP_NEAREST, .mag_filter = SG_FILTER_NEAREST, .num_mipmaps = mips, + .wrap_u = SG_WRAP_REPEAT, + .wrap_v = SG_WRAP_REPEAT, .data = sg_img_data }); diff --git a/source/engine/texture.h b/source/engine/texture.h index c37a886..f73a419 100644 --- a/source/engine/texture.h +++ b/source/engine/texture.h @@ -56,6 +56,8 @@ struct TextureOptions { int mips; unsigned int gamma:1; int animation; + int wrapx; + int wrapy; }; /* Represents an actual texture on the GPU */ diff --git a/source/engine/window.c b/source/engine/window.c index 8ad4505..26a4ed7 100644 --- a/source/engine/window.c +++ b/source/engine/window.c @@ -7,6 +7,7 @@ #include #include #include +#include "ffi.h" #include "openglrender.h" @@ -51,11 +52,14 @@ void window_maximize_callback(GLFWwindow *w, int maximized) { } void window_framebuffer_size_cb(GLFWwindow *w, int width, int height) { - struct window *win = winfind(w); + struct window *win = mainwin; win->width = width; win->height = height; window_makecurrent(win); win->render = 1; + + JSValue vals[2] = { int2js(width), int2js(height) }; + send_signal("window_resize", 2, vals); } void window_close_callback(GLFWwindow *w) { @@ -66,9 +70,8 @@ struct window *MakeSDLWindow(const char *name, int width, int height, uint32_t f if (arrcap(windows) == 0) arrsetcap(windows, 5); - GLFWwindow *sharewin = mainwin == NULL ? NULL : mainwin->window; - - if (sharewin) return sharewin; + if (mainwin != NULL) + return mainwin; glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); @@ -80,19 +83,17 @@ struct window *MakeSDLWindow(const char *name, int width, int height, uint32_t f .width = width, .height = height, .id = arrlen(windows), - .window = glfwCreateWindow(width, height, name, NULL, sharewin)}; + .window = glfwCreateWindow(width, height, name, NULL, mainwin)}; if (!w.window) { YughError("Couldn't make GLFW window\n", 1); return NULL; } + + mainwin = malloc(sizeof(struct window)); + *mainwin = w; glfwMakeContextCurrent(w.window); - // int version = gladLoadGL(glfwGetProcAddress); - // if (!version) { - // YughError("Failed to initialize OpenGL context."); - // exit(1); - // } YughInfo("Loaded OpenGL %d.%d", 3, 3); glfwSwapInterval(1); @@ -108,6 +109,8 @@ struct window *MakeSDLWindow(const char *name, int width, int height, uint32_t f if (arrlen(windows) == 1) mainwin = &windows[0]; + window_framebuffer_size_cb(mainwin, width, height); + return &arrlast(windows); } diff --git a/source/scripts/debug.js b/source/scripts/debug.js index b489c2e..d69200b 100644 --- a/source/scripts/debug.js +++ b/source/scripts/debug.js @@ -33,6 +33,10 @@ var Debug = { poly(points, color) { cmd_points(0,points,color); }, + + boundingbox(bb, color) { + cmd_points(0, bb2points(bb), color); + }, box(pos, wh, color) { color = color ? color : Color.white; @@ -174,6 +178,10 @@ var DebugControls = { input_f1_pressed() { Debug.draw_phys(!Debug.phys_drawing); }, + + input_f12_pressed() { + GUI.defaults.debug = !GUI.defaults.debug; + }, }; set_pawn(DebugControls); diff --git a/source/scripts/engine.js b/source/scripts/engine.js index 6455c9a..6407df3 100644 --- a/source/scripts/engine.js +++ b/source/scripts/engine.js @@ -110,20 +110,6 @@ function set_cam(id) { cmd(61, id); }; -var Window = { - get width() { - return cmd(48); - }, - - get height() { - return cmd(49); - }, - - get dimensions() { - return [this.width, this.height]; - } -}; - var Color = { white: [255,255,255,255], @@ -172,14 +158,27 @@ var GUI = { return def; } + var tex_wh = cmd(64,def.path); + var wh = tex_wh.slice(); + + if (def.width !== 0) + wh.x = def.width; + + if (def.height !== 0) + wh.y = def.height; + + wh = wh.scale(def.scale); + + var sendscale = []; + sendscale.x = wh.x / tex_wh.x; + sendscale.y = wh.y / tex_wh.y; + def.draw = function(pos) { def.calc_bb(pos); - var wh = cmd(64,def.path); - gui_img(def.path, pos.sub(def.anchor.scale(wh)), def.scale, def.angle, def.color); + gui_img(def.path, pos.sub(def.anchor.scale(wh)), sendscale, def.angle, def.image_repeat, def.image_repeat_offset, def.color); }; def.calc_bb = function(cursor) { - var wh = cmd(64,def.path).scale(def.scale); def.bb = cwh2bb(wh.scale([0.5,0.5]), wh); def.bb = movebb(def.bb, cursor.sub(wh.scale(def.anchor))); }; @@ -204,6 +203,9 @@ var GUI = { margin: [5,5], /* Distance between elements for things like columns */ width: 0, height: 0, + image_repeat: false, + image_repeat_offset: [0,0], + debug: false, /* set to true to draw debug boxes */ }, text_fn(str, defn) @@ -213,6 +215,9 @@ var GUI = { def.draw = function(cursor) { def.calc_bb(cursor); + + if (def.debug) + Debug.boundingbox(def.bb, def.debug_colors.bounds); var old = def; def = Object.create(def); @@ -254,11 +259,8 @@ var GUI = { }); def.draw = function(pos) { - var c = Color.red.slice(); - c.a = 100; def.items.forEach(function(item) { item.draw.call(this,pos); - Debug.poly(bb2points(item.bb), c); var wh = bb2wh(item.bb); pos.y -= wh.y; pos.y -= def.padding.x*2; @@ -269,6 +271,15 @@ var GUI = { }, }; +GUI.defaults.debug_colors = { + bounds: Color.red.slice(), + margin: Color.blue.slice(), + padding: Color.green.slice() +}; + +Object.values(GUI.defaults.debug_colors).forEach(function(v) { v.a = 100; }); + + function listbox(pos, item) { pos.y += (item[1] - 20); }; @@ -461,9 +472,6 @@ var Tween = { start(obj, target, tvals, options) { - var start = tvals[0]; - var end = tvals[1]; - var defn = Object.create(this.default); Object.assign(defn, options); @@ -493,6 +501,8 @@ var Tween = { nval = defn.ease(nval); obj[target] = tvals[i].lerp(tvals[i+1], nval); + + Log.warn(defn.pct); }; defn.restart = function() { defn.accum = 0; }; @@ -503,6 +513,48 @@ var Tween = { return defn; }, + + embed(obj, target, tvals, options) { + var defn = Object.create(this.default); + Object.assign(defn, options); + + defn.update_vals = function(vals) { + defn.vals = vals; + + if (defn.loop === 'circle') + defn.vals.push(defn.vals[0]); + else if (defn.loop === 'yoyo') { + for (var i = defn.vals.length-2; i >= 0; i--) + defn.vals.push(defn.vals[i]); + } + + defn.slices = defn.vals.length - 1; + defn.slicelen = 1 / defn.slices; + }; + + defn.update_vals(tvals); + + defn.time_s = Date.now(); + + Object.defineProperty(obj, target, { + get() { + defn.accum = (Date.now() - defn.time_s)/1000; + defn.pct = (defn.accum % defn.time) / defn.time; + var t = defn.whole ? defn.ease(defn.pct) : defn.pct; + + var nval = t / defn.slicelen; + var i = Math.trunc(nval); + nval -= i; + + if (!defn.whole) + nval = defn.ease(nval); + + return defn.vals[i].lerp(defn.vals[i+1],nval); + }, + }); + + return defn; + }, }; @@ -929,8 +981,33 @@ var Signal = { clera_obj(obj) { this.signals.filter(function(x) { return x[1] !== obj; }); }, + + c:{}, + register(name, fn) { + if (!this.c[name]) + this.c[name] = []; + + this.c[name].push(fn); + }, + + call(name, ...args) { + if (this.c[name]) + this.c[name].forEach(function(fn) { fn.call(this, ...args); }); + }, }; +var Window = { + width: 0, + height: 0, + dimensions:[0,0], +}; + +Signal.register("window_resize", function(w, h) { + Window.width = w; + Window.height = h; + Window.dimensions = [w, h]; +}); + var IO = { exists(file) { return cmd(65, file);}, slurp(file) {