add raylib dependency and desktop platform driver with interactive play mode

This commit is contained in:
2026-08-14 16:31:13 +02:00
parent 2946cda8be
commit 02a29b12b2
5 changed files with 177 additions and 20 deletions
+116
View File
@@ -0,0 +1,116 @@
const std = @import("std");
const contract = @import("contract");
const platform = @import("root.zig");
const c = @import("c_raylib");
pub const Driver = struct {
texture: c.Texture2D,
audio_stream: c.AudioStream,
width: i32,
height: i32,
scale: i32,
event_queue: [16]platform.Event = undefined,
event_head: usize = 0,
event_tail: usize = 0,
pub fn init(title: [*:0]const u8, width: i32, height: i32, scale: i32) Driver {
c.InitWindow(width * scale, height * scale, title);
c.SetTargetFPS(60);
c.InitAudioDevice();
c.SetAudioStreamBufferSizeDefault(1024);
const stream = c.LoadAudioStream(44100, 16, 1);
c.PlayAudioStream(stream);
const img = c.GenImageColor(width, height, c.BLACK);
defer c.UnloadImage(img);
const tex = c.LoadTextureFromImage(img);
c.SetTextureFilter(tex, c.TEXTURE_FILTER_POINT);
return .{
.texture = tex,
.audio_stream = stream,
.width = width,
.height = height,
.scale = scale,
};
}
pub fn deinit(self: *Driver) void {
c.UnloadAudioStream(self.audio_stream);
c.CloseAudioDevice();
c.UnloadTexture(self.texture);
c.CloseWindow();
}
pub fn shouldClose(_: *Driver) bool {
return c.WindowShouldClose();
}
pub fn pollEvent(self: *Driver) ?platform.Event {
if (self.event_head != self.event_tail) {
const ev = self.event_queue[self.event_tail];
self.event_tail = (self.event_tail + 1) % self.event_queue.len;
return ev;
}
// Poll Raylib Key Events
const key_mappings = [_]struct { c_key: c_int, key: platform.Key }{
.{ .c_key = c.KEY_Z, .key = .z },
.{ .c_key = c.KEY_X, .key = .x },
.{ .c_key = c.KEY_RIGHT_SHIFT, .key = .right_shift },
.{ .c_key = c.KEY_LEFT_SHIFT, .key = .left_shift },
.{ .c_key = c.KEY_ENTER, .key = .enter },
.{ .c_key = c.KEY_UP, .key = .up },
.{ .c_key = c.KEY_DOWN, .key = .down },
.{ .c_key = c.KEY_LEFT, .key = .left },
.{ .c_key = c.KEY_RIGHT, .key = .right },
.{ .c_key = c.KEY_F5, .key = .f5 },
.{ .c_key = c.KEY_F8, .key = .f8 },
.{ .c_key = c.KEY_P, .key = .p },
};
for (key_mappings) |mapping| {
if (c.IsKeyPressed(mapping.c_key)) {
return .{ .key_down = .{ .key = mapping.key } };
}
if (c.IsKeyReleased(mapping.c_key)) {
return .{ .key_up = .{ .key = mapping.key } };
}
}
return null;
}
pub fn renderVideo(self: *Driver, output: usize, frame: contract.VideoFrame) void {
_ = output;
if (frame.data.len > 0) {
c.UpdateTexture(self.texture, frame.data.ptr);
}
c.BeginDrawing();
defer c.EndDrawing();
c.ClearBackground(c.BLACK);
const src = c.Rectangle{ .x = 0, .y = 0, .width = @floatFromInt(self.width), .height = @floatFromInt(self.height) };
const dest = c.Rectangle{
.x = 0,
.y = 0,
.width = @floatFromInt(self.width * self.scale),
.height = @floatFromInt(self.height * self.scale),
};
c.DrawTexturePro(self.texture, src, dest, c.Vector2{ .x = 0, .y = 0 }, 0.0, c.WHITE);
}
pub fn queueAudio(self: *Driver, output: usize, buffer: contract.AudioBuffer) void {
_ = output;
if (buffer.frames > 0 and c.IsAudioStreamProcessed(self.audio_stream)) {
c.UpdateAudioStream(self.audio_stream, buffer.data.ptr, @intCast(buffer.frames));
}
}
pub fn setDeviceFeedback(_: *Driver, _: usize, _: contract.DeviceFeedback) void {}
};