add thumbnail making

This commit is contained in:
John Alanbrook 2024-06-18 16:14:23 -05:00
parent 1b5bd399cd
commit 2fe4e825aa
9 changed files with 400 additions and 268 deletions

View file

@ -267,7 +267,7 @@ crossmac: Prosperon.icns
cp Prosperon.icns Prosperon.app/Contents/Resources cp Prosperon.icns Prosperon.app/Contents/Resources
crosswin: crosswin:
make CROSS=x86_64-w64-mingw32ucrt- OS=Windows_NT CC=gcc make CROSS=x86_64-w64-mingw32- OS=Windows_NT CC=gcc
crossweb: crossweb:
make CC=emcc OS=wasm make CC=emcc OS=wasm

View file

@ -61,6 +61,7 @@ var sprite = {
this._p = p; this._p = p;
this.del_anim?.(); this.del_anim?.();
this.texture = game.texture(p); this.texture = game.texture(p);
say(p);
this.diffuse = this.texture; this.diffuse = this.texture;
this.rect = [0,0,1,1]; this.rect = [0,0,1,1];

View file

@ -1,38 +1,35 @@
"use math"; "use math";
Object.defineProperty(String.prototype, 'tolast', { Object.defineProperty(String.prototype, "tolast", {
value: function (val) { value: function (val) {
var idx = this.lastIndexOf(val); var idx = this.lastIndexOf(val);
if (idx === -1) return this.slice(); if (idx === -1) return this.slice();
return this.slice(0, idx); return this.slice(0, idx);
} },
}); });
Object.defineProperty(String.prototype, 'dir', { Object.defineProperty(String.prototype, "dir", {
value: function () { value: function () {
if (!this.includes('/')) return ""; if (!this.includes("/")) return "";
return this.tolast('/'); return this.tolast("/");
} },
}); });
Object.defineProperty(String.prototype, 'folder', { Object.defineProperty(String.prototype, "folder", {
value: function () { value: function () {
var dir = this.dir(); var dir = this.dir();
if (!dir) return ""; if (!dir) return "";
else return dir + "/"; else return dir + "/";
} },
}); });
globalThis.Resources = {}; globalThis.Resources = {};
Resources.replpath = function(str, path) Resources.replpath = function (str, path) {
{
if (!str) return str; if (!str) return str;
if (str[0] === "/") if (str[0] === "/") return str.rm(0);
return str.rm(0);
if (str[0] === "@") if (str[0] === "@") return os.prefpath() + "/" + str.rm(0);
return os.prefpath() + "/" + str.rm(0);
if (!path) return str; if (!path) return str;
@ -44,10 +41,9 @@ Resources.replpath = function(str, path)
} }
return str; return str;
} };
Resources.replstrs = function(path) Resources.replstrs = function (path) {
{
if (!path) return; if (!path) return;
var script = io.slurp(path); var script = io.slurp(path);
var regexp = /"[^"\s]*?\.[^"\s]+?"/g; var regexp = /"[^"\s]*?\.[^"\s]+?"/g;
@ -59,49 +55,43 @@ Resources.replstrs = function(path)
}); });
return script; return script;
} };
globalThis.json = {}; globalThis.json = {};
json.encode = function(value, replacer, space = 1) json.encode = function (value, replacer, space = 1) {
{
return JSON.stringify(value, replacer, space); return JSON.stringify(value, replacer, space);
} };
json.decode = function(text, reviver) json.decode = function (text, reviver) {
{
if (!text) return undefined; if (!text) return undefined;
return JSON.parse(text, reviver); return JSON.parse(text, reviver);
} };
json.readout = function(obj) json.readout = function (obj) {
{
var j = {}; var j = {};
for (var k in obj) for (var k in obj)
if (typeof obj[k] === 'function') if (typeof obj[k] === "function") j[k] = "function " + obj[k].toString();
j[k] = 'function ' + obj[k].toString(); else j[k] = obj[k];
else
j[k] = obj[k];
return json.encode(j); return json.encode(j);
} };
json.doc = { json.doc = {
doc: "json implementation.", doc: "json implementation.",
encode: "Encode a value to json.", encode: "Encode a value to json.",
decode: "Decode a json string to a value.", decode: "Decode a json string to a value.",
readout: "Encode an object fully, including function definitions." readout: "Encode an object fully, including function definitions.",
}; };
Resources.scripts = ["jsoc", "jsc", "jso", "js"]; Resources.scripts = ["jsoc", "jsc", "jso", "js"];
Resources.images = ["png", "gif", "jpg", "jpeg"]; Resources.images = ["png", "gif", "jpg", "jpeg"];
Resources.sounds = ["wav", 'flac', 'mp3', "qoa"]; Resources.sounds = ["wav", "flac", "mp3", "qoa"];
Resources.is_image = function (path) { Resources.is_image = function (path) {
var ext = path.ext(); var ext = path.ext();
return Resources.images.any(x => x === ext); return Resources.images.any((x) => x === ext);
} };
function find_ext(file, ext) function find_ext(file, ext) {
{
if (io.exists(file)) return file; if (io.exists(file)) return file;
for (var e of ext) { for (var e of ext) {
var nf = `${file}.${e}`; var nf = `${file}.${e}`;
@ -110,42 +100,45 @@ function find_ext(file, ext)
return; return;
} }
Resources.find_image = function(file) { return find_ext(file,Resources.images); } Resources.find_image = function (file) {
Resources.find_sound = function(file) { return find_ext(file,Resources.sounds); } return find_ext(file, Resources.images);
Resources.find_script = function(file) { return find_ext(file,Resources.scripts); } };
Resources.find_sound = function (file) {
return find_ext(file, Resources.sounds);
};
Resources.find_script = function (file) {
return find_ext(file, Resources.scripts);
};
profile.best_t = function (t) { profile.best_t = function (t) {
var qq = 'ns'; var qq = "ns";
if (t > 1000) { if (t > 1000) {
t /= 1000; t /= 1000;
qq = 'us'; qq = "us";
if (t > 1000) { if (t > 1000) {
t /= 1000; t /= 1000;
qq = 'ms'; qq = "ms";
} }
} }
return `${t.toPrecision(4)} ${qq}`; return `${t.toPrecision(4)} ${qq}`;
} };
profile.report = function(start, msg = "[undefined report]") profile.report = function (start, msg = "[undefined report]") {
{
console.info(`${msg} in ${profile.best_t(profile.now() - start)}`); console.info(`${msg} in ${profile.best_t(profile.now() - start)}`);
} };
profile.addreport = function(cache, line, start) profile.addreport = function (cache, line, start) {
{
cache[line] ??= []; cache[line] ??= [];
cache[line].push(profile.now() - start); cache[line].push(profile.now() - start);
} };
profile.printreport = function(cache, name) profile.printreport = function (cache, name) {
{
var report = name + "\n"; var report = name + "\n";
for (var i in cache) for (var i in cache)
report += `${i} ${profile.best_t(cache[i].reduce((a, b) => a + b) / cache[i].length)}\n`; report += `${i} ${profile.best_t(cache[i].reduce((a, b) => a + b) / cache[i].length)}\n`;
return report; return report;
} };
console.transcript = ""; console.transcript = "";
console.say = function (msg) { console.say = function (msg) {
@ -158,15 +151,13 @@ globalThis.say = console.say;
globalThis.print = console.print; globalThis.print = console.print;
console.pprint = function (msg, lvl = 0) { console.pprint = function (msg, lvl = 0) {
if (typeof msg === "object") msg = JSON.stringify(msg, null, 2);
if (typeof msg === 'object')
msg = JSON.stringify(msg, null, 2);
var file = "nofile"; var file = "nofile";
var line = 0; var line = 0;
console.rec(0, msg, file, line); console.rec(0, msg, file, line);
var caller = (new Error()).stack.split('\n')[2]; var caller = new Error().stack.split("\n")[2];
if (caller) { if (caller) {
var md = caller.match(/\((.*)\:/); var md = caller.match(/\((.*)\:/);
var m = md ? md[1] : "SCRIPT"; var m = md ? md[1] : "SCRIPT";
@ -179,19 +170,33 @@ console.pprint = function(msg,lvl = 0) {
console.rec(lvl, msg, file, line); console.rec(lvl, msg, file, line);
}; };
console.spam = function(msg) { console.pprint (msg,0); }; console.spam = function (msg) {
console.debug = function(msg) { console.pprint(msg,1); }; console.pprint(msg, 0);
console.info = function(msg) { console.pprint(msg, 2); }; };
console.warn = function(msg) { console.pprint(msg, 3); }; console.debug = function (msg) {
console.error = function(msg) { console.pprint(msg + "\n" + console.stackstr(2), 4);}; console.pprint(msg, 1);
console.panic = function(msg) { console.pprint(msg + "\n" + console.stackstr(2), 5); }; };
console.info = function (msg) {
console.pprint(msg, 2);
};
console.warn = function (msg) {
console.pprint(msg, 3);
};
console.error = function (msg) {
console.pprint(msg + "\n" + console.stackstr(2), 4);
};
console.panic = function (msg) {
console.pprint(msg + "\n" + console.stackstr(2), 5);
};
console.stackstr = function (skip = 0) { console.stackstr = function (skip = 0) {
var err = new Error(); var err = new Error();
var stack = err.stack.split('\n'); var stack = err.stack.split("\n");
return stack.slice(skip,stack.length).join('\n'); return stack.slice(skip, stack.length).join("\n");
}; };
console.stack = function(skip = 0) { console.log(console.stackstr(skip+1)); }; console.stack = function (skip = 0) {
console.log(console.stackstr(skip + 1));
};
console.stdout_lvl = 1; console.stdout_lvl = 1;
console.trace = console.stack; console.trace = console.stack;
@ -206,15 +211,14 @@ console.doc = {
say: "Write raw text to console, plus a newline.", say: "Write raw text to console, plus a newline.",
stack: "Output a stacktrace to console.", stack: "Output a stacktrace to console.",
console: "Output directly to in game console.", console: "Output directly to in game console.",
clear: "Clear console." clear: "Clear console.",
}; };
globalThis.global = globalThis; globalThis.global = globalThis;
var profcache = {}; var profcache = {};
function use(file, env = {}, script) function use(file, env = {}, script) {
{
file = Resources.find_script(file); file = Resources.find_script(file);
var st = profile.now(); var st = profile.now();
@ -236,35 +240,34 @@ function use(file, env = {}, script)
use.cache = {}; use.cache = {};
global.check_registers = function(obj) global.check_registers = function (obj) {
{ if (typeof obj.update === "function")
if (typeof obj.update === 'function')
obj.timers.push(Register.update.register(obj.update.bind(obj))); obj.timers.push(Register.update.register(obj.update.bind(obj)));
if (typeof obj.physupdate === 'function') if (typeof obj.physupdate === "function")
obj.timers.push(Register.physupdate.register(obj.physupdate.bind(obj))); obj.timers.push(Register.physupdate.register(obj.physupdate.bind(obj)));
if (typeof obj.draw === 'function') if (typeof obj.draw === "function")
obj.timers.push(Register.draw.register(obj.draw.bind(obj), obj)); obj.timers.push(Register.draw.register(obj.draw.bind(obj), obj));
if (typeof obj.debug === 'function') if (typeof obj.debug === "function")
obj.timers.push(Register.debug.register(obj.debug.bind(obj))); obj.timers.push(Register.debug.register(obj.debug.bind(obj)));
if (typeof obj.gui === 'function') if (typeof obj.gui === "function")
obj.timers.push(Register.gui.register(obj.gui.bind(obj))); obj.timers.push(Register.gui.register(obj.gui.bind(obj)));
if (typeof obj.screengui === 'function') if (typeof obj.screengui === "function")
obj.timers.push(Register.screengui.register(obj.screengui.bind(obj))); obj.timers.push(Register.screengui.register(obj.screengui.bind(obj)));
for (var k in obj) { for (var k in obj) {
if (!k.startswith("on_")) continue; if (!k.startswith("on_")) continue;
var signal = k.fromfirst("on_"); var signal = k.fromfirst("on_");
Event.observe(signal, obj, obj[k]); Event.observe(signal, obj, obj[k]);
};
} }
};
Object.assign(global, use("scripts/base")); Object.assign(global, use("scripts/base"));
global.obscure('global'); global.obscure("global");
global.mixin("scripts/render"); global.mixin("scripts/render");
global.mixin("scripts/debug"); global.mixin("scripts/debug");
@ -272,48 +275,53 @@ var frame_t = profile.secs(profile.now());
var sim = {}; var sim = {};
sim.mode = "play"; sim.mode = "play";
sim.play = function() { this.mode = "play"; os.reindex_static(); }; sim.play = function () {
sim.playing = function() { return this.mode === 'play'; }; this.mode = "play";
sim.pause = function() { this.mode = "pause"; }; os.reindex_static();
sim.paused = function() { return this.mode === 'pause'; }; };
sim.step = function() { this.mode = 'step'; }; sim.playing = function () {
sim.stepping = function() { return this.mode === 'step'; } return this.mode === "play";
};
sim.pause = function () {
this.mode = "pause";
};
sim.paused = function () {
return this.mode === "pause";
};
sim.step = function () {
this.mode = "step";
};
sim.stepping = function () {
return this.mode === "step";
};
var physlag = 0; var physlag = 0;
var gggstart = game.engine_start; var gggstart = game.engine_start;
game.engine_start = function (s) { game.engine_start = function (s) {
game.startengine = 1; game.startengine = 1;
gggstart(function() { gggstart(
function () {
global.mixin("scripts/sound.js"); global.mixin("scripts/sound.js");
world_start(); world_start();
window.set_icon(os.make_texture("icons/moon.gif")) window.set_icon(os.make_texture("icons/moon.gif"));
Object.readonly(window.__proto__, 'vsync'); Object.readonly(window.__proto__, "vsync");
Object.readonly(window.__proto__, 'enable_dragndrop'); Object.readonly(window.__proto__, "enable_dragndrop");
Object.readonly(window.__proto__, 'enable_clipboard'); Object.readonly(window.__proto__, "enable_clipboard");
Object.readonly(window.__proto__, 'high_dpi'); Object.readonly(window.__proto__, "high_dpi");
Object.readonly(window.__proto__, 'sample_count'); Object.readonly(window.__proto__, "sample_count");
s(); s();
shape.quad = { shape.quad = {
pos:os.make_buffer([ pos: os.make_buffer([0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0], 0),
0,0,0,
1,0,0,
0,1,0,
1,1,0
],0),
verts: 4, verts: 4,
uv: os.make_buffer([0, 1, 1, 1, 0, 0, 1, 0], 2), uv: os.make_buffer([0, 1, 1, 1, 0, 0, 1, 0], 2),
index: os.make_buffer([0, 1, 2, 2, 1, 3], 1), index: os.make_buffer([0, 1, 2, 2, 1, 3], 1),
count: 6 count: 6,
}; };
shape.triangle = { shape.triangle = {
pos: os.make_buffer([ pos: os.make_buffer([0, 0, 0, 0.5, 1, 0, 1, 0, 0], 0),
0,0,0,
0.5,1,0,
1,0,0]
,0),
uv: os.make_buffer([0, 0, 0.5, 1, 1, 0], 2), uv: os.make_buffer([0, 0, 0.5, 1, 1, 0], 2),
verts: 3, verts: 3,
count: 3, count: 3,
@ -321,14 +329,17 @@ game.engine_start = function(s) {
}; };
render.init(); render.init();
}, process, window.size.x, window.size.y); },
} process,
window.size.x,
window.size.y,
);
};
game.startengine = 0; game.startengine = 0;
var frames = []; var frames = [];
function process() function process() {
{
var startframe = profile.now(); var startframe = profile.now();
var dt = profile.secs(profile.now()) - frame_t; var dt = profile.secs(profile.now()) - frame_t;
frame_t = profile.secs(profile.now()); frame_t = profile.secs(profile.now());
@ -338,8 +349,7 @@ function process()
if (sim.mode === "play" || sim.mode === "step") { if (sim.mode === "play" || sim.mode === "step") {
prosperon.update(dt * game.timescale); prosperon.update(dt * game.timescale);
if (sim.mode === "step") if (sim.mode === "step") sim.pause();
sim.pause();
physlag += dt; physlag += dt;
@ -363,18 +373,15 @@ function process()
if (frames.length > 20) frames.shift(); if (frames.length > 20) frames.shift();
} }
globalThis.fps = function() globalThis.fps = function () {
{
var sum = 0; var sum = 0;
for (var i = 0; i < frames.length; i++) for (var i = 0; i < frames.length; i++) sum += frames[i];
sum += frames[i];
return frames.length / sum; return frames.length / sum;
} };
game.timescale = 1; game.timescale = 1;
var eachobj = function(obj,fn) var eachobj = function (obj, fn) {
{
var val = fn(obj); var val = fn(obj);
if (val) return val; if (val) return val;
for (var o in obj.objects) { for (var o in obj.objects) {
@ -383,34 +390,31 @@ var eachobj = function(obj,fn)
val = eachobj(obj.objects[o], fn); val = eachobj(obj.objects[o], fn);
if (val) return val; if (val) return val;
} }
} };
game.all_objects = function(fn, startobj = world) { return eachobj(startobj,fn); }; game.all_objects = function (fn, startobj = world) {
game.find_object = function(fn, startobj = world) { return eachobj(startobj, fn);
};
} game.find_object = function (fn, startobj = world) {};
game.tags = {}; game.tags = {};
game.tag_add = function (tag, obj) { game.tag_add = function (tag, obj) {
game.tags[tag] ??= {}; game.tags[tag] ??= {};
game.tags[tag][obj.guid] = obj; game.tags[tag][obj.guid] = obj;
} };
game.tag_rm = function (tag, obj) { game.tag_rm = function (tag, obj) {
delete game.tags[tag][obj.guid]; delete game.tags[tag][obj.guid];
} };
game.tag_clear_guid = function(guid) game.tag_clear_guid = function (guid) {
{ for (var tag in game.tags) delete game.tags[tag][guid];
for (var tag in game.tags) };
delete game.tags[tag][guid];
}
game.objects_with_tag = function(tag) game.objects_with_tag = function (tag) {
{
if (!game.tags[tag]) return []; if (!game.tags[tag]) return [];
return Object.values(game.tags[tag]); return Object.values(game.tags[tag]);
} };
game.doc = {}; game.doc = {};
game.doc.object = "Returns the entity belonging to a given id."; game.doc.object = "Returns the entity belonging to a given id.";
@ -418,64 +422,60 @@ game.doc.pause = "Pause game simulation.";
game.doc.play = "Resume or start game simulation."; game.doc.play = "Resume or start game simulation.";
game.doc.camera = "Current camera."; game.doc.camera = "Current camera.";
game.texture = function(path) game.texture = function (path) {
{
if (game.texture.cache[path]) return game.texture.cache[path]; if (game.texture.cache[path]) return game.texture.cache[path];
if (!io.exists(path)) { if (!io.exists(path)) {
console.warn(`Missing texture: ${path}`); console.warn(`Missing texture: ${path}`);
game.texture.cache[path] = game.texture("icons/no_tex.gif"); game.texture.cache[path] = game.texture("icons/no_tex.gif");
} else } else game.texture.cache[path] ??= os.make_texture(path);
game.texture.cache[path] ??= os.make_texture(path);
return game.texture.cache[path]; return game.texture.cache[path];
} };
game.texture.cache = {}; game.texture.cache = {};
prosperon.semver = {}; prosperon.semver = {};
prosperon.semver.valid = function(v, range) prosperon.semver.valid = function (v, range) {
{ v = v.split(".");
v = v.split('.'); range = range.split(".");
range = range.split('.');
if (v.length !== 3) return undefined; if (v.length !== 3) return undefined;
if (range.length !== 3) return undefined; if (range.length !== 3) return undefined;
if (range[0][0] === '^') { if (range[0][0] === "^") {
range[0] = range[0].slice(1); range[0] = range[0].slice(1);
if (parseInt(v[0]) >= parseInt(range[0])) return true; if (parseInt(v[0]) >= parseInt(range[0])) return true;
return false; return false;
} }
if (range[0] === '~') { if (range[0] === "~") {
range[0] = range[0].slice(1); range[0] = range[0].slice(1);
for (var i = 0; i < 2; i++) for (var i = 0; i < 2; i++)
if (parseInt(v[i]) < parseInt(range[i])) return false; if (parseInt(v[i]) < parseInt(range[i])) return false;
return true; return true;
} }
return prosperon.semver.cmp(v.join('.'), range.join('.')) === 0; return prosperon.semver.cmp(v.join("."), range.join(".")) === 0;
} };
prosperon.semver.cmp = function(v1, v2) prosperon.semver.cmp = function (v1, v2) {
{ var ver1 = v1.split(".");
var ver1 = v1.split('.'); var ver2 = v2.split(".");
var ver2 = v2.split('.');
for (var i = 0; i < 3; i++) { for (var i = 0; i < 3; i++) {
var n1 = parseInt(ver1[i]); var n1 = parseInt(ver1[i]);
var n2 = parseInt(ver2[i]); var n2 = parseInt(ver2[i]);
if (n1 > n2) if (n1 > n2) return 1;
return 1; else if (n1 < n2) return -1;
else if (n1 < n2)
return -1;
} }
return 0; return 0;
} };
prosperon.semver.doc = "Functions for semantic versioning numbers. Semantic versioning is given as a triple digit number, as MAJOR.MINOR.PATCH."; prosperon.semver.doc =
prosperon.semver.cmp.doc = "Compare two semantic version numbers, given like X.X.X."; "Functions for semantic versioning numbers. Semantic versioning is given as a triple digit number, as MAJOR.MINOR.PATCH.";
prosperon.semver.cmp.doc =
"Compare two semantic version numbers, given like X.X.X.";
prosperon.semver.valid.doc = `Test if semantic version v is valid, given a range. prosperon.semver.valid.doc = `Test if semantic version v is valid, given a range.
Range is given by a semantic versioning number, prefixed with nothing, a ~, or a ^. 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 and MINOR must match exactly, but any PATCH greater or equal is valid.
@ -500,7 +500,7 @@ prosperon.quit = function(){
console.info("QUITTING"); console.info("QUITTING");
for (var i in debug.log.time) for (var i in debug.log.time)
say(debug.log.time[i].map(x=>profile.ms(x))); say(debug.log.time[i].map((x) => profile.ms(x)));
}; };
global.mixin("scripts/input"); global.mixin("scripts/input");
@ -552,17 +552,20 @@ var Register = {
var fns = []; var fns = [];
n.register = function (fn, obj) { n.register = function (fn, obj) {
if (typeof fn !== 'function') return; if (typeof fn !== "function") return;
if (typeof obj === 'object') if (typeof obj === "object") fn = fn.bind(obj);
fn = fn.bind(obj);
fns.push(fn); fns.push(fn);
return function () { return function () {
fns.remove(fn); fns.remove(fn);
}; };
} };
prosperon[name] = function(...args) { fns.forEach(x => x(...args)); } prosperon[name] = function (...args) {
fns.forEach((x) => x(...args));
};
prosperon[name].fns = fns; prosperon[name].fns = fns;
n.clear = function() { fns = []; } n.clear = function () {
fns = [];
};
Register[name] = n; Register[name] = n;
Register.registries.push(n); Register.registries.push(n);
@ -588,11 +591,11 @@ var Event = {
}, },
unobserve(name, obj) { unobserve(name, obj) {
this.events[name] = this.events[name].filter(x => x[0] !== obj); this.events[name] = this.events[name].filter((x) => x[0] !== obj);
}, },
rm_obj(obj) { rm_obj(obj) {
Object.keys(this.events).forEach(name => Event.unobserve(name,obj)); Object.keys(this.events).forEach((name) => Event.unobserve(name, obj));
}, },
notify(name, ...args) { notify(name, ...args) {
@ -623,9 +626,11 @@ global.mixin("scripts/spline");
global.mixin("scripts/components"); global.mixin("scripts/components");
window.doc = {}; window.doc = {};
window.doc.dimensions = "Window width and height packaged in an array [width,height]"; window.doc.dimensions =
"Window width and height packaged in an array [width,height]";
window.doc.title = "Name in the title bar of the window."; window.doc.title = "Name in the title bar of the window.";
window.doc.boundingbox = "Boundingbox of the window, with top and right being its height and width."; window.doc.boundingbox =
"Boundingbox of the window, with top and right being its height and width.";
global.mixin("scripts/actor"); global.mixin("scripts/actor");
global.mixin("scripts/entity"); global.mixin("scripts/entity");
@ -634,9 +639,13 @@ function world_start() {
globalThis.world = Object.create(entity); globalThis.world = Object.create(entity);
world.transform = os.make_transform(); world.transform = os.make_transform();
world.objects = {}; world.objects = {};
world.toString = function() { return "world"; }; world.toString = function () {
return "world";
};
world.ur = "world"; world.ur = "world";
world.kill = function() { this.clear(); }; world.kill = function () {
this.clear();
};
world.phys = 2; world.phys = 2;
world.zoom = 1; world.zoom = 1;
world._ed = { selectable: false }; world._ed = { selectable: false };
@ -656,4 +665,4 @@ window.boundingbox = function() {
var pos = game.camera.pos; var pos = game.camera.pos;
var wh = window.rendersize.scale(game.camera.zoom); var wh = window.rendersize.scale(game.camera.zoom);
return bbox.fromcwh(pos, wh); return bbox.fromcwh(pos, wh);
} };

View file

@ -105,7 +105,7 @@ var entity = {
set scale(x) { this.transform.scale = x; }, set scale(x) { this.transform.scale = x; },
move(vec) { this.pos = this.pos.add(vec); }, move(vec) { this.pos = this.pos.add(vec); },
rotate(x) { this.angle += x; }, rotate(x) { this.transform.rotate(x, [0,0,-1]); },
grow(vec) { grow(vec) {
if (typeof vec === 'number') vec = [vec,vec]; if (typeof vec === 'number') vec = [vec,vec];
this.scale = this.scale.map((x,i) => x*vec[i]); this.scale = this.scale.map((x,i) => x*vec[i]);

View file

@ -1909,6 +1909,21 @@ HMM_Quat HMM_M4ToQ_LH(HMM_Mat4 M) {
return Q; return Q;
} }
float HMM_Q_Roll(HMM_Quat q)
{
return atan2(2.0*(q.x*q.y + q.w*q.z), q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z);
}
float HMM_Q_Pitch(HMM_Quat q)
{
return asin(-2.0*(q.x*q.z - q.w*q.y));
}
float HMM_Q_Yaw(HMM_Quat q)
{
return atan2(2.0*(q.y*q.z + q.w*q.x), q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z);
}
HMM_Quat HMM_QFromAxisAngle_RH(HMM_Vec3 Axis, float AngleOfRotation) { HMM_Quat HMM_QFromAxisAngle_RH(HMM_Vec3 Axis, float AngleOfRotation) {
HMM_Quat Result; HMM_Quat Result;

View file

@ -658,4 +658,8 @@ HMM_Quat HMM_M4ToQ_LH(HMM_Mat4 M);
HMM_Quat HMM_QFromAxisAngle_RH(HMM_Vec3 Axis, float AngleOfRotation); HMM_Quat HMM_QFromAxisAngle_RH(HMM_Vec3 Axis, float AngleOfRotation);
HMM_Quat HMM_QFromAxisAngle_LH(HMM_Vec3 Axis, float AngleOfRotation); HMM_Quat HMM_QFromAxisAngle_LH(HMM_Vec3 Axis, float AngleOfRotation);
float HMM_Q_Roll(HMM_Quat q);
float HMM_Q_Yaw(HMM_Quat q);
float HMM_Q_Pitch(HMM_Quat q);
#endif /* HANDMADE_MATH_H */ #endif /* HANDMADE_MATH_H */

View file

@ -1474,6 +1474,7 @@ JSC_GETSET(transform, pos, vec3)
JSC_GETSET(transform, scale, vec3) JSC_GETSET(transform, scale, vec3)
JSC_GETSET(transform, rotation, quat) JSC_GETSET(transform, rotation, quat)
JSC_CCALL(transform_move, transform_move(js2transform(self), js2vec3(argv[0])); ) JSC_CCALL(transform_move, transform_move(js2transform(self), js2vec3(argv[0])); )
JSC_CCALL(transform_lookat, JSC_CCALL(transform_lookat,
HMM_Vec3 point = js2vec3(argv[0]); HMM_Vec3 point = js2vec3(argv[0]);
transform *go = js2transform(self); transform *go = js2transform(self);
@ -1488,6 +1489,15 @@ JSC_CCALL(transform_rotate,
t->rotation = HMM_MulQ(t->rotation,rot); t->rotation = HMM_MulQ(t->rotation,rot);
) )
JSC_CCALL(transform_angle,
HMM_Vec3 axis = js2vec3(argv[0]);
transform *t = js2transform(self);
if (axis.x) return angle2js(HMM_Q_Roll(t->rotation));
if (axis.y) return angle2js(HMM_Q_Pitch(t->rotation));
if (axis.z) return angle2js(HMM_Q_Yaw(t->rotation));
return angle2js(0);
)
JSC_CCALL(transform_direction, JSC_CCALL(transform_direction,
transform *t = js2transform(self); transform *t = js2transform(self);
return vec32js(HMM_QVRot(js2vec3(argv[0]), t->rotation)); return vec32js(HMM_QVRot(js2vec3(argv[0]), t->rotation));
@ -1499,6 +1509,7 @@ static const JSCFunctionListEntry js_transform_funcs[] = {
CGETSET_ADD(transform, rotation), CGETSET_ADD(transform, rotation),
MIST_FUNC_DEF(transform, move, 1), MIST_FUNC_DEF(transform, move, 1),
MIST_FUNC_DEF(transform, rotate, 2), MIST_FUNC_DEF(transform, rotate, 2),
MIST_FUNC_DEF(transform, angle, 1),
MIST_FUNC_DEF(transform, lookat, 1), MIST_FUNC_DEF(transform, lookat, 1),
MIST_FUNC_DEF(transform, direction, 1), MIST_FUNC_DEF(transform, direction, 1),
}; };
@ -1988,11 +1999,18 @@ JSC_GET(texture, height, number)
JSC_GET(texture, frames, number) JSC_GET(texture, frames, number)
JSC_GET(texture, delays, ints) JSC_GET(texture, delays, ints)
JSC_SCALL(texture_save, texture_save(js2texture(self), str));
JSC_CCALL(texture_blit,
texture_blit(js2texture(self), js2texture(argv[0]), js2number(argv[1]), js2number(argv[2]), js2number(argv[3]), js2number(argv[4])))
static const JSCFunctionListEntry js_texture_funcs[] = { static const JSCFunctionListEntry js_texture_funcs[] = {
MIST_GET(texture, width), MIST_GET(texture, width),
MIST_GET(texture, height), MIST_GET(texture, height),
MIST_GET(texture, frames), MIST_GET(texture, frames),
MIST_GET(texture, delays), MIST_GET(texture, delays),
MIST_FUNC_DEF(texture, save, 2),
MIST_FUNC_DEF(texture, blit, 3)
}; };
JSC_GETSET(font, linegap, number) JSC_GETSET(font, linegap, number)
@ -2289,6 +2307,8 @@ JSC_SCALL(os_make_texture,
JS_SetPropertyStr(js, ret, "path", JS_DupValue(js,argv[0])); JS_SetPropertyStr(js, ret, "path", JS_DupValue(js,argv[0]));
) )
JSC_CCALL(os_make_tex_data, ret = texture2js(texture_empty(js2number(argv[0]), js2number(argv[1]), js2number(argv[2]))))
JSC_CCALL(os_make_font, JSC_CCALL(os_make_font,
font *f = MakeFont(js2str(argv[0]), js2number(argv[1])); font *f = MakeFont(js2str(argv[0]), js2number(argv[1]));
ret = font2js(f); ret = font2js(f);
@ -2517,6 +2537,7 @@ static const JSCFunctionListEntry js_os_funcs[] = {
MIST_FUNC_DEF(os, make_poly2d, 2), MIST_FUNC_DEF(os, make_poly2d, 2),
MIST_FUNC_DEF(os, make_seg2d, 1), MIST_FUNC_DEF(os, make_seg2d, 1),
MIST_FUNC_DEF(os, make_texture, 1), MIST_FUNC_DEF(os, make_texture, 1),
MIST_FUNC_DEF(os, make_tex_data, 3),
MIST_FUNC_DEF(os, make_font, 2), MIST_FUNC_DEF(os, make_font, 2),
MIST_FUNC_DEF(os, make_model, 1), MIST_FUNC_DEF(os, make_model, 1),
MIST_FUNC_DEF(os, make_transform, 0), MIST_FUNC_DEF(os, make_transform, 0),

View file

@ -5,6 +5,7 @@
#include "sokol/sokol_gfx.h" #include "sokol/sokol_gfx.h"
#include <math.h> #include <math.h>
#include <stb_image.h> #include <stb_image.h>
#include <stb_image_write.h>
#include "resources.h" #include "resources.h"
@ -173,6 +174,26 @@ void texture_free(texture *tex)
free(tex); free(tex);
} }
struct texture *texture_empty(int w, int h, int n)
{
texture *tex = calloc(1,sizeof(*tex));
tex->data = calloc(w*h*n, sizeof(unsigned char));
tex->width = w;
tex->height = h;
sg_image_data sgdata;
sgdata.subimage[0][0] = (sg_range){.ptr = tex->data, .size = w*h*4};
tex->id = sg_make_image(&(sg_image_desc){
.type = SG_IMAGETYPE_2D,
.width = tex->width,
.height = tex->height,
.usage = SG_USAGE_IMMUTABLE,
.num_mipmaps = 1,
.data = sgdata,
});
return tex;
}
struct texture *texture_fromdata(void *raw, long size) struct texture *texture_fromdata(void *raw, long size)
{ {
struct texture *tex = calloc(1, sizeof(*tex)); struct texture *tex = calloc(1, sizeof(*tex));
@ -260,6 +281,64 @@ double grad (int hash, double x, double y, double z)
}*/ }*/
} }
void texture_save(texture *tex, const char *file)
{
char *ext = strrchr(file, '.');
printf("SAVING TO %s with ext %s\n", file, ext);
if (!strcmp(ext, ".png"))
stbi_write_png(file, tex->width, tex->height, 4, tex->data, 4*tex->width);
else if (!strcmp(ext, ".bmp"))
stbi_write_bmp(file, tex->width, tex->height, 4, tex->data);
else if (!strcmp(ext, ".tga"))
stbi_write_tga(file, tex->width, tex->height, 4, tex->data);
else if (!strcmp(ext, ".jpg") || !strcmp(ext, ".jpeg"))
stbi_write_jpg(file, tex->width, tex->height, 4, tex->data, 5);
}
void blit_image(uint8_t* src, uint8_t* dest, int src_width, int src_height, int dest_width, int dest_height, int sx, int sy, int sw, int sh) {
int src_stride = src_width * 4;
int dest_stride = dest_width * 4;
for (int y = 0; y < sw; y++) {
for (int x = 0; x < sh; x++) {
int src_index = (y * src_stride) + (x * 4);
int dest_index = ((y + sy) * dest_stride) + ((x + sx) * 4);
// Calculate the alpha value for the source pixel
uint8_t src_alpha = src[src_index + 3];
// Calculate the alpha value for the destination pixel
uint8_t dest_alpha = dest[dest_index + 3];
// Calculate the resulting alpha value
uint8_t result_alpha = src_alpha + (255 - src_alpha) * dest_alpha / 255;
// Calculate the resulting RGB values
uint8_t result_red = (src[src_index + 0] * src_alpha + dest[dest_index + 0] * (255 - src_alpha) * dest_alpha / 255) / result_alpha;
uint8_t result_green = (src[src_index + 1] * src_alpha + dest[dest_index + 1] * (255 - src_alpha) * dest_alpha / 255) / result_alpha;
uint8_t result_blue = (src[src_index + 2] * src_alpha + dest[dest_index + 2] * (255 - src_alpha) * dest_alpha / 255) / result_alpha;
// Set the resulting pixel values
dest[dest_index + 0] = result_red;
dest[dest_index + 1] = result_green;
dest[dest_index + 2] = result_blue;
dest[dest_index + 3] = result_alpha;
}
}
}
// Function to draw source image pixels on top of a destination image
void texture_blit(texture *dest, texture *src, int x, int y, int w, int h) {
blit_image(src->data, dest->data, src->width, src->height, dest->height, dest->width, x, y, w, h);
}
void texture_flip(texture *tex, int y)
{
}
static int p[512] = {151,160,137,91,90,15, static int p[512] = {151,160,137,91,90,15,
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, 131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,

View file

@ -40,8 +40,11 @@ typedef struct img_sampler{
texture *texture_from_file(const char *path); texture *texture_from_file(const char *path);
void texture_free(texture *tex); void texture_free(texture *tex);
struct texture *texture_fromdata(void *raw, long size); struct texture *texture_fromdata(void *raw, long size);
texture *texture_empty(int width, int height, int n);
void texture_blit(texture *dest, texture *src, int x, int y, int w, int h);
void texture_flip(texture *tex, int y);
void texture_save(texture *tex, const char *file);
double perlin(double x, double y, double z); double perlin(double x, double y, double z);