do-OOP engine. fix entity tag caching
parent
4a21ff6ef1
commit
b195b95585
105
src/Engine.zig
105
src/Engine.zig
|
|
@ -1,5 +1,3 @@
|
||||||
const Engine = @This();
|
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Recti = @import("geometry/Recti.zig");
|
const Recti = @import("geometry/Recti.zig");
|
||||||
const Matrix4f = @import("geometry/Matrix4f.zig");
|
const Matrix4f = @import("geometry/Matrix4f.zig");
|
||||||
|
|
@ -17,52 +15,50 @@ const c = @cImport({
|
||||||
});
|
});
|
||||||
const AutoHashMap = std.AutoHashMap;
|
const AutoHashMap = std.AutoHashMap;
|
||||||
|
|
||||||
var store: AutoHashMap(*c.GLFWwindow, *Engine) = AutoHashMap(*c.GLFWwindow, *Engine).init(std.heap.page_allocator);
|
const Error = error {
|
||||||
|
WindowNotInitialized,
|
||||||
|
WindowAlreadyInitialized,
|
||||||
|
NoScene,
|
||||||
|
AlreadyRunning
|
||||||
|
};
|
||||||
|
|
||||||
// export const IGame = struct {
|
var window: ?*c.GLFWwindow = null;
|
||||||
// render: fn () void,
|
var current_scene: ?Scene = null;
|
||||||
// update: fn (f32) void,
|
var next_scene: ?Scene = null;
|
||||||
// };
|
var projection: Matrix4f = undefined;
|
||||||
current_scene: Scene,
|
|
||||||
projection: Matrix4f = undefined,
|
|
||||||
|
|
||||||
pub fn create(initial_scene: Scene) Engine {
|
fn glfw_on_error(err: c_int, desc_c: [*c]const u8) callconv(.C) void {
|
||||||
return .{
|
|
||||||
.current_scene = initial_scene
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn errorCallback(err: c_int, desc_c: [*c]const u8) callconv(.C) void {
|
|
||||||
const desc: *const u8 = @ptrCast(desc_c);
|
const desc: *const u8 = @ptrCast(desc_c);
|
||||||
std.log.err("glfw error {x:0>8}: {s}", .{ err, desc });
|
std.log.err("[Engine:glfw_on_error] glfw error {x:0>8}: {s}", .{ err, desc });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_resize (window: ?*c.GLFWwindow, width: c_int, height: c_int) callconv(.C) void {
|
fn glfw_on_resize (_: ?*c.GLFWwindow, width: c_int, height: c_int) callconv(.C) void {
|
||||||
std.debug.print("[Engine:on_resize] {?}: {d} x {d}\n", .{ window, width, height });
|
std.debug.print("[Engine:glfw_on_resize] {?}: {d} x {d}\n", .{ window, width, height });
|
||||||
c.glViewport(0, 0, width, height);
|
c.glViewport(0, 0, width, height);
|
||||||
const engine_instance = store.get(window.?).?;
|
projection = Matrix4f.orthographic(0, @floatFromInt(width), @floatFromInt(height), 0, 0, 100);
|
||||||
engine_instance.set_matrices(width, height);
|
shaders.set_projection_matrix(&projection);
|
||||||
engine_instance.current_scene.resize(width, height);
|
if (current_scene != null) current_scene.?.resize(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_matrices(self: *Engine, width: i32, height: i32) void {
|
fn get_size() struct { i32, i32 } {
|
||||||
self.projection = Matrix4f.orthographic(0, @floatFromInt(width), @floatFromInt(height), 0, 0, 100);
|
var width: c_int = undefined;
|
||||||
shaders.set_projection_matrix(&self.projection);
|
var height: c_int = undefined;
|
||||||
|
c.glfwGetFramebufferSize(window, @ptrCast(&width), @ptrCast(&height));
|
||||||
|
return .{ width, height };
|
||||||
}
|
}
|
||||||
|
|
||||||
// export fn run(game: *const IGame) !void {
|
pub fn setup() !void {
|
||||||
pub fn run(self: *Engine) !void {
|
if (window != null) return Error.WindowAlreadyInitialized;
|
||||||
|
|
||||||
// in case of errors, set callback early!
|
// in case of errors, set callback early!
|
||||||
// for some reason this returns an error function as well??
|
// for some reason this returns an error function as well??
|
||||||
_ = c.glfwSetErrorCallback(errorCallback);
|
_ = c.glfwSetErrorCallback(glfw_on_error);
|
||||||
|
|
||||||
// initialize glfw capabilities & cleanup
|
// initialize glfw capabilities & cleanup
|
||||||
if (c.glfwInit() != 1) {
|
if (c.glfwInit() != 1) {
|
||||||
std.log.err("Failed to init glfw", .{});
|
std.log.err("Failed to init glfw", .{});
|
||||||
return error.Initialization;
|
return error.Initialization;
|
||||||
}
|
}
|
||||||
defer c.glfwTerminate();
|
|
||||||
|
|
||||||
// ensure glfw knows what we're about
|
// ensure glfw knows what we're about
|
||||||
// c.glfwWindowHint(c.GLFW_CONTEXT_VERSION_MAJOR, 3);
|
// c.glfwWindowHint(c.GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||||
|
|
@ -72,13 +68,10 @@ pub fn run(self: *Engine) !void {
|
||||||
// c.glfwWindowHint(c.GLFW_OPENGL_PROFILE, c.GLFW_OPENGL_CORE_PROFILE);
|
// c.glfwWindowHint(c.GLFW_OPENGL_PROFILE, c.GLFW_OPENGL_CORE_PROFILE);
|
||||||
|
|
||||||
// create the window & cleanup
|
// create the window & cleanup
|
||||||
const window = c.glfwCreateWindow(640, 480, "My Title", null, null) orelse {
|
window = c.glfwCreateWindow(1920, 1080, "My Title", null, null) orelse {
|
||||||
std.log.err("Failed to open window", .{});
|
std.log.err("Failed to open window", .{});
|
||||||
return error.Initialization;
|
return error.Initialization;
|
||||||
};
|
};
|
||||||
defer c.glfwDestroyWindow(window);
|
|
||||||
|
|
||||||
try store.put(window, self);
|
|
||||||
|
|
||||||
// load opengl into the window
|
// load opengl into the window
|
||||||
c.glfwMakeContextCurrent(window);
|
c.glfwMakeContextCurrent(window);
|
||||||
|
|
@ -92,11 +85,9 @@ pub fn run(self: *Engine) !void {
|
||||||
|
|
||||||
// compile shaders...
|
// compile shaders...
|
||||||
try shaders.load();
|
try shaders.load();
|
||||||
|
|
||||||
try assets.load();
|
try assets.load();
|
||||||
|
|
||||||
_ = c.glfwSetWindowSizeCallback(window, on_resize);
|
_ = c.glfwSetWindowSizeCallback(window, glfw_on_resize);
|
||||||
|
|
||||||
|
|
||||||
const clearBrightness: f32 = 0.09;
|
const clearBrightness: f32 = 0.09;
|
||||||
c.glClearColor(clearBrightness, clearBrightness, clearBrightness, 1.0);
|
c.glClearColor(clearBrightness, clearBrightness, clearBrightness, 1.0);
|
||||||
|
|
@ -107,23 +98,47 @@ pub fn run(self: *Engine) !void {
|
||||||
c.glEnable(c.GL_DEPTH_TEST);
|
c.glEnable(c.GL_DEPTH_TEST);
|
||||||
c.glDepthFunc(c.GL_LEQUAL);
|
c.glDepthFunc(c.GL_LEQUAL);
|
||||||
c.glDepthMask(c.GL_TRUE);
|
c.glDepthMask(c.GL_TRUE);
|
||||||
|
|
||||||
|
const width, const height = get_size();
|
||||||
|
c.glViewport(0, 0, width, height);
|
||||||
|
projection = Matrix4f.orthographic(0, @floatFromInt(width), @floatFromInt(height), 0, 0, 100);
|
||||||
|
shaders.set_projection_matrix(&projection);
|
||||||
|
}
|
||||||
|
|
||||||
var width: c_int = undefined;
|
pub fn destroy() void {
|
||||||
var height: c_int = undefined;
|
c.glfwDestroyWindow(window);
|
||||||
c.glfwGetFramebufferSize(window, @ptrCast(&width), @ptrCast(&height));
|
c.glfwTerminate();
|
||||||
std.debug.print("[Engine:run] window size {d} x {d}\n", .{ width, height });
|
}
|
||||||
self.set_matrices(width, height);
|
|
||||||
try self.current_scene.start();
|
pub fn set_scene(scene: Scene) void {
|
||||||
|
next_scene = scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run() Error!void {
|
||||||
|
if (window == null) return Error.WindowNotInitialized;
|
||||||
|
if (current_scene != null) return Error.AlreadyRunning;
|
||||||
|
if (next_scene == null) return Error.NoScene;
|
||||||
|
|
||||||
// run the main loop
|
// run the main loop
|
||||||
while (c.glfwWindowShouldClose(window) == 0) {
|
while (c.glfwWindowShouldClose(window) == 0) {
|
||||||
|
// switch scenes if need be
|
||||||
|
if (next_scene != null) {
|
||||||
|
if (current_scene != null) current_scene.?.destroy();
|
||||||
|
current_scene = next_scene;
|
||||||
|
next_scene = null;
|
||||||
|
// start our scene
|
||||||
|
try current_scene.?.start();
|
||||||
|
// and send it the appropriate resize.
|
||||||
|
const width, const height = get_size();
|
||||||
|
current_scene.?.resize(width, height);
|
||||||
|
}
|
||||||
|
// setup for drawing
|
||||||
c.glClear(c.GL_COLOR_BUFFER_BIT | c.GL_DEPTH_BUFFER_BIT);
|
c.glClear(c.GL_COLOR_BUFFER_BIT | c.GL_DEPTH_BUFFER_BIT);
|
||||||
self.current_scene.draw();
|
current_scene.?.draw();
|
||||||
assets.terrain[0][0].draw(Recti.from_xywh(-1000, -1000, 50000, 50000), Layer.FLOOR, Color.WHITE);
|
|
||||||
|
|
||||||
c.glfwSwapBuffers(window);
|
c.glfwSwapBuffers(window);
|
||||||
c.glfwPollEvents();
|
c.glfwPollEvents();
|
||||||
|
|
||||||
self.current_scene.update(0.0042);
|
current_scene.?.update(0.0042);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,13 +11,15 @@ const std = @import("std");
|
||||||
const ArrayList = std.ArrayList;
|
const ArrayList = std.ArrayList;
|
||||||
const AutoHashMap = std.AutoHashMap;
|
const AutoHashMap = std.AutoHashMap;
|
||||||
|
|
||||||
|
// cache and list bothe store entities. treat entities as fat pointers.
|
||||||
|
// Pointers into an arraylist WILL become invalid.
|
||||||
entities: ArrayList(Entity) = undefined,
|
entities: ArrayList(Entity) = undefined,
|
||||||
tagged_entities: AutoHashMap(Tag.ID, *Entity) = undefined,
|
tagged_entities: AutoHashMap(Tag.ID, Entity) = undefined,
|
||||||
|
|
||||||
pub fn create() Scene {
|
pub fn create() Scene {
|
||||||
var self = Scene {};
|
var self = Scene {};
|
||||||
self.entities = ArrayList(Entity).init(std.heap.page_allocator);
|
self.entities = ArrayList(Entity).init(std.heap.page_allocator);
|
||||||
self.tagged_entities = AutoHashMap(Tag.ID, *Entity).init(std.heap.page_allocator);
|
self.tagged_entities = AutoHashMap(Tag.ID, Entity).init(std.heap.page_allocator);
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -32,33 +34,22 @@ pub fn start(self: *Scene) !void {
|
||||||
std.debug.print("[Scene:start] Scene starting...\n", .{});
|
std.debug.print("[Scene:start] Scene starting...\n", .{});
|
||||||
std.debug.print("[Scene:start] entities: {}\n", .{ self.entities.items.len });
|
std.debug.print("[Scene:start] entities: {}\n", .{ self.entities.items.len });
|
||||||
std.debug.print("[Scene:start] tagged entities: {}\n", .{ self.tagged_entities.count() });
|
std.debug.print("[Scene:start] tagged entities: {}\n", .{ self.tagged_entities.count() });
|
||||||
|
var tagged_entities_iterator = self.tagged_entities.iterator();
|
||||||
|
while (tagged_entities_iterator.next()) |entry| {
|
||||||
|
std.debug.print("[Scene:start] - {s}: {*}\n", .{ entry.key_ptr.*, entry.value_ptr });
|
||||||
|
}
|
||||||
for (self.entities.items) |entity| {
|
for (self.entities.items) |entity| {
|
||||||
entity.start(self);
|
entity.start(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(self: *const Scene, tag: Tag, comptime T: type) *T {
|
pub fn get(self: *const Scene, tag: Tag, comptime T: type) *T {
|
||||||
|
if (tag.id == Tag.NONE.id) @panic("Cannot find by Tag.NONE");
|
||||||
const tag_id = tag.id;
|
const tag_id = tag.id;
|
||||||
const entity_ptr: *Entity = self.tagged_entities.get(tag_id) orelse @panic("Could not find entity");
|
const entity: Entity = self.tagged_entities.get(tag_id) orelse @panic("Could not find entity");
|
||||||
// @compileLog(entity_ptr);
|
const opaque_ptr = entity.ptr;
|
||||||
const opaque_ptr = entity_ptr.ptr;
|
|
||||||
const real_ptr: *T = @ptrCast(@alignCast(opaque_ptr));
|
const real_ptr: *T = @ptrCast(@alignCast(opaque_ptr));
|
||||||
return real_ptr;
|
return real_ptr;
|
||||||
// var iterator = self.tagged_entities.iterator();
|
|
||||||
// while (iterator.next()) |entry| {
|
|
||||||
// const id_ptr: *Tag.ID = entry.key_ptr;
|
|
||||||
// const entity_ptr_ptr: **Entity = entry.value_ptr;
|
|
||||||
// const entity_ptr: *Entity = entity_ptr_ptr.*;
|
|
||||||
//
|
|
||||||
// const other_id = entity_ptr.tag.id;
|
|
||||||
// if (tag_id == other_id) {
|
|
||||||
// const opaque_ptr: *anyopaque = entity_ptr.ptr;
|
|
||||||
// const real_ptr: *T = @ptrCast(@alignCast(opaque_ptr));
|
|
||||||
// // @compileLog(r);
|
|
||||||
// return real_ptr;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// @panic("Could not find entity");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(self: *Scene, instance_ptr: anytype) !void {
|
pub fn add(self: *Scene, instance_ptr: anytype) !void {
|
||||||
|
|
@ -81,13 +72,11 @@ pub fn add(self: *Scene, instance_ptr: anytype) !void {
|
||||||
if (!@hasDecl(instance_type, "entity"))
|
if (!@hasDecl(instance_type, "entity"))
|
||||||
@compileError("Pointer must be to a struct with fn entity() Entity");
|
@compileError("Pointer must be to a struct with fn entity() Entity");
|
||||||
|
|
||||||
|
// again, entities are fat pointers. they are okay to be copied
|
||||||
const entity: Entity = instance_ptr.entity();
|
const entity: Entity = instance_ptr.entity();
|
||||||
|
try self.entities.append(entity);
|
||||||
const entity_ptr = try self.entities.addOne();
|
if (entity.tag.id != Tag.NONE.id) {
|
||||||
entity_ptr.* = entity;
|
try self.tagged_entities.put(entity.tag.id, entity);
|
||||||
|
|
||||||
if (entity_ptr.tag.id != Tag.NONE.id) {
|
|
||||||
try self.tagged_entities.put(entity.tag.id, entity_ptr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ const scenes = @import("scenes.zig");
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
// engine.preload(assets.load);
|
// engine.preload(assets.load);
|
||||||
var engine = Engine.create(try scenes.game());
|
try Engine.setup();
|
||||||
try engine.run();
|
Engine.set_scene(try scenes.game());
|
||||||
|
try Engine.run();
|
||||||
|
Engine.destroy();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,9 @@ pub fn game() !Scene {
|
||||||
// second try is for allocating terrain on the heap...
|
// second try is for allocating terrain on the heap...
|
||||||
try scene.add(try Camera.create());
|
try scene.add(try Camera.create());
|
||||||
try scene.add(try Terrain.create(123));
|
try scene.add(try Terrain.create(123));
|
||||||
try scene.add(try Pawn.random());
|
for (0..5) |_| {
|
||||||
|
try scene.add(try Pawn.random());
|
||||||
|
}
|
||||||
|
|
||||||
return scene;
|
return scene;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue