HelloWorld

This commit is contained in:
abux 2026-07-11 18:45:05 +01:00
commit e7c630411b
34 changed files with 873 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
.zig-cache/
zig-pkg/
zig-out/

66
build.zig Normal file
View file

@ -0,0 +1,66 @@
const std = @import("std");
pub fn build(b: *std.Build) void {
// --- TARGET ---
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
// --- EXE ---
const exe = b.addExecutable(.{
.name = "vampire_survivors",
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
.imports = &.{},
}),
});
b.installArtifact(exe);
const run_step = b.step("run", "Run the app");
const run_cmd = b.addRunArtifact(exe);
run_step.dependOn(&run_cmd.step);
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
const exe_tests = b.addTest(.{
.root_module = exe.root_module,
});
const run_exe_tests = b.addRunArtifact(exe_tests);
const test_step = b.step("test", "Run tests");
test_step.dependOn(&run_exe_tests.step);
//
// DEPENDENCIES
//
const app = b.dependency("app", .{
.target = target,
.optimize = optimize,
});
exe.root_module.addImport("app", app.module("app"));
//
// SYSTEM DEPENDENCIES
//
const sdl = b.addTranslateC(.{
.target = target,
.optimize = optimize,
.root_source_file = b.path("./src/vendors/sdl3/sdl.h"),
});
exe.root_module.addImport("sdl", sdl.createModule());
exe.root_module.linkSystemLibrary("SDL3", .{});
exe.root_module.linkSystemLibrary("SDL3_ttf", .{});
exe.root_module.linkSystemLibrary("SDL3_image", .{});
}

22
build.zig.zon Normal file
View file

@ -0,0 +1,22 @@
.{
.name = .vampire_survivors,
.version = "0.0.0",
.fingerprint = 0x27782ab1dd9d7c0f,
.minimum_zig_version = "0.16.0",
.dependencies = .{
.app = .{
.url = "git+http://2.120.146.66:25569/abux/NYXA#93a4606c94f67b1f0a559c2efff3d8ff030b3300",
.hash = "app-0.0.0-AOV9_ea_AACRsUJ2lZqYiUkPed0op9qgFSWB6ihDSrll",
},
},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
},
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

0
src/component/camera.zig Normal file
View file

View file

2
src/component/caster.zig Normal file
View file

@ -0,0 +1,2 @@
cooldown: f32 = 0.2,
current_cooldown: f32 = 0.0,

View file

@ -0,0 +1 @@
value: f32 = 5.0,

View file

@ -0,0 +1,9 @@
const Handle = @import("app").template.Handle;
const Texture = @import("../resource/textures.zig").Texture;
pub const Style = union(enum) {
solid: @Vector(4, u8),
textured: Handle(Texture),
};
style: Style,

0
src/component/player.zig Normal file
View file

View file

19
src/component/root.zig Normal file
View file

@ -0,0 +1,19 @@
// --- POSITION ---
pub const Transform = @import("transform.zig");
pub const Velocity = @import("velocity.zig");
pub const Friction = @import("friction.zig");
// --- STYLE ---
pub const Material = @import("material.zig");
// --- CAMERA ---
pub const Camera = @import("camera.zig");
pub const CameraTarget = @import("camera_target.zig");
// --- TIME ---
pub const Timer = @import("timer.zig");
// --- MARKERS ---
pub const Player = @import("player.zig");
pub const Caster = @import("caster.zig");
pub const Projectile = @import("projectile.zig");

0
src/component/shape.zig Normal file
View file

24
src/component/timer.zig Normal file
View file

@ -0,0 +1,24 @@
const Self = @This();
//
// FIELDS
//
duration: f32 = 0.0,
remaining: f32 = 0.0,
repeat: bool = false,
finished: bool = false,
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn set(
seconds: f32,
repeat: bool,
) Self {
return .{
.duration = seconds,
.remaining = seconds,
.repeat = repeat,
};
}

View file

@ -0,0 +1,2 @@
pos: @Vector(2, f32) = .{ 0, 0 },
size: @Vector(2, f32) = .{ 32, 32 },

View file

@ -0,0 +1 @@
value: @Vector(2, f32) = .{ 0, 0 },

