sdl
This commit is contained in:
@@ -664,6 +664,13 @@ Object.defineProperty(String.prototype, "ext", {
|
||||
},
|
||||
});
|
||||
|
||||
Object.defineProperty(String.prototype, 'has_ext', {
|
||||
value: function() {
|
||||
var lastdot = this.lastIndexOf('.');
|
||||
return lastdot > 0 && lastdot < this.length-1;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(String.prototype, "set_ext", {
|
||||
value: function (val) {
|
||||
return this.strip_ext() + val;
|
||||
|
||||
@@ -773,4 +773,4 @@ Object.mix(os.make_circle2d(), {
|
||||
},
|
||||
});
|
||||
|
||||
return { component, SpriteAnim };
|
||||
return { component };
|
||||
|
||||
@@ -153,18 +153,21 @@ Resources.is_image = function (path) {
|
||||
|
||||
var res_cache = {};
|
||||
|
||||
function find_ext(file, ext, root = "") {
|
||||
// ext is a list of extensions to search
|
||||
function find_ext(file, ext) {
|
||||
if (!file) return;
|
||||
|
||||
var file_ext = file.ext();
|
||||
var has_ext = file_ext.length > 0;
|
||||
|
||||
if (ext.some(x => x === file_ext)) return file;
|
||||
for (var e of ext) {
|
||||
var nf = `${file}.${e}`;
|
||||
if (io.exists(nf)) return nf;
|
||||
}
|
||||
|
||||
var all_files = io.glob(`**/${file}.*`);
|
||||
var glob_pat = has_ext ? `**/${file}` : `**/${file}.*`;
|
||||
|
||||
var all_files = io.glob(glob_pat);
|
||||
var find = undefined;
|
||||
for (var e of ext) {
|
||||
var finds = all_files.filter(x => x.ext() === e);
|
||||
@@ -338,13 +341,20 @@ io.slurpbytes = function(path)
|
||||
}
|
||||
|
||||
var ignore = io.slurp('.prosperonignore').split('\n');
|
||||
var allpaths = io.globfs(ignore);
|
||||
var allpaths;
|
||||
var tmpglob = io.glob;
|
||||
io.glob = function glob(pat) {
|
||||
// var allpaths = io.globfs(ignore);
|
||||
if (!allpaths)
|
||||
allpaths = io.globfs(ignore);
|
||||
|
||||
return allpaths.filter(str => game.glob(pat,str)).sort();
|
||||
}
|
||||
|
||||
io.invalidate = function()
|
||||
{
|
||||
allpaths = undefined;
|
||||
}
|
||||
|
||||
function splitPath(path) {
|
||||
return path.split('/').filter(part => part.length > 0);
|
||||
}
|
||||
|
||||
@@ -103,13 +103,13 @@ var mousepos = [0, 0];
|
||||
prosperon.textinput = function (c) {
|
||||
player[0].raw_input("char", "pressed", c);
|
||||
};
|
||||
prosperon.mousemove = function (pos, dx) {
|
||||
prosperon.mouse_move = function (pos, dx) {
|
||||
pos.y *= -1;
|
||||
dx.y *= -1;
|
||||
mousepos = pos;
|
||||
player[0].mouse_input("move", pos, dx);
|
||||
};
|
||||
prosperon.mousescroll = function mousescroll(dx) {
|
||||
prosperon.mouse_scroll = function mousescroll(dx) {
|
||||
player[0].mouse_input(modstr() + "scroll", dx);
|
||||
};
|
||||
prosperon.mousedown = function mousedown(b) {
|
||||
|
||||
@@ -250,54 +250,12 @@ function pack_into_sheet(images)
|
||||
return spritesheet;
|
||||
}
|
||||
|
||||
var SpriteAnim = {};
|
||||
globalThis.SpriteAnim = SpriteAnim;
|
||||
SpriteAnim.aseprite = function (path) {
|
||||
function aseframeset2anim(frameset, meta) {
|
||||
var anim = {};
|
||||
anim.frames = [];
|
||||
var dim = meta.size;
|
||||
|
||||
var ase_make_frame = function (ase_frame) {
|
||||
var f = ase_frame.frame;
|
||||
var frame = {};
|
||||
frame.rect = {
|
||||
x: f.x / dim.w,
|
||||
y: f.y / dim.h,
|
||||
width: f.w / dim.w,
|
||||
height: f.h / dim.h,
|
||||
};
|
||||
frame.time = ase_frame.duration / 1000;
|
||||
anim.frames.push(frame);
|
||||
};
|
||||
|
||||
frameset.forEach(ase_make_frame);
|
||||
anim.dim = frameset[0].sourceSize;
|
||||
anim.loop = true;
|
||||
return anim;
|
||||
}
|
||||
|
||||
var data = json.decode(io.slurp(path));
|
||||
if (!data?.meta?.app.includes("aseprite")) return;
|
||||
var anims = {};
|
||||
var frames = Array.isArray(data.frames) ? data.frames : Object.values(data.frames);
|
||||
|
||||
if (!data.meta.frameTags || data.meta.frameTags.length === 0) {
|
||||
anims[0] = aseframeset2anim(frames, data.meta);
|
||||
return anims;
|
||||
}
|
||||
for (var tag of data.meta.frameTags)
|
||||
anims[tag.name] = aseframeset2anim(frames.slice(tag.from, tag.to + 1), data.meta);
|
||||
|
||||
return anims;
|
||||
};
|
||||
|
||||
game.is_image = function(obj)
|
||||
{
|
||||
if (obj.texture && obj.rect) return true;
|
||||
}
|
||||
|
||||
// Any request to it returns an image, which is a texture and rect. But they can
|
||||
// Any request to it returns an image, which is a texture and rect.
|
||||
game.texture = function texture(path) {
|
||||
if (typeof path !== 'string') {
|
||||
return path;
|
||||
@@ -307,10 +265,22 @@ game.texture = function texture(path) {
|
||||
path = Resources.find_image(parts[0]);
|
||||
|
||||
if (game.texture.cache[path]) return game.texture.cache[path];
|
||||
var newimg = {};
|
||||
var data = io.slurpbytes(path);
|
||||
newimg.surface = os.make_texture(data);
|
||||
newimg.texture = render._main.load_texture(newimg.surface);
|
||||
var newimg;
|
||||
switch(path.ext()) {
|
||||
case 'gif':
|
||||
newimg = os.make_gif(data);
|
||||
break;
|
||||
case 'ase':
|
||||
newimg = os.make_aseprite(data);
|
||||
break;
|
||||
default:
|
||||
newimg = {
|
||||
surface: os.make_texture(data)
|
||||
};
|
||||
newimg.texture = render._main.load_texture(newimg.surface);
|
||||
break;
|
||||
}
|
||||
game.texture.cache[path] = newimg;
|
||||
return newimg;
|
||||
|
||||
@@ -399,9 +369,6 @@ game.texture = function texture(path) {
|
||||
var image;
|
||||
var anim;
|
||||
|
||||
if (io.exists(path.set_ext(".json")))
|
||||
anim = SpriteAnim.aseprite(path.set_ext(".json"));
|
||||
|
||||
if (!anim) {
|
||||
image = {
|
||||
texture: tex,
|
||||
@@ -490,16 +457,6 @@ Range is given by a semantic versioning number, prefixed with nothing, a ~, or a
|
||||
~ means that MAJOR and MINOR must match exactly, but any PATCH greater or equal is valid.
|
||||
^ means that MAJOR must match exactly, but any MINOR and PATCH greater or equal is valid.`;
|
||||
|
||||
prosperon.iconified = function (icon) {};
|
||||
prosperon.focus = function (focus) {};
|
||||
prosperon.suspended = function (sus) {};
|
||||
prosperon.mouseenter = function () {};
|
||||
prosperon.mouseleave = function () {};
|
||||
prosperon.touchpress = function (touches) {};
|
||||
prosperon.touchrelease = function (touches) {};
|
||||
prosperon.touchmove = function (touches) {};
|
||||
prosperon.clipboardpaste = function (str) {};
|
||||
|
||||
global.mixin("input");
|
||||
global.mixin("std");
|
||||
global.mixin("diff");
|
||||
@@ -669,6 +626,24 @@ function world_start() {
|
||||
game.cam = world;
|
||||
}
|
||||
|
||||
function make_spritesheet(paths, width, height)
|
||||
{
|
||||
var textures = paths.map(path => game.texture(path));
|
||||
var sizes = textures.map(tex => [tex.width, tex.height]);
|
||||
var pos = os.rectpack(width, height, sizes);
|
||||
if (!pos) return;
|
||||
|
||||
var sheet = os.make_tex_data(width,height);
|
||||
|
||||
var st = profile.now();
|
||||
for (var i = 0; i < pos.length; i++)
|
||||
sheet.copy(textures[i], pos[i].x, pos[i].y);
|
||||
|
||||
sheet.save("spritesheet.qoi");
|
||||
gamestate.spritess = sheet;
|
||||
sheet.load_gpu();
|
||||
}
|
||||
|
||||
return {
|
||||
Register,
|
||||
sim,
|
||||
|
||||
@@ -1038,47 +1038,23 @@ render.tile = function tile(image, rect = [0,0], color = Color.white)
|
||||
return;
|
||||
}
|
||||
|
||||
render.image = function image(image, rect = [0,0], rotation = 0, color) {
|
||||
render.image = function image(image, rect = [0,0], rotation = 0, color = Color.white) {
|
||||
if (!image) throw Error ('Need an image to render.')
|
||||
if (typeof image === "string")
|
||||
image = game.texture(image);
|
||||
|
||||
rect.width ??= image.texture.width;
|
||||
rect.height ??= image.texture.height;
|
||||
|
||||
render._main.texture(image.texture, rect, image.rect, color);
|
||||
return;
|
||||
|
||||
var tex = image.texture;
|
||||
if (!tex) return;
|
||||
|
||||
var image_size = calc_image_size(image); //image.size;
|
||||
|
||||
var size = [rect.width ? rect.width : image_size.x, rect.height ? rect.height : image_size.y];
|
||||
|
||||
if (!lasttex) {
|
||||
check_flush(flush_img);
|
||||
lasttex = tex;
|
||||
}
|
||||
|
||||
if (lasttex !== tex) {
|
||||
flush_img();
|
||||
lasttex = tex;
|
||||
}
|
||||
|
||||
render._main.texture(image.texture, rect, image.rect);
|
||||
return;
|
||||
|
||||
var e = img_e();
|
||||
var pos = [rect.x,rect.y].sub(size.scale([rect.anchor_x, rect.anchor_y]));
|
||||
e.transform.trs(pos, undefined, size);
|
||||
e.image = image;
|
||||
e.shade = color;
|
||||
|
||||
return;
|
||||
};
|
||||
|
||||
render.images = function images(image, rects)
|
||||
{
|
||||
if (!image) throw Error ('Need an image to render.');
|
||||
if (typeof image === "string") image = game.texture(image);
|
||||
for (var rect of rects) render.image(image,rect);
|
||||
return;
|
||||
var tex = image.texture;
|
||||
if (!tex) return;
|
||||
|
||||
@@ -1109,34 +1085,16 @@ render.images = function images(image, rects)
|
||||
return;
|
||||
}
|
||||
|
||||
var slice9_t = os.make_transform();
|
||||
// pos is the lower left corner, scale is the width and height
|
||||
// slice is given in pixels
|
||||
render.slice9 = function slice9(image, rect = [0,0], slice = 0, color = Color.white) {
|
||||
if (typeof image === 'string')
|
||||
image = game.texture(image);
|
||||
|
||||
var tex = image.texture;
|
||||
var image_size = calc_image_size(image);
|
||||
var size = [rect.width ? rect.width : image_size.x, rect.height ? rect.height : image_size.y];
|
||||
rect.width ??= image.texture.width;
|
||||
rect.height ??= image.texture.height;
|
||||
slice = clay.normalizeSpacing(slice);
|
||||
|
||||
check_flush();
|
||||
|
||||
slice9_t.trs([rect.x,rect.y].sub(size.scale([rect.anchor_x, rect.anchor_y])), undefined, size);
|
||||
slice = clay.normalizeSpacing(slice);
|
||||
var border = [slice.l/image_size.x, slice.b/image_size.y, slice.r/image_size.x, slice.t/image_size.y];
|
||||
render.use_shader(slice9shader);
|
||||
set_model(slice9_t);
|
||||
render.use_mat({
|
||||
shade: color,
|
||||
diffuse: tex,
|
||||
win_tex_scale: size.div(image_size),
|
||||
rect: [image.rect.x, image.rect.y,image.rect.width,image.rect.height],
|
||||
frag_rect: [image.rect.x, image.rect.y,image.rect.width,image.rect.height],
|
||||
border: border,
|
||||
});
|
||||
|
||||
render.draw(shape.quad);
|
||||
render._main.slice9(image.texture, rect, slice);
|
||||
};
|
||||
|
||||
var textssbos = [];
|
||||
@@ -1202,6 +1160,7 @@ render.scissor = function(rect)
|
||||
|
||||
// Camera viewport is a rectangle with the bottom left corner defined as x,y. Units are pixels on the window.
|
||||
function camviewport() {
|
||||
|
||||
var aspect = (((this.viewport[2] - this.viewport[0]) / (this.viewport[3] - this.viewport[1])) * prosperon.size.x) / prosperon.size.y;
|
||||
var raspect = this.size.x / this.size.y;
|
||||
|
||||
@@ -1288,16 +1247,6 @@ function screen2cam(pos) {
|
||||
return viewpos;
|
||||
}
|
||||
|
||||
function camextents() {
|
||||
var half = this.size; //.scale(0.5);
|
||||
return {
|
||||
l: this.pos.x - half.x,
|
||||
r: this.pos.x + half.x,
|
||||
t: this.pos.y + half.y,
|
||||
b: this.pos.y - half.y,
|
||||
};
|
||||
}
|
||||
|
||||
screen2cam.doc = "Convert a screen space position in pixels to a normalized viewport position in a camera.";
|
||||
|
||||
prosperon.gizmos = function gizmos() {
|
||||
@@ -1314,20 +1263,33 @@ function screen2hud(pos)
|
||||
return campos;
|
||||
}
|
||||
|
||||
/* cameras
|
||||
* Cameras have a position and rotation. They are not affected by scale.
|
||||
*/
|
||||
|
||||
prosperon.make_camera = function make_camera() {
|
||||
var cam = world.spawn();
|
||||
cam.near = 1;
|
||||
cam.far = -1000;
|
||||
cam.ortho = true;
|
||||
cam.ortho = true; // True if this is a 2d camera
|
||||
cam.viewport = [0, 0, 1, 1]; // normalized screen coordinates of where to draw
|
||||
cam.size = game.size.slice(); // The render size of this camera in pixels
|
||||
cam.size = prosperon.size.slice() // The render size of this camera in pixels
|
||||
// In ortho mode, this determines how many pixels it will see
|
||||
cam.mode = "stretch";
|
||||
cam.screen2world = camscreen2world;
|
||||
cam.screen2cam = screen2cam;
|
||||
cam.screen2hud = screen2hud;
|
||||
cam.extents = camextents;
|
||||
cam.view = camviewport;
|
||||
cam.zoom = 1; // the "scale factor" this camera demonstrates
|
||||
// camera renders draw calls, and then hud
|
||||
cam.render = function() {
|
||||
render._main.camera(this.transform);
|
||||
render._main.scale([this.zoom, this.zoom]);
|
||||
prosperon.draw();
|
||||
render._main.scale([1,1]);
|
||||
render._main.camera(unit_transform);
|
||||
prosperon.hud();
|
||||
}
|
||||
return cam;
|
||||
};
|
||||
|
||||
@@ -1434,14 +1396,14 @@ prosperon.render = function prosperon_render() {
|
||||
try{
|
||||
render._main.draw_color(clearcolor);
|
||||
render._main.clear();
|
||||
// set to world cam
|
||||
prosperon.draw();
|
||||
if (render.draw_hud) prosperon.hud();
|
||||
|
||||
// render each camera
|
||||
prosperon.camera.render();
|
||||
// prosperon.app();
|
||||
// if (debug.show) imgui_fn();
|
||||
} catch(e) {
|
||||
throw e;
|
||||
console.log(e);
|
||||
console.log(e.stack)
|
||||
// throw e;
|
||||
} finally {
|
||||
render._main.present();
|
||||
tracy.end_frame();
|
||||
@@ -1452,6 +1414,8 @@ if (dmon) dmon.watch('.');
|
||||
|
||||
function dmon_cb(e)
|
||||
{
|
||||
io.invalidated();
|
||||
|
||||
if (e.file.startsWith('.')) return;
|
||||
if (e.file.endsWith('.js'))
|
||||
actor.hotreload(e.file);
|
||||
@@ -1470,13 +1434,33 @@ prosperon.process = function process() {
|
||||
frame_t = profile.now();
|
||||
|
||||
prosperon.appupdate(dt);
|
||||
|
||||
input.procdown();
|
||||
if (sim.mode === "play" || sim.mode === "step") {
|
||||
prosperon.update(dt * game.timescale);
|
||||
update_emitters(dt * game.timescale);
|
||||
os.update_timers(dt * game.timescale);
|
||||
if (sim.mode === "step") sim.pause();
|
||||
}
|
||||
|
||||
game.engine_input(e => {
|
||||
switch(e.type) {
|
||||
case "quit":
|
||||
os.exit(0);
|
||||
break;
|
||||
case "mouse":
|
||||
prosperon.mousemove(e.mouse, e.mouse_d);
|
||||
break;
|
||||
case "text":
|
||||
prosperon.textinput(e.text);
|
||||
break;
|
||||
case "key":
|
||||
if (e.down)
|
||||
prosperon.keydown(e.key);
|
||||
else
|
||||
prosperon.keyup(e.key);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
update_emitters(dt * game.timescale);
|
||||
os.update_timers(dt * game.timescale);
|
||||
prosperon.update(dt*game.timescale);
|
||||
if (sim.mode === "step") sim.pause();
|
||||
|
||||
if (sim.mode === "play" || sim.mode === "step") {
|
||||
/*
|
||||
|
||||
@@ -83,6 +83,10 @@ Resources.gif.frames = function (path) {
|
||||
return render.gif_frames(path);
|
||||
};
|
||||
|
||||
prosperon.SIGINT = function() {
|
||||
os.exit();
|
||||
}
|
||||
|
||||
/*
|
||||
io path rules. Starts with, meaning:
|
||||
"@": user path
|
||||
@@ -221,15 +225,14 @@ Cmdline.register_order(
|
||||
}
|
||||
|
||||
var project = json.decode(io.slurp(projectfile));
|
||||
game.title = project.title;
|
||||
game.size = [1280, 720];
|
||||
|
||||
|
||||
prosperon.title = project.title;
|
||||
prosperon.width = 1280;
|
||||
prosperon.height = 720;
|
||||
prosperon.size = [1280,720];
|
||||
prosperon.size = [1280, 720];
|
||||
prosperon.cleanup = function(){}
|
||||
prosperon.event = function(e){
|
||||
prosperon[e.type]?.(e);
|
||||
switch(e.type) {
|
||||
case "mouse_move":
|
||||
prosperon.mousemove(e.mouse, e.mouse_d);
|
||||
@@ -252,34 +255,9 @@ Cmdline.register_order(
|
||||
case "char":
|
||||
prosperon.textinput(e.char_code);
|
||||
break;
|
||||
case "resized":
|
||||
prosperon.size = e.window_size;
|
||||
prosperon.resize?.(e.window_size);
|
||||
break;
|
||||
case "iconified":
|
||||
prosperon.iconified(false);
|
||||
break;
|
||||
case "restored":
|
||||
prosperon.iconified(true);
|
||||
break;
|
||||
case "focused":
|
||||
prosperon.focus(true);
|
||||
break;
|
||||
case "unfocused":
|
||||
prosperon.focus(false);
|
||||
break;
|
||||
case "suspended":
|
||||
prosperon.suspended(true);
|
||||
break;
|
||||
case "quit_requested":
|
||||
os.exit(0);
|
||||
break;
|
||||
case "mouse_enter":
|
||||
prosperon.mouseenter();
|
||||
break;
|
||||
case "mouse_leave":
|
||||
prosperon.mouseleave();
|
||||
break;
|
||||
case "files_dropped":
|
||||
console.log(json.encode(e));
|
||||
break;
|
||||
@@ -300,8 +278,8 @@ Cmdline.register_order(
|
||||
|
||||
if (io.exists("config.js")) global.mixin("config.js");
|
||||
else console.warn("No config.js file found. Starting with default parameters.");
|
||||
var window = game.engine_start(prosperon);
|
||||
var renderer = window.make_renderer("gpu");
|
||||
prosperon.window = game.engine_start(prosperon);
|
||||
var renderer = prosperon.window.make_renderer("gpu");
|
||||
render._main = renderer;
|
||||
|
||||
prosperon.init();
|
||||
|
||||
@@ -1801,6 +1801,24 @@ HMM_Mat4 HMM_M4TRS(HMM_Vec3 t, HMM_Quat q, HMM_Vec3 s)
|
||||
return l;
|
||||
}
|
||||
|
||||
HMM_Mat3 HMM_M3TRS(HMM_Vec2 pos, float angle, HMM_Vec2 s)
|
||||
{
|
||||
HMM_Mat3 m;
|
||||
float *lm = (float*)&m;
|
||||
lm[0] = s.x*cos(angle);
|
||||
lm[1] = s.x * sin(angle);
|
||||
lm[2] = 0;
|
||||
|
||||
lm[3] = -s.y*sin(angle);
|
||||
lm[4] = s.y*cos(angle);
|
||||
lm[5] = 0;
|
||||
|
||||
lm[6] = pos.x;
|
||||
lm[7] = pos.y;
|
||||
lm[8] = 1;
|
||||
return m;
|
||||
}
|
||||
|
||||
// This method taken from Mike Day at Insomniac Games.
|
||||
// https://d3cw3dd2w32x2b.cloudfront.net/wp-content/uploads/2015/01/matrix-to-quat.pdf
|
||||
//
|
||||
|
||||
@@ -660,6 +660,7 @@ HMM_Quat HMM_NLerp(HMM_Quat Left, float Time, HMM_Quat Right);
|
||||
HMM_Quat HMM_SLerp(HMM_Quat Left, float Time, HMM_Quat Right);
|
||||
HMM_Mat4 HMM_QToM4(HMM_Quat Left);
|
||||
HMM_Mat4 HMM_M4TRS(HMM_Vec3 t, HMM_Quat q, HMM_Vec3 s);
|
||||
HMM_Mat3 HMM_M3TRS(HMM_Vec2 t, float angle, HMM_Vec2 s);
|
||||
|
||||
HMM_Quat HMM_M4ToQ_RH(HMM_Mat4 M);
|
||||
HMM_Quat HMM_M4ToQ_LH(HMM_Mat4 M);
|
||||
|
||||
217
source/jsffi.c
217
source/jsffi.c
@@ -109,6 +109,7 @@ double js_getnum_uint32(JSContext *js, JSValue v, unsigned int i)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static HMM_Mat3 cam_mat;
|
||||
static HMM_Vec2 campos = (HMM_Vec2){0,0};
|
||||
static HMM_Vec2 logical = {0};
|
||||
|
||||
@@ -260,6 +261,11 @@ void SDL_Camera_free(JSRuntime *rt, SDL_Camera *cam)
|
||||
SDL_CloseCamera(cam);
|
||||
}
|
||||
|
||||
void SDL_Cursor_free(JSRuntime *rt, SDL_Cursor *c)
|
||||
{
|
||||
SDL_DestroyCursor(c);
|
||||
}
|
||||
|
||||
QJSCLASS(transform)
|
||||
QJSCLASS(font)
|
||||
//QJSCLASS(warp_gravity)
|
||||
@@ -267,9 +273,9 @@ QJSCLASS(font)
|
||||
QJSCLASS(datastream)
|
||||
QJSCLASS(timer)
|
||||
QJSCLASS(skin)
|
||||
|
||||
QJSCLASS(SDL_Window)
|
||||
QJSCLASS(SDL_Renderer)
|
||||
|
||||
QJSCLASS(SDL_Camera)
|
||||
QJSCLASS(SDL_Texture,
|
||||
TracyCAllocN(n, n->w*n->h*4, "vram");
|
||||
@@ -282,6 +288,8 @@ QJSCLASS(SDL_Surface,
|
||||
JS_SetProperty(js,j,height_atom,number2js(js,n->h));
|
||||
)
|
||||
|
||||
QJSCLASS(SDL_Cursor)
|
||||
|
||||
int js_arrlen(JSContext *js,JSValue v) {
|
||||
if (JS_IsUndefined(v)) return 0;
|
||||
int len;
|
||||
@@ -511,13 +519,23 @@ rect js2rect(JSContext *js,JSValue v) {
|
||||
JS_FreeValue(js,yv);
|
||||
float anchor_x = js_getnum(js,v, anchor_x_atom);
|
||||
float anchor_y = js_getnum(js,v, anchor_y_atom);
|
||||
|
||||
|
||||
rect.y -= anchor_y*rect.h;
|
||||
rect.x -= anchor_x*rect.w;
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
rect transform_rect(rect in, HMM_Mat3 *t)
|
||||
{
|
||||
in.y *= -1;
|
||||
in.y += logical.y;
|
||||
in.y -= in.h;
|
||||
in.x -= t->Columns[2].x;
|
||||
in.y -= t->Columns[2].y;
|
||||
return in;
|
||||
}
|
||||
|
||||
JSValue rect2js(JSContext *js,rect rect) {
|
||||
JSValue obj = JS_NewObject(js);
|
||||
JS_SetProperty(js, obj, x_atom, number2js(js,rect.x));
|
||||
@@ -733,8 +751,6 @@ JSC_CCALL(os_make_text_buffer,
|
||||
|
||||
for (int i = 0; i < arrlen(buffer); i++) {
|
||||
pos[i] = buffer[i].pos;
|
||||
pos[i].y *= -1;
|
||||
pos[i].y += logical.y;
|
||||
uv[i] = buffer[i].uv;
|
||||
color[i] = buffer[i].color;
|
||||
}
|
||||
@@ -1426,9 +1442,9 @@ JSC_CCALL(game_open_camera,
|
||||
#include "wildmatch.h"
|
||||
JSC_SSCALL(game_glob,
|
||||
if (wildmatch(str, str2, WM_PATHNAME | WM_PERIOD | WM_WILDSTAR) == WM_MATCH)
|
||||
return JS_NewBool(js,1);
|
||||
ret = JS_NewBool(js,1);
|
||||
else
|
||||
return JS_NewBool(js, 0);
|
||||
ret = JS_NewBool(js, 0);
|
||||
)
|
||||
|
||||
JSC_CCALL(game_camera_name,
|
||||
@@ -1481,10 +1497,84 @@ JSValue js_SDL_Window_keyboard_shown(JSContext *js, JSValue self) {
|
||||
return JS_NewBool(js,SDL_ScreenKeyboardShown(window));
|
||||
}
|
||||
|
||||
JSValue js_window_theme(JSContext *js, JSValue self)
|
||||
{
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
JSValue js_window_safe_area(JSContext *js, JSValue self)
|
||||
{
|
||||
SDL_Window *w = js2SDL_Window(js,self);
|
||||
rect r;
|
||||
SDL_GetWindowSafeArea(w, &r);
|
||||
return rect2js(js,r);
|
||||
}
|
||||
|
||||
JSValue js_window_bordered(JSContext *js, JSValue self, int argc, JSValue *argv)
|
||||
{
|
||||
SDL_Window *w = js2SDL_Window(js,self);
|
||||
SDL_SetWindowBordered(w, JS_ToBool(js,argv[0]));
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
JSValue js_window_get_title(JSContext *js, JSValue self)
|
||||
{
|
||||
SDL_Window *w = js2SDL_Window(js,self);
|
||||
const char *title = SDL_GetWindowTitle(w);
|
||||
return JS_NewString(js,title);
|
||||
|
||||
}
|
||||
|
||||
JSValue js_window_set_title(JSContext *js, JSValue self, JSValue val)
|
||||
{
|
||||
SDL_Window *w = js2SDL_Window(js,self);
|
||||
const char *title = JS_ToCString(js,val);
|
||||
SDL_SetWindowTitle(w,title);
|
||||
JS_FreeCString(js,title);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
JSValue js_window_get_size(JSContext *js, JSValue self)
|
||||
{
|
||||
SDL_Window *win = js2SDL_Window(js,self);
|
||||
int w, h;
|
||||
SDL_GetWindowSize(win, &w, &h);
|
||||
return vec22js(js, (HMM_Vec2){w,h});
|
||||
}
|
||||
|
||||
JSValue js_window_set_size(JSContext *js, JSValue self, JSValue val)
|
||||
{
|
||||
SDL_Window *w = js2SDL_Window(js,self);
|
||||
HMM_Vec2 size = js2vec2(js,val);
|
||||
SDL_SetWindowSize(w,size.x,size.y);
|
||||
}
|
||||
|
||||
JSValue js_window_set_icon(JSContext *js, JSValue self, int argc, JSValue *argv)
|
||||
{
|
||||
SDL_Window *w = js2SDL_Window(js,self);
|
||||
SDL_Surface *s = js2SDL_Surface(js,argv[0]);
|
||||
if (!SDL_SetWindowIcon(w,s))
|
||||
return JS_ThrowReferenceError(js, "could not set window icon: %s", SDL_GetError());
|
||||
}
|
||||
|
||||
JSValue js_window_mouse_grab(JSContext *js, JSValue self, int argc, JSValue *argv)
|
||||
{
|
||||
SDL_Window *w = js2SDL_Window(js,self);
|
||||
SDL_SetWindowMouseGrab(w, JS_ToBool(js,argv[0]));
|
||||
|
||||
}
|
||||
|
||||
static const JSCFunctionListEntry js_SDL_Window_funcs[] = {
|
||||
MIST_FUNC_DEF(SDL_Window, fullscreen, 0),
|
||||
MIST_FUNC_DEF(SDL_Window, make_renderer, 1),
|
||||
MIST_FUNC_DEF(SDL_Window, keyboard_shown, 0),
|
||||
MIST_FUNC_DEF(window, theme, 0),
|
||||
MIST_FUNC_DEF(window, safe_area, 0),
|
||||
MIST_FUNC_DEF(window, bordered, 1),
|
||||
MIST_FUNC_DEF(window, set_icon, 1),
|
||||
CGETSET_ADD(window, title),
|
||||
CGETSET_ADD(window, size),
|
||||
MIST_FUNC_DEF(window, mouse_grab, 1),
|
||||
};
|
||||
|
||||
JSC_CCALL(SDL_Renderer_clear,
|
||||
@@ -1514,10 +1604,7 @@ JSC_CCALL(SDL_Renderer_rect,
|
||||
rect rects[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
JSValue val = JS_GetPropertyUint32(js,argv[0],i);
|
||||
rects[i] = js2rect(js,val);
|
||||
rects[i].y *= -1;
|
||||
rects[i].y += logical.y;
|
||||
rects[i].y -= rects[i].h;
|
||||
rects[i] = transform_rect(js2rect(js,val), &cam_mat);
|
||||
JS_FreeValue(js,val);
|
||||
}
|
||||
SDL_RenderRects(r,rects,len);
|
||||
@@ -1525,9 +1612,7 @@ JSC_CCALL(SDL_Renderer_rect,
|
||||
}
|
||||
|
||||
rect rect = js2rect(js,argv[0]);
|
||||
rect.y *= -1;
|
||||
rect.y += logical.y;
|
||||
rect.y -= rect.h;
|
||||
rect = transform_rect(rect, &cam_mat);
|
||||
|
||||
SDL_RenderRect(r, &rect);
|
||||
)
|
||||
@@ -1558,24 +1643,19 @@ JSC_CCALL(SDL_Renderer_fillrect,
|
||||
rects[i] = js2rect(js,val);
|
||||
JS_FreeValue(js,val);
|
||||
}
|
||||
SDL_RenderFillRects(r,rects,len);
|
||||
return JS_UNDEFINED;
|
||||
if (!SDL_RenderFillRects(r,rects,len))
|
||||
return JS_ThrowReferenceError("Could not render rectangle: %s", SDL_GetError());
|
||||
}
|
||||
rect rect = js2rect(js,argv[0]);
|
||||
rect.y *= -1;
|
||||
rect.y += logical.y;
|
||||
rect.y -= rect.h;
|
||||
rect rect = transform_rect(js2rect(js,argv[0]),&cam_mat);
|
||||
|
||||
SDL_RenderFillRect(r, &rect);
|
||||
if (!SDL_RenderFillRect(r, &rect))
|
||||
return JS_ThrowReferenceError("Could not render rectangle: %s", SDL_GetError());
|
||||
)
|
||||
|
||||
JSC_CCALL(renderer_texture,
|
||||
SDL_Renderer *renderer = js2SDL_Renderer(js,self);
|
||||
SDL_Texture *tex = js2SDL_Texture(js,argv[0]);
|
||||
rect dst = js2rect(js,argv[1]);
|
||||
dst.y *= -1;
|
||||
dst.y += logical.y;
|
||||
dst.y -= dst.h;
|
||||
rect dst = transform_rect(js2rect(js,argv[1]), &cam_mat);
|
||||
|
||||
if (!JS_IsUndefined(argv[3])) {
|
||||
colorf color = js2color(js,argv[3]);
|
||||
@@ -1588,7 +1668,7 @@ JSC_CCALL(renderer_texture,
|
||||
|
||||
rect src = js2rect(js,argv[2]);
|
||||
|
||||
SDL_RenderTexture(renderer,tex,&src,&dst);
|
||||
SDL_RenderTextureRotated(renderer, tex, &src, &dst, 0, NULL, SDL_FLIP_NONE);
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1610,12 +1690,18 @@ JSC_CCALL(renderer_tile,
|
||||
}
|
||||
)
|
||||
|
||||
JSC_CCALL(renderer_9slice,
|
||||
JSC_CCALL(renderer_slice9,
|
||||
SDL_Renderer *renderer = js2SDL_Renderer(js,self);
|
||||
SDL_Texture *tex = js2SDL_Texture(js,argv[0]);
|
||||
rect *dst, *src = NULL;
|
||||
lrtb bounds = js2lrtb(js,argv[2]);
|
||||
SDL_RenderTexture9Grid(renderer, tex, src, bounds.l, bounds.r, bounds.t, bounds.b, 0.0, dst);
|
||||
rect src, dst;
|
||||
src = transform_rect(js2rect(js,argv[3]),&cam_mat);
|
||||
dst = transform_rect(js2rect(js,argv[1]), &cam_mat);
|
||||
|
||||
SDL_RenderTexture9Grid(renderer, tex,
|
||||
JS_IsUndefined(argv[3]) ? NULL : &src,
|
||||
bounds.l, bounds.r, bounds.t, bounds.b, 0.0,
|
||||
JS_IsUndefined(argv[1]) ? NULL : &dst);
|
||||
)
|
||||
|
||||
JSC_CCALL(renderer_get_image,
|
||||
@@ -1734,10 +1820,8 @@ JSC_CCALL(renderer_geometry,
|
||||
HMM_Vec2 *trans_pos = malloc(vertices*sizeof(HMM_Vec2));
|
||||
memcpy(trans_pos,posdata, sizeof(HMM_Vec2)*vertices);
|
||||
|
||||
for (int i = 0; i < vertices; i++) {
|
||||
trans_pos[i].x -= campos.x;
|
||||
trans_pos[i].y -= campos.y;
|
||||
}
|
||||
for (int i = 0; i < vertices; i++)
|
||||
trans_pos[i] = HMM_MulM3V3(cam_mat, (HMM_Vec3){trans_pos[i].x, trans_pos[i].y, 1}).xy;
|
||||
|
||||
if (!SDL_RenderGeometryRaw(r, tex, trans_pos, pos_stride,colordata,color_stride,uvdata, uv_stride, vertices, idxdata, count, indices_stride))
|
||||
ret = JS_ThrowReferenceError(js, "Error rendering geometry: %s",SDL_GetError());
|
||||
@@ -1800,6 +1884,21 @@ JSC_CCALL(renderer_coords,
|
||||
return vec22js(js,coord);
|
||||
)
|
||||
|
||||
JSC_CCALL(renderer_camera,
|
||||
HMM_Mat3 t;
|
||||
t.Columns[0] = (HMM_Vec3){1,0,0};
|
||||
t.Columns[1] = (HMM_Vec3){0,-1,0};
|
||||
t.Columns[2] = (HMM_Vec3){0,logical.y,1};
|
||||
|
||||
transform *tra = js2transform(js,argv[0]);
|
||||
tra->pos.x -= logical.x/2;
|
||||
tra->pos.y -= logical.y/2;
|
||||
HMM_Mat3 T = transform2mat3(tra);
|
||||
cam_mat = HMM_MulM3(t,T);
|
||||
tra->pos.x += logical.x/2;
|
||||
tra->pos.y += logical.y/2;
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_SDL_Renderer_funcs[] = {
|
||||
MIST_FUNC_DEF(SDL_Renderer, draw_color, 1),
|
||||
MIST_FUNC_DEF(SDL_Renderer, present, 0),
|
||||
@@ -1810,7 +1909,7 @@ static const JSCFunctionListEntry js_SDL_Renderer_funcs[] = {
|
||||
MIST_FUNC_DEF(renderer, point, 2),
|
||||
MIST_FUNC_DEF(renderer, load_texture, 1),
|
||||
MIST_FUNC_DEF(renderer, texture, 4),
|
||||
MIST_FUNC_DEF(renderer, 9slice, 4),
|
||||
MIST_FUNC_DEF(renderer, slice9, 4),
|
||||
MIST_FUNC_DEF(renderer, tile, 4),
|
||||
MIST_FUNC_DEF(renderer, get_image, 1),
|
||||
MIST_FUNC_DEF(renderer, fasttext, 2),
|
||||
@@ -1822,6 +1921,7 @@ static const JSCFunctionListEntry js_SDL_Renderer_funcs[] = {
|
||||
MIST_FUNC_DEF(renderer,clip,1),
|
||||
MIST_FUNC_DEF(renderer,vsync,1),
|
||||
MIST_FUNC_DEF(renderer, coords, 1),
|
||||
MIST_FUNC_DEF(renderer, camera, 1),
|
||||
};
|
||||
|
||||
JSC_CCALL(surface_blit,
|
||||
@@ -1931,6 +2031,8 @@ static const JSCFunctionListEntry js_SDL_Camera_funcs[] =
|
||||
MIST_FUNC_DEF(camera, release_frame, 1),
|
||||
};
|
||||
|
||||
static const JSCFunctionListEntry js_SDL_Cursor_funcs[] = {};
|
||||
|
||||
JSC_CCALL(texture_mode,
|
||||
SDL_Texture *tex = js2SDL_Texture(js,self);
|
||||
SDL_SetTextureScaleMode(tex,js2number(js,argv[0]));
|
||||
@@ -1948,9 +2050,17 @@ JSC_CCALL(input_mouse_show,
|
||||
SDL_HideCursor();
|
||||
)
|
||||
|
||||
JSC_CCALL(input_cursor_set,
|
||||
SDL_Cursor *c = js2SDL_Cursor(js,argv[0]);
|
||||
printf("setting cursor to %p\n", c);
|
||||
if (!SDL_SetCursor(c))
|
||||
return JS_ThrowReferenceError(js, "could not set cursor: %s", SDL_GetError());
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_input_funcs[] = {
|
||||
MIST_FUNC_DEF(input, mouse_show, 1),
|
||||
MIST_FUNC_DEF(input, mouse_lock, 1),
|
||||
MIST_FUNC_DEF(input, cursor_set, 1),
|
||||
};
|
||||
|
||||
JSC_CCALL(prosperon_guid,
|
||||
@@ -2161,7 +2271,7 @@ int globfs_cb(struct globdata *data, char *dir, char *file)
|
||||
|
||||
char **glob = data->globs;
|
||||
while (*glob != NULL) {
|
||||
if (wildmatch(*glob, path, WM_PATHNAME | WM_PERIOD | WM_WILDSTAR) == WM_MATCH)
|
||||
if (wildmatch(*glob, path, WM_WILDSTAR) == WM_MATCH)
|
||||
goto END;
|
||||
*glob++;
|
||||
}
|
||||
@@ -2669,20 +2779,40 @@ JSC_CCALL(os_make_gif,
|
||||
void *pixels = stbi_load_gif_from_memory(raw, rawlen, &delays, &width, &height, &frames, &n, 4);
|
||||
|
||||
JSValue gif = JS_NewObject(js);
|
||||
ret = gif;
|
||||
|
||||
if (frames == 1) {
|
||||
// still image, so return just that
|
||||
JS_SetPropertyStr(js, gif, "surface", SDL_Surface2js(js,SDL_CreateSurfaceFrom(width,height,SDL_PIXELFORMAT_RGBA32, pixels, width*4)));
|
||||
return gif;
|
||||
}
|
||||
|
||||
JSValue delay_arr = JS_NewArray(js);
|
||||
|
||||
for (int i = 0; i < frames; i++) {
|
||||
JSValue frame = JS_NewObject(js);
|
||||
JS_SetPropertyStr(js, frame, "time", number2js(js,(float)delays[i]/1000.0));
|
||||
SDL_Surface *framesurf = SDL_CreateSurfaceFrom(width,height,SDL_PIXELFORMAT_RGBA32,pixels+(width*height*4*i), width*4);
|
||||
void *frame_pixels = malloc(width*height*4);
|
||||
if (!frame_pixels) {
|
||||
JS_FreeValue(js,gif);
|
||||
ret = JS_ThrowOutOfMemory(js);
|
||||
goto CLEANUP;
|
||||
}
|
||||
memcpy(frame_pixels, (unsigned char*)pixels+(width*height*4*i), width*height*4);
|
||||
SDL_Surface *framesurf = SDL_CreateSurfaceFrom(width,height,SDL_PIXELFORMAT_RGBA32,frame_pixels, width*4);
|
||||
if (!framesurf) {
|
||||
ret = JS_ThrowReferenceError(js, "failed to create SDL_Surface: %s", SDL_GetError());
|
||||
goto CLEANUP;
|
||||
}
|
||||
JS_SetPropertyStr(js, frame, "surface", SDL_Surface2js(js,framesurf));
|
||||
JS_SetPropertyUint32(js, delay_arr, i, frame);
|
||||
}
|
||||
|
||||
JS_SetPropertyStr(js, gif, "frames", delay_arr);
|
||||
|
||||
CLEANUP:
|
||||
free(delays);
|
||||
|
||||
ret = gif;
|
||||
free(pixels);
|
||||
)
|
||||
|
||||
JSValue aseframe2js(JSContext *js, ase_frame_t aframe)
|
||||
@@ -2756,6 +2886,15 @@ JSC_CCALL(os_make_surface,
|
||||
ret = SDL_Surface2js(js, surface);
|
||||
)
|
||||
|
||||
JSC_CCALL(os_make_cursor,
|
||||
SDL_Surface *s = js2SDL_Surface(js,argv[0]);
|
||||
HMM_Vec2 hot = js2vec2(js,argv[1]);
|
||||
SDL_Cursor *c = SDL_CreateColorCursor(s, hot.x, hot.y);
|
||||
if (!c) return JS_ThrowReferenceError("couldn't make cursor: %s", SDL_GetError());
|
||||
printf("made cursor %p\n", c);
|
||||
return SDL_Cursor2js(js,c);
|
||||
)
|
||||
|
||||
JSC_CCALL(os_make_font,
|
||||
size_t len;
|
||||
void *data = JS_GetArrayBuffer(js,&len,argv[0]);
|
||||
@@ -3117,6 +3256,7 @@ static const JSCFunctionListEntry js_os_funcs[] = {
|
||||
MIST_FUNC_DEF(os, make_gif, 1),
|
||||
MIST_FUNC_DEF(os, make_aseprite, 1),
|
||||
MIST_FUNC_DEF(os, make_surface, 1),
|
||||
MIST_FUNC_DEF(os, make_cursor, 1),
|
||||
MIST_FUNC_DEF(os, make_font, 2),
|
||||
MIST_FUNC_DEF(os, make_transform, 0),
|
||||
MIST_FUNC_DEF(os, make_line_prim, 4),
|
||||
@@ -3216,6 +3356,7 @@ void ffi_load(JSContext *js) {
|
||||
QJSCLASSPREP_FUNCS(SDL_Texture)
|
||||
QJSCLASSPREP_FUNCS(SDL_Renderer)
|
||||
QJSCLASSPREP_FUNCS(SDL_Camera)
|
||||
QJSCLASSPREP_FUNCS(SDL_Cursor)
|
||||
|
||||
QJSGLOBALCLASS(os);
|
||||
|
||||
@@ -3226,8 +3367,6 @@ void ffi_load(JSContext *js) {
|
||||
QJSCLASSPREP_FUNCS(datastream);
|
||||
QJSCLASSPREP_FUNCS(timer);
|
||||
|
||||
|
||||
|
||||
QJSGLOBALCLASS(input);
|
||||
QJSGLOBALCLASS(io);
|
||||
QJSGLOBALCLASS(prosperon);
|
||||
|
||||
@@ -52,6 +52,11 @@ char* read_file(const char* filename) {
|
||||
return content;
|
||||
}
|
||||
|
||||
int js_interrupt(JSRuntime *rt, void *data)
|
||||
{
|
||||
// printf("INTERRUPT\n");
|
||||
}
|
||||
|
||||
void script_startup() {
|
||||
rt = JS_NewRuntime();
|
||||
js = JS_NewContextRaw(rt);
|
||||
|
||||
@@ -53,19 +53,14 @@ HMM_Vec3 mat3_t_dir(HMM_Mat4 m, HMM_Vec3 dir)
|
||||
return mat3_t_pos(m, dir);
|
||||
}
|
||||
|
||||
HMM_Mat4 transform2mat(transform *t) {
|
||||
HMM_Mat4 transform2mat(transform *t)
|
||||
{
|
||||
return HMM_M4TRS(t->pos, t->rotation, t->scale);
|
||||
HMM_Mat4 scale = HMM_Scale(t->scale);
|
||||
HMM_Mat4 rot = HMM_QToM4(t->rotation);
|
||||
HMM_Mat4 pos = HMM_Translate(t->pos);
|
||||
return HMM_MulM4(pos, HMM_MulM4(rot, scale));
|
||||
}
|
||||
|
||||
if (t->dirty) {
|
||||
t->cache = HMM_M4TRS(t->pos, t->rotation, t->scale);
|
||||
t->dirty = 0;
|
||||
}
|
||||
|
||||
return t->cache;
|
||||
HMM_Mat3 transform2mat3(transform *t)
|
||||
{
|
||||
return HMM_M3TRS(t->pos.xy, t->rotation.x, t->scale.xy);
|
||||
}
|
||||
|
||||
HMM_Quat angle2rotation(float angle)
|
||||
|
||||
@@ -39,6 +39,7 @@ HMM_Vec3 mat3_t_pos(HMM_Mat4 m, HMM_Vec3 pos);
|
||||
HMM_Vec3 mat3_t_dir(HMM_Mat4 m, HMM_Vec3 dir);
|
||||
|
||||
HMM_Mat4 transform2mat(transform *t);
|
||||
HMM_Mat3 transform2mat3(transform *t);
|
||||
transform mat2transform(HMM_Mat4 m);
|
||||
|
||||
HMM_Quat angle2rotation(float angle);
|
||||
|
||||
Reference in New Issue
Block a user