Add game_init_window, separate window and game hot reload

This commit is contained in:
sergeypdev 2024-01-30 17:34:43 +04:00
parent 8d397f3941
commit 0390109ff4
No known key found for this signature in database
2 changed files with 135 additions and 47 deletions

View File

@ -1,14 +1,62 @@
const std = @import("std");
const c = @import("c.zig");
pub const InitMemory = struct {
global_allocator: std.mem.Allocator,
window: *c.SDL_Window,
context: ?*anyopaque,
some_var: i32 = 0,
};
pub const GameMemory = struct {
global_allocator: std.mem.Allocator,
counter: i32 = 0,
};
var g_init: *InitMemory = undefined;
var g_mem: *GameMemory = undefined;
fn game_init_window_err(global_allocator: std.mem.Allocator) !void {
try sdl_try(c.SDL_Init(c.SDL_INIT_EVERYTHING));
try sdl_try(c.SDL_GL_SetAttribute(c.SDL_GL_DOUBLEBUFFER, 1));
try sdl_try(c.SDL_GL_SetAttribute(c.SDL_GL_CONTEXT_MAJOR_VERSION, 4));
try sdl_try(c.SDL_GL_SetAttribute(c.SDL_GL_CONTEXT_MINOR_VERSION, 1));
try sdl_try(c.SDL_GL_SetAttribute(c.SDL_GL_CONTEXT_PROFILE_MASK, c.SDL_GL_CONTEXT_PROFILE_CORE));
const maybe_window = c.SDL_CreateWindow("Learn OpenGL with Zig!", c.SDL_WINDOWPOS_CENTERED, c.SDL_WINDOWPOS_CENTERED, 800, 600, c.SDL_WINDOW_SHOWN | c.SDL_WINDOW_OPENGL);
if (maybe_window == null) {
std.log.err("SDL Error: {s}", .{c.SDL_GetError()});
return error.SDLWindowError;
}
const window = maybe_window.?;
const context = c.SDL_GL_CreateContext(window);
if (c.gladLoadGLLoader(c.SDL_GL_GetProcAddress) == 0) {
return error.GladInitError;
}
std.log.debug("OpenGL Version: {}.{}", .{ c.GLVersion.major, c.GLVersion.minor });
g_init = try global_allocator.create(InitMemory);
g_init.* = .{
.global_allocator = global_allocator,
.window = window,
.context = context,
};
}
export fn game_init_window(global_allocator: *std.mem.Allocator) void {
std.log.debug("game_init_window\n", .{});
game_init_window_err(global_allocator.*) catch |err| {
std.log.err("Failed to init window {}\n", .{err});
@panic("Failed to init window");
};
}
export fn game_init(global_allocator: *std.mem.Allocator) void {
std.log.debug("game_init\n", .{});
g_mem = global_allocator.create(GameMemory) catch @panic("OOM");
g_mem.* = .{
.global_allocator = global_allocator.*,
@ -28,29 +76,71 @@ export fn game_update() bool {
return false;
}
},
c.SDL_WINDOWEVENT => {
switch (event.window.type) {
c.SDL_WINDOWEVENT_SIZE_CHANGED => {
// var width = event.window.data1;
// var height = event.window.data2;
},
else => {},
}
},
else => {},
}
g_mem.counter += 1;
c.glClearColor(0.3, 0.6, 0.3, 1.0);
c.glClear(c.GL_COLOR_BUFFER_BIT);
c.SDL_GL_SwapWindow(g_init.window);
c.SDL_Delay(1);
}
return true;
}
export fn game_shutdown() void {
std.log.debug("game_shutdown\n", .{});
g_mem.global_allocator.destroy(g_mem);
}
export fn game_hot_reload(memory: *anyopaque) void {
g_mem = @alignCast(@ptrCast(memory));
export fn game_shutdown_window() void {
std.log.debug("game_shutdown_window\n", .{});
c.SDL_GL_DeleteContext(g_init.context);
c.SDL_DestroyWindow(g_init.window);
g_init.global_allocator.destroy(g_init);
c.SDL_Quit();
}
export fn game_hot_reload(init_memory: ?*anyopaque, gmemory: ?*anyopaque) void {
std.log.debug("game_hot_reload {any} {any}\n", .{ init_memory, gmemory });
if (init_memory) |init_mem| {
g_init = @alignCast(@ptrCast(init_mem));
}
if (gmemory) |gmem| {
g_mem = @alignCast(@ptrCast(gmem));
}
}
export fn game_memory() *anyopaque {
return @ptrCast(g_mem);
}
export fn game_init_memory() *anyopaque {
return @ptrCast(g_init);
}
export fn game_memory_size() usize {
return @sizeOf(GameMemory);
}
export fn game_init_memory_size() usize {
return @sizeOf(InitMemory);
}
fn sdl_try(result: c_int) !void {
if (result < 0) {
std.log.err("SDL Error: {s}", .{c.SDL_GetError()});
return error.SDLError;
}
}

View File

@ -2,13 +2,6 @@ const std = @import("std");
const c = @import("c.zig");
const builtin = @import("builtin");
fn sdl_try(result: c_int) !void {
if (result < 0) {
std.log.err("SDL Error: {s}", .{c.SDL_GetError()});
return error.SDLError;
}
}
const game_lib_basename = "learnopengl";
const game_lib_name: [:0]const u8 = builtin.target.libPrefix() ++ game_lib_basename ++ builtin.target.dynamicLibSuffix();
@ -23,31 +16,11 @@ pub fn main() !void {
const game_lib_path = try getGameLibPath(allocator);
try sdl_try(c.SDL_Init(c.SDL_INIT_EVERYTHING));
defer c.SDL_Quit();
try sdl_try(c.SDL_GL_SetAttribute(c.SDL_GL_DOUBLEBUFFER, 1));
try sdl_try(c.SDL_GL_SetAttribute(c.SDL_GL_CONTEXT_MAJOR_VERSION, 4));
try sdl_try(c.SDL_GL_SetAttribute(c.SDL_GL_CONTEXT_MINOR_VERSION, 1));
try sdl_try(c.SDL_GL_SetAttribute(c.SDL_GL_CONTEXT_PROFILE_MASK, c.SDL_GL_CONTEXT_PROFILE_CORE));
const maybe_window = c.SDL_CreateWindow("Learn OpenGL with Zig!", c.SDL_WINDOWPOS_CENTERED, c.SDL_WINDOWPOS_CENTERED, 800, 600, c.SDL_WINDOW_SHOWN | c.SDL_WINDOW_OPENGL);
if (maybe_window == null) {
std.log.err("SDL Error: {s}", .{c.SDL_GetError()});
return error.SDLWindowError;
}
const window = maybe_window.?;
const context = c.SDL_GL_CreateContext(window);
defer c.SDL_GL_DeleteContext(context);
_ = c.gladLoadGLLoader(c.SDL_GL_GetProcAddress);
std.log.debug("OpenGL Version: {}.{}", .{ c.GLVersion.major, c.GLVersion.minor });
var modified = try getFileModifiedZ(game_lib_path);
game_api = try loadGameAPI(allocator, game_lib_path);
game_api.game_init_window(&allocator);
game_api.game_init(&allocator);
defer {
game_api.game_shutdown();
@ -65,25 +38,42 @@ pub fn main() !void {
modified = new_modified;
var new_game_api = try loadGameAPI(allocator, game_lib_path);
if (game_api.game_memory_size() == new_game_api.game_memory_size()) {
std.log.debug("Hot reload with state!\n", .{});
const game_memory = game_api.game_memory();
game_api.deinit(allocator);
new_game_api.game_hot_reload(game_memory);
game_api = new_game_api;
} else {
std.log.debug("Hot reload with shutdown!\n", .{});
game_api.game_shutdown();
game_api.deinit(allocator);
game_api = new_game_api;
game_api.game_init(&allocator);
var recreate_state = false;
var recreate_window = false;
const game_init_memory = game_api.game_init_memory();
const game_memory = game_api.game_memory();
if (game_api.game_memory_size() != new_game_api.game_memory_size()) {
recreate_state = true;
}
if (game_api.game_init_memory_size() != new_game_api.game_init_memory_size()) {
recreate_window = true;
}
if (recreate_state) {
game_api.game_shutdown();
}
if (recreate_window) {
game_api.game_shutdown_window();
}
if (recreate_window) {
new_game_api.game_init_window(&allocator);
} else {
new_game_api.game_hot_reload(game_init_memory, null);
}
if (recreate_state) {
new_game_api.game_init(&allocator);
} else {
new_game_api.game_hot_reload(null, game_memory);
}
game_api.deinit(allocator);
game_api = new_game_api;
}
exit = !game_api.game_update();
c.SDL_GL_SwapWindow(window);
c.SDL_Delay(1);
}
}
@ -128,22 +118,30 @@ fn loadGameAPI(arena: std.mem.Allocator, game_lib_path: [:0]const u8) !GameAPI {
}
const GameAPI = struct {
game_init_window: *const fn (*std.mem.Allocator) callconv(.C) void,
game_init: *const fn (*std.mem.Allocator) callconv(.C) void,
game_update: *const fn () callconv(.C) bool,
game_shutdown: *const fn () callconv(.C) void,
game_shutdown_window: *const fn () callconv(.C) void,
game_memory_size: *const fn () callconv(.C) usize,
game_init_memory_size: *const fn () callconv(.C) usize,
game_memory: *const fn () callconv(.C) *anyopaque,
game_hot_reload: *const fn (*anyopaque) callconv(.C) void,
game_init_memory: *const fn () callconv(.C) *anyopaque,
game_hot_reload: *const fn (?*anyopaque, ?*anyopaque) callconv(.C) void,
dll: ?*anyopaque,
path: [:0]const u8,
pub fn init(dll: ?*anyopaque, path: [:0]const u8) !GameAPI {
return GameAPI{
.game_init_window = @alignCast(@ptrCast(c.SDL_LoadFunction(dll, "game_init_window") orelse return error.MissingGameInitWindow)),
.game_init = @alignCast(@ptrCast(c.SDL_LoadFunction(dll, "game_init") orelse return error.MissingGameInit)),
.game_update = @alignCast(@ptrCast(c.SDL_LoadFunction(dll, "game_update") orelse return error.MissingGameUpdate)),
.game_shutdown = @alignCast(@ptrCast(c.SDL_LoadFunction(dll, "game_shutdown") orelse return error.MissingGameShutdown)),
.game_shutdown_window = @alignCast(@ptrCast(c.SDL_LoadFunction(dll, "game_shutdown_window") orelse return error.MissingGameShutdownWindow)),
.game_memory_size = @alignCast(@ptrCast(c.SDL_LoadFunction(dll, "game_memory_size") orelse return error.MissingGameMemorySize)),
.game_init_memory_size = @alignCast(@ptrCast(c.SDL_LoadFunction(dll, "game_init_memory_size") orelse return error.MissingGameInitMemorySize)),
.game_memory = @alignCast(@ptrCast(c.SDL_LoadFunction(dll, "game_memory") orelse return error.MissingGameMemory)),
.game_init_memory = @alignCast(@ptrCast(c.SDL_LoadFunction(dll, "game_init_memory") orelse return error.MissingGameInitMemory)),
.game_hot_reload = @alignCast(@ptrCast(c.SDL_LoadFunction(dll, "game_hot_reload") orelse return error.MissingGameHotReload)),
.dll = dll,
.path = path,