4
src/data/camera.zig Normal file
View file

@ -0,0 +1,4 @@
const component = @import("../component/root.zig");
value: *const component.Camera,
transform: *const component.Transform,

1
src/data/root.zig Normal file
View file

@ -0,0 +1 @@
pub const Camera = @import("camera.zig");

0
src/event/root.zig Normal file
View file

45
src/main.zig Normal file
View file

@ -0,0 +1,45 @@
const std = @import("std");
const App = @import("app");
const plugin = @import("plugin/root.zig");
const resource = @import("resource/root.zig");
const template = @import("template/root.zig");
pub fn main(init: std.process.Init) !void {
// --- APP ---
var app: App = .init(init.gpa);
defer app.deinit();
// --- ADD DEFAULT PLUGIN & BUILD ---
try app.plugins.add(plugin.default);
try app.plugins.build(.{ .app = &app });
// --- LIFETIME ---
try app.schedules.run(App.stage.init, .{ .app = &app });
defer app.schedules.run(App.stage.deinit, .{ .app = &app }) catch unreachable;
// errdefer {
// app.schedules.run(App.stage.deinit, .{ .app = &app }) catch unreachable;
// }
try app.schedules.run(App.stage.post_init, .{ .app = &app });
// --- MAIN GAME LOOP ---
while (true) {
// --- BREAK ON EXIT ---
if (app.events.consume(App.event.AppExit)) |_| {
break;
}
// --- FRAME ---
try app.schedules.runMany(&.{
App.stage.begin_frame,
App.stage.inputs,
App.stage.update,
App.stage.draw,
App.stage.end_frame,
}, .{
.app = &app,
});
}
}

37
src/plugin/default.zig Normal file
View file

@ -0,0 +1,37 @@
const App = @import("app");
const component = @import("../component/root.zig");
const resource = @import("../resource/root.zig");
const system = @import("../system/root.zig");
/// ----------------------------------------------------
/// ----------------------------------------------------
pub const plugin: App.plugin.Plugin = .{
.name = "Default",
.build = build,
};
/// ----------------------------------------------------
/// ----------------------------------------------------
fn build(
_: *App.plugin.Plugin,
ctx: App.plugin.Context,
) !void {
// --- LIFETIME ---
try ctx.app.schedules.add(App.stage.init, system.core.init);
try ctx.app.schedules.add(App.stage.post_init, system.core.build);
try ctx.app.schedules.add(App.stage.deinit, system.core.deinit);
// --- FRAME ---
try ctx.app.schedules.add(App.stage.begin_frame, system.frame.beginFrame);
try ctx.app.schedules.add(App.stage.end_frame, system.frame.endFrame);
// --- UPDATE ---
try ctx.app.schedules.add(App.stage.inputs, system.frame.inputs);
try ctx.app.schedules.addMany(App.stage.update, &.{
system.frame.updateTimers,
system.frame.updateTransforms,
system.frame.cast,
});
try ctx.app.schedules.add(App.stage.draw, system.frame.draw);
}

1
src/plugin/root.zig Normal file
View file

@ -0,0 +1 @@
pub const default = @import("default.zig").plugin;

7
src/resource/frame.zig Normal file
View file

@ -0,0 +1,7 @@
const data = @import("../data/root.zig");
//
// FIELDS
//
camera: ?data.Camera = null,

View file

@ -0,0 +1,3 @@
const sdl = @import("sdl");
raw: *sdl.SDL_Renderer,

8
src/resource/root.zig Normal file
View file

@ -0,0 +1,8 @@
// --- CORE ---
pub const Window = @import("window.zig");
pub const Renderer = @import("renderer.zig");
pub const Frame = @import("frame.zig");
pub const Time = @import("time.zig");
// --- ASSETS ---
pub const Textures = @import("textures.zig");

132
src/resource/textures.zig Normal file
View file

