Move main process into javascript

This commit is contained in:
John Alanbrook 2024-03-15 11:21:36 -05:00
parent 32b0cc7377
commit 088dd4d4fd
20 changed files with 94 additions and 397 deletions

View file

@ -53,10 +53,6 @@ actor.delay.doc = `Call 'fn' after 'seconds' with 'this' set to the actor.`;
actor.padawans = [];
global.app = Object.create(actor);
app.die = function()
{
Game.quit();
}
app.die = function() { os.quit(); }
return {actor, app};

View file

@ -48,7 +48,7 @@ var Debug = {
if (this.draw_bb)
Game.all_objects(function(x) { Debug.boundingbox(x.boundingbox(), Color.Debug.boundingbox.alpha(0.05)); });
if (Game.paused()) GUI.text("PAUSED", [0,0],1);
if (sim.paused()) GUI.text("PAUSED", [0,0],1);
if (this.draw_gizmos)
Game.all_objects(function(x) {
@ -66,10 +66,10 @@ var Debug = {
GUI.text(time.timecode(time.timenow() - Debug.Options.gif.start_time, Debug.Options.gif.fps), [0,30], 1);
}
GUI.text(Game.playing() ? "PLAYING"
: Game.stepping() ?
GUI.text(sim.playing() ? "PLAYING"
: sim.stepping() ?
"STEP" :
Game.paused() ?
sim.paused() ?
"PAUSED; EDITING" :
"EDIT", [0, 0], 1);
},
@ -80,7 +80,7 @@ function assert(op, str)
str ??= `assertion failed [value '${op}']`;
if (!op) {
console.error(`Assertion failed: ${str}`);
Game.quit();
os.quit();
}
}
@ -141,6 +141,8 @@ Object.assign(profile, {
fn();
say(`profile [${str}]: ${profile.lap(start)}`);
},
secs() { return this.now()/1000000000; },
});

View file

@ -191,7 +191,7 @@ var editor = {
this.stash = this.desktop.instance_obj();
world.clear();
global.mixin("config.js");
Game.play();
sim.play();
player[0].uncontrol(this);
player[0].control(limited_editor);
editor.cbs.forEach(cb => cb());
@ -206,7 +206,7 @@ var editor = {
start_play() {
world.clear();
global.mixin("config.js");
Game.play();
sim.play();
player[0].uncontrol(this);
player[0].control(limited_editor);
editor.cbs.forEach(cb=>cb());
@ -217,7 +217,7 @@ var editor = {
cbs: [],
enter_editor() {
Game.pause();
sim.pause();
player[0].control(this);
player[0].uncontrol(limited_editor);
@ -832,15 +832,15 @@ editor.inputs.f6 = function() { editor.start_play(); }
editor.inputs.f6.doc = "Start game as if the player started it.";
editor.inputs['M-p'] = function() {
if (Game.playing())
Game.pause();
if (sim.playing())
sim.pause();
Game.step();
sim.step();
}
editor.inputs['M-p'].doc = "Do one time step, pausing if necessary.";
editor.inputs['C-M-p'] = function() {
if (!Game.playing()) {
if (!sim.playing()) {
editor.start_play_ed();
}
console.warn(`Starting edited level ...`);
@ -1928,9 +1928,7 @@ var groupsaveaspanel = Object.copy(inputpanel, {
var quitpanel = Object.copy(inputpanel, {
title: "really quit?",
action() {
Game.quit();
},
action() { os.quit(); },
guibody () {
return Mum.text({str: "Really quit?"});
@ -2043,16 +2041,16 @@ limited_editor.inputs = {};
limited_editor.inputs['C-p'] = function()
{
if (Game.playing())
Game.pause();
if (sim.playing())
sim.pause();
else
Game.play();
sim.play();
}
limited_editor.inputs['M-p'] = function()
{
Game.pause();
Game.step();
sim.pause();
sim.step();
}
limited_editor.inputs['C-q'] = function()
@ -2072,7 +2070,7 @@ if (io.exists("editor.config"))
load_configs("editor.config");
/* This is the editor level & camera - NOT the currently edited level, but a level to hold editor things */
Game.stop();
sim.pause();
Window.editor = true;
Debug.draw_phys(true);

View file

@ -143,10 +143,47 @@ var load = use;
Object.assign(global, use("scripts/base.js"));
global.obscure('global');
global.mixin("scripts/render.js");
global.mixin("scripts/debug.js");
var frame_t = profile.secs();
var updateMS = 1/60;
var physMS = 1/60;
var sim = {
mode: "play",
play() { this.mode = "play"; os.reindex_static(); },
playing() { return this.mode === 'play'; },
pause() { this.mode = "pause"; console.stack(); },
paused() { return this.mode === 'pause'; },
step() { this.mode = 'step'; },
stepping() { return this.mode === 'step'; }
}
var physlag = 0;
var timescale = 1;
function process()
{
say ('holy cow');
var dt = profile.secs() - frame_t;
frame_t = profile.secs();
prosperon.appupdate(dt);
prosperon.emitters_step(dt);
if (sim.mode === "play" || sim.mode === "step") {
prosperon.update(dt*game.timescale);
if (sim.mode === "step")
sim.pause();
}
physlag += dt;
while (physlag > physMS) {
physlag -= physMS;
prosperon.phys2d_step(physMS*timescale);
prosperon.physupdate(physMS*timescale);
}
prosperon.window_render();
}
global.Game = {
@ -178,18 +215,6 @@ global.Game = {
},
quit() {
sys_cmd(0);
},
pause() { sys_cmd(3); },
stop() { Game.pause(); },
step() { sys_cmd(4);},
playing() { return sys_cmd(5); },
paused() { return sys_cmd(6); },
stepping() { return cmd(79); },
play() { sys_cmd(1); },
wait_fns: [],
wait_exec(fn) {
@ -349,8 +374,8 @@ var Register = {
},
};
Register.add_cb("update").doc = "Called once per frame.";
Register.add_cb("appupdate");
Register.add_cb("update").doc = "Called once per frame.";
Register.add_cb("physupdate");
Register.add_cb("gui");
Register.add_cb("debug");
@ -405,7 +430,7 @@ Window.world2screen = function(worldpos) {
Window.icon = function(path) { cmd(90, path); };
Window.icon.doc = "Set the icon of the window using the PNG image at path.";
global.mixin("scripts/debug.js");
global.mixin("scripts/spline.js");
global.mixin("scripts/components.js");
@ -453,3 +478,4 @@ Game.view_camera = function(cam)
}
Window.title = `Prosperon v${prosperon.version}`;
Window.size = [500,500];

View file

@ -362,7 +362,7 @@ var gameobject = {
if (typeof ent.load === 'function') ent.load();
if (Game.playing())
if (sim.playing())
if (typeof ent.start === 'function') ent.start();
var mur = ent.get_ur();
@ -838,4 +838,4 @@ Game.loadurs = function() {
return {
gameobject
}
}

View file

@ -35,4 +35,4 @@ say(`Failed tests are:`);
for (var f of failed)
say(f);
Game.quit();
os.quit();

View file

@ -1,6 +1,5 @@
#include "2dphysics.h"
#include "debug.h"
#include "gameobject.h"
#include <string.h>

View file

@ -1,45 +0,0 @@
#include "debug.h"
#include "stb_ds.h"
#include "log.h"
#include "sokol/sokol_time.h"
unsigned long long triCount = 0;
void prof_start(struct d_prof *prof)
{
arrsetlen(prof->ms, prof->laps);
}
void prof_reset(struct d_prof *prof)
{
prof->lap = stm_now();
}
float prof_lap_avg(struct d_prof *prof)
{
float avg;
for (int i = 0; i < arrlen(prof->ms); i++)
avg += prof->ms[i];
avg /= arrlen(prof->ms);
return avg;
}
void prof_lap(struct d_prof *prof)
{
if (prof->ms == NULL)
prof_start(prof);
if (arrlen(prof->ms) >= prof->laps) {
YughWarn("Profiled time of %s is avg %g", prof->name, prof_lap_avg(prof));
arrsetlen(prof->ms, 0);
}
uint64_t t = stm_since(prof->lap);
arrput(prof->ms, stm_sec(t));
}
void resetTriangles()
{
triCount = 0;
}

View file

@ -1,20 +0,0 @@
#ifndef DEBUG_GUI_H
#define DEBUG_GUI_H
#include <stdint.h>
struct d_prof {
char *name;
float *ms;
uint64_t lap;
int laps;
};
extern unsigned long long triCount;
void resetTriangles();
void prof_start(struct d_prof *prof);
void prof_reset(struct d_prof *prof);
void prof_lap(struct d_prof *prof);
float prof_lap_avg(struct d_prof *prof);
#endif

View file

@ -4,7 +4,6 @@
#include "yugine.h"
#include "log.h"
#include <assert.h>
#include "debug.h"
#include "window.h"
#include "2dphysics.h"
#include "stb_ds.h"

View file

@ -18,8 +18,4 @@ void touch_cancelled(sapp_touchpoint *touch, int n);
void input_dropped_files(int n);
void input_clipboard_paste(char *str);
const char *keyname_extd(int key);
void quit();
#endif

View file

@ -3,8 +3,6 @@
#include "script.h"
#include "anim.h"
#include "timer.h"
#include "debug.h"
#include "debugdraw.h"
#include "font.h"
#include "gameobject.h"
@ -206,8 +204,6 @@ JSValue ptr2js(void *ptr) {
return obj;
}
struct timer *js2timer(JSValue v) { return id2timer(js2int(v)); }
double js_get_prop_number(JSValue v, const char *p) {
double num;
JS_ToFloat64(js, &num, js_getpropstr(v,p));
@ -758,10 +754,6 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
set_cat_mask(js2int(argv[1]), js2bitmask(argv[2]));
break;
case 79:
ret = JS_NewBool(js, phys_stepping());
break;
case 80:
ids = phys2d_query_shape(js2ptr(argv[1]));
ret = gos2ref(ids);
@ -1114,37 +1106,6 @@ JSValue duk_register_collide(JSContext *js, JSValueConst this, int argc, JSValue
return JS_UNDEFINED;
}
JSValue duk_sys_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) {
int cmd = js2int(argv[0]);
switch (cmd) {
case 0:
quit();
break;
case 1:
sim_start();
cpSpaceReindexStatic(space);
break;
case 3:
sim_pause();
break;
case 4:
sim_step();
break;
case 5:
return JS_NewBool(js, sim_playing());
case 6:
return JS_NewBool(js, sim_paused());
}
return JS_UNDEFINED;
}
JSValue duk_make_gameobject(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) {
return gameobject2js(MakeGameobject());
}
@ -1465,6 +1426,9 @@ JSValue js_os_sys(JSContext *js, JSValueConst this, int argc, JSValue *argv)
return JS_UNDEFINED;
}
JSValue js_os_quit(JSContext *js, JSValueConst this) { quit(); return JS_UNDEFINED; }
JSValue js_os_reindex_static(JSContext *js, JSValueConst this) { cpSpaceReindexStatic(space); return JS_UNDEFINED; }
static const JSCFunctionListEntry js_os_funcs[] = {
MIST_FUNC_DEF(os, cwd, 0),
MIST_FUNC_DEF(os, env, 1),
@ -1481,14 +1445,28 @@ JSValue global_get_##ENTRY (JSContext *js, JSValue this) { \
return TYPE##2js(ENTRY); \
} \
GETSET_GLOBAL(physMS, number)
GETSET_GLOBAL(timescale, number)
GETSET_GLOBAL(updateMS, number)
JSValue js_prosperon_emitters_step(JSContext *js, JSValue this, int argc, JSValue *argv)
{
emitters_step(js2number(argv[0]));
return JS_UNDEFINED;
}
JSValue js_prosperon_phys2d_step(JSContext *js, JSValue this, int argc, JSValue *argv)
{
phys2d_update(js2number(argv[0]));
return JS_UNDEFINED;
}
JSValue js_prosperon_window_render(JSContext *js, JSValue this, int argc, JSValue *argv)
{
window_render(&mainwin);
return JS_UNDEFINED;
}
static const JSCFunctionListEntry js_prosperon_funcs[] = {
CGETSET_ADD(global, updateMS),
CGETSET_ADD(global, physMS),
CGETSET_ADD(global, timescale),
MIST_FUNC_DEF(prosperon, emitters_step, 1),
MIST_FUNC_DEF(prosperon, phys2d_step, 1),
MIST_FUNC_DEF(prosperon, window_render, 0)
};
JSValue js_time_now(JSContext *js, JSValue this) {
@ -1547,11 +1525,9 @@ static const JSCFunctionListEntry js_console_funcs[] = {
};
JSValue js_profile_now(JSContext *js, JSValue this) { return number2js(stm_now()); }
JSValue js_profile_fps(JSContext *js, JSValue this) { return number2js(frame_fps()); }
static const JSCFunctionListEntry js_profile_funcs[] = {
MIST_FUNC_DEF(profile,now,0),
MIST_FUNC_DEF(profile,fps,0)
};
JSValue js_io_exists(JSContext *js, JSValueConst this, int argc, JSValue *argv)
@ -1780,15 +1756,12 @@ static JSValue window_get_title(JSContext *js, JSValueConst this, JSValue v)
return str2js(js2window(this)->title);
}
GETSET_PAIR(window, editor, bool)
static const JSCFunctionListEntry js_window_funcs[] = {
CGETSET_ADD(window, size),
CGETSET_ADD(window, rendersize),
CGETSET_ADD(window, mode),
CGETSET_ADD(window, fullscreen),
CGETSET_ADD(window, title),
CGETSET_ADD(window, editor)
};
#define GETSET_PAIR_BODY(ID, ENTRY, TYPE) \
@ -2020,7 +1993,6 @@ void ffi_load() {
DUK_FUNC(make_gameobject, 0)
DUK_FUNC(set_body, 3)
DUK_FUNC(q_body, 2)
DUK_FUNC(sys_cmd, 1)
DUK_FUNC(spline_cmd, 6)
DUK_FUNC(make_circle2d, 1)
DUK_FUNC(cmd_circle2d, 6)

View file

@ -8,7 +8,6 @@
#include "time.h"
#include <stdlib.h>
#include "pthread.h"
#include "debug.h"
#include "jsffi.h"
pthread_mutex_t soundrun = PTHREAD_MUTEX_INITIALIZER;

View file

@ -5,7 +5,6 @@
#include "render.h"
#include "stb_ds.h"
#include "texture.h"
#include "timer.h"
#include "HandmadeMath.h"
#include "sprite.sglsl.h"

View file

@ -112,7 +112,6 @@ void quickjs_set_dumpout(FILE *f)
//#define DUMP_READ_OBJECT
#ifdef DUMP
#define DUMP_FREE
#define DUMP_CLOSURE
#define DUMP_GC
#define DUMP_GC_FREE

View file

@ -1,100 +0,0 @@
#include "timer.h"
#include "log.h"
#include <stdlib.h>
#include <stb_ds.h>
#include "script.h"
struct timer *timers;
static int first = -1;
void check_timer(struct timer *t, double dt) {
if (!t->on)
return;
t->remain_time -= dt;
if (t->remain_time <= 0) {
t->cb(t->data);
if (t->repeat) {
t->remain_time = t->interval;
return;
}
timer_pause(t);
return;
}
}
void timer_update(double dt, double scale) {
double sdt = dt*scale;
for (int i = 0; i < arrlen(timers); i++)
if (timers[i].app)
check_timer(&timers[i], dt);
else
check_timer(&timers[i], sdt);
}
int timer_make(double interval, void (*callback)(void *param), void *param, int own, int app) {
struct timer new;
new.remain_time = interval;
new.interval = interval;
new.cb = callback;
new.data = param;
new.repeat = 1;
new.owndata = own;
new.next = -1;
new.app = app;
if (first < 0) {
timer_start(&new);
arrput(timers, new);
return arrlen(timers) - 1;
} else {
int retid = first;
first = id2timer(first)->next;
*id2timer(retid) = new;
timer_start(id2timer(retid));
return retid;
}
}
void timer_pause(struct timer *t) {
if (!t->on) return;
t->on = 0;
}
void timer_stop(struct timer *t) {
if (!t->on) return;
t->on = 0;
t->remain_time = t->interval;
}
void timer_start(struct timer *t) {
if (t->on) return;
t->on = 1;
}
void timer_remove(int id) {
struct timer *t = id2timer(id);
// free_callee(t->data);
t->next = first;
t->on = 0;
first = id;
}
void timerr_settime(struct timer *t, double interval) {
t->remain_time += (interval - t->interval);
t->interval = interval;
}
struct timer *id2timer(int id) {
return &timers[id];
}
void timers_free()
{
// for (int i = 0; i < arrlen(timers); i++)
// if (timers[i].on)
// free_callee(timers[i].data);
}

View file

@ -1,29 +0,0 @@
#ifndef TIMER
#define TIMER
struct timer {
int timerid;
int on;
double interval; // Time of timer
int repeat;
double remain_time; // How much time until the timer executes
void (*cb)(void *data);
void *data;
int owndata;
int next;
int app; /* True if this timer is an "app" timer, and should always update; otherwise, only update with game time */
};
int timer_make(double interval, void (*callback)(void *param), void *param, int own, int app);
struct timer *id2timer(int id);
void timer_remove(int id);
void timer_start(struct timer *t);
void timer_pause(struct timer *t);
void timer_stop(struct timer *t);
void timer_update(double dt, double scale);
void timerr_settime(struct timer *t, double interval);
void timers_free();
#endif

View file

@ -20,7 +20,6 @@ struct window {
int focus;
int shown;
int mode;
int editor; // true if only should redraw on input
float aspect;
float raspect;
char *title;
@ -35,7 +34,6 @@ void window_focused(int focus);
void window_iconified(int s);
void window_suspended(int s);
void window_apply(window *w);
void window_free(window *w);

View file

@ -1,7 +1,5 @@
#include "yugine.h"
#include "font.h"
#include "transform.h"
#include "gameobject.h"
#include "input.h"
#include "render.h"
#include "window.h"
@ -14,7 +12,6 @@
#include "datastream.h"
#include "timer.h"
#include "quickjs/quickjs.h"
#include "jsffi.h"
@ -52,27 +49,9 @@
#include "stb_image_write.h"
#include <pl_mpeg.h>
#include "debug.h"
static struct d_prof prof_draw;
static struct d_prof prof_update;
static struct d_prof prof_input;
static struct d_prof prof_physics;
double physlag = 0;
double physMS = 1 / 60.f;
uint64_t physlast = 0;
double updateMS = 1/60.f;
uint64_t updatelast = 0;
static int phys_step = 0;
uint64_t start_t;
uint64_t frame_t;
double timescale = 1.f;
#define SIM_PLAY 0
#define SIM_PAUSE 1
#define SIM_STEP 2
@ -83,11 +62,11 @@ static int argc;
static char **args;
static JSValue c_init_fn;
static JSValue c_process_fn;
void c_init() {
mainwin.start = 1;
window_resize(sapp_width(), sapp_height());
script_evalf("world_start();");
render_init();
window_set_icon("icons/moon.gif");
@ -97,53 +76,7 @@ void c_init() {
script_call_sym(c_init_fn,0,NULL);
}
int frame_fps() { return 1.0/sapp_frame_duration(); }
static void process_frame()
{
script_call_sym(c_process_fn,0,NULL);
double elapsed = stm_sec(stm_laptime(&frame_t));
script_evalf("prosperon.appupdate(%g);", elapsed);
/* Timers all update every frame - once per monitor refresh */
timer_update(elapsed, timescale);
emitters_step(elapsed);
if (sim_play == SIM_PLAY || sim_play == SIM_STEP) {
if (stm_sec(stm_diff(frame_t, updatelast)) > updateMS) {
double dt = stm_sec(stm_diff(frame_t, updatelast));
updatelast = frame_t;
// prof_start(&prof_update);
script_evalf("prosperon.update(%g);", dt*timescale);
// prof_lap(&prof_update);
if (sim_play == SIM_STEP)
sim_pause();
}
physlag += elapsed;
while (physlag > physMS) {
physlag -= physMS;
// prof_start(&prof_physics);
phys_step = 1;
phys2d_update(physMS * timescale);
script_evalf("prosperon.physupdate(%g);", physMS*timescale);
phys_step = 0;
// prof_lap(&prof_physics);
}
}
// prof_start(&prof_draw);
window_render(&mainwin);
// prof_lap(&prof_draw);
}
void c_frame()
{
if (mainwin.editor) return;
process_frame();
}
void c_frame() { script_call_sym(c_process_fn,0,NULL); }
void cleanup()
{
@ -252,18 +185,8 @@ void c_event(const sapp_event *e)
default:
break;
}
if (mainwin.editor)
process_frame();
}
int sim_playing() { return sim_play == SIM_PLAY; }
int sim_paused() { return sim_play == SIM_PAUSE; }
void sim_start() { sim_play = SIM_PLAY; }
void sim_pause() { sim_play = SIM_PAUSE; }
int phys_stepping() { return sim_play == SIM_STEP; }
void sim_step() { sim_play = SIM_STEP; }
static sapp_desc start_desc = {
.width = 720,
.height = 1080,
@ -290,8 +213,6 @@ int main(int argc, char **argv) {
signal(SIGSEGV, seghandle);
signal(SIGABRT, seghandle);
signal(SIGFPE, seghandle);
// signal(SIGBUS, seghandle);
#endif
resources_init();
@ -328,8 +249,6 @@ void engine_start(JSValue fn, JSValue procfn)
c_init_fn = fn;
c_process_fn = procfn;
start_t = frame_t = stm_now();
physlast = updatelast = start_t;
sound_init();
phys2d_init();
@ -340,7 +259,7 @@ void engine_start(JSValue fn, JSValue procfn)
sapp_run(&start_desc);
}
double apptime() { return stm_sec(stm_diff(stm_now(), start_t)); }
double apptime() { return stm_sec(stm_now()); }
void quit() {
if (mainwin.start)

View file

@ -3,22 +3,11 @@
#include "script.h"
int sim_playing();
int sim_paused();
void sim_start();
void sim_pause();
void sim_stop();
void sim_step();
int phys_stepping();
double apptime();
void print_stacktrace();
void engine_start(JSValue fn, JSValue proc_fn); /* fn runs after the engine starts */
int frame_fps();
void quit();
double apptime();
extern double timescale;
extern double renderMS;
extern double physMS;
extern double updateMS;
#endif