separate input and events; pull camera out of render
This commit is contained in:
@@ -5,7 +5,12 @@ With Javascript's C-like syntax, it makes it easy to make classic style games li
|
||||
# API usage
|
||||
A lot of the API usage is informed from 'duck typing'. If something "looks" like a camera - it can be used like one! If something "looks" like a sprite, it can be used like one! There are fast paths on nearly everything for well defined objects
|
||||
|
||||
Uniformity is prioritized.
|
||||
Uniformity is prioritized. Javascript allows for a powerful abstraction - the object - which Prosperon makes much use of. It allows for another - the arraybuffer - which makes it simple to plug different parts of the engine into each other.
|
||||
|
||||
The object is the lingua franca of the API. For example, json.encode and json.decode converts objects to and fromt json strings; nota.encode and nota.decode converts objects to and from nota bytes, represented as a javascript arraybuffer. To convert a json string to a nota buffer, one would do:
|
||||
nota.encode(json.decode(str))
|
||||
|
||||
Most functions take objects just like this, increasing flexibility for what you can send into functions.
|
||||
|
||||
# Gradual performance
|
||||
Prosperon makes it easy to make something quickly, and if it runs well, you're golden! But if it's slow, there are a plethora of options to make it faster. Plus, with native C plugins, there is nothing that can't be figured out.
|
||||
@@ -14,42 +19,64 @@ Prosperon makes it easy to make something quickly, and if it runs well, you're g
|
||||
~~prosperon master
|
||||
Here are the modules that can be included via 'use'.
|
||||
|
||||
// extensions
|
||||
Object.id - get a unique id for the given javascript object
|
||||
|
||||
// global syntax level things
|
||||
Globals have been kept to a minimum to ensure game objects are as flexible as possible in what they can call their state. The vast majority of access to prosperon is done through the 'use' statement.
|
||||
use - import a module
|
||||
on actors: /* look to web windows for a comparison */
|
||||
- spawn: create a new actor
|
||||
- delay: execute a function after seconds
|
||||
-
|
||||
|
||||
prosperon global object; information about the engine; process related (ie, if there are multiple threads running, prosperon will be different in each, os will be the same)
|
||||
- version: 0.6.1
|
||||
- revision: git revision
|
||||
- argv: the string of arguments passed to the process
|
||||
- semver: functions to compare use
|
||||
|
||||
// core
|
||||
prosperon
|
||||
input
|
||||
json
|
||||
layout
|
||||
resources
|
||||
sound
|
||||
os - sys calls; information about the underlying hardware
|
||||
js - information about the scripting language; gc functions; etc
|
||||
|
||||
// mixed in
|
||||
base
|
||||
std
|
||||
time
|
||||
search
|
||||
color
|
||||
tween
|
||||
util
|
||||
io
|
||||
os
|
||||
|
||||
// core use fns
|
||||
input - user input settings
|
||||
json - json encoding and decoding
|
||||
resources - access resources
|
||||
sound - play sounds
|
||||
time - time access
|
||||
actor - actor helpers
|
||||
color - color constants
|
||||
tween - helper to tween
|
||||
util - random helpers
|
||||
io - file system access, mounting, unmounting
|
||||
event - system events
|
||||
|
||||
math - math help
|
||||
geometry - geometry help
|
||||
|
||||
// rendering
|
||||
draw2d
|
||||
render
|
||||
graphics
|
||||
|
||||
// game components
|
||||
emitter
|
||||
sprite
|
||||
transform
|
||||
|
||||
// math
|
||||
pmath
|
||||
vector
|
||||
geometry
|
||||
draw2d - immediate mode draw 2d stuff functions
|
||||
render - render configuration and use; shaders, pipelines, render state.
|
||||
graphics - create graphics objects (textures, fonts, etc); memory usage of fonts, textures, etc.
|
||||
|
||||
// game component modules
|
||||
emitter - particle drawing helper
|
||||
sprite - sprite drawing helper
|
||||
transform - helper to turn programs into transforms
|
||||
layout - a gui layout helper
|
||||
imgui - add for imgui calls
|
||||
controller - higher level controller based on events
|
||||
|
||||
~~prosperon dev
|
||||
nota
|
||||
dmon
|
||||
enet
|
||||
|
||||
convert
|
||||
debug
|
||||
diff
|
||||
@@ -69,4 +96,5 @@ yaml
|
||||
spline
|
||||
profile
|
||||
sim
|
||||
dmon
|
||||
|
||||
noise // using stb perlin
|
||||
@@ -110,7 +110,7 @@ if get_option('enet')
|
||||
endif
|
||||
|
||||
sources = []
|
||||
src += ['anim.c', 'config.c', 'datastream.c','font.c','gameobject.c','HandmadeMath.c','jsffi.c','model.c','render.c','script.c','simplex.c','spline.c', 'timer.c', 'transform.c','yugine.c', 'wildmatch.c', 'sprite.c', 'quadtree.c', 'aabb.c', 'rtree.c']
|
||||
src += ['anim.c', 'config.c', 'datastream.c','font.c','gameobject.c','HandmadeMath.c','jsffi.c','model.c','render.c','script.c','simplex.c','spline.c', 'timer.c', 'transform.c','prosperon.c', 'wildmatch.c', 'sprite.c', 'quadtree.c', 'aabb.c', 'rtree.c']
|
||||
|
||||
imsrc = ['GraphEditor.cpp','ImCurveEdit.cpp','ImGradient.cpp','imgui_draw.cpp','imgui_tables.cpp','imgui_widgets.cpp','imgui.cpp','ImGuizmo.cpp','imnodes.cpp','implot_items.cpp','implot.cpp', 'imgui_impl_sdlrenderer3.cpp', 'imgui_impl_sdl3.cpp', 'imgui_impl_sdlgpu3.cpp']
|
||||
|
||||
|
||||
@@ -338,10 +338,8 @@ Cmdline.register_order(
|
||||
"Display Prosperon info.",
|
||||
);
|
||||
|
||||
function cmd_args(cmdargs) {
|
||||
function cmd_args(cmds) {
|
||||
var play = false;
|
||||
var cmds = cmdargs.split(/\s+/).slice(1);
|
||||
|
||||
if (cmds.length === 0) cmds[0] = "play";
|
||||
else if (!Cmdline.orders[cmds[0]]) {
|
||||
console.warn(`Command ${cmds[0]} not found. Playing instead.`);
|
||||
@@ -420,4 +418,4 @@ function convertYAMLtoJSON(yamlString) {
|
||||
return jsonObj;
|
||||
}
|
||||
|
||||
return {cmd_args}
|
||||
return cmd_args;
|
||||
@@ -1,6 +1,7 @@
|
||||
var render = use('render')
|
||||
var graphics = use('graphics')
|
||||
var math = use('math')
|
||||
var util = use('util')
|
||||
|
||||
var base_pipeline = {
|
||||
vertex: "sprite.vert",
|
||||
@@ -54,7 +55,6 @@ var base_pipeline = {
|
||||
target: {}
|
||||
}
|
||||
|
||||
|
||||
var sprite_pipeline = Object.create(base_pipeline);
|
||||
sprite_pipeline.blend = {
|
||||
enabled:true,
|
||||
@@ -88,7 +88,7 @@ draw.point = function (pos, size, color = Color.blue) {
|
||||
};
|
||||
|
||||
draw.line = function render_line(points, color = Color.white, thickness = 1, pipeline = rect_pipeline) {
|
||||
var mesh = os.make_line_prim(points,thickness, 0,0,color);
|
||||
var mesh = graphics.make_line_prim(points,thickness, 0,0,color);
|
||||
render.queue({
|
||||
type: 'geometry',
|
||||
mesh,
|
||||
@@ -157,7 +157,7 @@ draw.slice9 = function slice9(image, rect = [0,0], slice = 0, color = Color.whit
|
||||
if (typeof image === "string")
|
||||
image = graphics.texture(image);
|
||||
|
||||
var mesh = render._main.slice9(image.texture, rect, gizmo.normalizeSpacing(slice), info);
|
||||
var mesh = render._main.slice9(image.texture, rect, util.normalizeSpacing(slice), info);
|
||||
render.queue({
|
||||
type: 'geometry',
|
||||
mesh,
|
||||
@@ -188,7 +188,7 @@ draw.image = function image(image, rect = [0,0], rotation = 0, color, pipeline)
|
||||
if (color) cmd.color = color;
|
||||
render.queue(cmd)
|
||||
|
||||
var sprite = os.make_sprite();
|
||||
var sprite = graphics.make_sprite();
|
||||
sprite.set_image(image);
|
||||
sprite.set_rect(rect);
|
||||
return sprite;
|
||||
@@ -207,14 +207,14 @@ draw.images = function images(image, rects, config)
|
||||
for (var rect of rects) {
|
||||
// get sprite from sprite_buf, or make a new one
|
||||
rect.__proto__ = bb;
|
||||
var sprite = os.make_sprite();
|
||||
var sprite = graphics.make_sprite();
|
||||
sprite.set_rect(rect);
|
||||
sprite.set_image(image);
|
||||
sprites.push(sprite)
|
||||
}
|
||||
|
||||
// var sprites = os.rects_to_sprites(image,rects);
|
||||
var cmds = render._main.make_sprite_queue(sprites, prosperon.camera, sprite_pipeline)
|
||||
// var sprites = graphics.rects_to_sprites(image,rects);
|
||||
var cmds = graphics.make_sprite_queue(sprites, prosperon.camera, sprite_pipeline)
|
||||
for (var i = 0; i < cmds.length; i++)
|
||||
render.queue(cmds[i])
|
||||
|
||||
@@ -223,7 +223,7 @@ draw.images = function images(image, rects, config)
|
||||
|
||||
draw.sprites = function(sprites, sort = 0, pipeline = sprite_pipeline)
|
||||
{
|
||||
var cmds = render._main.make_sprite_queue(sprites, prosperon.camera, pipeline, sort);
|
||||
var cmds = graphics.make_sprite_queue(sprites, prosperon.camera, pipeline, sort);
|
||||
for (var i = 0; i < cmds.length; i++)
|
||||
render.queue(cmds[i]);
|
||||
}
|
||||
@@ -237,7 +237,7 @@ var sysfont = graphics.get_font('fonts/c64.ttf', 8);
|
||||
draw.text = function text(text, rect, font = sysfont, size = 0, color = Color.white, wrap = 0, pipeline = sprite_pipeline) {
|
||||
if (typeof font === 'string')
|
||||
font = graphics.get_font(font)
|
||||
var mesh = os.make_text_buffer(text, rect, 0, color, wrap, font);
|
||||
var mesh = graphics.make_text_buffer(text, rect, 0, color, wrap, font);
|
||||
|
||||
render.queue({
|
||||
type: 'geometry',
|
||||
@@ -250,4 +250,6 @@ draw.text = function text(text, rect, font = sysfont, size = 0, color = Color.wh
|
||||
});
|
||||
};
|
||||
|
||||
draw.sprite_pipeline = sprite_pipeline;
|
||||
|
||||
return draw
|
||||
|
||||
@@ -1,10 +1,42 @@
|
||||
globalThis.prosperon = {}
|
||||
var os = use_embed('os')
|
||||
// set up events on prosperon
|
||||
var listeners = new Map()
|
||||
prosperon.on = function(type, callback)
|
||||
{
|
||||
if (!listeners.has(type)) listeners.set(type, [])
|
||||
listeners.get(type).push(callback)
|
||||
|
||||
prosperon.SIGINT = function() {
|
||||
os.exit();
|
||||
return function() {
|
||||
var arr = listeners.get(type)
|
||||
if (!arr) return
|
||||
var idx = arr.indexOf(callback)
|
||||
if (idx >= 0) arr.splice(idx,1)
|
||||
}
|
||||
}
|
||||
|
||||
prosperon.dispatch = function(type, data)
|
||||
{
|
||||
var arr = listeners.get(type)
|
||||
if (!arr) return
|
||||
for (var callback of arr) callback(data)
|
||||
}
|
||||
|
||||
var os = use_embed('os')
|
||||
var js = use_embed('js')
|
||||
|
||||
prosperon.on('SIGINT', function() {
|
||||
os.exit();
|
||||
})
|
||||
|
||||
prosperon.on('SIGABRT', function() {
|
||||
console.error(new Error('SIGABRT'));
|
||||
os.exit(1);
|
||||
})
|
||||
|
||||
prosperon.on('SIGSEGV', function() {
|
||||
console.error(new Error('SIGSEGV'));
|
||||
os.exit(1);
|
||||
})
|
||||
|
||||
var use_cache = {}
|
||||
|
||||
Object.defineProperty(Function.prototype, "hashify", {
|
||||
@@ -28,11 +60,10 @@ io.mount("core")
|
||||
|
||||
var canonical = io.realdir('resources.js') + 'resources.js'
|
||||
var content = io.slurp('resources.js')
|
||||
var resources = os.eval('resources.js', `(function setup_resources(){${content}})`).call({})
|
||||
var resources = js.eval('resources.js', `(function setup_resources(){${content}})`).call({})
|
||||
console.print(resources.canonical('resources.js'))
|
||||
use_cache[resources.canonical('resources.js')] = resources
|
||||
|
||||
|
||||
function print_api(obj) {
|
||||
for (var prop in obj) {
|
||||
if (!obj.hasOwnProperty(prop)) continue
|
||||
@@ -65,7 +96,7 @@ var script_fn = function script_fn(path) {
|
||||
|
||||
if (parsed.module) {
|
||||
var mod_script = `(function setup_${module_name}_module(){ var self = this; var $ = this; var exports = {}; var module = {exports: exports}; var define = undefined; ${parsed.module}})`;
|
||||
var module_fn = os.eval(file, mod_script);
|
||||
var module_fn = js.eval(file, mod_script);
|
||||
parsed.module_ret = module_fn.call(parsed.module_ret);
|
||||
if (parsed.module_ret === undefined || parsed.module_ret === null)
|
||||
throw new Error(`Module ${module_name} must return a value`);
|
||||
@@ -76,7 +107,7 @@ var script_fn = function script_fn(path) {
|
||||
|
||||
if (parsed.program) {
|
||||
var prog_script = `(function use_${module_name}() { var self = this; var $ = this.__proto__; ${parsed.program}})`;
|
||||
parsed.prog_fn = os.eval(file, prog_script);
|
||||
parsed.prog_fn = js.eval(file, prog_script);
|
||||
}
|
||||
|
||||
return parsed;
|
||||
@@ -183,19 +214,7 @@ console.doc = {
|
||||
var script = io.slurp("core/scripts/base.js")
|
||||
var fnname = "base"
|
||||
script = `(function ${fnname}() { ${script}; })`
|
||||
os.eval('core/scripts/base.js', script)()
|
||||
|
||||
prosperon.SIGABRT = function()
|
||||
{
|
||||
console.error(new Error('SIGABRT'));
|
||||
os.exit(1);
|
||||
}
|
||||
|
||||
prosperon.SIGSEGV = function()
|
||||
{
|
||||
console.error(new Error('SIGSEGV'));
|
||||
os.exit(1);
|
||||
}
|
||||
js.eval('core/scripts/base.js', script)()
|
||||
|
||||
function add_timer(obj, fn, seconds)
|
||||
{
|
||||
@@ -240,7 +259,7 @@ var OVERLING = Symbol()
|
||||
var actor = {};
|
||||
|
||||
var so_ext;
|
||||
switch(os.sys()) {
|
||||
switch(os.platform()) {
|
||||
case 'Windows':
|
||||
so_ext = '.dll';
|
||||
break;
|
||||
@@ -471,7 +490,7 @@ try{
|
||||
|
||||
this[UNDERLINGS].add(underling);
|
||||
if (underling.tag)
|
||||
search.tag_add(underling.tag, underling)
|
||||
act.tag_add(underling.tag, underling)
|
||||
|
||||
underling[GARBAGE] = underling.garbage
|
||||
return underling;
|
||||
@@ -501,7 +520,7 @@ actor.kill = function kill() {
|
||||
if (typeof this.garbage === "function") this.garbage();
|
||||
if (typeof this.then === "function") this.then();
|
||||
|
||||
search.tag_clear_guid(this)
|
||||
act.tag_clear_guid(this)
|
||||
};
|
||||
|
||||
actor.kill.doc = `Remove this actor and all its underlings from existence.`;
|
||||
@@ -509,9 +528,11 @@ actor.kill.doc = `Remove this actor and all its underlings from existence.`;
|
||||
actor.delay = function (fn, seconds) { add_timer(this, fn, seconds) }
|
||||
actor.delay.doc = `Call 'fn' after 'seconds' with 'this' set to the actor.`;
|
||||
|
||||
var search = use('search')
|
||||
var act = use('actor')
|
||||
|
||||
actor[UNDERLINGS] = new Set()
|
||||
|
||||
globalThis.mixin("color");
|
||||
globalThis.mixin("std")
|
||||
|
||||
use('cmd')(prosperon.argv)
|
||||
|
||||
|
||||
5
scripts/event.js
Normal file
5
scripts/event.js
Normal file
@@ -0,0 +1,5 @@
|
||||
var event = this
|
||||
|
||||
|
||||
|
||||
return event
|
||||
@@ -1,5 +1,4 @@
|
||||
var graphics = {}
|
||||
var os = use('os')
|
||||
var graphics = this
|
||||
var io = use('io')
|
||||
var res = use('resources')
|
||||
|
||||
@@ -15,7 +14,7 @@ function create_image(path)
|
||||
var newimg;
|
||||
switch(path.ext()) {
|
||||
case 'gif':
|
||||
newimg = os.make_gif(data);
|
||||
newimg = graphics.make_gif(data);
|
||||
if (newimg.surface)
|
||||
newimg.texture = prosperon.gpu.load_texture(newimg.surface);
|
||||
else
|
||||
@@ -24,7 +23,7 @@ function create_image(path)
|
||||
break;
|
||||
case 'ase':
|
||||
case 'aseprite':
|
||||
newimg = os.make_aseprite(data);
|
||||
newimg = graphics.make_aseprite(data);
|
||||
if (newimg.surface)
|
||||
newimg.texture = prosperon.gpu.load_texture(newimg.surface);
|
||||
else {
|
||||
@@ -37,7 +36,7 @@ function create_image(path)
|
||||
break;
|
||||
default:
|
||||
newimg = {
|
||||
surface: os.make_texture(data)
|
||||
surface: graphics.make_texture(data)
|
||||
};
|
||||
newimg.texture = prosperon.gpu.load_texture(newimg.surface);
|
||||
break;
|
||||
@@ -62,14 +61,14 @@ function pack_into_sheet(images)
|
||||
if (images[0].texture.width > 300 && images[0].texture.height > 300) return;
|
||||
sheet_frames = sheet_frames.concat(images);
|
||||
var sizes = sheet_frames.map(x => [x.rect.width*x.texture.width, x.rect.height*x.texture.height]);
|
||||
var pos = os.rectpack(sheetsize, sheetsize, sizes);
|
||||
var pos = graphics.rectpack(sheetsize, sheetsize, sizes);
|
||||
if (!pos) {
|
||||
console.error(`did not make spritesheet properly from images ${images}`);
|
||||
console.info(sizes);
|
||||
return;
|
||||
}
|
||||
|
||||
var newsheet = os.make_tex_data(sheetsize,sheetsize);
|
||||
var newsheet = graphics.make_tex_data(sheetsize,sheetsize);
|
||||
|
||||
for (var i = 0; i < pos.length; i++) {
|
||||
// Copy the texture to the new sheet
|
||||
@@ -147,10 +146,10 @@ function make_spritesheet(paths, width, height)
|
||||
return
|
||||
var textures = paths.map(path => graphics.texture(path));
|
||||
var sizes = textures.map(tex => [tex.width, tex.height]);
|
||||
var pos = os.rectpack(width, height, sizes);
|
||||
var pos = graphics.rectpack(width, height, sizes);
|
||||
if (!pos) return;
|
||||
|
||||
var sheet = os.make_tex_data(width,height);
|
||||
var sheet = graphics.make_tex_data(width,height);
|
||||
|
||||
var st = profile.now();
|
||||
for (var i = 0; i < pos.length; i++)
|
||||
@@ -177,52 +176,23 @@ graphics.get_font = function get_font(path,size)
|
||||
if (fontcache[fontstr]) return fontcache[fontstr];
|
||||
|
||||
var data = io.slurpbytes(fullpath);
|
||||
fontcache[fontstr] = os.make_font(data,size);
|
||||
fontcache[fontstr] = graphics.make_font(data,size);
|
||||
fontcache[fontstr].texture = prosperon.gpu.load_texture(fontcache[fontstr].surface);
|
||||
return fontcache[fontstr];
|
||||
}
|
||||
|
||||
graphics.semver = {};
|
||||
graphics.semver.valid = function (v, range) {
|
||||
v = v.split(".");
|
||||
range = range.split(".");
|
||||
if (v.length !== 3) return undefined;
|
||||
if (range.length !== 3) return undefined;
|
||||
|
||||
if (range[0][0] === "^") {
|
||||
range[0] = range[0].slice(1);
|
||||
if (parseInt(v[0]) >= parseInt(range[0])) return true;
|
||||
|
||||
return false;
|
||||
graphics.queue_sprite_mesh = function(queue)
|
||||
{
|
||||
var sprites = queue.filter(x => x.type === 'sprite');
|
||||
if (sprites.length === 0) return [];
|
||||
var mesh = graphics.make_sprite_mesh(sprites);
|
||||
for (var i = 0; i < sprites.length; i++) {
|
||||
sprites[i].mesh = mesh;
|
||||
sprites[i].first_index = i*6;
|
||||
sprites[i].num_indices = 6;
|
||||
}
|
||||
|
||||
if (range[0] === "~") {
|
||||
range[0] = range[0].slice(1);
|
||||
for (var i = 0; i < 2; i++) if (parseInt(v[i]) < parseInt(range[i])) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return graphics.semver.cmp(v.join("."), range.join(".")) === 0;
|
||||
};
|
||||
|
||||
graphics.semver.cmp = function (v1, v2) {
|
||||
var ver1 = v1.split(".");
|
||||
var ver2 = v2.split(".");
|
||||
|
||||
for (var i = 0; i < 3; i++) {
|
||||
var n1 = parseInt(ver1[i]);
|
||||
var n2 = parseInt(ver2[i]);
|
||||
if (n1 > n2) return 1;
|
||||
else if (n1 < n2) return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
graphics.semver.cmp.doc = "Compare two semantic version numbers, given like X.X.X.";
|
||||
graphics.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 ^.
|
||||
~ 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.`;
|
||||
return [mesh.pos,mesh.uv,mesh.color,mesh.indices]
|
||||
}
|
||||
|
||||
return graphics
|
||||
|
||||
102
scripts/modules/camera.js
Normal file
102
scripts/modules/camera.js
Normal file
@@ -0,0 +1,102 @@
|
||||
var cam = {}
|
||||
|
||||
var os = use('os')
|
||||
|
||||
var basecam = {}
|
||||
basecam.draw_rect = function(size)
|
||||
{
|
||||
var mode = this.presentation || "letterbox"
|
||||
var vp = {
|
||||
x:this.viewport.x,
|
||||
y:1-this.viewport.y-this.viewport.height,
|
||||
width:this.viewport.width,
|
||||
height:this.viewport.height
|
||||
}
|
||||
var src_rect = {x:0,y:0,width:this.size.x,height:this.size.y}
|
||||
var dst_rect = {x:vp.x*size.x,y:vp.y*size.y,width:vp.width*size.x,height:vp.height*size.y};
|
||||
return mode_rect(src_rect,dst_rect,mode);
|
||||
}
|
||||
|
||||
basecam.screen2camera = function(pos)
|
||||
{
|
||||
var draw_rect = this.draw_rect(prosperon.window.size);
|
||||
var ret = [pos.x-draw_rect.x, pos.y - draw_rect.y];
|
||||
ret.x /= draw_rect.width;
|
||||
ret.y /= draw_rect.height;
|
||||
ret.y = 1 - ret.y;
|
||||
return ret;
|
||||
}
|
||||
|
||||
basecam.screen2hud = function(pos)
|
||||
{
|
||||
var cam = this.screen2camera(pos);
|
||||
cam.x *= this.size.x;
|
||||
cam.y *= this.size.y;
|
||||
return cam;
|
||||
}
|
||||
|
||||
basecam.screen2world = function(pos)
|
||||
{
|
||||
var hud = this.screen2hud(pos);
|
||||
hud.x += this.transform.pos.x - this.size.x/2;
|
||||
hud.y += this.transform.pos.y - this.size.y/2;
|
||||
return hud;
|
||||
}
|
||||
|
||||
function mode_rect(src,dst,mode = "stretch")
|
||||
{
|
||||
var aspect_src = src.width/src.height;
|
||||
var aspect_dst = dst.width/dst.height;
|
||||
var out = {
|
||||
x:dst.x,
|
||||
y:dst.y,
|
||||
width:dst.width,
|
||||
height:dst.height
|
||||
};
|
||||
if (mode == "stretch") return out;
|
||||
|
||||
if (mode == "letterbox") {
|
||||
if (aspect_src > aspect_dst) {
|
||||
var scaled_h = out.width/aspect_src;
|
||||
var off = (out.height - scaled_h) * 0.5;
|
||||
out.y += off;
|
||||
out.height = scaled_h;
|
||||
} else {
|
||||
var scaled_w =out.height * aspect_src;
|
||||
var off = (out.width - scaled_w) * 0.5;
|
||||
out.x += off;
|
||||
out.width = scaled_w;
|
||||
}
|
||||
} else if (mode == "overscan"){
|
||||
if (aspect_src > aspect_dst) {
|
||||
var scaled_w = out.height * aspect_src;
|
||||
var off = (out.width - scaled_w) * 0.5;
|
||||
out.x += off;
|
||||
out.width = scaled_w;
|
||||
} else {
|
||||
var scaled_h = out.width / aspect_src;
|
||||
var off = (out.height - scaled_h) * 0.5;
|
||||
out.y += off;
|
||||
out.height = scaled_h;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// If camera viewport is defined, will draw to the screen
|
||||
// If target is defined, will render to a target, too
|
||||
cam.make = function()
|
||||
{
|
||||
var c = Object.create(basecam)
|
||||
c.transform = os.make_transform()
|
||||
c.zoom = 1
|
||||
c.size = [640,360]
|
||||
c.mode = 'keep'
|
||||
c.viewport = {x:0,y:0,width:1,height:1}
|
||||
c.fov = 45
|
||||
c.type = 'ortho'
|
||||
c.aspect = 16/9
|
||||
return c
|
||||
}
|
||||
|
||||
return cam
|
||||
@@ -1,5 +1,4 @@
|
||||
var input = this
|
||||
|
||||
var input = use('input')
|
||||
var util = use('util')
|
||||
|
||||
var downkeys = {};
|
||||
@@ -18,54 +17,52 @@ function modstr(mod = input.keymod()) {
|
||||
return s;
|
||||
}
|
||||
|
||||
prosperon.key_down = function key_down(e) {
|
||||
prosperon.on('key_down', function key_down(e) {
|
||||
downkeys[e.key] = true;
|
||||
var emacs = modstr(e.mod) + keyname(e.key);
|
||||
if (e.repeat) player[0].raw_input(emacs, "rep");
|
||||
else player[0].raw_input(emacs, "pressed");
|
||||
};
|
||||
})
|
||||
|
||||
prosperon.quit = function()
|
||||
{
|
||||
prosperon.on('quit', function() {
|
||||
os.exit(0);
|
||||
}
|
||||
})
|
||||
|
||||
prosperon.key_up = function key_up(e) {
|
||||
prosperon.on('key_up', function key_up(e) {
|
||||
delete downkeys[e.key];
|
||||
var emacs = modstr(e.mod) + keyname(e.key);
|
||||
player[0].raw_input(emacs, "released");
|
||||
};
|
||||
})
|
||||
|
||||
prosperon.drop_file = function (path) {
|
||||
prosperon.on('drop_file', function (path) {
|
||||
player[0].raw_input("drop", "pressed", path);
|
||||
};
|
||||
})
|
||||
|
||||
var mousepos = [0, 0];
|
||||
|
||||
prosperon.text_input = function (e) {
|
||||
prosperon.on('text_input', function (e) {
|
||||
player[0].raw_input("char", "pressed", e.text);
|
||||
};
|
||||
})
|
||||
|
||||
prosperon.mouse_motion = function (e)
|
||||
prosperon.on('mouse_motion', function (e)
|
||||
{
|
||||
mousepos = e.pos;
|
||||
player[0].mouse_input("move", e.pos, e.d_pos);
|
||||
};
|
||||
prosperon.mouse_wheel = function mousescroll(e) {
|
||||
player[0].mouse_input(modstr() + "scroll", e.scroll);
|
||||
};
|
||||
})
|
||||
|
||||
prosperon.mouse_button_down = function(e)
|
||||
{
|
||||
prosperon.on('mouse_wheel', function mousescroll(e) {
|
||||
player[0].mouse_input(modstr() + "scroll", e.scroll);
|
||||
})
|
||||
|
||||
prosperon.on('mouse_button_down', function(e) {
|
||||
player[0].mouse_input(modstr() + e.button, "pressed");
|
||||
input.mouse.buttons[e.button] = true
|
||||
}
|
||||
})
|
||||
|
||||
prosperon.mouse_button_up = function(e)
|
||||
{
|
||||
prosperon.on('mouse_button_up', function(e) {
|
||||
player[0].mouse_input(modstr() + e.button, "released");
|
||||
input.mouse.buttons[e.button] = false
|
||||
}
|
||||
})
|
||||
|
||||
input.mouse = {};
|
||||
input.mouse.screenpos = function mouse_screenpos() {
|
||||
@@ -1,5 +1,7 @@
|
||||
var Color = use('color')
|
||||
var os = use('os')
|
||||
var graphics = use('graphics')
|
||||
//var render = use('render')
|
||||
|
||||
var ex = {}
|
||||
|
||||
@@ -104,6 +106,24 @@ ex.spawn_timer = 0
|
||||
ex.pps = 0
|
||||
ex.color = Color.white
|
||||
|
||||
ex.draw = function()
|
||||
{
|
||||
/* var diff = graphics.texture(this.diffuse)
|
||||
if (!diff) throw new Error("emitter does not have a proper diffuse texture")
|
||||
|
||||
var mesh = render._main.make_sprite_mesh(this.particles)
|
||||
if (mesh.num_indices === 0) return
|
||||
render.queue({
|
||||
type:'geometry',
|
||||
mesh,
|
||||
image:diff,
|
||||
pipeline,
|
||||
first_index:0,
|
||||
num_indices:mesh.num_indices
|
||||
})
|
||||
*/
|
||||
}
|
||||
|
||||
return ex
|
||||
|
||||
---
|
||||
@@ -113,5 +133,4 @@ this.dead = []
|
||||
|
||||
this.transform = this.overling.transform
|
||||
|
||||
|
||||
$.emitters.add(this)
|
||||
|
||||
@@ -1,5 +1,69 @@
|
||||
var graphics = use('graphics')
|
||||
|
||||
var base_pipeline = {
|
||||
vertex: "sprite.vert",
|
||||
fragment: "sprite.frag",
|
||||
primitive: "triangle", // point, line, linestrip, triangle, trianglestrip
|
||||
fill: true, // false for lines
|
||||
depth: {
|
||||
compare: "greater_equal", // never/less/equal/less_equal/greater/not_equal/greater_equal/always
|
||||
test: false,
|
||||
write: false,
|
||||
bias: 0,
|
||||
bias_slope_scale: 0,
|
||||
bias_clamp: 0
|
||||
},
|
||||
stencil: {
|
||||
enabled: true,
|
||||
front: {
|
||||
compare: "equal", // never/less/equal/less_equal/greater/neq/greq/always
|
||||
fail: "keep", // keep/zero/replace/incr_clamp/decr_clamp/invert/incr_wrap/decr_wrap
|
||||
depth_fail: "keep",
|
||||
pass: "keep"
|
||||
},
|
||||
back: {
|
||||
compare: "equal", // never/less/equal/less_equal/greater/neq/greq/always
|
||||
fail: "keep", // keep/zero/replace/incr_clamp/decr_clamp/invert/incr_wrap/decr_wrap
|
||||
depth_fail: "keep",
|
||||
pass: "keep"
|
||||
},
|
||||
test: true,
|
||||
compare_mask: 0,
|
||||
write_mask: 0
|
||||
},
|
||||
blend: {
|
||||
enabled: false,
|
||||
src_rgb: "zero", // zero/one/src_color/one_minus_src_color/dst_color/one_minus_dst_color/src_alpha/one_minus_src_alpha/dst_alpha/one_minus_dst_alpha/constant_color/one_minus_constant_color/src_alpha_saturate
|
||||
dst_rgb: "zero",
|
||||
op_rgb: "add", // add/sub/rev_sub/min/max
|
||||
src_alpha: "one",
|
||||
dst_alpha: "zero",
|
||||
op_alpha: "add"
|
||||
},
|
||||
cull: "none", // none/front/back
|
||||
face: "cw", // cw/ccw
|
||||
alpha_to_coverage: false,
|
||||
multisample: {
|
||||
count: 1, // number of multisamples
|
||||
mask: 0xFFFFFFFF,
|
||||
domask: false
|
||||
},
|
||||
label: "scripted pipeline",
|
||||
target: {}
|
||||
}
|
||||
|
||||
var sprite_pipeline = Object.create(base_pipeline);
|
||||
sprite_pipeline.blend = {
|
||||
enabled:true,
|
||||
src_rgb: "src_alpha", // zero/one/src_color/one_minus_src_color/dst_color/one_minus_dst_color/src_alpha/one_minus_src_alpha/dst_alpha/one_minus_dst_alpha/constant_color/one_minus_constant_color/src_alpha_saturate
|
||||
dst_rgb: "one_minus_src_alpha",
|
||||
op_rgb: "add", // add/sub/rev_sub/min/max
|
||||
src_alpha: "one",
|
||||
dst_alpha: "zero",
|
||||
op_alpha: "add"
|
||||
};
|
||||
|
||||
|
||||
var sprite = {
|
||||
image: undefined,
|
||||
set color(x) { this._sprite.color = x; },
|
||||
@@ -184,7 +248,7 @@ sprite.inputs.kp1 = function () {
|
||||
this.setanchor("ul");
|
||||
};
|
||||
|
||||
var tree = os.make_rtree()
|
||||
var tree = graphics.make_rtree()
|
||||
sprite.tree = tree;
|
||||
|
||||
sprite.t_hook = function() {
|
||||
@@ -199,19 +263,36 @@ sprite.t_hook = function() {
|
||||
|
||||
Object.mixin(sprite,use("transform"))
|
||||
|
||||
sprite.to_queue = function(ysort = false)
|
||||
{
|
||||
var pos = prosperon.camera.transform.pos;
|
||||
var size = prosperon.camera.size;
|
||||
var camrect = {
|
||||
x:pos.x-size.x/2,
|
||||
y:pos.y-size.y/2,
|
||||
width:size.x,
|
||||
height:size.y
|
||||
};
|
||||
var culled = sprite.tree.query(camrect)
|
||||
if (culled.length == 0) return [];
|
||||
var cmd = graphics.make_sprite_queue(culled, prosperon.camera, sprite_pipeline, 1);
|
||||
return cmd;
|
||||
}
|
||||
|
||||
return sprite;
|
||||
|
||||
---
|
||||
|
||||
var Color = use('color')
|
||||
var os = use('os')
|
||||
var graphics = use('graphics')
|
||||
|
||||
this.transform = os.make_transform();
|
||||
if (this.overling.transform)
|
||||
this.transform.parent = this.overling.transform;
|
||||
|
||||
this.transform.change_hook = $.t_hook;
|
||||
var msp = os.make_sprite();
|
||||
var msp = graphics.make_sprite();
|
||||
this._sprite = msp;
|
||||
msp.color = Color.white;
|
||||
this.transform.sprite = this
|
||||
|
||||
@@ -5,23 +5,26 @@ var io = use('io')
|
||||
var os = use('os')
|
||||
var util = use('util')
|
||||
var emitter = use('emitter')
|
||||
var input = use('input')
|
||||
var controller = use('controller')
|
||||
var event = use('event')
|
||||
|
||||
var sprite = use('sprite')
|
||||
var graphics = use('graphics')
|
||||
|
||||
var appy = {};
|
||||
appy.inputs = {};
|
||||
if (os.sys() === "macos") {
|
||||
if (os.platform() === "macos") {
|
||||
appy.inputs["S-q"] = os.exit;
|
||||
}
|
||||
|
||||
appy.inputs["M-f4"] = os.exit;
|
||||
|
||||
input.player[0].control(appy);
|
||||
controller.player[0].control(appy);
|
||||
|
||||
prosperon.window = os.engine_start(config);
|
||||
prosperon.window = prosperon.engine_start(config);
|
||||
|
||||
var driver = "vulkan"
|
||||
switch(os.sys()) {
|
||||
switch(os.platform()) {
|
||||
case "Linux":
|
||||
driver = "vulkan"
|
||||
break
|
||||
@@ -40,8 +43,6 @@ render._main.window = prosperon.window
|
||||
render._main.claim_window(prosperon.window)
|
||||
render._main.set_swapchain('sdr', 'vsync')
|
||||
|
||||
var graphics = use('graphics')
|
||||
|
||||
var unit_transform = os.make_transform();
|
||||
|
||||
var cur = {};
|
||||
@@ -56,19 +57,6 @@ function full_upload(buffers)
|
||||
cmds.submit();
|
||||
}
|
||||
|
||||
function queue_sprite_mesh(queue)
|
||||
{
|
||||
var sprites = queue.filter(x => x.type === 'sprite');
|
||||
if (sprites.length === 0) return [];
|
||||
var mesh = render._main.make_sprite_mesh(sprites);
|
||||
for (var i = 0; i < sprites.length; i++) {
|
||||
sprites[i].mesh = mesh;
|
||||
sprites[i].first_index = i*6;
|
||||
sprites[i].num_indices = 6;
|
||||
}
|
||||
|
||||
return [mesh.pos,mesh.uv,mesh.color,mesh.indices]
|
||||
}
|
||||
function bind_pipeline(pass, pipeline)
|
||||
{
|
||||
make_pipeline(pipeline)
|
||||
@@ -431,12 +419,12 @@ var pass;
|
||||
}
|
||||
|
||||
var buffers = [];
|
||||
buffers = buffers.concat(queue_sprite_mesh(render_queue));
|
||||
buffers = buffers.concat(graphics.queue_sprite_mesh(render_queue));
|
||||
var unique_meshes = [...new Set(render_queue.map(x => x.mesh))];
|
||||
for (var q of unique_meshes)
|
||||
buffers = buffers.concat([q.pos, q.color,q.uv,q.indices]);
|
||||
|
||||
buffers = buffers.concat(queue_sprite_mesh(hud_queue));
|
||||
buffers = buffers.concat(graphics.queue_sprite_mesh(hud_queue));
|
||||
for (var q of hud_queue)
|
||||
if (q.type === 'geometry') buffers = buffers.concat([q.mesh.pos, q.mesh.color,q.mesh.uv,q.mesh.indices]);
|
||||
|
||||
@@ -521,102 +509,8 @@ var pass;
|
||||
hud_queue = [];
|
||||
}
|
||||
|
||||
function mode_rect(src,dst,mode = "stretch")
|
||||
{
|
||||
var aspect_src = src.width/src.height;
|
||||
var aspect_dst = dst.width/dst.height;
|
||||
var out = {
|
||||
x:dst.x,
|
||||
y:dst.y,
|
||||
width:dst.width,
|
||||
height:dst.height
|
||||
};
|
||||
if (mode == "stretch") return out;
|
||||
|
||||
if (mode == "letterbox") {
|
||||
if (aspect_src > aspect_dst) {
|
||||
var scaled_h = out.width/aspect_src;
|
||||
var off = (out.height - scaled_h) * 0.5;
|
||||
out.y += off;
|
||||
out.height = scaled_h;
|
||||
} else {
|
||||
var scaled_w =out.height * aspect_src;
|
||||
var off = (out.width - scaled_w) * 0.5;
|
||||
out.x += off;
|
||||
out.width = scaled_w;
|
||||
}
|
||||
} else if (mode == "overscan"){
|
||||
if (aspect_src > aspect_dst) {
|
||||
var scaled_w = out.height * aspect_src;
|
||||
var off = (out.width - scaled_w) * 0.5;
|
||||
out.x += off;
|
||||
out.width = scaled_w;
|
||||
} else {
|
||||
var scaled_h = out.width / aspect_src;
|
||||
var off = (out.height - scaled_h) * 0.5;
|
||||
out.y += off;
|
||||
out.height = scaled_h;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
prosperon.camera = {};
|
||||
// If camera viewport is defined, will draw to the screen
|
||||
// If target is defined, will render to a target, too
|
||||
|
||||
prosperon.camera.transform = os.make_transform();
|
||||
prosperon.camera.transform.unit();
|
||||
prosperon.camera.zoom = 1;
|
||||
prosperon.camera.size = [640,360];
|
||||
prosperon.camera.mode = 'keep';
|
||||
prosperon.camera.viewport = {x:0,y:0,width:1,height:1}
|
||||
prosperon.camera.fov = 45;
|
||||
prosperon.camera.type = 'ortho';
|
||||
prosperon.camera.ortho = true
|
||||
prosperon.camera.aspect = 16/9;
|
||||
delete prosperon.camera.target;
|
||||
|
||||
prosperon.camera.draw_rect = function(size)
|
||||
{
|
||||
var mode = this.presentation || "letterbox"
|
||||
var vp = {
|
||||
x:this.viewport.x,
|
||||
y:1-this.viewport.y-this.viewport.height,
|
||||
width:this.viewport.width,
|
||||
height:this.viewport.height
|
||||
}
|
||||
var src_rect = {x:0,y:0,width:this.size.x,height:this.size.y}
|
||||
var dst_rect = {x:vp.x*size.x,y:vp.y*size.y,width:vp.width*size.x,height:vp.height*size.y};
|
||||
return mode_rect(src_rect,dst_rect,mode);
|
||||
}
|
||||
|
||||
// Camera coordinates are [0,0]
|
||||
prosperon.camera.screen2camera = function(pos)
|
||||
{
|
||||
var draw_rect = this.draw_rect(prosperon.window.size);
|
||||
var ret = [pos.x-draw_rect.x, pos.y - draw_rect.y];
|
||||
ret.x /= draw_rect.width;
|
||||
ret.y /= draw_rect.height;
|
||||
ret.y = 1 - ret.y;
|
||||
return ret;
|
||||
}
|
||||
|
||||
prosperon.camera.screen2hud = function(pos)
|
||||
{
|
||||
var cam = this.screen2camera(pos);
|
||||
cam.x *= this.size.x;
|
||||
cam.y *= this.size.y;
|
||||
return cam;
|
||||
}
|
||||
|
||||
prosperon.camera.screen2world = function(pos)
|
||||
{
|
||||
var hud = this.screen2hud(pos);
|
||||
hud.x += this.transform.pos.x - this.size.x/2;
|
||||
hud.y += this.transform.pos.y - this.size.y/2;
|
||||
return hud;
|
||||
}
|
||||
prosperon.camera = use('camera').make()
|
||||
|
||||
var swaps = [];
|
||||
function gpupresent()
|
||||
@@ -624,7 +518,7 @@ function gpupresent()
|
||||
os.clean_transforms();
|
||||
prosperon.prerender();
|
||||
var cmds = render._main.acquire_cmd_buffer();
|
||||
render_queue = sprites_to_queue().concat(render_queue);
|
||||
render_queue = sprite.to_queue().concat(render_queue);
|
||||
render_camera(cmds, prosperon.camera);
|
||||
var swapchain_tex = cmds.acquire_swapchain();
|
||||
if (!swapchain_tex)
|
||||
@@ -660,39 +554,6 @@ render.toggles = {
|
||||
draw_gui:true
|
||||
}
|
||||
|
||||
function sprites_to_queue(ysort = false)
|
||||
{
|
||||
var pos = prosperon.camera.transform.pos;
|
||||
var size = prosperon.camera.size;
|
||||
var camrect = {
|
||||
x:pos.x-size.x/2,
|
||||
y:pos.y-size.y/2,
|
||||
width:size.x,
|
||||
height:size.y
|
||||
};
|
||||
var culled = sprite.tree.query(camrect)
|
||||
if (culled.length == 0) return [];
|
||||
var cmd = render._main.make_sprite_queue(culled, prosperon.camera, sprite_pipeline, 1);
|
||||
return cmd;
|
||||
}
|
||||
|
||||
render.particles = function render_particles(emitter, pipeline = sprite_pipeline)
|
||||
{
|
||||
var diff = graphics.texture(emitter.diffuse)
|
||||
if (!diff) throw new Error("emitter does not have a proper diffuse");
|
||||
|
||||
var mesh = render._main.make_sprite_mesh(emitter.particles);
|
||||
if (mesh.num_indices === 0) return;
|
||||
current_queue.push({
|
||||
type:'geometry',
|
||||
mesh,
|
||||
image:diff,
|
||||
pipeline,
|
||||
first_index:0,
|
||||
num_indices:mesh.num_indices
|
||||
});
|
||||
}
|
||||
|
||||
var stencil_write = {
|
||||
compare: "always",
|
||||
fail_op: "replace",
|
||||
@@ -766,65 +627,7 @@ render.scissor = function(rect)
|
||||
{
|
||||
render.viewport(rect)
|
||||
}
|
||||
|
||||
function camscreen2world(pos) {
|
||||
var view = this.screen2cam(pos);
|
||||
var viewport = render._main.get_viewport();
|
||||
view.x *= viewport.width;
|
||||
view.y *= viewport.height;
|
||||
view = view.add(this.pos.xy);
|
||||
view = view.sub([viewport.width,viewport.height].scale(0.5))
|
||||
// view = view.scale(this.transform.scale);
|
||||
return view;
|
||||
}
|
||||
|
||||
// world coordinates, the "actual" view relative to the game's universe
|
||||
// camera coordinates, normalized from 0 to 1 inside of a camera's viewport, bottom left is 0,0, top right is 1,1
|
||||
// screen coordinates, pixels, 0,0 at the top left of the window and [w,h] at the bottom right of the window
|
||||
// hud coordinates, same as screen coordinates but the top left is 0,0
|
||||
|
||||
camscreen2world.doc = "Convert a view position for a camera to world.";
|
||||
|
||||
// return camera coordinates given a screen position
|
||||
function screen2cam(pos) {
|
||||
var tpos = render._main.coords(pos);
|
||||
var viewport = render._main.get_viewport();
|
||||
var viewpos = tpos.div([viewport.width,viewport.height]);
|
||||
viewpos.y *= -1;
|
||||
viewpos.y += 1;
|
||||
return viewpos;
|
||||
}
|
||||
|
||||
screen2cam.doc = "Convert a screen space position in pixels to a normalized viewport position in a camera.";
|
||||
|
||||
function screen2hud(pos)
|
||||
{
|
||||
var campos = this.screen2cam(pos);
|
||||
var viewport = render._main.get_viewport();
|
||||
campos = campos.scale([viewport.width,viewport.height]);
|
||||
return campos;
|
||||
}
|
||||
|
||||
/* cameras
|
||||
* Cameras have a position and rotation. They are not affected by scale.
|
||||
*/
|
||||
|
||||
prosperon.make_camera = function (make_camera) {
|
||||
return;
|
||||
/* var cam = world.spawn();
|
||||
cam.near = 1;
|
||||
cam.far = -1000;
|
||||
cam.ortho = true; // True if this is a 2d camera
|
||||
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.zoom = 1; // the "scale factor" this camera demonstrates
|
||||
return cam;*/
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
var screencolor;
|
||||
|
||||
globalThis.imtoggle = function (name, obj, field) {
|
||||
@@ -941,8 +744,8 @@ render.process = function process() {
|
||||
var dt = last_frame_time - frame_t;
|
||||
frame_t = last_frame_time;
|
||||
|
||||
os.engine_input(e => {
|
||||
prosperon[e.type]?.(e);
|
||||
event.engine_input(e => {
|
||||
prosperon.dispatch(e.type, e);
|
||||
});
|
||||
|
||||
layout.newframe();
|
||||
@@ -956,7 +759,6 @@ render.process = function process() {
|
||||
|
||||
current_queue = render_queue;
|
||||
prosperon.draw()
|
||||
emitter.emitters.forEach(e => render.particles(e))
|
||||
current_queue = hud_queue;
|
||||
prosperon.hud()
|
||||
imgui_fn()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
var Resources = {}
|
||||
|
||||
var so_ext;
|
||||
switch(os.sys()) {
|
||||
switch(os.platform()) {
|
||||
case 'Windows':
|
||||
so_ext = '.dll';
|
||||
break;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
var util = {}
|
||||
var util = this
|
||||
|
||||
util.deepfreeze = function (obj) {
|
||||
for (var key in obj) {
|
||||
|
||||
813
source/jsffi.c
813
source/jsffi.c
@@ -9,7 +9,6 @@
|
||||
#include "stb_dxt.h"
|
||||
#include "string.h"
|
||||
#include "spline.h"
|
||||
#include "yugine.h"
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
@@ -29,13 +28,22 @@
|
||||
#include "cgltf.h"
|
||||
#include "physfs.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/utsname.h>
|
||||
#ifdef __linux__
|
||||
#include <sys/sysinfo.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "wildmatch.h"
|
||||
|
||||
#include "freelist.h"
|
||||
|
||||
#include "sprite.h"
|
||||
|
||||
#include "quadtree.h"
|
||||
#include "rtree.h"
|
||||
|
||||
typedef struct rtree rtree;
|
||||
@@ -45,6 +53,7 @@ typedef struct rtree rtree;
|
||||
#include <SDL3/SDL_error.h>
|
||||
#include <SDL3/SDL_properties.h>
|
||||
#include <SDL3/SDL_loadso.h>
|
||||
#include <SDL3/SDL_cpuinfo.h>
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
@@ -410,8 +419,6 @@ static BufferCheckResult get_or_extend_buffer(
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#include "stb_perlin.h"
|
||||
|
||||
#if (defined(_WIN32) || defined(__WIN32__))
|
||||
#include <direct.h>
|
||||
#define mkdir(x,y) _mkdir(x)
|
||||
@@ -1105,10 +1112,6 @@ char *js2strdup(JSContext *js, JSValue v) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
void skin_free(JSRuntime *rt,skin *sk) {
|
||||
arrfree(sk->invbind);
|
||||
free(sk);
|
||||
}
|
||||
|
||||
#include "qjs_macros.h"
|
||||
|
||||
@@ -1194,7 +1197,6 @@ static void js_timer_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_fun
|
||||
}
|
||||
QJSCLASSMARK(timer)
|
||||
|
||||
QJSCLASS(skin)
|
||||
QJSCLASS(SDL_Window)
|
||||
QJSCLASS(SDL_Renderer)
|
||||
QJSCLASS(SDL_Camera)
|
||||
@@ -1241,13 +1243,6 @@ static void PHYSFS_File_free(JSRuntime *rt, PHYSFS_File *f)
|
||||
|
||||
QJSCLASS(PHYSFS_File)
|
||||
|
||||
void qtree_free(JSRuntime *rt, qtree *tree)
|
||||
{
|
||||
qtree_destroy(*tree);
|
||||
}
|
||||
|
||||
QJSCLASS(qtree)
|
||||
|
||||
void rtree_free(JSRuntime *rt, rtree *tree)
|
||||
{
|
||||
rtree_destroy(tree);
|
||||
@@ -2869,20 +2864,6 @@ static JSValue event2js(JSContext *js, SDL_Event event)
|
||||
return e;
|
||||
}
|
||||
|
||||
void gui_input(SDL_Event *e);
|
||||
// Polls and handles all input events
|
||||
JSC_CCALL(os_engine_input,
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
#ifndef NEDITOR
|
||||
gui_input(&event);
|
||||
#endif
|
||||
JSValue e = event2js(js,event);
|
||||
JSValue ret = JS_Call(js,argv[0], JS_UNDEFINED, 1, &e);
|
||||
uncaught_exception(js,ret);
|
||||
}
|
||||
)
|
||||
|
||||
JSC_CCALL(camera_list,
|
||||
int num;
|
||||
SDL_CameraID *ids = SDL_GetCameras(&num);
|
||||
@@ -5061,8 +5042,6 @@ static const JSCFunctionListEntry js_SDL_GPUDevice_funcs[] = {
|
||||
MIST_FUNC_DEF(gpu, make_sampler,1),
|
||||
MIST_FUNC_DEF(gpu, load_texture, 2),
|
||||
MIST_FUNC_DEF(gpu, texture, 1),
|
||||
MIST_FUNC_DEF(gpu, make_sprite_mesh, 2),
|
||||
MIST_FUNC_DEF(gpu, make_sprite_queue, 4),
|
||||
MIST_FUNC_DEF(gpu, make_quad, 0),
|
||||
MIST_FUNC_DEF(gpu, driver, 0),
|
||||
MIST_FUNC_DEF(gpu, make_shader, 1),
|
||||
@@ -5704,18 +5683,6 @@ JSC_SCALL(os_openurl,
|
||||
ret = JS_ThrowReferenceError(js, "unable to open url %s: %s\n", str, SDL_GetError());
|
||||
)
|
||||
|
||||
JSC_CCALL(os_push_event,
|
||||
SDL_UserEvent e;
|
||||
SDL_zero(e);
|
||||
e.type = SDL_EVENT_USER;
|
||||
e.timestamp = SDL_GetTicksNS();
|
||||
e.code = 0;
|
||||
JSValue fn = JS_DupValue(js,argv[0]);
|
||||
e.data1 = malloc(sizeof(JSValue));
|
||||
*(JSValue*)e.data1 = fn;
|
||||
SDL_PushEvent(&e);
|
||||
)
|
||||
|
||||
JSC_CCALL(time_now,
|
||||
struct timeval ct;
|
||||
gettimeofday(&ct, NULL);
|
||||
@@ -6401,18 +6368,6 @@ static const JSCFunctionListEntry js_geometry_funcs[] = {
|
||||
MIST_FUNC_DEF(geometry, rect_move, 2),
|
||||
};
|
||||
|
||||
JSValue js_os_cwd(JSContext *js, JSValue self, int argc, JSValue *argv)
|
||||
{
|
||||
char cwd[PATH_MAX];
|
||||
#ifndef __EMSCRIPTEN__
|
||||
getcwd(cwd, sizeof(cwd));
|
||||
#else
|
||||
cwd[0] = '.';
|
||||
cwd[1] = 0;
|
||||
#endif
|
||||
return JS_NewString(js,cwd);
|
||||
}
|
||||
|
||||
JSC_SCALL(os_env,
|
||||
char *env = getenv(str);
|
||||
if (env) ret = JS_NewString(js,env);
|
||||
@@ -6556,7 +6511,7 @@ JSC_CCALL(os_dump_mem,
|
||||
)
|
||||
|
||||
JSC_CCALL(os_value_id,
|
||||
return number2js(js,(intptr_t)JS_VALUE_GET_PTR(argv[0]));
|
||||
return number2js(js,(intptr_t)JS_VALUE_GET_PTR(self));
|
||||
)
|
||||
|
||||
static double gc_t = 0;
|
||||
@@ -6750,271 +6705,6 @@ JSC_CCALL(os_make_sprite, return sprite2js(js,make_sprite()))
|
||||
|
||||
JSC_SCALL(os_system, ret = number2js(js,system(str)); )
|
||||
|
||||
JSC_SCALL(os_model_buffer,
|
||||
/*
|
||||
int mesh_idx = 0;
|
||||
|
||||
// Configure cgltf
|
||||
cgltf_options options;
|
||||
memset(&options, 0, sizeof(options));
|
||||
|
||||
// Parse the file
|
||||
cgltf_data* data = NULL;
|
||||
cgltf_result result = cgltf_parse_file(&options, str, &data);
|
||||
if (result != cgltf_result_success) {
|
||||
JS_ThrowInternalError(js, "Failed to load glTF model: parse error");
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
// Load any external buffers (bin files, images)
|
||||
result = cgltf_load_buffers(&options, data, str);
|
||||
if (result != cgltf_result_success) {
|
||||
cgltf_free(data);
|
||||
JS_ThrowInternalError(js, "Failed to load glTF model: buffer load error");
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
// We only check for mesh_idx vs. the count of cgltf_data->meshes
|
||||
// (though note that glTF organizes data in scenes, nodes, etc.,
|
||||
// so you might want to handle multiple nodes or node->mesh references)
|
||||
if (mesh_idx < 0 || mesh_idx >= (int)data->meshes_count) {
|
||||
cgltf_free(data);
|
||||
JS_ThrowInternalError(js, "Invalid mesh index");
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
JSValue materials[data->materials_count];
|
||||
for (int i = 0; i < (int)data->materials_count; i++) {
|
||||
JSValue mat = JS_NewObject(js);
|
||||
materials[i] = mat;
|
||||
cgltf_material *cgmat = &data->materials[i];
|
||||
|
||||
// Grab the base color texture if it exists
|
||||
cgltf_texture_view *bc_view = &cgmat->pbr_metallic_roughness.base_color_texture;
|
||||
if (bc_view->texture && bc_view->texture->image) {
|
||||
cgltf_image *img = bc_view->texture->image;
|
||||
// If the image is an external URI
|
||||
if (img->uri) {
|
||||
// For glTF 2.0, this often points to a .png/.jpg
|
||||
JS_SetPropertyStr(js, mat, "diffuse", JS_NewString(js, img->uri));
|
||||
}
|
||||
// If it's an embedded buffer view (e.g., "data:" or bufferView-based image)
|
||||
else if (img->buffer_view) {
|
||||
size_t size = img->buffer_view->size;
|
||||
uint8_t *ptr = (uint8_t*)img->buffer_view->buffer->data + img->buffer_view->offset;
|
||||
JS_SetPropertyStr(js, mat, "diffuse", JS_NewArrayBufferCopy(js, ptr, size));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create an array to hold all the "model" objects
|
||||
JSValue ret_arr = JS_NewArray(js);
|
||||
|
||||
for (int m = 0; m < (int)data->meshes_count; m++) {
|
||||
cgltf_mesh *cgmesh = &data->meshes[m];
|
||||
// Go through each primitive in this mesh
|
||||
for (int p = 0; p < (int)cgmesh->primitives_count; p++) {
|
||||
cgltf_primitive *prim = &cgmesh->primitives[p];
|
||||
if (!prim->attributes) {
|
||||
// No attributes => no geometry
|
||||
continue;
|
||||
}
|
||||
|
||||
// We'll collect attribute data in arrays, just like with Assimp
|
||||
float *posdata = NULL, *normdata = NULL, *uvdata = NULL, *colordata = NULL;
|
||||
Uint16 *indicesdata = NULL;
|
||||
size_t num_verts = 0;
|
||||
size_t index_count = 0;
|
||||
|
||||
// Helper function to find an accessor by "POSITION", "NORMAL", "TEXCOORD_0", etc.
|
||||
// We'll parse it below in parseAttributeFloat.
|
||||
cgltf_accessor* findAccessor(cgltf_primitive* prim, const char* semantic) {
|
||||
for (int a = 0; a < (int)prim->attributes_count; a++) {
|
||||
if (prim->attributes[a].name && strcmp(prim->attributes[a].name, semantic) == 0)
|
||||
return prim->attributes[a].data;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// parseAttributeFloat:
|
||||
// read floats from a cgltf_accessor into outBuffer
|
||||
// The 'stride' is how many floats we read per element (e.g. 3 for POSITION)
|
||||
// Returns the number of elements read
|
||||
size_t parseAttributeFloat(JSContext* js, cgltf_accessor* acc, float** outBuffer, int stride, float defaultVal) {
|
||||
if (!acc) {
|
||||
// If the attribute doesn't exist, fill default
|
||||
size_t count = 0;
|
||||
*outBuffer = NULL;
|
||||
return count;
|
||||
}
|
||||
size_t count = acc->count;
|
||||
size_t total_floats = count * stride;
|
||||
*outBuffer = malloc(total_floats * sizeof(float));
|
||||
if (!(*outBuffer)) return 0;
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
float tmp[4] = { defaultVal, defaultVal, defaultVal, defaultVal };
|
||||
cgltf_accessor_read_float(acc, i, tmp, 4);
|
||||
// copy only 'stride' components
|
||||
for (int c = 0; c < stride; c++)
|
||||
(*outBuffer)[i*stride + c] = tmp[c];
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// 1) POSITION
|
||||
cgltf_accessor *accPos = findAccessor(prim, "POSITION");
|
||||
num_verts = parseAttributeFloat(js, accPos, &posdata, 3, 0.0f);
|
||||
|
||||
// 2) NORMAL
|
||||
cgltf_accessor *accNorm = findAccessor(prim, "NORMAL");
|
||||
// If missing normals, default them to (0,0,1)
|
||||
parseAttributeFloat(js, accNorm, &normdata, 3, 0.0f);
|
||||
if (!normdata && num_verts > 0) {
|
||||
normdata = malloc(num_verts*3*sizeof(float));
|
||||
for (size_t i = 0; i < num_verts; i++) {
|
||||
normdata[i*3+0] = 0.0f;
|
||||
normdata[i*3+1] = 0.0f;
|
||||
normdata[i*3+2] = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// 3) TEXCOORD_0
|
||||
cgltf_accessor *accUV = findAccessor(prim, "TEXCOORD_0");
|
||||
parseAttributeFloat(js, accUV, &uvdata, 2, 0.0f);
|
||||
if (!uvdata && num_verts > 0) {
|
||||
uvdata = malloc(num_verts*2*sizeof(float));
|
||||
for (size_t i = 0; i < num_verts; i++) {
|
||||
uvdata[i*2+0] = 0.0f;
|
||||
uvdata[i*2+1] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// 4) COLOR_0
|
||||
cgltf_accessor *accColor = findAccessor(prim, "COLOR_0");
|
||||
parseAttributeFloat(js, accColor, &colordata, 4, 1.0f);
|
||||
if (!colordata && num_verts > 0) {
|
||||
colordata = malloc(num_verts*4*sizeof(float));
|
||||
for (size_t i = 0; i < num_verts; i++) {
|
||||
colordata[i*4+0] = 1.0f;
|
||||
colordata[i*4+1] = 1.0f;
|
||||
colordata[i*4+2] = 1.0f;
|
||||
colordata[i*4+3] = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// 5) Indices (if present)
|
||||
if (prim->indices) {
|
||||
cgltf_accessor *idxAcc = prim->indices;
|
||||
index_count = idxAcc->count;
|
||||
indicesdata = malloc(index_count*sizeof(Uint16));
|
||||
if (indicesdata) {
|
||||
for (size_t i = 0; i < index_count; i++) {
|
||||
// cgltf_accessor_read_index can read the index as uint32_t
|
||||
uint32_t val = 0;
|
||||
val = cgltf_accessor_read_index(idxAcc, i);
|
||||
// NOTE: if val > 65535, you'll need 32-bit index buffers
|
||||
indicesdata[i] = (Uint16)val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build a JS object for the mesh data
|
||||
JSValue js_mesh = JS_NewObject(js);
|
||||
|
||||
// Positions
|
||||
if (posdata && num_verts > 0)
|
||||
JS_SetProperty(js, js_mesh, pos_atom,
|
||||
make_gpu_buffer(js, posdata, sizeof(float)*3*num_verts, JS_TYPED_ARRAY_FLOAT32, 3, 1, 0));
|
||||
|
||||
// UV
|
||||
if (uvdata && num_verts > 0)
|
||||
JS_SetProperty(js, js_mesh, uv_atom,
|
||||
make_gpu_buffer(js, uvdata, sizeof(float)*2*num_verts, JS_TYPED_ARRAY_FLOAT32, 2, 1, 0));
|
||||
|
||||
// Color
|
||||
if (colordata && num_verts > 0)
|
||||
JS_SetProperty(js, js_mesh, color_atom,
|
||||
make_gpu_buffer(js, colordata, sizeof(float)*4*num_verts, JS_TYPED_ARRAY_FLOAT32, 4, 1, 0));
|
||||
|
||||
// Normal
|
||||
if (normdata && num_verts > 0)
|
||||
JS_SetProperty(js, js_mesh, norm_atom,
|
||||
make_gpu_buffer(js, normdata, sizeof(float)*3*num_verts, JS_TYPED_ARRAY_FLOAT32, 3, 1, 0));
|
||||
|
||||
// Indices
|
||||
if (indicesdata && index_count > 0)
|
||||
JS_SetProperty(js, js_mesh, indices_atom,
|
||||
make_gpu_buffer(js, indicesdata, sizeof(Uint16)*index_count, JS_TYPED_ARRAY_UINT16, 0, 1, 1));
|
||||
|
||||
// Metadata
|
||||
JS_SetProperty(js, js_mesh, vertices_atom, number2js(js, (double)num_verts));
|
||||
JS_SetProperty(js, js_mesh, count_atom, number2js(js, (double)index_count));
|
||||
|
||||
// Build final "model" object with mesh + material
|
||||
JSValue model_obj = JS_NewObject(js);
|
||||
JS_SetPropertyStr(js, model_obj, "mesh", js_mesh);
|
||||
|
||||
// Figure out the index of the material in data->materials. If prim->material is non-null,
|
||||
// its index is `prim->material - data->materials`.
|
||||
int mat_index = -1;
|
||||
if (prim->material) mat_index = (int)(prim->material - data->materials);
|
||||
if (mat_index >= 0 && mat_index < (int)data->materials_count)
|
||||
JS_SetPropertyStr(js, model_obj, "material", JS_DupValue(js, materials[mat_index]));
|
||||
else
|
||||
JS_SetPropertyStr(js, model_obj, "material", JS_NewObject(js));
|
||||
|
||||
// Place this "model" object into our return array
|
||||
uint32_t idx_in_array = js_arrlen(js,ret_arr);
|
||||
JS_SetPropertyUint32(js, ret_arr, idx_in_array, model_obj);
|
||||
|
||||
// Cleanup (per-primitive)
|
||||
if (posdata) free(posdata);
|
||||
if (normdata) free(normdata);
|
||||
if (uvdata) free(uvdata);
|
||||
if (colordata) free(colordata);
|
||||
if (indicesdata) free(indicesdata);
|
||||
}
|
||||
}
|
||||
|
||||
cgltf_free(data);
|
||||
|
||||
ret = ret_arr;
|
||||
*/
|
||||
)
|
||||
|
||||
JSC_SCALL(os_gltf_buffer,
|
||||
// int buffer_idx = js2number(js,argv[1]);
|
||||
// int type = js2number(js,argv[2]);
|
||||
// cgltf_options options = {0};
|
||||
// cgltf_data *data = NULL;
|
||||
// cgltf_result result = cgltf_parse_file(&options, str, &data);
|
||||
// result = cgltf_load_buffers(&options, data, str);
|
||||
|
||||
// SDL_GPUBuffer *b = SDL_CreateGPUBuffer(NULL,NULL);
|
||||
// *b = accessor2buffer(&data->accessors[buffer_idx], type);
|
||||
// cgltf_free(data);
|
||||
|
||||
// ret = sg_buffer2js(js,b);
|
||||
)
|
||||
|
||||
JSC_SCALL(os_gltf_skin,
|
||||
cgltf_options options = {0};
|
||||
cgltf_data *data = NULL;
|
||||
cgltf_parse_file(&options,str,&data);
|
||||
cgltf_load_buffers(&options,data,str);
|
||||
|
||||
if (data->skins_count <= 0) {
|
||||
ret = (JS_UNDEFINED);
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
ret = skin2js(js,make_gltf_skin(data->skins+0, data));
|
||||
|
||||
CLEANUP:
|
||||
cgltf_free(data);
|
||||
)
|
||||
|
||||
JSValue make_color_buffer(JSContext *js, colorf c, int verts)
|
||||
{
|
||||
HMM_Vec4 *colordata = malloc(sizeof(*colordata)*verts);
|
||||
@@ -7065,79 +6755,6 @@ JSC_CCALL(os_make_line_prim,
|
||||
return prim;
|
||||
)
|
||||
|
||||
JSValue parmesh2js(JSContext *js,par_shapes_mesh *m)
|
||||
{
|
||||
return JS_UNDEFINED;
|
||||
/* JSValue obj = JS_NewObject(js);
|
||||
sg_buffer *pos = malloc(sizeof(*pos));
|
||||
*pos = float_buffer(m->points, 3*m->npoints);
|
||||
JS_SetPropertyStr(js, obj, "pos", sg_buffer2js(js,pos));
|
||||
|
||||
if (m->tcoords) {
|
||||
sg_buffer *uv = malloc(sizeof(*uv));
|
||||
*uv = texcoord_floats(m->tcoords, 2*m->npoints);
|
||||
JS_SetPropertyStr(js, obj, "uv", sg_buffer2js(js,uv));
|
||||
}
|
||||
|
||||
if (m->normals) {
|
||||
sg_buffer *norm = malloc(sizeof(*norm));
|
||||
*norm = normal_floats(m->normals, 3*m->npoints);
|
||||
JS_SetPropertyStr(js, obj, "norm", sg_buffer2js(js,norm));
|
||||
}
|
||||
|
||||
sg_buffer *index = malloc(sizeof(*index));
|
||||
*index = sg_make_buffer(&(sg_buffer_desc){
|
||||
.data = {
|
||||
.ptr = m->triangles,
|
||||
.size = sizeof(*m->triangles)*3*m->ntriangles
|
||||
},
|
||||
.type = SG_BUFFERTYPE_INDEXBUFFER
|
||||
});
|
||||
JS_SetPropertyStr(js, obj, "index", sg_buffer2js(js,index));
|
||||
|
||||
JS_SetPropertyStr(js, obj, "count", number2js(js,3*m->ntriangles));
|
||||
|
||||
par_shapes_free_mesh(m);
|
||||
return obj;
|
||||
*/
|
||||
}
|
||||
|
||||
JSC_CCALL(os_make_cylinder,
|
||||
return parmesh2js(js,par_shapes_create_cylinder(js2number(js,argv[0]), js2number(js,argv[1])));
|
||||
)
|
||||
|
||||
JSC_CCALL(os_make_cone,
|
||||
return parmesh2js(js,par_shapes_create_cone(js2number(js,argv[0]), js2number(js,argv[1])));
|
||||
)
|
||||
|
||||
JSC_CCALL(os_make_disk,
|
||||
return parmesh2js(js,par_shapes_create_parametric_disk(js2number(js,argv[0]), js2number(js,argv[1])));
|
||||
)
|
||||
|
||||
JSC_CCALL(os_make_torus,
|
||||
return parmesh2js(js,par_shapes_create_torus(js2number(js,argv[0]), js2number(js,argv[1]), js2number(js,argv[2])));
|
||||
)
|
||||
|
||||
JSC_CCALL(os_make_sphere,
|
||||
return parmesh2js(js,par_shapes_create_parametric_sphere(js2number(js,argv[0]), js2number(js,argv[1])));
|
||||
)
|
||||
|
||||
JSC_CCALL(os_make_klein_bottle,
|
||||
return parmesh2js(js,par_shapes_create_klein_bottle(js2number(js,argv[0]), js2number(js,argv[1])));
|
||||
)
|
||||
|
||||
JSC_CCALL(os_make_trefoil_knot,
|
||||
return parmesh2js(js,par_shapes_create_trefoil_knot(js2number(js,argv[0]), js2number(js,argv[1]), js2number(js,argv[2])));
|
||||
)
|
||||
|
||||
JSC_CCALL(os_make_hemisphere,
|
||||
return parmesh2js(js,par_shapes_create_hemisphere(js2number(js,argv[0]), js2number(js,argv[1])));
|
||||
)
|
||||
|
||||
JSC_CCALL(os_make_plane,
|
||||
return parmesh2js(js,par_shapes_create_plane(js2number(js,argv[0]), js2number(js,argv[1])));
|
||||
)
|
||||
|
||||
static void render_frame(plm_t *mpeg, plm_frame_t *frame, datastream *ds) {
|
||||
if (JS_IsUndefined(ds->callback)) return;
|
||||
uint8_t *rgb = malloc(frame->height*frame->width*4);
|
||||
@@ -7164,11 +6781,6 @@ JSC_CCALL(os_make_video,
|
||||
return datastream2js(js,ds);
|
||||
)
|
||||
|
||||
JSC_CCALL(os_skin_calculate,
|
||||
skin *sk = js2skin(js,argv[0]);
|
||||
skin_calculate(sk);
|
||||
)
|
||||
|
||||
JSC_CCALL(os_rectpack,
|
||||
int width = js2number(js,argv[0]);
|
||||
int height = js2number(js,argv[1]);
|
||||
@@ -7200,27 +6812,6 @@ JSC_CCALL(os_rectpack,
|
||||
}
|
||||
)
|
||||
|
||||
JSC_CCALL(os_perlin,
|
||||
HMM_Vec3 coord = js2vec3(js,argv[0]);
|
||||
HMM_Vec3 wrap = js2vec3(js,argv[2]);
|
||||
return number2js(js,stb_perlin_noise3_seed(coord.x, coord.y, coord.z, wrap.x, wrap.y, wrap.z, js2number(js,argv[1])));
|
||||
)
|
||||
|
||||
JSC_CCALL(os_ridge,
|
||||
HMM_Vec3 c = js2vec3(js,argv[0]);
|
||||
return number2js(js,stb_perlin_ridge_noise3(c.x, c.y, c.z, js2number(js,argv[1]), js2number(js,argv[2]), js2number(js,argv[3]), js2number(js,argv[4])));
|
||||
)
|
||||
|
||||
JSC_CCALL(os_fbm,
|
||||
HMM_Vec3 c = js2vec3(js,argv[0]);
|
||||
return number2js(js,stb_perlin_fbm_noise3(c.x, c.y, c.z, js2number(js,argv[1]), js2number(js,argv[2]), js2number(js,argv[3])));
|
||||
)
|
||||
|
||||
JSC_CCALL(os_turbulence,
|
||||
HMM_Vec3 c = js2vec3(js,argv[0]);
|
||||
return number2js(js,stb_perlin_turbulence_noise3(c.x, c.y, c.z, js2number(js,argv[1]), js2number(js,argv[2]), js2number(js,argv[3])));
|
||||
)
|
||||
|
||||
JSC_SCALL(os_kill,
|
||||
int sig = 0;
|
||||
if (!strcmp(str, "SIGABRT")) sig = SIGABRT;
|
||||
@@ -7232,16 +6823,8 @@ JSC_SCALL(os_kill,
|
||||
|
||||
if (!sig) return JS_ThrowReferenceError(js, "string %s is not a valid signal", str);
|
||||
raise(sig);
|
||||
return JS_UNDEFINED;
|
||||
)
|
||||
int detectImageInWebcam(SDL_Surface *a, SDL_Surface *b);
|
||||
/*JSC_CCALL(os_match_img,
|
||||
SDL_Surface *img1 = js2SDL_Surface(js,argv[0]);
|
||||
SDL_Surface *img2 = js2SDL_Surface(js,argv[1]);
|
||||
int n = detectImageInWebcam(img1,img2);
|
||||
return number2js(js,n);
|
||||
)
|
||||
*/
|
||||
|
||||
JSC_CCALL(os_sleep,
|
||||
double time = js2number(js,argv[0]);
|
||||
time *= 1000000000.;
|
||||
@@ -7341,36 +6924,6 @@ JSC_CCALL(os_cull_sprites,
|
||||
}
|
||||
)
|
||||
|
||||
struct qtree_sprite {
|
||||
rect rect;
|
||||
JSValue value;
|
||||
};
|
||||
|
||||
int js_qtree_cmp(struct qtree_sprite *v, aabb *range)
|
||||
{
|
||||
rect ab = {
|
||||
.x = range->center.x-range->dims.w,
|
||||
.y = range->center.y-range->dims.h,
|
||||
.w = range->dims.w*2.0,
|
||||
.h = range->dims.h*2.0
|
||||
};
|
||||
return SDL_HasRectIntersectionFloat(&v->rect, &ab);
|
||||
}
|
||||
|
||||
int js_qtree_rm(struct qtree_sprite *val, struct qtree_sprite *cmp)
|
||||
{
|
||||
int same = JS_SameValue(global_js, val->value, cmp->value);
|
||||
if (same)
|
||||
JS_FreeValue(global_js, val->value);
|
||||
return same;
|
||||
}
|
||||
|
||||
JSC_CCALL(os_make_quadtree,
|
||||
rect area = js2rect(js,argv[0]);
|
||||
qtree tree = qtree_new(area.x,area.y,area.w,area.h, js_qtree_cmp, js_qtree_rm);
|
||||
return qtree2js(js,tree);
|
||||
)
|
||||
|
||||
JSC_CCALL(os_make_rtree,
|
||||
struct rtree *tree = rtree_new();
|
||||
if (!tree) return JS_ThrowOutOfMemory(js);
|
||||
@@ -7421,106 +6974,216 @@ typedef struct {
|
||||
size_t fn_count;
|
||||
} ModuleEntry;
|
||||
|
||||
JSC_SSCALL(os_trimchr,
|
||||
int len;
|
||||
JS_GETPROP(js,len,argv[0],length,number)
|
||||
const char *start = str;
|
||||
|
||||
while (*start == *str2)
|
||||
start++;
|
||||
|
||||
const char *end = str + len-1;
|
||||
while(*end == *str2)
|
||||
end--;
|
||||
|
||||
ret = JS_NewStringLen(js, start, end-start+1);
|
||||
JSC_CCALL(os_totalmem, return number2js(js, SDL_GetSystemRAM()))
|
||||
JSC_CCALL(os_platform, return JS_NewString(js,SDL_GetPlatform()))
|
||||
JSC_CCALL(os_hostname,
|
||||
char buf[256];
|
||||
if (gethostname(buf,sizeof(buf)) == 0) return JS_NewString(js,buf);
|
||||
return JS_NewString(js,"");
|
||||
)
|
||||
|
||||
JSC_CCALL(os_freemem,
|
||||
#ifdef _WIN32
|
||||
MEMORYSTATUSEX statex;
|
||||
statex.dwLength = sizeof(statex);
|
||||
if (!GlobalMemoryStatusEx(&statex)) return JS_ThrowInternalError(js,"GlobalMemoryStatusEx failed");
|
||||
return JS_NewInt64(js,(int64_t)statex.ullAvailPhys);
|
||||
#elif defined(__linux__)
|
||||
struct sysinfo info;
|
||||
if (sysinfo(&info) == 0)
|
||||
return JS_NewInt64(js,(int64_t)info.freeram * info.mem_unit);
|
||||
return JS_NewInt64(js,0);
|
||||
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
// A very rough fallback using the same sysconf approach
|
||||
// (macOS or *BSD typically need specialized APIs to get free mem accurately)
|
||||
// This is often only "unused" pages, ignoring caches, etc.
|
||||
long pages = sysconf(_SC_AVPHYS_PAGES);
|
||||
long page_size = sysconf(_SC_PAGE_SIZE);
|
||||
if (pages < 0 || page_size < 0) return JS_NewInt64(js,0);
|
||||
return JS_NewInt64(js,(int64_t)pages * (int64_t)page_size);
|
||||
#else
|
||||
// Fallback: unknown
|
||||
return JS_NewInt64(js,0);
|
||||
#endif
|
||||
)
|
||||
|
||||
JSC_CCALL(os_arch,
|
||||
#if defined(__x86_64__) || defined(_M_X64)
|
||||
return JS_NewString(js,"x64");
|
||||
#elif defined(__aarch64__) || defined(_M_ARM64)
|
||||
return JS_NewString(js,"arm64");
|
||||
#elif defined(__arm__) || defined(_M_ARM)
|
||||
return JS_NewString(js,"arm");
|
||||
#elif defined(__i386__) || defined(_M_IX86)
|
||||
return JS_NewString(js,"ia32");
|
||||
#elif defined(__loongarch__) || defined(__loongarch32) || defined(__loongarch64)
|
||||
return JS_NewString(js,"loong64");
|
||||
#elif defined(__mips__) || defined(__mips) || defined(_M_MIPS)
|
||||
// You might want to distinguish mips vs mipsel
|
||||
return JS_NewString(js,"mips");
|
||||
#elif defined(__ppc64__) || defined(__powerpc64__) || defined(_M_PPC)
|
||||
// You might want to distinguish ppc vs ppc64, big-endian vs little-endian
|
||||
return JS_NewString(js,"ppc64");
|
||||
#elif defined(__riscv) && __riscv_xlen == 64
|
||||
return JS_NewString(js,"riscv64");
|
||||
#elif defined(__s390x__)
|
||||
return JS_NewString(js,"s390x");
|
||||
#else
|
||||
return JS_NewString(js,"unknown");
|
||||
#endif
|
||||
)
|
||||
|
||||
JSC_CCALL(os_version,
|
||||
return JS_NewString(js,PROSPERON_VERSION);
|
||||
)
|
||||
|
||||
JSC_CCALL(os_commit,
|
||||
return JS_NewString(js,PROSPERON_COMMIT);
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef LONG (WINAPI *RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
|
||||
HMODULE h = GetModuleHandleA("ntdll.dll");
|
||||
if (h) {
|
||||
RtlGetVersionPtr fx = (RtlGetVersionPtr)GetProcAddress(h, "RtlGetVersion");
|
||||
if (fx) {
|
||||
RTL_OSVERSIONINFOW ver;
|
||||
memset(&ver, 0, sizeof(ver));
|
||||
ver.dwOSVersionInfoSize = sizeof(ver);
|
||||
if (!fx(&ver)) {
|
||||
char buf[128];
|
||||
sprintf(buf, "%u.%u.%u",
|
||||
(unsigned)ver.dwMajorVersion,
|
||||
(unsigned)ver.dwMinorVersion,
|
||||
(unsigned)ver.dwBuildNumber
|
||||
);
|
||||
return JS_NewString(js, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
OSVERSIONINFOW wver;
|
||||
memset(&wver, 0, sizeof(wver));
|
||||
wver.dwOSVersionInfoSize = sizeof(wver);
|
||||
if (GetVersionExW(&wver)) {
|
||||
char buf[128];
|
||||
sprintf(buf, "%u.%u.%u",
|
||||
(unsigned)wver.dwMajorVersion,
|
||||
(unsigned)wver.dwMinorVersion,
|
||||
(unsigned)wver.dwBuildNumber
|
||||
);
|
||||
return JS_NewString(js, buf);
|
||||
}
|
||||
return JS_NewString(js, "Windows_Unknown");
|
||||
#else
|
||||
struct utsname info;
|
||||
if (!uname(&info)) return JS_NewString(js, info.release);
|
||||
return JS_NewString(js, "");
|
||||
#endif
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_os_funcs[] = {
|
||||
MIST_FUNC_DEF(os, version, 0),
|
||||
MIST_FUNC_DEF(os, commit, 0),
|
||||
MIST_FUNC_DEF(os, engine_start, 1),
|
||||
MIST_FUNC_DEF(os, engine_input, 1),
|
||||
MIST_FUNC_DEF(os, turbulence, 4),
|
||||
MIST_FUNC_DEF(os, model_buffer, 1),
|
||||
MIST_FUNC_DEF(os, clean_transforms, 0),
|
||||
MIST_FUNC_DEF(os, fbm, 4),
|
||||
MIST_FUNC_DEF(os, ridge, 5),
|
||||
MIST_FUNC_DEF(os, perlin, 3),
|
||||
MIST_FUNC_DEF(os, rectpack, 3),
|
||||
MIST_FUNC_DEF(os, cwd, 0),
|
||||
MIST_FUNC_DEF(os, rusage, 0),
|
||||
MIST_FUNC_DEF(os, mallinfo, 0),
|
||||
MIST_FUNC_DEF(os, env, 1),
|
||||
MIST_FUNC_DEF(os, sys, 0),
|
||||
MIST_FUNC_DEF(os, system, 1),
|
||||
MIST_FUNC_DEF(os, exit, 1),
|
||||
MIST_FUNC_DEF(os, gc, 0),
|
||||
MIST_FUNC_DEF(os, now, 0),
|
||||
MIST_FUNC_DEF(os, guid, 0),
|
||||
MIST_FUNC_DEF(os, openurl, 1),
|
||||
MIST_FUNC_DEF(os, push_event, 1),
|
||||
MIST_FUNC_DEF(os, eval, 2),
|
||||
MIST_FUNC_DEF(os, make_quadtree, 1),
|
||||
MIST_FUNC_DEF(os, make_rtree, 0),
|
||||
MIST_FUNC_DEF(os, make_texture, 1),
|
||||
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_sprite, 0),
|
||||
MIST_FUNC_DEF(os, make_line_prim, 5),
|
||||
MIST_FUNC_DEF(os, make_cylinder, 2),
|
||||
MIST_FUNC_DEF(os, make_cone, 2),
|
||||
MIST_FUNC_DEF(os, make_disk, 2),
|
||||
MIST_FUNC_DEF(os, make_torus, 3),
|
||||
MIST_FUNC_DEF(os, make_sphere, 2),
|
||||
MIST_FUNC_DEF(os, make_klein_bottle, 2),
|
||||
MIST_FUNC_DEF(os, make_trefoil_knot, 3),
|
||||
MIST_FUNC_DEF(os, make_hemisphere, 2),
|
||||
MIST_FUNC_DEF(os, make_plane, 2),
|
||||
MIST_FUNC_DEF(os, make_video, 1),
|
||||
MIST_FUNC_DEF(os, clean_transforms, 0),
|
||||
|
||||
MIST_FUNC_DEF(os, platform, 0),
|
||||
MIST_FUNC_DEF(os, arch, 0),
|
||||
MIST_FUNC_DEF(os, totalmem, 0),
|
||||
MIST_FUNC_DEF(os, freemem, 0),
|
||||
MIST_FUNC_DEF(os, hostname, 0),
|
||||
MIST_FUNC_DEF(os, version, 0),
|
||||
|
||||
MIST_FUNC_DEF(os, kill, 1),
|
||||
MIST_FUNC_DEF(os, exit, 1),
|
||||
|
||||
MIST_FUNC_DEF(os, now, 0),
|
||||
|
||||
MIST_FUNC_DEF(os, openurl, 1),
|
||||
|
||||
|
||||
|
||||
MIST_FUNC_DEF(os, make_timer, 1),
|
||||
MIST_FUNC_DEF(os, make_text_buffer, 6),
|
||||
MIST_FUNC_DEF(os, update_timers, 1),
|
||||
MIST_FUNC_DEF(os, mem, 1),
|
||||
MIST_FUNC_DEF(os, mem_limit, 1),
|
||||
MIST_FUNC_DEF(os, gc_threshold, 1),
|
||||
MIST_FUNC_DEF(os, max_stacksize, 1),
|
||||
MIST_FUNC_DEF(os, rt_info, 0),
|
||||
MIST_FUNC_DEF(os, dump_mem, 0),
|
||||
MIST_FUNC_DEF(os, dump_shapes, 0),
|
||||
MIST_FUNC_DEF(os, dump_atoms,0),
|
||||
MIST_FUNC_DEF(os, calc_mem, 1),
|
||||
MIST_FUNC_DEF(os, memstate, 0),
|
||||
MIST_FUNC_DEF(os, value_id, 1),
|
||||
MIST_FUNC_DEF(os, gltf_buffer, 3),
|
||||
MIST_FUNC_DEF(os, gltf_skin, 1),
|
||||
MIST_FUNC_DEF(os, skin_calculate, 1),
|
||||
MIST_FUNC_DEF(os, kill, 1),
|
||||
// MIST_FUNC_DEF(os, match_img, 2),
|
||||
|
||||
MIST_FUNC_DEF(os, sleep, 1),
|
||||
MIST_FUNC_DEF(os, battery_pct, 0),
|
||||
MIST_FUNC_DEF(os, battery_voltage, 0),
|
||||
MIST_FUNC_DEF(os, battery_seconds, 0),
|
||||
MIST_FUNC_DEF(os, power_state, 0),
|
||||
MIST_FUNC_DEF(os, insertion_sort, 2),
|
||||
|
||||
MIST_FUNC_DEF(os, on, 2),
|
||||
|
||||
MIST_FUNC_DEF(os, rt_info, 0),
|
||||
MIST_FUNC_DEF(os, rusage, 0),
|
||||
MIST_FUNC_DEF(os, mallinfo, 0),
|
||||
|
||||
// dangerous ones that need disabled for shipping
|
||||
MIST_FUNC_DEF(os, env, 1),
|
||||
MIST_FUNC_DEF(os, system, 1),
|
||||
};
|
||||
|
||||
static const JSCFunctionListEntry js_js_funcs[] = {
|
||||
MIST_FUNC_DEF(os, dump_mem, 0),
|
||||
MIST_FUNC_DEF(os, dump_shapes, 0),
|
||||
MIST_FUNC_DEF(os, dump_atoms,0),
|
||||
MIST_FUNC_DEF(os, calc_mem, 1),
|
||||
MIST_FUNC_DEF(os, mem, 1),
|
||||
MIST_FUNC_DEF(os, mem_limit, 1),
|
||||
MIST_FUNC_DEF(os, gc_threshold, 1),
|
||||
MIST_FUNC_DEF(os, max_stacksize, 1),
|
||||
MIST_FUNC_DEF(os, memstate, 0),
|
||||
MIST_FUNC_DEF(os, gc, 0),
|
||||
MIST_FUNC_DEF(os, eval, 2),
|
||||
};
|
||||
|
||||
static const JSCFunctionListEntry js_util_funcs[] = {
|
||||
MIST_FUNC_DEF(os, guid, 0),
|
||||
MIST_FUNC_DEF(os, insertion_sort, 2),
|
||||
};
|
||||
|
||||
static const JSCFunctionListEntry js_graphics_funcs[] = {
|
||||
MIST_FUNC_DEF(gpu, make_sprite_mesh, 2),
|
||||
MIST_FUNC_DEF(gpu, make_sprite_queue, 4),
|
||||
MIST_FUNC_DEF(os, make_text_buffer, 6),
|
||||
MIST_FUNC_DEF(os, rectpack, 3),
|
||||
MIST_FUNC_DEF(os, make_rtree, 0),
|
||||
MIST_FUNC_DEF(os, make_texture, 1),
|
||||
MIST_FUNC_DEF(os, make_gif, 1),
|
||||
MIST_FUNC_DEF(os, make_aseprite, 1),
|
||||
MIST_FUNC_DEF(os, cull_sprites, 2),
|
||||
MIST_FUNC_DEF(os, rects_to_sprites,2),
|
||||
MIST_FUNC_DEF(os, on, 2),
|
||||
MIST_FUNC_DEF(os, trimchr, 2),
|
||||
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_sprite, 0),
|
||||
MIST_FUNC_DEF(os, make_line_prim, 5),
|
||||
};
|
||||
|
||||
static const JSCFunctionListEntry js_video_funcs[] = {
|
||||
MIST_FUNC_DEF(os, make_video, 1),
|
||||
};
|
||||
|
||||
void gui_input(SDL_Event *e);
|
||||
// Polls and handles all input events
|
||||
JSC_CCALL(os_engine_input,
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
#ifndef NEDITOR
|
||||
gui_input(&event);
|
||||
#endif
|
||||
JSValue e = event2js(js,event);
|
||||
JSValue ret = JS_Call(js,argv[0], JS_UNDEFINED, 1, &e);
|
||||
uncaught_exception(js,ret);
|
||||
}
|
||||
)
|
||||
|
||||
JSC_CCALL(os_push_event,
|
||||
SDL_UserEvent e;
|
||||
SDL_zero(e);
|
||||
e.type = SDL_EVENT_USER;
|
||||
e.timestamp = SDL_GetTicksNS();
|
||||
e.code = 0;
|
||||
JSValue fn = JS_DupValue(js,argv[0]);
|
||||
e.data1 = malloc(sizeof(JSValue));
|
||||
*(JSValue*)e.data1 = fn;
|
||||
SDL_PushEvent(&e);
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_event_funcs[] = {
|
||||
MIST_FUNC_DEF(os, push_event, 1),
|
||||
MIST_FUNC_DEF(os, engine_input, 1),
|
||||
};
|
||||
|
||||
#define MISTLINE(NAME) { #NAME, js_##NAME##_funcs, countof(js_##NAME##_funcs) }
|
||||
@@ -7533,6 +7196,11 @@ static ModuleEntry module_registry[] = {
|
||||
MISTLINE(math),
|
||||
MISTLINE(spline),
|
||||
MISTLINE(geometry),
|
||||
MISTLINE(graphics),
|
||||
MISTLINE(js),
|
||||
MISTLINE(util),
|
||||
MISTLINE(video),
|
||||
MISTLINE(event),
|
||||
};
|
||||
|
||||
JSC_SCALL(os_use_embed,
|
||||
@@ -7565,41 +7233,6 @@ JSC_SCALL(os_use_dyn,
|
||||
SDL_UnloadObject(ptr);
|
||||
)
|
||||
|
||||
JSC_CCALL(qtree_insert,
|
||||
qtree tree = js2qtree(js,self);
|
||||
JSValue v = argv[0];
|
||||
struct qtree_sprite *item = malloc(sizeof(*item));
|
||||
item->value = JS_DupValue(js,v);
|
||||
JS_GETATOM(js,item->rect,v,rect_atom,rect)
|
||||
qtree_insert(tree, item);
|
||||
)
|
||||
|
||||
JSC_CCALL(qtree_remove,
|
||||
struct qtree_sprite tmp;
|
||||
tmp.value = argv[0];
|
||||
qtree tree = js2qtree(js,self);
|
||||
qtree_remove(tree, &tmp);
|
||||
)
|
||||
|
||||
JSC_CCALL(qtree_query,
|
||||
qtree tree = js2qtree(js,self);
|
||||
rect area = js2rect(js,argv[0]);
|
||||
uint32_t n;
|
||||
struct qtree_sprite **items = qtree_findInArea(tree, area.x, area.y, area.w, area.h, &n);
|
||||
|
||||
ret = JS_NewArray(js);
|
||||
for (int i = 0; i < n; i++)
|
||||
JS_SetPropertyUint32(js,ret,i, JS_DupValue(js,items[i]->value));
|
||||
|
||||
free(items);
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_qtree_funcs[] = {
|
||||
MIST_FUNC_DEF(qtree, insert, 1),
|
||||
MIST_FUNC_DEF(qtree, remove, 1),
|
||||
MIST_FUNC_DEF(qtree, query, 2),
|
||||
};
|
||||
|
||||
JSC_CCALL(rtree_add,
|
||||
rtree *tree = js2rtree(js,self);
|
||||
JSValue v = argv[0];
|
||||
@@ -7832,19 +7465,18 @@ static void signal_handler(int sig) {
|
||||
break;
|
||||
}
|
||||
if (!str) return;
|
||||
script_evalf("prosperon.%s?.();", str);
|
||||
script_evalf("prosperon.dispatch('%s')", str);
|
||||
}
|
||||
|
||||
static void exit_handler()
|
||||
{
|
||||
script_evalf("prosperon.exit?.();");
|
||||
script_evalf("prosperon.dispatch('exit')");
|
||||
script_stop();
|
||||
}
|
||||
|
||||
void ffi_load(JSContext *js) {
|
||||
void ffi_load(JSContext *js, int argc, char **argv) {
|
||||
JSValue globalThis = JS_GetGlobalObject(js);
|
||||
|
||||
QJSCLASSPREP_FUNCS(qtree)
|
||||
QJSCLASSPREP_FUNCS(rtree)
|
||||
QJSCLASSPREP_FUNCS(SDL_Window)
|
||||
QJSCLASSPREP_FUNCS(SDL_Surface)
|
||||
@@ -7883,6 +7515,10 @@ void ffi_load(JSContext *js) {
|
||||
QJSGLOBALCLASS(os);
|
||||
QJSGLOBALCLASS(console);
|
||||
|
||||
JSValue jsobject = JS_GetPropertyStr(js,globalThis, "Object");
|
||||
JS_SetPropertyStr(js, jsobject, "id", JS_NewCFunction(js, js_os_value_id, "id", 1));
|
||||
JS_FreeValue(js,jsobject);
|
||||
|
||||
JSValue jsarray = JS_GetPropertyStr(js,globalThis, "Array");
|
||||
JSValue array_proto = JS_GetPropertyStr(js,jsarray, "prototype");
|
||||
JS_SetPropertyFunctionList(js, array_proto, js_array_funcs, countof(js_array_funcs));
|
||||
@@ -8008,5 +7644,18 @@ void ffi_load(JSContext *js) {
|
||||
|
||||
m_seedRand(&mrand, time(NULL));
|
||||
|
||||
JSValue prosp = JS_NewObject(js);
|
||||
|
||||
JSValue args = JS_NewArray(js);
|
||||
for (int i = 0; i < argc; i++)
|
||||
JS_SetPropertyUint32(js,args, i, JS_NewString(js,argv[i]));
|
||||
|
||||
JS_SetPropertyStr(js,prosp,"argv", args);
|
||||
JS_SetPropertyStr(js,prosp, "version", JS_NewString(js,PROSPERON_VERSION));
|
||||
JS_SetPropertyStr(js,prosp,"revision",JS_NewString(js,PROSPERON_COMMIT));
|
||||
JS_SetPropertyStr(js,prosp,"engine_start", JS_NewCFunction(js,js_os_engine_start, "engine_start", 1));
|
||||
|
||||
JS_SetPropertyStr(js,globalThis,"prosperon", prosp);
|
||||
|
||||
JS_FreeValue(js,globalThis);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef FFI_H
|
||||
#define FFI_H
|
||||
#include <quickjs.h>
|
||||
void ffi_load(JSContext *js);
|
||||
void ffi_load(JSContext *js, int argc, char **argv);
|
||||
int js_print_exception(JSContext *js, JSValue v);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "yugine.h"
|
||||
|
||||
#include "jsffi.h"
|
||||
|
||||
|
||||
12
source/prosperon.c
Normal file
12
source/prosperon.c
Normal file
@@ -0,0 +1,12 @@
|
||||
#include "script.h"
|
||||
#include "physfs.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
PHYSFS_init(argv[0]);
|
||||
char *base = PHYSFS_getBaseDir();
|
||||
PHYSFS_setWriteDir(base);
|
||||
PHYSFS_mount(base,NULL,0);
|
||||
PHYSFS_mount(base,"/",0);
|
||||
script_startup(argc, argv); // runs engine.js
|
||||
return 0;
|
||||
}
|
||||
@@ -61,7 +61,7 @@ int js_interrupt(JSRuntime *rt, void *data)
|
||||
// printf("INTERRUPT\n");
|
||||
}
|
||||
|
||||
void script_startup() {
|
||||
void script_startup(int argc, char **argv) {
|
||||
rt = JS_NewRuntime();
|
||||
js = JS_NewContextRaw(rt);
|
||||
JS_AddIntrinsicBaseObjects(js);
|
||||
@@ -77,7 +77,7 @@ void script_startup() {
|
||||
JS_AddIntrinsicBigDecimal(js);
|
||||
JS_AddIntrinsicOperators(js);
|
||||
|
||||
ffi_load(js);
|
||||
ffi_load(js, argc, argv);
|
||||
|
||||
char *eng = read_file("core/scripts/engine.js");
|
||||
JSValue v = script_eval(js, "core/scripts/engine.js", eng);
|
||||
@@ -87,11 +87,12 @@ void script_startup() {
|
||||
|
||||
void script_stop()
|
||||
{
|
||||
return;
|
||||
JS_FreeContext(js);
|
||||
js = NULL;
|
||||
JS_FreeRuntime(rt);
|
||||
JS_FreeValue(js,on_exception);
|
||||
|
||||
rt = NULL;
|
||||
js = NULL;
|
||||
}
|
||||
|
||||
void uncaught_exception(JSContext *js, JSValue v)
|
||||
@@ -118,10 +119,6 @@ void uncaught_exception(JSContext *js, JSValue v)
|
||||
JS_FreeValue(js,v);
|
||||
}
|
||||
|
||||
void script_mem_limit(size_t limit) { JS_SetMemoryLimit(rt, limit); }
|
||||
void script_gc_threshold(size_t threshold) { JS_SetGCThreshold(rt, threshold); }
|
||||
void script_max_stacksize(size_t size) { JS_SetMaxStackSize(rt, size); }
|
||||
|
||||
void script_evalf(const char *format, ...)
|
||||
{
|
||||
JSValue obj;
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
#include "yugine.h"
|
||||
#include "script.h"
|
||||
#include <string.h>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include "physfs.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
PHYSFS_init(argv[0]);
|
||||
char *base = PHYSFS_getBaseDir();
|
||||
PHYSFS_setWriteDir(base);
|
||||
PHYSFS_mount(base,NULL,0);
|
||||
PHYSFS_mount(base,"/",0);
|
||||
script_startup(); // runs engine.js
|
||||
|
||||
int argsize = 0;
|
||||
for (int i = 0; i < argc; i++) {
|
||||
argsize += strlen(argv[i]);
|
||||
if (argc > i+1) argsize++;
|
||||
}
|
||||
|
||||
char cmdstr[argsize+1];
|
||||
cmdstr[0] = '\0';
|
||||
|
||||
for (int i = 0; i < argc; i++) {
|
||||
strcat(cmdstr, argv[i]);
|
||||
if (argc > i+1) strcat(cmdstr, " ");
|
||||
}
|
||||
|
||||
script_evalf("cmd_args('%s');", cmdstr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
#ifndef YUGINE_H
|
||||
#define YUGINE_H
|
||||
|
||||
#include "script.h"
|
||||
|
||||
void engine_start(JSContext *js, JSValue start_fn, JSValue proc_fn, float x, float y); /* fn runs after the engine starts */
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user