@ -0,0 +1,132 @@
const std = @import("std");
const sdl = @import("sdl");
const Renderer = @import("../resource/renderer.zig");
const Handle = @import("app").template.Handle;
const Storage = @import("../template/storage.zig").Storage;
const Self = @This();
/// ----------------------------------------------------
/// ----------------------------------------------------
pub const Size = union(enum) {
source,
fixed: [2]u32,
};
/// ----------------------------------------------------
/// ----------------------------------------------------
pub const Filter = enum {
linear,
nearest,
};
/// ----------------------------------------------------
/// ----------------------------------------------------
pub const Texture = struct {
path: []const u8,
size: [2]u32 = .{ 0, 0 },
filter: Filter = .nearest,
};
/// ----------------------------------------------------
/// ----------------------------------------------------
pub const GPUTexture = struct {
raw: *sdl.SDL_Texture,
};
//
// FIELDS
//
textures: Storage(Texture, GPUTexture),
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn init(alloc: std.mem.Allocator) Self {
return .{
.textures = .init(alloc),
};
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn deinit(self: *Self) void {
self.textures.deinit();
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn load(
self: *Self,
name: []const u8,
path: []const u8,
) !Handle(Texture) {
return try self.textures.put(name, .{
.path = path,
});
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn get(
self: *Self,
value: Handle(Texture),
) ?*GPUTexture {
const record = self.textures.get(value) orelse return null;
return if (record.gpu) |*v| v else null;
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn build(
self: *Self,
renderer: *const Renderer,
) !void {
for (self.textures.items()) |*record| {
// --- SKIP IF BUILD ---
if (record.gpu != null) continue;
// --- LOAD SURFACE ---
const surface = sdl.IMG_Load(
record.cpu.path.ptr,
) orelse {
std.debug.print("\x1b[31mFailed to load texture:\x1b[0m {s}\n", .{sdl.SDL_GetError()});
return error.Texture;
};
defer sdl.SDL_DestroySurface(surface);
// --- CREATE TEXTURE ---
const texture = sdl.SDL_CreateTextureFromSurface(
renderer.raw,
surface,
) orelse return error.Texture;
// --- SET FILTER ---
_ = sdl.SDL_SetTextureScaleMode(texture, switch (record.cpu.filter) {
.linear => sdl.SDL_SCALEMODE_LINEAR,
.nearest => sdl.SDL_SCALEMODE_PIXELART,
});
// --- ASSIGN CPU ---
record.cpu.size = .{
@intCast(surface.*.w),
@intCast(surface.*.h),
};
// --- ASSIGN GPU ---
record.gpu = .{
.raw = texture,
};
}
// --- DEBUG ---
var it = self.textures.lookup.iterator();
while (it.next()) |entry| {
const record = self.textures.get(entry.key_ptr.*) orelse continue;
std.debug.print("\x1b[35m┏━ TEXTURE\n", .{});
std.debug.print("\x1b[35m┃\x1b[0m Name: \"{s}\"\n", .{entry.value_ptr.*});
std.debug.print("\x1b[35m┃\x1b[0m Path: \"{s}\"\n", .{record.cpu.path});
std.debug.print("\x1b[35m┃\x1b[0m Size: {}x{}\n", .{ record.cpu.size[0], record.cpu.size[1] });
std.debug.print("\x1b[35m┗━\x1b[0m\n", .{});
}
}

5
src/resource/time.zig Normal file
View file

@ -0,0 +1,5 @@
dt: f32 = 0.0,
now: u64 = 0,
last: u64 = 0,
frequency: u64 = 0,
target_dt: f32 = 1.0 / 60.0,

6
src/resource/window.zig Normal file
View file

@ -0,0 +1,6 @@
const sdl = @import("sdl");
title: []const u8 = "Vampire Survivors",
width: u32 = 800,
height: u32 = 600,
raw: *sdl.SDL_Window,

107
src/system/core.zig Normal file
View file

@ -0,0 +1,107 @@
const std = @import("std");
const sdl = @import("sdl");
const App = @import("app");
const component = @import("../component/root.zig");
const resource = @import("../resource/root.zig");
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn init(ctx: App.scheduler.Context) !void {
// --- SDL3 INIT ---
if (!sdl.SDL_Init(sdl.SDL_INIT_VIDEO)) {
return error.SDL_Init;
}
// --- WINDOW ---
const window = try ctx.app.resources.getOrSet(resource.Window{
.raw = sdl.SDL_CreateWindow(
"Vampire Survivors",
800,
600,
sdl.SDL_WINDOW_RESIZABLE | sdl.SDL_WINDOW_HIGH_PIXEL_DENSITY,
) orelse return error.Window,
});
// --- RENDERER ---
try ctx.app.resources.set(resource.Renderer{
.raw = sdl.SDL_CreateRenderer(
window.raw,
null,
) orelse return error.Renderer,
});
// --- FRAME ---
try ctx.app.resources.set(resource.Time{
.now = sdl.SDL_GetPerformanceCounter(),
.last = sdl.SDL_GetPerformanceCounter(),
.frequency = sdl.SDL_GetPerformanceFrequency(),
});
try ctx.app.resources.set(resource.Frame{});
// --- ASSETS ---
const textures = try ctx.app.resources.getOrSet(resource.Textures.init(ctx.app.alloc));
// --- DEBUG ---
std.debug.print("\x1b[35m┏━ WINDOW\n", .{});
std.debug.print("\x1b[35m┃\x1b[0m Title: \"{s}\"\n", .{window.title});
std.debug.print("\x1b[35m┃\x1b[0m Size: {}x{}\n", .{ window.width, window.height });
std.debug.print("\x1b[35m┗━\x1b[0m\n", .{});
{ // ENTITIES
// --- CAMERA ---
try ctx.app.world.spawn(.{
component.Camera{},
component.Transform{},
});
// --- PLAYER ---
try ctx.app.world.spawn(.{
component.Player{},
component.Caster{},
component.Friction{},
component.Velocity{},
component.Transform{ .size = .{ 200, 200 } },
component.Material{ .style = .{
.textured = try textures.load("Player", "src/assets/textures/player.png"),
} },
component.CameraTarget{},
});
try ctx.app.world.spawn(.{
component.Transform{ .pos = .{ 100, 100 } },
component.Material{ .style = .{
.solid = .{ 20, 200, 20, 255 },
} },
});
}
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn deinit(ctx: App.scheduler.Context) !void {
const res = try ctx.app.resources.getMany(struct {
window: *resource.Window,
renderer: *resource.Renderer,
textures: *resource.Textures,
});
res.textures.deinit();
sdl.SDL_DestroyRenderer(res.renderer.raw);
sdl.SDL_DestroyWindow(res.window.raw);
sdl.SDL_Quit();
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn build(ctx: App.scheduler.Context) !void {
const res = try ctx.app.resources.getMany(struct {
renderer: *resource.Renderer,
textures: *resource.Textures,
});
try res.textures.build(
res.renderer,
);
}

277
src/system/frame.zig Normal file
View file

@ -0,0 +1,277 @@
const std = @import("std");
const sdl = @import("sdl");
const App = @import("app");
const component = @import("../component/root.zig");
const resource = @import("../resource/root.zig");
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn inputs(ctx: App.scheduler.Context) !void {
const res = try ctx.app.resources.getMany(struct {
window: *resource.Window,
renderer: *resource.Renderer,
});
_ = res;
// --- POLL EVENTS ---
var raw_event: sdl.SDL_Event = undefined;
while (sdl.SDL_PollEvent(&raw_event)) {
switch (raw_event.type) {
sdl.SDL_EVENT_QUIT => try ctx.app.events.send(App.event.AppExit{}),
else => {},
}
}
const keyboard: [*c]const bool = sdl.SDL_GetKeyboardState(null);
var query = ctx.app.world.query(struct {
player: *component.Player,
velocity: *component.Velocity,
}, .{});
while (query.next()) |e| {
const speed: f32 = 100.0;
if (keyboard[sdl.SDL_SCANCODE_W]) e.velocity.value[1] = -speed;
if (keyboard[sdl.SDL_SCANCODE_S]) e.velocity.value[1] = speed;
if (keyboard[sdl.SDL_SCANCODE_A]) e.velocity.value[0] = -speed;
if (keyboard[sdl.SDL_SCANCODE_D]) e.velocity.value[0] = speed;
}
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn beginFrame(ctx: App.scheduler.Context) !void {
const res = try ctx.app.resources.getMany(struct {
window: *resource.Window,
frame: *resource.Frame,
time: *resource.Time,
});
//
// TIME
//
res.time.last = res.time.now;
res.time.now = sdl.SDL_GetPerformanceCounter();
res.time.dt =
@as(f32, @floatFromInt(res.time.now - res.time.last)) /
@as(f32, @floatFromInt(res.time.frequency));
//
// CAMERA
//
var target_transform: ?*const component.Transform = null;
{ // GATHER CAMERAS TARGET
var query = ctx.app.world.query(struct {
transform: *component.Transform,
camera_target: ?*component.CameraTarget,
}, .{});
while (query.next()) |e| {
if (e.camera_target) |_| {
target_transform = e.transform;
}
}
}
{ // GATHER CAMERAS
var query = ctx.app.world.query(struct {
camera: *component.Camera,
transform: *component.Transform,
}, .{});
while (query.next()) |e| {
const window_width: f32 = @floatFromInt(res.window.width);
const window_height: f32 = @floatFromInt(res.window.height);
const target = if (target_transform) |v| v else continue;
e.transform.pos[0] += ((window_width / 2.0) - (target.pos[0] + target.size[0] / 2.0) - e.transform.pos[0]) / 20.0;
e.transform.pos[1] += ((window_height / 2.0) - (target.pos[1] + target.size[1] / 2.0) - e.transform.pos[1]) / 20.0;
// --- SET CURRENT FRAME CAMERA ---
res.frame.camera = .{
.value = e.camera,
.transform = e.transform,
};
}
}
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn endFrame(ctx: App.scheduler.Context) !void {
const res = try ctx.app.resources.getMany(struct {
frame: *resource.Frame,
time: *resource.Time,
});
res.frame.camera = null;
const frame_time =
@as(f32, @floatFromInt(sdl.SDL_GetPerformanceCounter() - res.time.now)) /
@as(f32, @floatFromInt(res.time.frequency));
if (frame_time < res.time.target_dt) {
const delay_ms = (res.time.target_dt - frame_time) * 1000.0;
sdl.SDL_Delay(@intFromFloat(delay_ms));
}
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn updateTransforms(ctx: App.scheduler.Context) !void {
const res = try ctx.app.resources.getMany(struct {
time: *resource.Time,
});
// --- QUERY ---
var query = ctx.app.world.query(struct {
transform: *component.Transform,
velocity: *component.Velocity,
friction: ?*component.Friction,
}, .{});
while (query.next()) |e| {
// --- APPLY VELOCITY ---
e.transform.pos[0] += e.velocity.value[0] * res.time.dt;
e.transform.pos[1] += e.velocity.value[1] * res.time.dt;
// --- APPLY FRICTION ---
if (e.friction) |friction| {
const damping = std.math.exp(-friction.value * res.time.dt);
e.velocity.value[0] *= damping;
e.velocity.value[1] *= damping;
}
}
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn updateTimers(ctx: App.scheduler.Context) !void {
const res = try ctx.app.resources.getMany(struct {
time: *resource.Time,
});
var query = ctx.app.world.query(struct {
timer: *component.Timer,
}, .{});
while (query.next()) |e| {
// --- # ---
if (e.timer.finished and !e.timer.repeat)
continue;
// --- PROGRESS ---
e.timer.remaining -=
res.time.dt;
if (e.timer.remaining <= 0.0) {
e.timer.finished = true;
if (e.timer.repeat) {
e.timer.remaining = e.timer.duration;
e.timer.finished = false;
}
}
}
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn cast(ctx: App.scheduler.Context) !void {
const res = try ctx.app.resources.getMany(struct {
time: *resource.Time,
});
// --- QUERY ---
var query = ctx.app.world.query(struct {
caster: *component.Caster,
transform: *component.Transform,
}, .{});
while (query.next()) |e| {
// --- SUBTRACT COOLDOWN ---
e.caster.current_cooldown -=
@max(0, res.time.dt);
// --- SKIP IF ON COOLDOWN ---
if (e.caster.current_cooldown >= 0)
continue;
// --- SPAWN PROJECTILE ---
try ctx.app.world.spawn(.{
component.Transform{
.pos = e.transform.pos,
},
component.Velocity{
.value = .{ 400, 0 },
},
component.Material{
.style = .{ .solid = .{ 200, 20, 20, 255 } },
},
component.Projectile{},
});
// --- SET COOLDOWN ---
e.caster.current_cooldown =
e.caster.cooldown;
}
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn draw(ctx: App.scheduler.Context) !void {
const res = try ctx.app.resources.getMany(struct {
window: *resource.Window,
renderer: *resource.Renderer,
textures: *resource.Textures,
frame: *resource.Frame,
});
// --- SET CLEAR COLOR ---
_ = sdl.SDL_SetRenderDrawColor(
res.renderer.raw,
10,
10,
10,
255,
);
// --- DRAW ---
_ = sdl.SDL_RenderClear(res.renderer.raw);
defer _ = sdl.SDL_RenderPresent(res.renderer.raw);
{ // DRAW
var query = ctx.app.world.query(struct {
transform: *component.Transform,
material: *component.Material,
camera_target: ?*component.CameraTarget,
}, .{});
while (query.next()) |e| {
const camera = if (res.frame.camera) |*v| v else continue;
// --- SHAPE ---
var rect: sdl.SDL_FRect = .{
.x = e.transform.pos[0] + camera.transform.pos[0],
.y = e.transform.pos[1] + camera.transform.pos[1],
.w = e.transform.size[0],
.h = e.transform.size[1],
};
// --- MATERIAL ---
switch (e.material.style) {
.solid => |albedo| {
_ = sdl.SDL_SetRenderDrawColor(res.renderer.raw, albedo[0], albedo[1], albedo[2], albedo[3]);
_ = sdl.SDL_RenderFillRect(res.renderer.raw, &rect);
},
.textured => |handle| {
const gpu = res.textures.get(handle) orelse continue;
_ = sdl.SDL_RenderTexture(
res.renderer.raw,
gpu.raw,
null,
&rect,
);
},
}
}
}
}

2
src/system/root.zig Normal file
View file

@ -0,0 +1,2 @@
pub const core = @import("core.zig");
pub const frame = @import("frame.zig");

1
src/template/root.zig Normal file
View file

@ -0,0 +1 @@
pub const Storage = @import("storage.zig").Storage;

85
src/template/storage.zig Normal file
View file

@ -0,0 +1,85 @@
const std = @import("std");
const App = @import("app");
const Handle = App.template.Handle;
pub fn Storage(
comptime CPU: type,
comptime GPU: type,
) type {
return struct {
const Self = @This();
/// ----------------------------------------------------
/// ----------------------------------------------------
pub const Record = struct {
cpu: CPU,
gpu: ?GPU = null,
};
//
// FIELDS
//
data: std.ArrayList(Record),
lookup: std.AutoHashMap(Handle(CPU), []const u8),
alloc: std.mem.Allocator,
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn init(alloc: std.mem.Allocator) Self {
return .{
.data = .empty,
.lookup = .init(alloc),
.alloc = alloc,
};
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn deinit(self: *Self) void {
self.data.deinit(self.alloc);
self.lookup.deinit();
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn put(
self: *Self,
name: []const u8,
value: CPU,
) !Handle(CPU) {
// --- HANDLE ---
const handle: Handle(CPU) = .{
.idx = @intCast(self.data.items.len),
};
// --- ADD DATA ---
try self.data.append(self.alloc, .{ .cpu = value });
errdefer _ = self.data.swapRemove(self.data.items.len - 1);
// --- ADD LOOKUP ---
try self.lookup.put(
handle,
name,
);
return handle;
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn get(
self: *Self,
handle: Handle(CPU),
) ?*Record {
if (!self.lookup.contains(handle)) return null;
return &self.data.items[@intCast(handle.idx)];
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn items(self: *Self) []Record {
return self.data.items;
}
};
}

3
src/vendors/sdl3/sdl.h vendored Normal file
View file

@ -0,0 +1,3 @@
#include <SDL3/SDL.h>
#include <SDL3_image/SDL_image.h>
#include <SDL3_ttf/SDL_ttf.h>