From a57aaeb5d5c0697048ddc0f0567319f17f6f1d2b Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Tue, 19 Sep 2023 17:35:12 +0000 Subject: [PATCH] Windows now compiles with directx; separated out ur and entity methods --- Makefile | 12 +++-- docs/game.md | 15 +++++- scripts/base.js | 5 ++ scripts/editor.js | 11 ++++- scripts/engine.js | 9 +++- scripts/entity.js | 102 +++++++++++++++++++++++------------------ source/engine/ffi.c | 2 +- source/engine/render.c | 10 ---- source/engine/render.h | 2 +- source/engine/yugine.c | 23 ++++------ source/engine/yugine.h | 3 +- 11 files changed, 115 insertions(+), 79 deletions(-) diff --git a/Makefile b/Makefile index 051924fd..2d9a2441 100755 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ MAKEFLAGS = --jobs=4 UNAME != uname -nMAKEDIR != pwd +MAKEDIR != pwd # Options # DBG --- build with debugging symbols and logging @@ -71,7 +71,7 @@ ARCH = x64 ifeq ($(OS), Windows_NT) LDFLAGS += -mwin32 -static CFLAGS += -mwin32 - LDLIBS += mingw32 kernel32 opengl32 user32 shell32 dxgi gdi32 ws2_32 ole32 winmm setupapi m + LDLIBS += mingw32 kernel32 d3d11 user32 shell32 dxgi gdi32 ws2_32 ole32 winmm setupapi m EXT = .exe PLAT = w64 PKGCMD = cd $(BIN); zip -q -r $(MAKEDIR)/$(DISTDIR)/$(DIST) . -x \*.a ./obj/\* @@ -142,11 +142,12 @@ SHADERS = $(shell ls source/shaders/*.sglsl) SHADERS := $(patsubst %.sglsl, %.sglsl.h, $(SHADERS)) install: $(BIN)/$(NAME) - cp $(BIN)/$(NAME) $(DESTDIR) + cp -f $(BIN)/$(NAME) $(DESTDIR) $(BIN)/$(NAME): $(BIN)/libengine.a $(BIN)/libquickjs.a $(BIN)/libcdb.a @echo Linking $(NAME) $(LD) $^ $(LDFLAGS) -L$(BIN) $(LDLIBS) -o $@ + cp $(BIN)/$(NAME) . @echo Finished build $(DISTDIR)/$(DIST): $(BIN)/$(NAME) @@ -207,6 +208,11 @@ jso: tools/jso.c $(BIN)/libquickjs.a @echo Making $@ from $< ./jso $< > $@ +WINCC = x86_64-w64-mingw32-gcc +.PHONY: crosswin +crosswin: + make CC=$(WINCC) OS=Windows_NT + clean: @echo Cleaning project @rm -rf bin dist diff --git a/docs/game.md b/docs/game.md index c33a8656..a0dc273b 100644 --- a/docs/game.md +++ b/docs/game.md @@ -42,7 +42,7 @@ In edit mode, there are no running scripts; only editing them. There are two distinct items in the Primum Machina: the Entity, and the Component. Components give qualities to Entities. An Entity is any real, tangible thing in the universe, and so every entity has a position. Components do not necessarily have a position; they can be things like the image that draws where the entity is located, and colliders that allow the entity to respond with the world. ### Components -The most "bare metal" are the components. These are essentially hooks into the engine that tell it how to do particular things. For example, to render a sprite, Javascript does no rendering, but rather tells the engine to create an image and render it in a particular spot. +The most "bare metal" are the components. These are essentially hooks into the engine that tell it how to do particular things. For example, to render a sprite, Javascript does no rendering, but rather tells the engine to create an image and render it in a particular spot. Javascript does the accounting to make or destroy the sprite as needed - but besides that initial startup, no scripting is done. Components are rendered in an "ECS" style. To work, components must be installed on an entity. They have no meaning outside of a physical object in the world. @@ -62,7 +62,7 @@ All objects follow the prototyping model of inheritence. This makes it trivial t Components cannot be prototyped. They are fundamentally tied to the entity they are bound to. -Entities can be prototyped out. What this means is that, when you select an object in the game, you can either make a "subtype" of it, where changes to the object trickle down to the created one, or a "sidetype" of it, which is a total duplicate of the object. +Entities can be prototyped out. What this means is that, when you select an object in the game, you can either make a "subtype" of it, where changes to the object trickle down to the created one, or a "sidetype" of it, which is a total duplicate of the object. Javascript handled creating entites with components that have your saved values. entity.clone(parent) -> create a subtyped version of the entity entity.dup(parent) -> create a copy of the entity. @@ -79,6 +79,17 @@ Only first Ur-types can have components. Every inherited thing after it can only Ur-types also remember the list of entities that compose the given Ur. +Visually it looks like this: + +Ur-ur, the thing all Ur-types derive from + - Ur-type 1, defined in script, with components + - Variant 1, same component combination but different values + - Variant 2, other different values + - Variant 2A, overwritten values from Variant 2 + - Ur-type 2 + +All ur-types and variants can be created in the world, where they become a true blue ENTITY. Entities can be under entities infinitely. + ### Loading traits Traits are defined by code and a data file. When an Ur-type is extended with a trait, the code is run, and then the data file contains modifications and diff --git a/scripts/base.js b/scripts/base.js index d46aa1c4..0c28ac4f 100644 --- a/scripts/base.js +++ b/scripts/base.js @@ -24,6 +24,11 @@ Object.defineProperty(Object.prototype, 'getOwnPropertyDescriptors', { } }); +Object.defHidden = function(obj, prop) +{ + Object.defineProperty(obj, prop, {enumerable:false, writable:true}); +} + Object.defineProperty(Object.prototype, 'obscure', { value: function(name) { Object.defineProperty(this, name, { enumerable: false }); diff --git a/scripts/editor.js b/scripts/editor.js index 48614735..6a654e1f 100644 --- a/scripts/editor.js +++ b/scripts/editor.js @@ -762,7 +762,15 @@ editor.inputs['C-d'] = function() { }; editor.inputs['C-d'].doc = "Duplicate all selected objects."; -editor.inputs.f3 = function() { editor.selectlist.forEach(x => Log.say(JSON.stringify(x,null,2))); }; +editor.inputs.f3 = function() { + Log.say("Selected JSON ..."); + editor.selectlist.forEach(x => Log.say(JSON.stringify(x,null,2))); + Log.say("UR JSON ..."); + for (var key of Object.keys(editor.selectlist[0].ur.type)) + Log.say(key); + + editor.selectlist.forEach(x => Log.say(JSON.stringify(x.ur.type,null,2))); +}; editor.inputs['C-m'] = function() { if (editor.sel_comp) { @@ -1922,3 +1930,4 @@ if (IO.exists("editor.config")) editor.clear_level(); editor.camera = Game.camera; Game.stop(); +Game.editor_mode(false); diff --git a/scripts/engine.js b/scripts/engine.js index 34073445..9a145cb6 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -510,7 +510,7 @@ var Game = { sys_cmd(4); }, - render() { sys_cmd(10); }, + editor_mode(m) { sys_cmd(10, m); }, playing() { return sys_cmd(5); }, paused() { return sys_cmd(6); }, @@ -554,6 +554,13 @@ gameobject.make_parentable(Primum); Primum.tag = "PRIMUM"; Primum.selectable = false; Primum.ur = { tag: "Primum" }; +Primum.spawn = function(ur) { + if (typeof ur === 'string') + ur = prototypes.get_ur(ur); + + return ur.type.make(this); + }; + /* Reparent this object to a new one */ World.reparent = function(parent) { Log.warn("Cannot reparent the Primum."); } World.unparent = function() { Log.warn("The Primum has no parent, always."); } diff --git a/scripts/entity.js b/scripts/entity.js index ad966a40..8df3f435 100644 --- a/scripts/entity.js +++ b/scripts/entity.js @@ -15,13 +15,7 @@ var gameobject = { save: true, selectable: true, - spawn(ur) { - if (typeof ur === 'string') - ur = prototypes.get_ur(ur); - - return ur.type.make(this); - }, - + /* Make a duplicate of this exact object */ clone(name, ext) { var obj = Object.create(this); complete_assign(obj, ext); @@ -113,37 +107,12 @@ var gameobject = { gizmo: "", /* Path to an image to draw for this gameobject */ - /* Bounding box of the object in world dimensions */ + /* Bounding box of the ur, if it were to be spawned */ boundingbox() { - var boxes = []; - boxes.push({t:0, r:0,b:0,l:0}); - for (var key in this.components) { - if ('boundingbox' in this.components[key]) - boxes.push(this.components[key].boundingbox()); - } - - if (boxes.empty) return cwh2bb([0,0], [0,0]); - - var bb = boxes[0]; - - boxes.forEach(function(x) { - bb = bb_expand(bb, x); - }); - - var cwh = bb2cwh(bb); - - if (!bb) return; - - if (this.flipx) cwh.c.x *= -1; - if (this.flipy) cwh.c.y *= -1; - - cwh.c = cwh.c.add(this.pos); - bb = cwh2bb(cwh.c, cwh.wh); - - return bb ? bb : cwh2bb([0,0], [0,0]); }, + width() { var bb = this.boundingbox(); return bb.r - bb.l; @@ -204,7 +173,8 @@ var gameobject = { make(level) { level ??= Primum; var obj = Object.create(this); - this.instances.push(obj); +// this.instances.push(obj); +// obj.ur = this; obj.toString = function() { if (obj.ur) return obj.ur.tag; @@ -272,6 +242,45 @@ var gameobject = { sync() { }, dirty() { return false; }, + spawn(ur) { + if (typeof ur === 'string') + ur = prototypes.get_ur(ur); + + return ur.type.make(this); + }, + + + /* Bounding box of the object in world dimensions */ + boundingbox() { + var boxes = []; + boxes.push({t:0, r:0,b:0,l:0}); + + for (var key in this.components) { + if ('boundingbox' in this.components[key]) + boxes.push(this.components[key].boundingbox()); + } + + if (boxes.empty) return cwh2bb([0,0], [0,0]); + + var bb = boxes[0]; + + boxes.forEach(function(x) { + bb = bb_expand(bb, x); + }); + + var cwh = bb2cwh(bb); + + if (!bb) return; + + if (this.flipx) cwh.c.x *= -1; + if (this.flipy) cwh.c.y *= -1; + + cwh.c = cwh.c.add(this.pos); + bb = cwh2bb(cwh.c, cwh.wh); + + return bb ? bb : cwh2bb([0,0], [0,0]); + }, + dup(diff) { var dup = Primum.spawn(this.ur); Object.assign(dup, this); @@ -312,7 +321,9 @@ var gameobject = { down() { return [0,-1].rotate(Math.deg2rad(this.angle));}, right() { return [1,0].rotate(Math.deg2rad(this.angle));}, left() { return [-1,0].rotate(Math.deg2rad(this.angle));}, - + + /* Given an ur-type, spawn one attached to us */ + toJSON() { var ret = {}; for (var key in this) { @@ -371,6 +382,7 @@ var gameobject = { gameobject.make_parentable = function(obj) { var objects = []; + Object.defHidden(obj, 'level'); obj.remove_child = function(child) { objects.remove(child); @@ -434,19 +446,20 @@ prototypes.from_file = function(file) return; } - var newobj = gameobject.clone(file, {}); + var newur = gameobject.clone(file, {}); var script = IO.slurp(file); - newobj.$ = {}; + Object.defHidden(newur, '$'); + newur.$ = {}; var json = {}; if (IO.exists(file.name() + ".json")) { json = JSON.parse(IO.slurp(file.name() + ".json")); - Object.assign(newobj.$, json.$); + Object.assign(newur.$, json.$); delete json.$; } - compile_env(`var self = this; var $ = self.$; ${script}`, newobj, file); - dainty_assign(newobj, json); + compile_env(`var self = this; var $ = self.$; ${script}`, newur, file); + dainty_assign(newur, json); file = file.replaceAll('/', '.'); var path = file.name().split('.'); @@ -457,12 +470,13 @@ prototypes.from_file = function(file) return base; }; var a = nested_access(ur, path); - + Object.defHidden(a, 'instances'); + a.instances = []; a.tag = file.name(); prototypes.list.push(a.tag); - a.type = newobj; + a.type = newur; a.instances = []; - newobj.ur = a; +// newur.ur = a; return a; } diff --git a/source/engine/ffi.c b/source/engine/ffi.c index 3128cb21..544e3145 100644 --- a/source/engine/ffi.c +++ b/source/engine/ffi.c @@ -1249,7 +1249,7 @@ JSValue duk_sys_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *ar break; case 10: - render_dirty = 1; + editor_mode = js2bool(argv[1]); break; } diff --git a/source/engine/render.c b/source/engine/render.c index d3777ca8..95393e1b 100644 --- a/source/engine/render.c +++ b/source/engine/render.c @@ -430,15 +430,6 @@ void full_2d_pass(struct window *window) //////////// 2D projection cpVect pos = cam_pos(); -#if defined SOKOL_GLCORE33 || defined SOKOL_GLES3 - projection = HMM_Orthographic_RH_ZO( - pos.x - zoom * window->rwidth / 2, - pos.x + zoom * window->rwidth / 2, - pos.y + zoom * window->rheight / 2, - pos.y - zoom * window->rheight / 2, -1.f, 1.f); - - hudproj = HMM_Orthographic_RH_ZO(0, window->width, window->height, 0, -1.f, 1.f); -#else projection = HMM_Orthographic_LH_ZO( pos.x - zoom * window->rwidth / 2, pos.x + zoom * window->rwidth / 2, @@ -446,7 +437,6 @@ void full_2d_pass(struct window *window) pos.y + zoom * window->rheight / 2, -1.f, 1.f); hudproj = HMM_Orthographic_LH_ZO(0, window->rwidth, 0, window->rheight, -1.f, 1.f); -#endif sprite_draw_all(); call_draw(); diff --git a/source/engine/render.h b/source/engine/render.h index 5b42815b..418fcd30 100644 --- a/source/engine/render.h +++ b/source/engine/render.h @@ -6,7 +6,7 @@ #elif __EMSCRIPTEN__ #define SOKOL_GLES3 #elif __WIN32 - #define SOKOL_GLCORE33 + #define SOKOL_D3D11 #define SOKOL_WIN32_FORCE_MAIN #elif __APPLE__ #define SOKOL_METAL diff --git a/source/engine/yugine.c b/source/engine/yugine.c index 1075f386..414fa4b6 100644 --- a/source/engine/yugine.c +++ b/source/engine/yugine.c @@ -58,7 +58,6 @@ static struct d_prof prof_input; static struct d_prof prof_physics; double physlag = 0; -int render_dirty = 0; double physMS = 1 / 60.f; @@ -74,6 +73,8 @@ static float timescale = 1.f; static int sim_play = SIM_PLAY; +static int editor_mode = 0; + #ifdef __TINYC__ int backtrace(void **buffer, int size) { extern uint64_t *__libc_stack_end; @@ -168,25 +169,21 @@ static void process_frame() prof(&prof_physics); } - if (sim_play == SIM_STEP) { + if (sim_play == SIM_STEP) sim_pause(); - render_dirty = 1; - } } - if (sim_play == SIM_PLAY || render_dirty) { - prof_start(&prof_draw); - window_render(&mainwin); - prof(&prof_draw); - render_dirty = 0; - } + prof_start(&prof_draw); + window_render(&mainwin); + prof(&prof_draw); + gameobjects_cleanup(); } void c_frame() { - if (sim_play != SIM_PLAY) return; + if (editor_mode) return; process_frame(); } @@ -196,8 +193,6 @@ void c_clean() { void c_event(const sapp_event *e) { - render_dirty = 1; - #ifndef NO_EDITOR snk_handle_event(e); #endif @@ -260,7 +255,7 @@ void c_event(const sapp_event *e) break; } - if (sim_play != SIM_PLAY) + if (editor_mode) process_frame(); } diff --git a/source/engine/yugine.h b/source/engine/yugine.h index 72b45644..13c77ff3 100644 --- a/source/engine/yugine.h +++ b/source/engine/yugine.h @@ -21,6 +21,5 @@ extern double appTime; extern double renderMS; extern double physMS; extern double updateMS; -extern int render_dirty; - +extern int editor_mode; #endif