initial commit
This commit is contained in:
commit
937693b16e
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
zig-out
|
||||||
|
.zig-cache
|
||||||
|
.cache
|
||||||
|
compile_commands.json
|
||||||
164
build.zig
Normal file
164
build.zig
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const zcc = @import("compile_commands");
|
||||||
|
|
||||||
|
pub fn build(b: *std.Build) !void {
|
||||||
|
const target = b.standardTargetOptions(.{ });
|
||||||
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
|
const tracy_enabled = b.option(bool, "tracy", "Enable tracy profiling") orelse (optimize == .Debug);
|
||||||
|
const imgui_enabled = b.option(bool, "imgui", "Enable ImGui integration") orelse (optimize == .Debug);
|
||||||
|
|
||||||
|
var targets: std.ArrayList(*std.Build.Step.Compile) = .empty;
|
||||||
|
|
||||||
|
const mod = b.createModule(.{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.link_libc = true,
|
||||||
|
});
|
||||||
|
mod.addIncludePath(b.path("./src/"));
|
||||||
|
|
||||||
|
var cflags: std.ArrayList([]const u8) = .empty;
|
||||||
|
|
||||||
|
const raylib_dep = b.dependency("raylib", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize
|
||||||
|
});
|
||||||
|
mod.linkLibrary(raylib_dep.artifact("raylib"));
|
||||||
|
|
||||||
|
const tracy_dep = b.dependency("tracy", .{
|
||||||
|
.tracy_enable = tracy_enabled,
|
||||||
|
});
|
||||||
|
mod.linkLibrary(tracy_dep.artifact("tracy"));
|
||||||
|
|
||||||
|
const incbin_dep = b.dependency("incbin", .{});
|
||||||
|
mod.addIncludePath(incbin_dep.path("."));
|
||||||
|
|
||||||
|
if (imgui_enabled) {
|
||||||
|
if (try buildImGui(b, .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.raylib = raylib_dep.artifact("raylib")
|
||||||
|
})) |imgui| {
|
||||||
|
mod.linkLibrary(imgui);
|
||||||
|
try targets.append(b.allocator, imgui);
|
||||||
|
}
|
||||||
|
|
||||||
|
try cflags.append(b.allocator, "-DIMGUI_ENABLED");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var src_dir = try std.fs.cwd().openDir("src", .{ .iterate = true });
|
||||||
|
defer src_dir.close();
|
||||||
|
|
||||||
|
var iter = src_dir.iterate();
|
||||||
|
while (try iter.next()) |entry| {
|
||||||
|
if (entry.kind == .file and std.mem.endsWith(u8, entry.name, ".c")) {
|
||||||
|
mod.addCSourceFile(.{
|
||||||
|
.file = b.path(b.pathJoin(&.{ "src", entry.name })),
|
||||||
|
.flags = cflags.items
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const exe = b.addExecutable(.{
|
||||||
|
.name = "gaem",
|
||||||
|
.root_module = mod
|
||||||
|
});
|
||||||
|
try targets.append(b.allocator, exe);
|
||||||
|
|
||||||
|
if (target.result.os.tag == .windows) {
|
||||||
|
const show_console = b.option(bool, "console", "Show windows console") orelse (optimize == .Debug);
|
||||||
|
exe.subsystem = if (show_console) .Console else .Windows;
|
||||||
|
}
|
||||||
|
|
||||||
|
b.installArtifact(exe);
|
||||||
|
|
||||||
|
{
|
||||||
|
const run_cmd = b.addRunArtifact(exe);
|
||||||
|
run_cmd.step.dependOn(b.getInstallStep());
|
||||||
|
|
||||||
|
if (b.args) |args| {
|
||||||
|
run_cmd.addArgs(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const run_step = b.step("run", "Run the program");
|
||||||
|
run_step.dependOn(&run_cmd.step);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = zcc.createStep(b, "cdb", try targets.toOwnedSlice(b.allocator));
|
||||||
|
}
|
||||||
|
|
||||||
|
const ImGuiOptions = struct {
|
||||||
|
target: std.Build.ResolvedTarget,
|
||||||
|
optimize: std.builtin.OptimizeMode,
|
||||||
|
raylib: *std.Build.Step.Compile
|
||||||
|
};
|
||||||
|
|
||||||
|
fn buildImGui(b: *std.Build, opts: ImGuiOptions) !?*std.Build.Step.Compile {
|
||||||
|
const imgui = b.lazyDependency("imgui", .{}) orelse return null;
|
||||||
|
const cimgui = b.lazyDependency("cimgui", .{}) orelse return null;
|
||||||
|
const rlimgui = b.lazyDependency("rlimgui", .{}) orelse return null;
|
||||||
|
|
||||||
|
const cpp_flags = .{
|
||||||
|
"-fno-exceptions",
|
||||||
|
"-fno-rtti",
|
||||||
|
"-std=c++11",
|
||||||
|
"-DNO_FONT_AWESOME"
|
||||||
|
};
|
||||||
|
|
||||||
|
const imgui_lib = b.addLibrary(.{
|
||||||
|
.name = "imgui",
|
||||||
|
.root_module = b.createModule(.{
|
||||||
|
.target = opts.target,
|
||||||
|
.optimize = opts.optimize,
|
||||||
|
.link_libcpp = true,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
imgui_lib.root_module.addCSourceFiles(.{
|
||||||
|
.root = imgui.path("."),
|
||||||
|
.files = &.{
|
||||||
|
"imgui.cpp",
|
||||||
|
"imgui_demo.cpp",
|
||||||
|
"imgui_draw.cpp",
|
||||||
|
"imgui_tables.cpp",
|
||||||
|
"imgui_widgets.cpp",
|
||||||
|
},
|
||||||
|
.flags = &cpp_flags
|
||||||
|
});
|
||||||
|
imgui_lib.root_module.addIncludePath(imgui.path("."));
|
||||||
|
|
||||||
|
// Needed for cimgui
|
||||||
|
imgui_lib.installHeadersDirectory(imgui.path("."), "imgui", .{});
|
||||||
|
// Needed for rlimgui
|
||||||
|
imgui_lib.installHeadersDirectory(imgui.path("."), ".", .{});
|
||||||
|
|
||||||
|
const lib = b.addLibrary(.{
|
||||||
|
.name = "imgui_raylib_cimgui",
|
||||||
|
.root_module = b.createModule(.{
|
||||||
|
.target = opts.target,
|
||||||
|
.optimize = opts.optimize,
|
||||||
|
.link_libcpp = true,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
lib.root_module.linkLibrary(imgui_lib);
|
||||||
|
|
||||||
|
lib.root_module.addCSourceFile(.{
|
||||||
|
.file = cimgui.path("cimgui.cpp"),
|
||||||
|
.flags = &cpp_flags
|
||||||
|
});
|
||||||
|
lib.root_module.addIncludePath(cimgui.path("."));
|
||||||
|
|
||||||
|
lib.root_module.addCSourceFile(.{
|
||||||
|
.file = rlimgui.path("rlImGui.cpp"),
|
||||||
|
.flags = &cpp_flags,
|
||||||
|
});
|
||||||
|
lib.root_module.addIncludePath(rlimgui.path("."));
|
||||||
|
lib.root_module.linkLibrary(opts.raylib);
|
||||||
|
|
||||||
|
lib.installHeader(rlimgui.path("rlImGui.h"), "rlImGui.h");
|
||||||
|
lib.installHeader(cimgui.path("cimgui.h"), "cimgui.h");
|
||||||
|
|
||||||
|
return lib;
|
||||||
|
}
|
||||||
39
build.zig.zon
Normal file
39
build.zig.zon
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
.{
|
||||||
|
.name = .raylib_template,
|
||||||
|
.version = "0.0.1",
|
||||||
|
.dependencies = .{
|
||||||
|
.raylib = .{
|
||||||
|
.url = "git+https://github.com/raysan5/raylib.git#6a048b7afeada62f9071969ba277ad14e0dce256",
|
||||||
|
.hash = "raylib-5.6.0-dev-whq8uM0UCAWTJ_Wd2f8GItDMnDg3hMImKT-nk78bscfL",
|
||||||
|
},
|
||||||
|
.tracy = .{
|
||||||
|
.path = "./libs/tracy"
|
||||||
|
},
|
||||||
|
.incbin = .{
|
||||||
|
.url = "git+https://github.com/graphitemaster/incbin.git#22061f51fe9f2f35f061f85c2b217b55dd75310d",
|
||||||
|
.hash = "N-V-__8AABmOAAB00zlm0f7NkMnWJxJD7g3y1PNsbgO7SCiQ",
|
||||||
|
},
|
||||||
|
.compile_commands = .{
|
||||||
|
.url = "https://github.com/the-argus/zig-compile-commands/archive/f74e2d13e43fafab3a71e19557a0e1cfbf0f2e1b.tar.gz",
|
||||||
|
.hash = "zig_compile_commands-0.0.1-OZg5-a3CAACM-h32Kjb1obTMqrKGs9YoDhorVZ8-LGle",
|
||||||
|
},
|
||||||
|
.imgui = .{
|
||||||
|
.url = "https://github.com/ocornut/imgui/archive/6d910d5487d11ca567b61c7824b0c78c569d62f0.tar.gz",
|
||||||
|
.hash = "N-V-__8AALp9cwA8tEuEno2YCZyivsMaobnF-Z7qZGY3qBOt",
|
||||||
|
.lazy = true
|
||||||
|
},
|
||||||
|
.rlimgui = .{
|
||||||
|
.url = "https://github.com/raylib-extras/rlImGui/archive/dc7f97679a024eee8f5f009e77cc311748200415.tar.gz",
|
||||||
|
.hash = "N-V-__8AAC-taQCKZ-3IjRuWJ-5Dc47QKHDPEmqlwXhvjBGq",
|
||||||
|
.lazy = true
|
||||||
|
},
|
||||||
|
.cimgui = .{
|
||||||
|
.url = "https://github.com/cimgui/cimgui/archive/bfd30140a9c5832b5e0dcf179d6e1e5c69373d5a.tar.gz",
|
||||||
|
.hash = "N-V-__8AAOY-OACWjhmHu289AXFy9Fro3w_30mGFYL8FTq71",
|
||||||
|
.lazy = true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.minimum_zig_version = "0.15.2",
|
||||||
|
.paths = .{""},
|
||||||
|
.fingerprint = 0xd9c063dda43688bf,
|
||||||
|
}
|
||||||
124
libs/tracy/build.zig
Normal file
124
libs/tracy/build.zig
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn build(b: *std.Build) void {
|
||||||
|
const target = b.standardTargetOptions(.{});
|
||||||
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
|
const options = b.addOptions();
|
||||||
|
const tracy_enable = option(b, options, bool, "tracy_enable", "Enable profiling", true);
|
||||||
|
const tracy_on_demand = option(b, options, bool, "tracy_on_demand", "On-demand profiling", false);
|
||||||
|
const tracy_callstack = callstack: {
|
||||||
|
const opt = b.option(u8, "tracy_callstack", "Enforce callstack collection for tracy regions");
|
||||||
|
options.addOption(?u8, "tracy_callstack", opt);
|
||||||
|
break :callstack opt;
|
||||||
|
};
|
||||||
|
const tracy_no_callstack = option(b, options, bool, "tracy_no_callstack", "Disable all callstack related functionality", false);
|
||||||
|
const tracy_no_callstack_inlines = option(b, options, bool, "tracy_no_callstack_inlines", "Disables the inline functions in callstacks", false);
|
||||||
|
const tracy_only_localhost = option(b, options, bool, "tracy_only_localhost", "Only listen on the localhost interface", false);
|
||||||
|
const tracy_no_broadcast = option(b, options, bool, "tracy_no_broadcast", "Disable client discovery by broadcast to local network", false);
|
||||||
|
const tracy_only_ipv4 = option(b, options, bool, "tracy_only_ipv4", "Tracy will only accept connections on IPv4 addresses (disable IPv6)", false);
|
||||||
|
const tracy_no_code_transfer = option(b, options, bool, "tracy_no_code_transfer", "Disable collection of source code", false);
|
||||||
|
const tracy_no_context_switch = option(b, options, bool, "tracy_no_context_switch", "Disable capture of context switches", false);
|
||||||
|
const tracy_no_exit = option(b, options, bool, "tracy_no_exit", "Client executable does not exit until all profile data is sent to server", false);
|
||||||
|
const tracy_no_sampling = option(b, options, bool, "tracy_no_sampling", "Disable call stack sampling", false);
|
||||||
|
const tracy_no_verify = option(b, options, bool, "tracy_no_verify", "Disable zone validation for C API", false);
|
||||||
|
const tracy_no_vsync_capture = option(b, options, bool, "tracy_no_vsync_capture", "Disable capture of hardware Vsync events", false);
|
||||||
|
const tracy_no_frame_image = option(b, options, bool, "tracy_no_frame_image", "Disable the frame image support and its thread", false);
|
||||||
|
// @FIXME: For some reason system tracing crashes the program, will need to investigate
|
||||||
|
// panics during some drawf thing within libbacktrace (c++)
|
||||||
|
const tracy_no_system_tracing = option(b, options, bool, "tracy_no_system_tracing", "Disable systrace sampling", true);
|
||||||
|
const tracy_delayed_init = option(b, options, bool, "tracy_delayed_init", "Enable delayed initialization of the library (init on first call)", false);
|
||||||
|
const tracy_manual_lifetime = option(b, options, bool, "tracy_manual_lifetime", "Enable the manual lifetime management of the profile", false);
|
||||||
|
const tracy_fibers = option(b, options, bool, "tracy_fibers", "Enable fibers support", false);
|
||||||
|
const tracy_no_crash_handler = option(b, options, bool, "tracy_no_crash_handler", "Disable crash handling", false);
|
||||||
|
const tracy_timer_fallback = option(b, options, bool, "tracy_timer_fallback", "Use lower resolution timers", false);
|
||||||
|
const shared = option(b, options, bool, "shared", "Build the tracy client as a shared libary", false);
|
||||||
|
|
||||||
|
const tracy_source_dep = b.dependency("tracy_source", .{});
|
||||||
|
|
||||||
|
const mod = b.addModule("tracy", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Avoid building Tracy completely if it is disabled.
|
||||||
|
|
||||||
|
mod.addIncludePath(tracy_source_dep.path("public"));
|
||||||
|
|
||||||
|
if (target.result.os.tag == .windows) {
|
||||||
|
mod.linkSystemLibrary("dbghelp", .{ .needed = true });
|
||||||
|
mod.linkSystemLibrary("ws2_32", .{ .needed = true });
|
||||||
|
}
|
||||||
|
mod.link_libcpp = true;
|
||||||
|
|
||||||
|
const config_header = b.addConfigHeader(.{ .include_path = "TracyConfig.h" }, .{});
|
||||||
|
|
||||||
|
inline for (.{
|
||||||
|
.{ tracy_enable, "TRACY_ENABLE", "" },
|
||||||
|
.{ tracy_on_demand, "TRACY_ON_DEMAND", "" },
|
||||||
|
.{ tracy_callstack != null, "TRACY_CALLSTACK", b.fmt("{?d}", .{tracy_callstack}) },
|
||||||
|
.{ tracy_no_callstack, "TRACY_NO_CALLSTACK", "" },
|
||||||
|
.{ tracy_no_callstack_inlines, "TRACY_NO_CALLSTACK_INLINES", "" },
|
||||||
|
.{ tracy_only_localhost, "TRACY_ONLY_LOCALHOST", "" },
|
||||||
|
.{ tracy_no_broadcast, "TRACY_NO_BROADCAST", "" },
|
||||||
|
.{ tracy_only_ipv4, "TRACY_ONLY_IPV4", "" },
|
||||||
|
.{ tracy_no_code_transfer, "TRACY_NO_CODE_TRANSFER", "" },
|
||||||
|
.{ tracy_no_context_switch, "TRACY_NO_CONTEXT_SWITCH", "" },
|
||||||
|
.{ tracy_no_exit, "TRACY_NO_EXIT", "" },
|
||||||
|
.{ tracy_no_sampling, "TRACY_NO_SAMPLING", "" },
|
||||||
|
.{ tracy_no_verify, "TRACY_NO_VERIFY", "" },
|
||||||
|
.{ tracy_no_vsync_capture, "TRACY_NO_VSYNC_CAPTURE", ""},
|
||||||
|
.{ tracy_no_frame_image, "TRACY_NO_FRAME_IMAGE", ""},
|
||||||
|
.{ tracy_no_system_tracing, "TRACY_NO_SYSTEM_TRACING", ""},
|
||||||
|
.{ tracy_delayed_init, "TRACY_DELAYED_INIT", ""},
|
||||||
|
.{ tracy_manual_lifetime, "TRACY_MANUAL_LIFETIME", ""},
|
||||||
|
.{ tracy_fibers, "TRACY_FIBERS", "" },
|
||||||
|
.{ tracy_no_crash_handler, "TRACY_NO_CRASH_HANDLER", "" },
|
||||||
|
.{ tracy_timer_fallback, "TRACY_TIMER_FALLBACK", "" },
|
||||||
|
.{ shared and target.result.os.tag == .windows, "TRACY_EXPORTS", "" }
|
||||||
|
}) |triplet| {
|
||||||
|
const enabled, const name, const value = triplet;
|
||||||
|
if (enabled) {
|
||||||
|
mod.addCMacro(name, value);
|
||||||
|
config_header.addValue(name, []const u8, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod.addCSourceFile(.{
|
||||||
|
.file = tracy_source_dep.path("public/TracyClient.cpp"),
|
||||||
|
.flags = &.{}
|
||||||
|
});
|
||||||
|
|
||||||
|
const lib = b.addLibrary(.{
|
||||||
|
.linkage = if (shared) .dynamic else .static,
|
||||||
|
.name = "tracy",
|
||||||
|
.root_module = mod,
|
||||||
|
});
|
||||||
|
|
||||||
|
const include_extensions = &.{".h",".hpp"};
|
||||||
|
lib.installHeadersDirectory(tracy_source_dep.path("public/tracy"), "tracy", .{
|
||||||
|
.include_extensions = include_extensions,
|
||||||
|
});
|
||||||
|
lib.installHeadersDirectory(tracy_source_dep.path("public/common"), "common", .{
|
||||||
|
.include_extensions = include_extensions,
|
||||||
|
});
|
||||||
|
lib.installHeadersDirectory(tracy_source_dep.path("public/client"), "client", .{
|
||||||
|
.include_extensions = include_extensions,
|
||||||
|
});
|
||||||
|
lib.installConfigHeader(config_header);
|
||||||
|
|
||||||
|
b.installArtifact(lib);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn option(
|
||||||
|
b: *std.Build,
|
||||||
|
options: *std.Build.Step.Options,
|
||||||
|
comptime T: type,
|
||||||
|
name_raw: []const u8,
|
||||||
|
description_raw: []const u8,
|
||||||
|
default: T,
|
||||||
|
) T {
|
||||||
|
const opt = b.option(T, name_raw, description_raw) orelse default;
|
||||||
|
options.addOption(T, name_raw, opt);
|
||||||
|
return opt;
|
||||||
|
}
|
||||||
13
libs/tracy/build.zig.zon
Normal file
13
libs/tracy/build.zig.zon
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
.{
|
||||||
|
.name = .tracy,
|
||||||
|
.version = "0.0.1",
|
||||||
|
.minimum_zig_version = "0.15.1",
|
||||||
|
.dependencies = .{
|
||||||
|
.tracy_source = .{
|
||||||
|
.url = "https://github.com/wolfpld/tracy/archive/refs/tags/v0.13.0.zip",
|
||||||
|
.hash = "N-V-__8AAHW7KwHH_eNEviRWLkRfsxpWFrdOYM9f8VeCin4q",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.paths = .{""},
|
||||||
|
.fingerprint = 0x255a89ee3ed46b42,
|
||||||
|
}
|
||||||
36
src/entity_id.c
Normal file
36
src/entity_id.c
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#include "entity_id.h"
|
||||||
|
|
||||||
|
bool entity_id_eql(EntityId lhs, EntityId rhs)
|
||||||
|
{
|
||||||
|
return lhs.packed == rhs.packed;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool entity_id_is_nil(EntityId id)
|
||||||
|
{
|
||||||
|
return entity_id_eql(id, ENTITY_ID_NIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t entity_id_get_index(EntityId id)
|
||||||
|
{
|
||||||
|
return (id.packed & 0x00FFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t entity_id_get_generation(EntityId id)
|
||||||
|
{
|
||||||
|
return (id.packed >> 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct UnpackedEntityId entity_id_unpack(EntityId id)
|
||||||
|
{
|
||||||
|
return (struct UnpackedEntityId){
|
||||||
|
.generation = entity_id_get_generation(id),
|
||||||
|
.index = entity_id_get_index(id)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityId entity_id_pack(struct UnpackedEntityId unpacked_id)
|
||||||
|
{
|
||||||
|
return (EntityId){
|
||||||
|
.packed = (unpacked_id.generation << 24) | (unpacked_id.index & 0x00FFFFFF)
|
||||||
|
};
|
||||||
|
}
|
||||||
27
src/entity_id.h
Normal file
27
src/entity_id.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
#define ENTITY_ID_INDEX_BITS 24
|
||||||
|
#define ENTITY_ID_GENERATION_BITS 8
|
||||||
|
|
||||||
|
#define MAX_INDEX ((1 << ENTITY_ID_INDEX_BITS) - 1)
|
||||||
|
#define MAX_GENERATION ((1 << ENTITY_ID_GENERATION_BITS) - 1)
|
||||||
|
|
||||||
|
#define ENTITY_ID_NIL (EntityId){ 0 }
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t packed;
|
||||||
|
} EntityId;
|
||||||
|
|
||||||
|
struct UnpackedEntityId {
|
||||||
|
uint32_t index;
|
||||||
|
uint8_t generation;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool entity_id_eql(EntityId lhs, EntityId rhs);
|
||||||
|
bool entity_id_is_nil(EntityId id);
|
||||||
|
EntityId entity_id_pack(struct UnpackedEntityId unpacked_id);
|
||||||
|
struct UnpackedEntityId entity_id_unpack(EntityId id);
|
||||||
|
uint32_t entity_id_get_index(EntityId id);
|
||||||
|
uint8_t entity_id_get_generation(EntityId id);
|
||||||
142
src/entity_list.c
Normal file
142
src/entity_list.c
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
#include "entity_list.h"
|
||||||
|
|
||||||
|
void entity_list_ensure_capacity(struct EntityList *list, size_t expected_capacity)
|
||||||
|
{
|
||||||
|
if (expected_capacity > list->capacity) {
|
||||||
|
size_t larger_capacity = MAX(MAX(list->capacity*2, 8), expected_capacity);
|
||||||
|
struct EntitySlot *larger_items = realloc(list->items, larger_capacity * sizeof(*larger_items));
|
||||||
|
if (larger_items == NULL) {
|
||||||
|
PANIC_OOM();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = list->capacity; i < larger_capacity; i++) {
|
||||||
|
larger_items[i].used = false;
|
||||||
|
larger_items[i].generation = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
list->items = larger_items;
|
||||||
|
list->capacity = larger_capacity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void entity_list_copy(struct EntityList *destination, struct EntityList *source)
|
||||||
|
{
|
||||||
|
entity_list_ensure_capacity(destination, source->len);
|
||||||
|
|
||||||
|
if (source->len > 0) {
|
||||||
|
memcpy(
|
||||||
|
destination->items,
|
||||||
|
source->items,
|
||||||
|
sizeof(*source->items) * source->len
|
||||||
|
);
|
||||||
|
}
|
||||||
|
destination->len = source->len;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Entity *entity_list_add(struct EntityList *list)
|
||||||
|
{
|
||||||
|
struct Entity *result = NULL;
|
||||||
|
|
||||||
|
for (size_t i = 1; i < list->len; i++) {
|
||||||
|
struct EntitySlot *slot = &list->items[i];
|
||||||
|
if (!slot->used) {
|
||||||
|
slot->used = true;
|
||||||
|
result = &slot->entity;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == NULL) {
|
||||||
|
uint32_t index = MAX(list->len, 1);
|
||||||
|
ASSERT(index <= MAX_INDEX);
|
||||||
|
|
||||||
|
entity_list_ensure_capacity(list, index + 1);
|
||||||
|
list->len = index + 1;
|
||||||
|
|
||||||
|
struct EntitySlot *slot = &list->items[index];
|
||||||
|
ASSERT(!slot->used);
|
||||||
|
slot->used = true;
|
||||||
|
|
||||||
|
result = &slot->entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(result != NULL);
|
||||||
|
memset(result, 0, sizeof(*result));
|
||||||
|
|
||||||
|
list->used_count++;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool entity_list_remove(struct EntityList *list, struct Entity *entity)
|
||||||
|
{
|
||||||
|
ASSERT(entity != NULL);
|
||||||
|
|
||||||
|
struct EntitySlot *slot = container_of(entity, struct EntitySlot, entity);
|
||||||
|
if (!slot->used) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
slot->used = false;
|
||||||
|
slot->generation++;
|
||||||
|
|
||||||
|
ASSERT(list->used_count > 0);
|
||||||
|
list->used_count--;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool entity_list_remove_by_id(struct EntityList *list, EntityId entity_id)
|
||||||
|
{
|
||||||
|
struct Entity *entity = entity_list_get(list, entity_id);
|
||||||
|
if (!entity) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return entity_list_remove(list, entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool entity_list_exists(struct EntityList *list, EntityId entity_id)
|
||||||
|
{
|
||||||
|
struct UnpackedEntityId unpacked = entity_id_unpack(entity_id);
|
||||||
|
if (unpacked.index >= list->len) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct EntitySlot *entity_slot = &list->items[unpacked.index];
|
||||||
|
if (!entity_slot->used) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return entity_slot->generation == unpacked.generation;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Entity *entity_list_get(struct EntityList *list, EntityId entity_id)
|
||||||
|
{
|
||||||
|
if (entity_list_exists(list, entity_id)) {
|
||||||
|
struct UnpackedEntityId unpacked = entity_id_unpack(entity_id);
|
||||||
|
return &list->items[unpacked.index].entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityId entity_list_get_id(struct EntityList *list, struct Entity *entity)
|
||||||
|
{
|
||||||
|
ASSERT(entity != NULL);
|
||||||
|
|
||||||
|
struct EntitySlot *slot = container_of(entity, struct EntitySlot, entity);
|
||||||
|
uint32_t offset = (void*)slot - (void*)list->items;
|
||||||
|
uint32_t index = offset / sizeof(struct EntitySlot);
|
||||||
|
|
||||||
|
return entity_id_pack((struct UnpackedEntityId){
|
||||||
|
.generation = slot->generation,
|
||||||
|
.index = index
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void entity_list_free(struct EntityList *list)
|
||||||
|
{
|
||||||
|
free(list->items);
|
||||||
|
*list = (struct EntityList){ 0 };
|
||||||
|
}
|
||||||
37
src/entity_list.h
Normal file
37
src/entity_list.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "main.h"
|
||||||
|
#include "entity_id.h"
|
||||||
|
|
||||||
|
struct Entity {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EntitySlot {
|
||||||
|
bool used;
|
||||||
|
uint8_t generation;
|
||||||
|
struct Entity entity;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EntityList {
|
||||||
|
struct EntitySlot *items;
|
||||||
|
size_t len;
|
||||||
|
size_t capacity;
|
||||||
|
size_t used_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
void entity_list_ensure_capacity(struct EntityList *list, size_t expected_capacity);
|
||||||
|
void entity_list_copy(struct EntityList *destination, struct EntityList *source);
|
||||||
|
void entity_list_free(struct EntityList *list);
|
||||||
|
struct Entity *entity_list_add(struct EntityList *list);
|
||||||
|
bool entity_list_exists(struct EntityList *list, EntityId entity_id);
|
||||||
|
struct Entity *entity_list_get(struct EntityList *list, EntityId entity_id);
|
||||||
|
EntityId entity_list_get_id(struct EntityList *list, struct Entity *entity);
|
||||||
|
bool entity_list_remove(struct EntityList *list, struct Entity *entity);
|
||||||
|
bool entity_list_remove_by_id(struct EntityList *list, EntityId entity_id);
|
||||||
|
|
||||||
|
#define entity_list_foreach(list, _entity) for ( \
|
||||||
|
size_t i = 1; \
|
||||||
|
i < (list)->len && (_entity = &(list)->items[i].entity, true); \
|
||||||
|
i++ \
|
||||||
|
) \
|
||||||
|
if (!(list)->items[i].used) {} else
|
||||||
37
src/game.c
Normal file
37
src/game.c
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include "game.h"
|
||||||
|
|
||||||
|
void game_init(struct Game *game)
|
||||||
|
{
|
||||||
|
*game = (struct Game){
|
||||||
|
.canvas_size = { 800, 600 }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void game_free(struct Game *game)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void game_tick(struct Game *game)
|
||||||
|
{
|
||||||
|
TracyCZoneN(game_tick, "game_tick", true);
|
||||||
|
|
||||||
|
Vector2 dir = { 0 };
|
||||||
|
if (IsKeyDown(KEY_W)) {
|
||||||
|
dir.y -= 1;
|
||||||
|
}
|
||||||
|
if (IsKeyDown(KEY_S)) {
|
||||||
|
dir.y += 1;
|
||||||
|
}
|
||||||
|
if (IsKeyDown(KEY_D)) {
|
||||||
|
dir.x += 1;
|
||||||
|
}
|
||||||
|
if (IsKeyDown(KEY_A)) {
|
||||||
|
dir.x -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
game->player_position = Vector2Add(game->player_position, Vector2Scale(dir, 50 * game->input.dt));
|
||||||
|
|
||||||
|
DrawRectangleV(game->player_position, (Vector2){ 50, 50 }, RED);
|
||||||
|
|
||||||
|
TracyCZoneEnd(game_tick)
|
||||||
|
}
|
||||||
22
src/game.h
Normal file
22
src/game.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "main.h"
|
||||||
|
#include "entity_list.h"
|
||||||
|
|
||||||
|
struct Input {
|
||||||
|
float dt;
|
||||||
|
Vector2 mouse;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Game {
|
||||||
|
Vector2 canvas_size;
|
||||||
|
struct EntityList entities;
|
||||||
|
|
||||||
|
Vector2 player_position;
|
||||||
|
|
||||||
|
struct Input input;
|
||||||
|
};
|
||||||
|
|
||||||
|
void game_init(struct Game *game);
|
||||||
|
void game_free(struct Game *game);
|
||||||
|
void game_tick(struct Game *game);
|
||||||
58
src/game_debug.c
Normal file
58
src/game_debug.c
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#include "game_debug.h"
|
||||||
|
|
||||||
|
#ifdef IMGUI_ENABLED
|
||||||
|
#define NO_FONT_AWESOME
|
||||||
|
#include <rlImGui.h>
|
||||||
|
|
||||||
|
#define CIMGUI_DEFINE_ENUMS_AND_STRUCTS
|
||||||
|
#include <cimgui.h>
|
||||||
|
|
||||||
|
void game_debug_init()
|
||||||
|
{
|
||||||
|
rlImGuiBeginInitImGui();
|
||||||
|
|
||||||
|
ImGuiIO *io = igGetIO_ContextPtr(igGetCurrentContext());
|
||||||
|
io->IniFilename = NULL;
|
||||||
|
|
||||||
|
igStyleColorsDark(NULL);
|
||||||
|
|
||||||
|
rlImGuiEndInitImGui();
|
||||||
|
}
|
||||||
|
|
||||||
|
void game_debug_deinit()
|
||||||
|
{
|
||||||
|
rlImGuiShutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
void game_debug_show(struct Game *game)
|
||||||
|
{
|
||||||
|
rlImGuiBegin();
|
||||||
|
|
||||||
|
igSetNextWindowSize((ImVec2_c){ 400, 200 }, ImGuiCond_Once);
|
||||||
|
if (igBegin("Debug", NULL, ImGuiWindowFlags_None)) {
|
||||||
|
char label[64] = { 0 };
|
||||||
|
snprintf(label, sizeof(label), "FPS: %.1f (%.2fms)", 1.0f / game->input.dt, game->input.dt * 1000);
|
||||||
|
igTextEx(label, NULL, ImGuiTextFlags_None);
|
||||||
|
|
||||||
|
igTextEx("Hello, World", NULL, ImGuiTextFlags_None);
|
||||||
|
}
|
||||||
|
igEnd();
|
||||||
|
|
||||||
|
rlImGuiEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
void game_debug_init()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void game_debug_deinit()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void game_debug_show(struct Game *game)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
8
src/game_debug.h
Normal file
8
src/game_debug.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "main.h"
|
||||||
|
#include "game.h"
|
||||||
|
|
||||||
|
void game_debug_init();
|
||||||
|
void game_debug_deinit();
|
||||||
|
void game_debug_show(struct Game *game);
|
||||||
133
src/main.c
Normal file
133
src/main.c
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
#include "main.h"
|
||||||
|
#include "resources.h"
|
||||||
|
#include "game.h"
|
||||||
|
#include "game_debug.h"
|
||||||
|
|
||||||
|
struct Resources g_resources = { 0 };
|
||||||
|
|
||||||
|
struct WindowTransform {
|
||||||
|
Vector2 offset;
|
||||||
|
float scale;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void begin_window_scaling(struct WindowTransform *transform, Vector2 virtual_screen_size)
|
||||||
|
{
|
||||||
|
Vector2 screen_size = {
|
||||||
|
GetScreenWidth(),
|
||||||
|
GetScreenHeight()
|
||||||
|
};
|
||||||
|
|
||||||
|
float scale = MIN(
|
||||||
|
screen_size.x / virtual_screen_size.x,
|
||||||
|
screen_size.y / virtual_screen_size.y
|
||||||
|
);
|
||||||
|
transform->scale = scale;
|
||||||
|
|
||||||
|
Vector2 filler_size = Vector2Scale(Vector2Subtract(screen_size, Vector2Scale(virtual_screen_size, transform->scale)), 0.5);
|
||||||
|
transform->offset = filler_size;
|
||||||
|
|
||||||
|
rlPushMatrix();
|
||||||
|
rlTranslatef(
|
||||||
|
filler_size.x,
|
||||||
|
filler_size.y,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
rlScalef(scale, scale, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void end_window_scaling(struct WindowTransform *transform, Color color)
|
||||||
|
{
|
||||||
|
rlPopMatrix();
|
||||||
|
|
||||||
|
Vector2 filler_size = transform->offset;
|
||||||
|
|
||||||
|
DrawRectangleRec(
|
||||||
|
(struct Rectangle){
|
||||||
|
.x = 0,
|
||||||
|
.y = 0,
|
||||||
|
.width = GetScreenWidth(),
|
||||||
|
.height = filler_size.y
|
||||||
|
},
|
||||||
|
color
|
||||||
|
);
|
||||||
|
|
||||||
|
DrawRectangleRec(
|
||||||
|
(struct Rectangle){
|
||||||
|
.x = 0,
|
||||||
|
.y = GetScreenHeight() - filler_size.y,
|
||||||
|
.width = GetScreenWidth(),
|
||||||
|
.height = filler_size.y
|
||||||
|
},
|
||||||
|
color
|
||||||
|
);
|
||||||
|
|
||||||
|
DrawRectangleRec(
|
||||||
|
(struct Rectangle){
|
||||||
|
.x = 0,
|
||||||
|
.y = 0,
|
||||||
|
.width = filler_size.x,
|
||||||
|
.height = GetScreenHeight()
|
||||||
|
},
|
||||||
|
color
|
||||||
|
);
|
||||||
|
|
||||||
|
DrawRectangleRec(
|
||||||
|
(struct Rectangle){
|
||||||
|
.x = GetScreenWidth() - filler_size.x,
|
||||||
|
.y = 0,
|
||||||
|
.width = filler_size.x,
|
||||||
|
.height = GetScreenHeight()
|
||||||
|
},
|
||||||
|
color
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
InitWindow(800, 600, "gaem");
|
||||||
|
InitAudioDevice();
|
||||||
|
SetWindowState(FLAG_WINDOW_RESIZABLE);
|
||||||
|
SetTargetFPS(60);
|
||||||
|
|
||||||
|
resources_init(&g_resources);
|
||||||
|
|
||||||
|
struct Game game = { 0 };
|
||||||
|
game_init(&game);
|
||||||
|
|
||||||
|
game_debug_init();
|
||||||
|
|
||||||
|
while (!WindowShouldClose())
|
||||||
|
{
|
||||||
|
TracyCFrameMark;
|
||||||
|
|
||||||
|
// TODO: Can this be called every frame? Will it impact performance? Needs research.
|
||||||
|
SetWindowMinSize(game.canvas_size.x, game.canvas_size.y);
|
||||||
|
|
||||||
|
float dt = GetFrameTime();
|
||||||
|
BeginDrawing();
|
||||||
|
ClearBackground(RAYWHITE);
|
||||||
|
|
||||||
|
struct WindowTransform transform = { 0 };
|
||||||
|
begin_window_scaling(&transform, game.canvas_size);
|
||||||
|
Vector2 mouse = GetMousePosition();
|
||||||
|
mouse = Vector2Subtract(mouse, transform.offset);
|
||||||
|
mouse = Vector2Scale(mouse, 1/transform.scale);
|
||||||
|
|
||||||
|
game.input = (struct Input){
|
||||||
|
.dt = dt,
|
||||||
|
.mouse = mouse
|
||||||
|
};
|
||||||
|
game_tick(&game);
|
||||||
|
end_window_scaling(&transform, BLACK);
|
||||||
|
|
||||||
|
game_debug_show(&game);
|
||||||
|
|
||||||
|
EndDrawing();
|
||||||
|
}
|
||||||
|
|
||||||
|
game_free(&game);
|
||||||
|
game_debug_deinit();
|
||||||
|
CloseWindow();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
38
src/main.h
Normal file
38
src/main.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <raylib.h>
|
||||||
|
#include <raymath.h>
|
||||||
|
#include <rlgl.h>
|
||||||
|
#include <TracyConfig.h>
|
||||||
|
#include <tracy/TracyC.h>
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define INCBIN_STYLE INCBIN_STYLE_SNAKE
|
||||||
|
#define INCBIN_PREFIX
|
||||||
|
#include <incbin.h>
|
||||||
|
|
||||||
|
#define PANIC(message, ...) \
|
||||||
|
do { \
|
||||||
|
printf("%s:%d "message"\n", __FILE__, __LINE__, ##__VA_ARGS__); \
|
||||||
|
exit(EXIT_FAILURE); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
#define ASSERT(condition) if (!(condition)) PANIC("Assertion failed: %s", #condition)
|
||||||
|
#define PANIC_OOM() PANIC("Out of memory")
|
||||||
|
#define UNREACHABLE() PANIC("Reached unreachable")
|
||||||
|
|
||||||
|
#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
|
||||||
|
|
||||||
|
#define container_of(ptr, type, member) ((type *)((char *)(ptr) - offsetof(type, member)))
|
||||||
|
|
||||||
|
extern struct Resources g_resources;
|
||||||
|
|
||||||
|
Color rgb(uint8_t r, uint8_t g, uint8_t b);
|
||||||
|
Color hex(const char *str);
|
||||||
5
src/resources.c
Normal file
5
src/resources.c
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
void resources_init(struct Resources *resources)
|
||||||
|
{
|
||||||
|
}
|
||||||
6
src/resources.h
Normal file
6
src/resources.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct Resources {
|
||||||
|
};
|
||||||
|
|
||||||
|
void resources_init(struct Resources *resources);
|
||||||
39
src/utils.c
Normal file
39
src/utils.c
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
Color rgb(uint8_t r, uint8_t g, uint8_t b)
|
||||||
|
{
|
||||||
|
return (Color){
|
||||||
|
.r = r,
|
||||||
|
.g = g,
|
||||||
|
.b = b,
|
||||||
|
.a = 255
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t parse_hex_nibble(char nibble)
|
||||||
|
{
|
||||||
|
if ('0' <= nibble && nibble <= '9') {
|
||||||
|
return nibble - '0';
|
||||||
|
} else if ('a' <= nibble && nibble <= 'f') {
|
||||||
|
return nibble - 'a';
|
||||||
|
} else if ('A' <= nibble && nibble <= 'F') {
|
||||||
|
return nibble - 'A';
|
||||||
|
} else {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t parse_hex_byte(const char *two_bytes)
|
||||||
|
{
|
||||||
|
return (parse_hex_nibble(two_bytes[0]) << 4) | parse_hex_nibble(two_bytes[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Color hex(const char *str)
|
||||||
|
{
|
||||||
|
ASSERT(strlen(str) == 7);
|
||||||
|
ASSERT(str[0] == '#');
|
||||||
|
uint8_t r = parse_hex_byte(&str[1]);
|
||||||
|
uint8_t g = parse_hex_byte(&str[3]);
|
||||||
|
uint8_t b = parse_hex_byte(&str[5]);
|
||||||
|
return rgb(r, g, b);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user