Basic setup.
- Allegro wrapper. - Setting up of new window etc.
This commit is contained in:
commit
5bfa8b2c51
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
.vscode
|
||||||
|
zig-cache
|
||||||
|
zig-out
|
||||||
|
allegro.path
|
15
README.md
Normal file
15
README.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# TINS 2023
|
||||||
|
|
||||||
|
# Building
|
||||||
|
|
||||||
|
For building you need:
|
||||||
|
- A recent (0.11.0-dev) Zig compiler.
|
||||||
|
- Allegro 5.28 development libraries.
|
||||||
|
|
||||||
|
You can use `allegro.path` if your Allegro development libraries can't be natively found. In this file you can put the path to a directory contain the Allegro `lib`, `bin` and `include` folders.
|
||||||
|
|
||||||
|
# Licenses
|
||||||
|
|
||||||
|
## Cabin font
|
||||||
|
|
||||||
|
[Open Font License version 1.1](src/assets/fonts/Cabin-OFL.txt)
|
0
allegro.path
Normal file
0
allegro.path
Normal file
697
allegro/allegro.zig
Normal file
697
allegro/allegro.zig
Normal file
@ -0,0 +1,697 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub const c = @import("c.zig").c;
|
||||||
|
|
||||||
|
pub const Bitmap = struct {
|
||||||
|
native: *c.ALLEGRO_BITMAP,
|
||||||
|
|
||||||
|
pub fn destroy(self: Bitmap) void {
|
||||||
|
destroyBitmap(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(self: Bitmap, x: f32, y: f32, flags: DrawFlags) void {
|
||||||
|
drawBitmap(self, x, y, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn drawCentered(self: Bitmap, x: f32, y: f32) void {
|
||||||
|
self.draw(x - 0.5 * @intToFloat(f32, self.width()), y - 0.5 * @intToFloat(f32, self.height()), DrawFlags{});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn drawCenteredScaled(self: Bitmap, x: f32, y: f32, s: f32) void {
|
||||||
|
const w = s * @intToFloat(f32, self.width());
|
||||||
|
const h = s * @intToFloat(f32, self.height());
|
||||||
|
self.drawScaled(x - 0.5 * w, y - 0.5 * h, w, h, DrawFlags{});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn drawScaled(self: Bitmap, x: f32, y: f32, w: f32, h: f32, flags: DrawFlags) void {
|
||||||
|
drawScaledBitmap(self, 0, 0, @intToFloat(f32, self.width()), @intToFloat(f32, self.height()), x, y, w, h, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn drawTinted(self: Bitmap, tint: Color, x: f32, y: f32, flags: DrawFlags) void {
|
||||||
|
drawTintedBitmap(self, tint, x, y, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn drawTintedCentered(self: Bitmap, tint: Color, x: f32, y: f32) void {
|
||||||
|
self.drawTinted(tint, x - 0.5 * @intToFloat(f32, self.width()), y - 0.5 * @intToFloat(f32, self.height()), DrawFlags{});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn drawTintedCenteredScaled(self: Bitmap, tint: Color, x: f32, y: f32, s: f32) void {
|
||||||
|
const w = s * @intToFloat(f32, self.width());
|
||||||
|
const h = s * @intToFloat(f32, self.height());
|
||||||
|
self.drawTintedScaled(tint, x - 0.5 * w, y - 0.5 * h, w, h, DrawFlags{});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn drawTintedScaled(self: Bitmap, tint: Color, x: f32, y: f32, w: f32, h: f32, flags: DrawFlags) void {
|
||||||
|
drawTintedScaledBitmap(self, tint, 0, 0, @intToFloat(f32, self.width()), @intToFloat(f32, self.height()), x, y, w, h, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn height(self: Bitmap) i32 {
|
||||||
|
return getBitmapHeight(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn width(self: Bitmap) i32 {
|
||||||
|
return getBitmapWidth(self);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Color = struct {
|
||||||
|
native: c.ALLEGRO_COLOR,
|
||||||
|
|
||||||
|
fn hexToU4(hex: u8) u4 {
|
||||||
|
return switch (hex) {
|
||||||
|
'0'...'9' => @intCast(u4, hex - '0'),
|
||||||
|
'a'...'f' => @intCast(u4, hex - 'a') + 10,
|
||||||
|
'A'...'F' => @intCast(u4, hex - 'A') + 10,
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initFromHex(hex: []const u8) Color {
|
||||||
|
if (hex.len == 0) unreachable;
|
||||||
|
|
||||||
|
const left: usize = if (hex[0] == '#') 1 else 0;
|
||||||
|
|
||||||
|
if (hex.len < left + 6) unreachable;
|
||||||
|
|
||||||
|
const r = (@intCast(u8, hexToU4(hex[left])) << 4) + @intCast(u8, hexToU4(hex[left + 1]));
|
||||||
|
const g = (@intCast(u8, hexToU4(hex[left + 2])) << 4) + @intCast(u8, hexToU4(hex[left + 3]));
|
||||||
|
const b = (@intCast(u8, hexToU4(hex[left + 4])) << 4) + @intCast(u8, hexToU4(hex[left + 5]));
|
||||||
|
if (hex.len < left + 8) {
|
||||||
|
return mapRgb(r, g, b);
|
||||||
|
}
|
||||||
|
const a = (@intCast(u8, hexToU4(hex[left + 6])) << 4) + @intCast(u8, hexToU4(hex[left + 7]));
|
||||||
|
return mapRgba(r, g, b, a);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Display = struct {
|
||||||
|
native: *c.ALLEGRO_DISPLAY,
|
||||||
|
|
||||||
|
pub fn destroy(self: Display) void {
|
||||||
|
destroyDisplay(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eventSource(self: Display) EventSource {
|
||||||
|
return getDisplayEventSource(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn height(self: Display) i32 {
|
||||||
|
return getDisplayHeight(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn width(self: Display) i32 {
|
||||||
|
return getDisplayWidth(self);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const DrawFlags = packed struct(c_int) {
|
||||||
|
FLIP_HORIZONTAL: bool = false, // 0x00001
|
||||||
|
FLIP_VERTICAL: bool = false, // 0x00002
|
||||||
|
_NOT_USED: u30 = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const DrawTextFlags = enum(c_int) {
|
||||||
|
NO_KERNING = -1,
|
||||||
|
ALIGN_LEFT = 0,
|
||||||
|
ALIGN_CENTER = 1,
|
||||||
|
ALIGN_RIGHT = 2,
|
||||||
|
ALIGN_LEFT_INTEGER = 4,
|
||||||
|
ALIGN_CENTER_INTEGER = 5,
|
||||||
|
ALIGN_RIGHT_INTEGER = 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Event = c.ALLEGRO_EVENT;
|
||||||
|
|
||||||
|
pub const EventQueue = struct {
|
||||||
|
native: *c.ALLEGRO_EVENT_QUEUE,
|
||||||
|
|
||||||
|
pub fn destroy(self: EventQueue) void {
|
||||||
|
destroyEventQueue(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn drop(self: EventQueue) void {
|
||||||
|
dropNextEvent(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn flush(self: EventQueue) void {
|
||||||
|
flushEventQueue(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(self: EventQueue, event: *Event) bool {
|
||||||
|
return getNextEvent(self, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isEmpty(self: EventQueue) bool {
|
||||||
|
return isEventQueueEmpty(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn peek(self: EventQueue, event: *Event) void {
|
||||||
|
peekNextEvent(self, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register(self: EventQueue, source: EventSource) void {
|
||||||
|
registerEventSource(self, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn registerDisplay(self: EventQueue, display: Display) void {
|
||||||
|
self.register(display.eventSource());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn registerKeyboard(self: EventQueue) void {
|
||||||
|
self.register(getKeyboardEventSource());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn registerMouse(self: EventQueue) void {
|
||||||
|
self.register(getMouseEventSource());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn registerTimer(self: EventQueue, timer: Timer) void {
|
||||||
|
self.register(timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unregister(self: EventQueue, source: EventSource) void {
|
||||||
|
unregisterEventSource(self, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unregisterDisplay(self: EventQueue, display: Display) void {
|
||||||
|
self.unregister(display.eventSource());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wait(self: EventQueue, event: *Event) void {
|
||||||
|
waitForEvent(self, event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const EventSource = struct {
|
||||||
|
native: *c.ALLEGRO_EVENT_SOURCE,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const File = struct {
|
||||||
|
native: *c.ALLEGRO_FILE,
|
||||||
|
|
||||||
|
pub fn close(file: File) void {
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Font = struct {
|
||||||
|
native: *c.ALLEGRO_FONT,
|
||||||
|
|
||||||
|
pub fn destroy(self: Font) void {
|
||||||
|
destroyFont(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(self: Font, color: Color, x: f32, y: f32, flags: DrawTextFlags, text: [*:0]const u8) void {
|
||||||
|
drawText(self, color, x, y, flags, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn textWidth(self: Font, text: [*:0]const u8) i32 {
|
||||||
|
return getTextWidth(self, text);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const LoadBitmapFlags = packed struct(c_int) {
|
||||||
|
_NOT_USED_1: bool = false,
|
||||||
|
KEEP_BITMAP_FORMAT: bool = false, // 0x0002 // was a bitmap flag in 5.0
|
||||||
|
_NOT_USED_2: u7 = 0,
|
||||||
|
NO_PREMULTIPLIED_ALPHA: bool = false, // 0x0200 // was a bitmap flag in 5.0
|
||||||
|
_NOT_USED_3: bool = false,
|
||||||
|
KEEP_INDEX: bool = false, // 0x0800
|
||||||
|
_NOT_USED_4: u20 = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const LoadTtfFontFlags = packed struct(c_int) {
|
||||||
|
NO_KERNING: bool = false,
|
||||||
|
MONOCHROME: bool = false,
|
||||||
|
NO_AUTOHINT: bool = false,
|
||||||
|
_NOT_USED: u29 = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const NewBitmapFlags = packed struct(c_int) {
|
||||||
|
MEMORY_BITMAP: bool = false, // 0x0001,
|
||||||
|
_KEEP_BITMAP_FORMAT: bool = false, // 0x0002,
|
||||||
|
FORCE_LOCKING: bool = false, // 0x0004,
|
||||||
|
NO_PRESERVE_TEXTURE: bool = false, // 0x0008,
|
||||||
|
_ALPHA_TEST: bool = false, // 0x0010,
|
||||||
|
_INTERNAL_OPENGL: bool = false, // 0x0020,
|
||||||
|
MIN_LINEAR: bool = false, // 0x0040,
|
||||||
|
MAG_LINEAR: bool = false, // 0x0080,
|
||||||
|
MIPMAP: bool = false, // 0x0100,
|
||||||
|
_NO_PREMULTIPLIED_ALPHA: bool = false, // 0x0200,
|
||||||
|
VIDEO_BITMAP: bool = false, // 0x0400,
|
||||||
|
_NOT_USED_1: bool = false, // 0x0800
|
||||||
|
CONVERT_BITMAP: bool = false, // 0x1000,
|
||||||
|
_NOT_USED_4: u19 = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const NewDisplayFlags = packed struct(c_int) {
|
||||||
|
WINDOWED: bool = false,
|
||||||
|
FULLSCREEN: bool = false,
|
||||||
|
OPENGL: bool = false,
|
||||||
|
DIRECT3D_INTERNAL: bool = false,
|
||||||
|
RESIZABLE: bool = false,
|
||||||
|
FRAMELESS: bool = false,
|
||||||
|
GENERATE_EXPOSE_EVENTS: bool = false,
|
||||||
|
OPENGL_3_0: bool = false,
|
||||||
|
OPENGL_FORWARD_COMPATIBLE: bool = false,
|
||||||
|
FULLSCREEN_WINDOW: bool = false,
|
||||||
|
MINIMIZED: bool = false,
|
||||||
|
PROGRAMMABLE_PIPELINE: bool = false,
|
||||||
|
GTK_TOPLEVEL_INTERNAL: bool = false,
|
||||||
|
MAXIMIZED: bool = false,
|
||||||
|
OPENGL_ES_PROFILE: bool = false,
|
||||||
|
OPENGL_CORE_PROFILE: bool = false,
|
||||||
|
_NOT_USED: u16 = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const NewDisplayOption = enum(c_int) {
|
||||||
|
RED_SIZE, // 0
|
||||||
|
GREEN_SIZE, // 1
|
||||||
|
BLUE_SIZE, // 2
|
||||||
|
ALPHA_SIZE, // 3
|
||||||
|
RED_SHIFT, // 4
|
||||||
|
GREEN_SHIFT, // 5
|
||||||
|
BLUE_SHIFT, // 6
|
||||||
|
ALPHA_SHIFT, // 7
|
||||||
|
ACC_RED_SIZE, // 8
|
||||||
|
ACC_GREEN_SIZE, // 9
|
||||||
|
ACC_BLUE_SIZE, // 10
|
||||||
|
ACC_ALPHA_SIZE, // 11
|
||||||
|
STEREO, // 12
|
||||||
|
AUX_BUFFERS, // 13
|
||||||
|
COLOR_SIZE, // 14
|
||||||
|
DEPTH_SIZE, // 15
|
||||||
|
STENCIL_SIZE, // 16
|
||||||
|
SAMPLE_BUFFERS, // 17
|
||||||
|
SAMPLES, // 18
|
||||||
|
RENDER_METHOD, // 19
|
||||||
|
FLOAT_COLOR, // 20
|
||||||
|
FLOAT_DEPTH, // 21
|
||||||
|
SINGLE_BUFFER, // 22
|
||||||
|
SWAP_METHOD, // 23
|
||||||
|
COMPATIBLE_DISPLAY, // 24
|
||||||
|
UPDATE_DISPLAY_REGION, // 25
|
||||||
|
VSYNC, // 26
|
||||||
|
MAX_BITMAP_SIZE, // 27
|
||||||
|
SUPPORT_NPOT_BITMAP, // 28
|
||||||
|
CAN_DRAW_INTO_BITMAP, // 29
|
||||||
|
SUPPORT_SEPARATE_ALPHA, // 30
|
||||||
|
AUTO_CONVERT_BITMAPS, // 31
|
||||||
|
SUPPORTED_ORIENTATIONS, // 32
|
||||||
|
OPENGL_MAJOR_VERSION, // 33
|
||||||
|
OPENGL_MINOR_VERSION, // 34
|
||||||
|
DEFAULT_SHADER_PLATFORM, // 35
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const OptionImportance = enum(c_int) {
|
||||||
|
DONTCARE, // 0
|
||||||
|
REQUIRE, // 1
|
||||||
|
SUGGEST, // 2
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const PixelFormat = enum(c_int) {
|
||||||
|
ANY, // 0
|
||||||
|
ANY_NO_ALPHA, // 1
|
||||||
|
ANY_WITH_ALPHA, // 2
|
||||||
|
ANY_15_NO_ALPHA, // 3
|
||||||
|
ANY_16_NO_ALPHA, // 4
|
||||||
|
ANY_16_WITH_ALPHA, // 5
|
||||||
|
ANY_24_NO_ALPHA, // 6
|
||||||
|
ANY_32_NO_ALPHA, // 7
|
||||||
|
ANY_32_WITH_ALPHA, // 8
|
||||||
|
ARGB_8888, // 9
|
||||||
|
RGBA_8888, // 10
|
||||||
|
ARGB_4444, // 11
|
||||||
|
RGB_888, // 12 // 24 bit format
|
||||||
|
RGB_565, // 13
|
||||||
|
RGB_555, // 14
|
||||||
|
RGBA_5551, // 15
|
||||||
|
ARGB_1555, // 16
|
||||||
|
ABGR_8888, // 17
|
||||||
|
XBGR_8888, // 18
|
||||||
|
BGR_888, // 19 // 24 bit format
|
||||||
|
BGR_565, // 20
|
||||||
|
BGR_555, // 21
|
||||||
|
RGBX_8888, // 22
|
||||||
|
XRGB_8888, // 23
|
||||||
|
ABGR_F32, // 24
|
||||||
|
ABGR_8888_LE, // 25
|
||||||
|
RGBA_4444, // 26
|
||||||
|
SINGLE_CHANNEL_8, // 27
|
||||||
|
COMPRESSED_RGBA_DXT1, // 28
|
||||||
|
COMPRESSED_RGBA_DXT3, // 29
|
||||||
|
COMPRESSED_RGBA_DXT5, // 30
|
||||||
|
ALLEGRO_NUM_PIXEL_FORMATS,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Timer = struct {
|
||||||
|
native: *c.ALLEGRO_TIMER,
|
||||||
|
|
||||||
|
pub fn destroy(self: Timer) void {
|
||||||
|
destroyTimer(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eventSource(self: Timer) EventSource {
|
||||||
|
return getTimerEventSource(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start(self: Timer) void {
|
||||||
|
startTimer(self);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn acknowledgeResize(display: Display) bool {
|
||||||
|
return c.al_acknowledge_resize(display.native);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clearToColor(color: Color) void {
|
||||||
|
c.al_clear_to_color(color.native);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn convertMemoryBitmaps() void {
|
||||||
|
c.al_convert_memory_bitmaps();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn createBitmap(width: i32, height: i32) !Bitmap {
|
||||||
|
const bitmap = c.al_create_bitmap(width, height);
|
||||||
|
if (bitmap) |native| {
|
||||||
|
return Bitmap{ .native = native };
|
||||||
|
}
|
||||||
|
return error.FailedToCreateBitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn createDisplay(width: i32, height: i32) !Display {
|
||||||
|
const display = c.al_create_display(width, height);
|
||||||
|
if (display) |native| {
|
||||||
|
return Display{ .native = native };
|
||||||
|
}
|
||||||
|
return error.FailedToCreateDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn createEventQueue() !EventQueue {
|
||||||
|
const queue = c.al_create_event_queue();
|
||||||
|
if (queue) |native| {
|
||||||
|
return EventQueue{ .native = native };
|
||||||
|
}
|
||||||
|
return error.FailedToCreateEventQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn createTimer(interval: f32) !Timer {
|
||||||
|
const timer = c.al_create_timer(interval);
|
||||||
|
if (timer) |native| {
|
||||||
|
return Timer{ .native = native };
|
||||||
|
}
|
||||||
|
return error.FailedToCreateTimer;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroyBitmap(bitmap: Bitmap) void {
|
||||||
|
c.al_destroy_bitmap(bitmap.native);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroyDisplay(display: Display) void {
|
||||||
|
c.al_destroy_display(display.native);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroyEventQueue(queue: EventQueue) void {
|
||||||
|
c.al_destroy_event_queue(queue.native);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroyFont(font: Font) void {
|
||||||
|
c.al_destroy_font(font.native);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroyTimer(timer: Timer) void {
|
||||||
|
c.al_destroy_timer(timer.native);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn drawBitmap(bitmap: Bitmap, dx: f32, dy: f32, flags: DrawFlags) void {
|
||||||
|
c.al_draw_bitmap(bitmap.native, dx, dy, @bitCast(c_int, flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn drawScaledBitmap(bitmap: Bitmap, sx: f32, sy: f32, sw: f32, sh: f32, dx: f32, dy: f32, dw: f32, dh: f32, flags: DrawFlags) void {
|
||||||
|
c.al_draw_scaled_bitmap(bitmap.native, sx, sy, sw, sh, dx, dy, dw, dh, @bitCast(c_int, flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn drawText(font: Font, color: Color, x: f32, y: f32, flags: DrawTextFlags, text: [*:0]const u8) void {
|
||||||
|
c.al_draw_text(font.native, color.native, x, y, @enumToInt(flags), text);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn drawTintedBitmap(bitmap: Bitmap, tint: Color, dx: f32, dy: f32, flags: DrawFlags) void {
|
||||||
|
c.al_draw_tinted_bitmap(bitmap.native, tint.native, dx, dy, @bitCast(c_int, flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn drawTintedScaledBitmap(bitmap: Bitmap, tint: Color, sx: f32, sy: f32, sw: f32, sh: f32, dx: f32, dy: f32, dw: f32, dh: f32, flags: DrawFlags) void {
|
||||||
|
c.al_draw_tinted_scaled_bitmap(bitmap.native, tint.native, sx, sy, sw, sh, dx, dy, dw, dh, @bitCast(c_int, flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dropNextEvent(queue: EventQueue) bool {
|
||||||
|
return c.al_drop_next_event(queue.native);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fclose(file: File) bool {
|
||||||
|
return c.al_fclose(file.native);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn flipDisplay() void {
|
||||||
|
c.al_flip_display();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn flushEventQueue(queue: EventQueue) void {
|
||||||
|
c.al_flush_event_queue(queue.native);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isEventQueueEmpty(queue: EventQueue) bool {
|
||||||
|
return c.al_is_event_queue_empty(queue.native);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getBackbuffer(display: Display) !Bitmap {
|
||||||
|
const bitmap = c.al_get_backbuffer(display.native);
|
||||||
|
if (bitmap) |native| {
|
||||||
|
return Bitmap{ .native = native };
|
||||||
|
}
|
||||||
|
return error.FailedToGetBackBufferForDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getBitmapHeight(bitmap: Bitmap) c_int {
|
||||||
|
return c.al_get_bitmap_height(bitmap.native);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getBitmapWidth(bitmap: Bitmap) c_int {
|
||||||
|
return c.al_get_bitmap_width(bitmap.native);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getCurrentDisplay() !Display {
|
||||||
|
const display = c.al_get_current_display();
|
||||||
|
if (display) |native| {
|
||||||
|
return Display{ .native = native };
|
||||||
|
}
|
||||||
|
return error.NoCurrentDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getDisplayEventSource(display: Display) EventSource {
|
||||||
|
return EventSource{ .native = c.al_get_display_event_source(display.native) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getDisplayFlags(display: Display) NewDisplayFlags {
|
||||||
|
return @bitCast(NewDisplayFlags, c.al_get_display_flags(display.native));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getDisplayHeight(display: Display) i32 {
|
||||||
|
return c.al_get_display_height(display.native);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getDisplayWidth(display: Display) i32 {
|
||||||
|
return c.al_get_display_width(display.native);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getFontAscent(font: Font) i32 {
|
||||||
|
return c.al_get_font_ascent(font.native);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getFontDescent(font: Font) i32 {
|
||||||
|
return c.al_get_font_descent(font.native);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getFontLineHeight(font: Font) i32 {
|
||||||
|
return c.al_get_font_line_height(font.native);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getKeyboardEventSource() EventSource {
|
||||||
|
return EventSource{ .native = c.al_get_keyboard_event_source() };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getNewBitmapFlags() NewBitmapFlags {
|
||||||
|
return c.al_set_new_bitmap_flags();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getNewDisplayOption(option: NewDisplayOption, importance: *OptionImportance) c_int {
|
||||||
|
return c.al_get_new_display_option(@enumToInt(option), @ptrCast(*c_int, importance));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getNewBitmapFormat() PixelFormat {
|
||||||
|
return c.al_set_new_bitmap_format();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getNewDisplayFlags() NewDisplayFlags {
|
||||||
|
return c.al_get_new_display_flags();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getNextEvent(queue: EventQueue, event: *Event) bool {
|
||||||
|
return c.al_get_next_event(queue.native, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getMouseEventSource() EventSource {
|
||||||
|
return EventSource{ .native = c.al_get_mouse_event_source() };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getTextWidth(font: Font, text: [*:0]const u8) void {
|
||||||
|
c.al_get_text_width(font.native, &text[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getTime() f64 {
|
||||||
|
return c.al_get_time();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getTimerEventSource(timer: Timer) EventSource {
|
||||||
|
return EventSource{ .native = c.al_get_timer_event_source(timer.native) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init() bool {
|
||||||
|
return c.al_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initFontAddon() bool {
|
||||||
|
return c.al_init_font_addon();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initImageAddon() bool {
|
||||||
|
return c.al_init_image_addon();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initTtfAddon() bool {
|
||||||
|
return c.al_init_ttf_addon();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn installKeyboard() bool {
|
||||||
|
return c.al_install_keyboard();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn installMouse() bool {
|
||||||
|
return c.al_install_mouse();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn loadBitmap(path: [*:0]const u8) !Bitmap {
|
||||||
|
const bitmap = c.al_load_bitmap(path);
|
||||||
|
if (bitmap) |native| {
|
||||||
|
return Bitmap{ .native = native };
|
||||||
|
}
|
||||||
|
return error.FailedToLoadBitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn loadBitmapF(file: File, ident: []const u8) !Bitmap {
|
||||||
|
const bitmap = c.al_load_bitmap_f(file.native, &ident[0]);
|
||||||
|
if (bitmap) |native| {
|
||||||
|
return Bitmap{ .native = native };
|
||||||
|
}
|
||||||
|
return error.FailedToLoadBitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn loadBitmapFont(path: [*:0]const u8) !Font {
|
||||||
|
const font = c.al_load_bitmap_font(path);
|
||||||
|
if (font) |native| {
|
||||||
|
return Font{ .native = native };
|
||||||
|
}
|
||||||
|
return error.FailedToLoadFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn loadFont(path: [*:0]const u8, size: i32, flags: c_int) !Font {
|
||||||
|
const font = c.al_load_font(path, size, flags);
|
||||||
|
if (font) |native| {
|
||||||
|
return Font{ .native = native };
|
||||||
|
}
|
||||||
|
return error.FailedToLoadFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn loadTtfFont(path: [*:0]const u8, size: i32, flags: LoadTtfFontFlags) !Font {
|
||||||
|
const font = c.al_load_ttf_font(path, size, @bitCast(c_int, flags));
|
||||||
|
if (font) |native| {
|
||||||
|
return Font{ .native = native };
|
||||||
|
}
|
||||||
|
return error.FailedToLoadFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mapRgb(r: u8, g: u8, b: u8) Color {
|
||||||
|
return Color{ .native = c.al_map_rgb(r, g, b) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mapRgba(r: u8, g: u8, b: u8, a: u8) Color {
|
||||||
|
return Color{ .native = c.al_map_rgba(r, g, b, a) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mapRgbaF(r: f32, g: f32, b: f32, a: f32) Color {
|
||||||
|
return Color{ .native = c.al_map_rgba_f(r, g, b, a) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mapRgbF(r: f32, g: f32, b: f32) Color {
|
||||||
|
return Color{ .native = c.al_map_rgb_f(r, g, b) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn openMemfile(data: []u8, mode: []const u8) !File {
|
||||||
|
const file = c.al_open_memfile(&data[0], @intCast(i64, data.len), &mode[0]);
|
||||||
|
if (file) |native| {
|
||||||
|
return File{ .native = native };
|
||||||
|
}
|
||||||
|
return error.FailedToOpenMemfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn peekNextEvent(queue: EventQueue, event: *Event) bool {
|
||||||
|
return c.al_peek_next_event(queue.native, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn registerEventSource(queue: EventQueue, source: EventSource) void {
|
||||||
|
c.al_register_event_source(queue.native, source.native);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setDisplayFlag(display: Display, flag: NewDisplayFlags, on: bool) bool {
|
||||||
|
return c.al_set_display_flag(display.native, @bitCast(c_int, flag), on);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setNewBitmapFlags(flags: NewBitmapFlags) void {
|
||||||
|
c.al_set_new_bitmap_flags(@bitCast(c_int, flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setNewBitmapFormat(format: PixelFormat) void {
|
||||||
|
c.al_set_new_bitmap_format(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setNewDisplayFlags(flags: NewDisplayFlags) void {
|
||||||
|
c.al_set_new_display_flags(@bitCast(c_int, flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setNewDisplayOption(option: NewDisplayOption, value: i32, importance: OptionImportance) void {
|
||||||
|
c.al_set_new_display_option(@enumToInt(option), value, @enumToInt(importance));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setTargetBitmap(bitmap: Bitmap) void {
|
||||||
|
c.al_set_target_bitmap(bitmap.native);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setTargetBackbuffer(display: Display) void {
|
||||||
|
c.al_set_target_bitmap(display.native);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn startTimer(timer: Timer) void {
|
||||||
|
c.al_start_timer(timer.native);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unregisterEventSource(queue: EventQueue, source: EventSource) void {
|
||||||
|
c.al_unregister_event_source(queue.native, source.native);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn waitForEvent(queue: EventQueue, event: *Event) void {
|
||||||
|
c.al_wait_for_event(queue.native, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn waitForVsync() bool {
|
||||||
|
return c.al_wait_for_vsync();
|
||||||
|
}
|
24
allegro/build.zig
Normal file
24
allegro/build.zig
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
fn current_file() []const u8 {
|
||||||
|
return @src().file;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cwd = std.fs.path.dirname(current_file()).?;
|
||||||
|
const path_separator = std.fs.path.sep_str;
|
||||||
|
|
||||||
|
/// add this package to exe
|
||||||
|
pub fn addTo(comptime allegro_dir: []const u8, exe: *std.build.LibExeObjStep) void {
|
||||||
|
exe.addAnonymousModule("allegro", .{ .source_file = .{ .path = cwd ++ path_separator ++ "allegro.zig" } });
|
||||||
|
if (allegro_dir.len > 0) {
|
||||||
|
exe.addIncludePath(allegro_dir ++ path_separator ++ "include");
|
||||||
|
exe.addLibraryPath(allegro_dir ++ path_separator ++ "lib");
|
||||||
|
}
|
||||||
|
exe.linkLibC();
|
||||||
|
|
||||||
|
exe.linkSystemLibrary("allegro");
|
||||||
|
exe.linkSystemLibrary("allegro_font");
|
||||||
|
exe.linkSystemLibrary("allegro_image");
|
||||||
|
exe.linkSystemLibrary("allegro_memfile");
|
||||||
|
exe.linkSystemLibrary("allegro_ttf");
|
||||||
|
}
|
8
allegro/c.zig
Normal file
8
allegro/c.zig
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
pub const c = @cImport({
|
||||||
|
@cInclude("stdint.h");
|
||||||
|
@cInclude("allegro5/allegro.h");
|
||||||
|
@cInclude("allegro5/allegro_font.h");
|
||||||
|
@cInclude("allegro5/allegro_image.h");
|
||||||
|
@cInclude("allegro5/allegro_memfile.h");
|
||||||
|
@cInclude("allegro5/allegro_ttf.h");
|
||||||
|
});
|
75
build.zig
Normal file
75
build.zig
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const allegro = @import("allegro/build.zig");
|
||||||
|
|
||||||
|
const allegroPath = @embedFile("allegro.path");
|
||||||
|
|
||||||
|
// Although this function looks imperative, note that its job is to
|
||||||
|
// declaratively construct a build graph that will be executed by an external
|
||||||
|
// runner.
|
||||||
|
pub fn build(b: *std.Build) void {
|
||||||
|
// Standard target options allows the person running `zig build` to choose
|
||||||
|
// what target to build for. Here we do not override the defaults, which
|
||||||
|
// means any target is allowed, and the default is native. Other options
|
||||||
|
// for restricting supported target set are available.
|
||||||
|
const target = b.standardTargetOptions(.{});
|
||||||
|
|
||||||
|
// Standard optimization options allow the person running `zig build` to select
|
||||||
|
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
|
||||||
|
// set a preferred release mode, allowing the user to decide how to optimize.
|
||||||
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
|
const exe = b.addExecutable(.{
|
||||||
|
.name = "tins2023",
|
||||||
|
// In this case the main source file is merely a path, however, in more
|
||||||
|
// complicated build scripts, this could be a generated file.
|
||||||
|
.root_source_file = .{ .path = "src/main.zig" },
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
|
||||||
|
allegro.addTo(allegroPath, exe);
|
||||||
|
|
||||||
|
// This declares intent for the executable to be installed into the
|
||||||
|
// standard location when the user invokes the "install" step (the default
|
||||||
|
// step when running `zig build`).
|
||||||
|
b.installArtifact(exe);
|
||||||
|
|
||||||
|
// This *creates* a Run step in the build graph, to be executed when another
|
||||||
|
// step is evaluated that depends on it. The next line below will establish
|
||||||
|
// such a dependency.
|
||||||
|
const run_cmd = b.addRunArtifact(exe);
|
||||||
|
|
||||||
|
// By making the run step depend on the install step, it will be run from the
|
||||||
|
// installation directory rather than directly from within the cache directory.
|
||||||
|
// This is not necessary, however, if the application depends on other installed
|
||||||
|
// files, this ensures they will be present and in the expected location.
|
||||||
|
run_cmd.step.dependOn(b.getInstallStep());
|
||||||
|
|
||||||
|
// This allows the user to pass arguments to the application in the build
|
||||||
|
// command itself, like this: `zig build run -- arg1 arg2 etc`
|
||||||
|
if (b.args) |args| {
|
||||||
|
run_cmd.addArgs(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This creates a build step. It will be visible in the `zig build --help` menu,
|
||||||
|
// and can be selected like this: `zig build run`
|
||||||
|
// This will evaluate the `run` step rather than the default, which is "install".
|
||||||
|
const run_step = b.step("run", "Run the app");
|
||||||
|
run_step.dependOn(&run_cmd.step);
|
||||||
|
|
||||||
|
// Creates a step for unit testing. This only builds the test executable
|
||||||
|
// but does not run it.
|
||||||
|
const unit_tests = b.addTest(.{
|
||||||
|
.root_source_file = .{ .path = "src/main.zig" },
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
|
||||||
|
const run_unit_tests = b.addRunArtifact(unit_tests);
|
||||||
|
|
||||||
|
// Similar to creating the run step earlier, this exposes a `test` step to
|
||||||
|
// the `zig build --help` menu, providing a way for the user to request
|
||||||
|
// running the unit tests.
|
||||||
|
const test_step = b.step("test", "Run unit tests");
|
||||||
|
test_step.dependOn(&run_unit_tests.step);
|
||||||
|
}
|
93
src/assets/fonts/Cabin-OFL.txt
Normal file
93
src/assets/fonts/Cabin-OFL.txt
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
Copyright 2018 The Cabin Project Authors (https://github.com/impallari/Cabin.git)
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
http://scripts.sil.org/OFL
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
BIN
src/assets/fonts/Cabin-Regular.ttf
Normal file
BIN
src/assets/fonts/Cabin-Regular.ttf
Normal file
Binary file not shown.
BIN
src/assets/images/opaque.png
Normal file
BIN
src/assets/images/opaque.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 135 B |
BIN
src/assets/images/title_untitled.png
Normal file
BIN
src/assets/images/title_untitled.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
92
src/context.zig
Normal file
92
src/context.zig
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const allegro = @import("allegro");
|
||||||
|
const engine = @import("engine.zig");
|
||||||
|
const Palette = @import("palette.zig").Palette;
|
||||||
|
const Scene = @import("scene.zig").Scene;
|
||||||
|
|
||||||
|
pub const Context = struct {
|
||||||
|
const DefaultDisplayWidth = 1280;
|
||||||
|
const DefaultDisplayHeight = 720;
|
||||||
|
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
|
palette: Palette = undefined,
|
||||||
|
shouldQuit: bool = false,
|
||||||
|
scene: ?Scene = null,
|
||||||
|
|
||||||
|
display: allegro.Display,
|
||||||
|
events: allegro.EventQueue,
|
||||||
|
|
||||||
|
viewport: engine.Viewport,
|
||||||
|
fonts: engine.Fonts,
|
||||||
|
textures: engine.Textures,
|
||||||
|
|
||||||
|
pub fn init(allocator: std.mem.Allocator) !Context {
|
||||||
|
_ = allegro.init();
|
||||||
|
_ = allegro.initImageAddon();
|
||||||
|
_ = allegro.installKeyboard();
|
||||||
|
_ = allegro.installMouse();
|
||||||
|
_ = allegro.initFontAddon();
|
||||||
|
_ = allegro.initTtfAddon();
|
||||||
|
|
||||||
|
allegro.setNewDisplayOption(allegro.NewDisplayOption.VSYNC, 1, allegro.OptionImportance.REQUIRE);
|
||||||
|
allegro.setNewDisplayOption(allegro.NewDisplayOption.SAMPLE_BUFFERS, 1, allegro.OptionImportance.REQUIRE);
|
||||||
|
allegro.setNewDisplayOption(allegro.NewDisplayOption.SAMPLES, 4, allegro.OptionImportance.REQUIRE);
|
||||||
|
allegro.setNewDisplayFlags(allegro.NewDisplayFlags{ .RESIZABLE = true });
|
||||||
|
|
||||||
|
const viewport = engine.Viewport.init(DefaultDisplayWidth, DefaultDisplayHeight);
|
||||||
|
const display = try allegro.createDisplay(DefaultDisplayWidth, DefaultDisplayHeight);
|
||||||
|
|
||||||
|
const events = try allegro.createEventQueue();
|
||||||
|
|
||||||
|
events.registerDisplay(display);
|
||||||
|
events.registerKeyboard();
|
||||||
|
events.registerMouse();
|
||||||
|
|
||||||
|
return Context{
|
||||||
|
.allocator = allocator,
|
||||||
|
.display = display,
|
||||||
|
.events = events,
|
||||||
|
.viewport = viewport,
|
||||||
|
.fonts = engine.Fonts.init(allocator),
|
||||||
|
.textures = engine.Textures.init(allocator),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exitScene(self: *Context) void {
|
||||||
|
if (self.scene) |scene| {
|
||||||
|
scene.exit(self);
|
||||||
|
scene.deinit();
|
||||||
|
self.scene = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Context) void {
|
||||||
|
self.events.destroy();
|
||||||
|
self.display.destroy();
|
||||||
|
self.exitScene();
|
||||||
|
self.fonts.deinit();
|
||||||
|
self.textures.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn quit(self: *Context) void {
|
||||||
|
self.shouldQuit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resized(self: *Context, width: i32, height: i32) void {
|
||||||
|
self.viewport.update(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn switchToScene(self: *Context, comptime SceneType: type, build: ?*const fn (*SceneType) void) !void {
|
||||||
|
self.exitScene();
|
||||||
|
|
||||||
|
const scene = try Scene.init(SceneType, self.allocator, build);
|
||||||
|
self.scene = scene;
|
||||||
|
scene.enter(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toggleFullScreen(self: *Context) void {
|
||||||
|
var displayFlags = allegro.getDisplayFlags(self.display);
|
||||||
|
_ = allegro.setDisplayFlag(self.display, allegro.NewDisplayFlags{ .FULLSCREEN_WINDOW = true }, !displayFlags.FULLSCREEN_WINDOW);
|
||||||
|
self.viewport.update(self.display.width(), self.display.height());
|
||||||
|
}
|
||||||
|
};
|
11
src/engine.zig
Normal file
11
src/engine.zig
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
const assets = @import("engine/assets.zig");
|
||||||
|
|
||||||
|
pub const Fonts = assets.Fonts;
|
||||||
|
pub const OpaquePtr = @import("engine/opaque_ptr.zig").OpaquePtr;
|
||||||
|
pub const Point = @import("engine/point.zig").Point;
|
||||||
|
pub const PointF = @import("engine/point_f.zig").PointF;
|
||||||
|
pub const Rectangle = @import("engine/rectangle.zig").Rectangle;
|
||||||
|
pub const RectangleF = @import("engine/rectangle_f.zig").RectangleF;
|
||||||
|
pub const Scene = @import("engine/scene.zig").Scene;
|
||||||
|
pub const Textures = assets.Textures;
|
||||||
|
pub const Viewport = @import("engine/viewport.zig").Viewport;
|
97
src/engine/assets.zig
Normal file
97
src/engine/assets.zig
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const allegro = @import("allegro");
|
||||||
|
|
||||||
|
pub fn Assets(comptime Asset: type, comptime destroy: *const fn (Asset) void) type {
|
||||||
|
return struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
assets: std.StringHashMap(Asset),
|
||||||
|
|
||||||
|
pub fn init(allocator: std.mem.Allocator) Self {
|
||||||
|
return Self{
|
||||||
|
.assets = std.StringHashMap(Asset).init(allocator),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Self) void {
|
||||||
|
var assets = self.assets.iterator();
|
||||||
|
while (assets.next()) |entry| {
|
||||||
|
destroy(entry.value_ptr.*);
|
||||||
|
}
|
||||||
|
self.assets.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(self: Self, name: []const u8) ?Asset {
|
||||||
|
return self.assets.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn put(self: *Self, name: []const u8, asset: Asset) !void {
|
||||||
|
try self.assets.put(name, asset);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const Fonts = struct {
|
||||||
|
fn destroy(font: allegro.Font) void {
|
||||||
|
font.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
const Map = Assets(allegro.Font, Fonts.destroy);
|
||||||
|
|
||||||
|
assets: Map,
|
||||||
|
|
||||||
|
pub fn init(allocator: std.mem.Allocator) Fonts {
|
||||||
|
return Fonts{
|
||||||
|
.assets = Map.init(allocator),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Fonts) void {
|
||||||
|
self.assets.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addFromFileTTF(self: *Fonts, name: []const u8, path: [*:0]const u8, size: i32) !void {
|
||||||
|
const font = try allegro.loadTtfFont(path, size, allegro.LoadTtfFontFlags{});
|
||||||
|
try self.assets.put(name, font);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(self: Fonts, name: []const u8) ?allegro.Font {
|
||||||
|
return self.assets.get(name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Textures = struct {
|
||||||
|
fn destroy(bitmap: allegro.Bitmap) void {
|
||||||
|
bitmap.destroy();
|
||||||
|
}
|
||||||
|
const Map = Assets(allegro.Bitmap, destroy);
|
||||||
|
|
||||||
|
assets: Map,
|
||||||
|
|
||||||
|
pub fn init(allocator: std.mem.Allocator) Textures {
|
||||||
|
return Textures{
|
||||||
|
.assets = Map.init(allocator),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Textures) void {
|
||||||
|
self.assets.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addFromFile(self: *Textures, name: []const u8, path: [*:0]const u8) !void {
|
||||||
|
const bitmap = try allegro.loadBitmap(path);
|
||||||
|
try self.assets.put(name, bitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addFromMemoryPNG(self: *Textures, name: []const u8, data: []const u8) !void {
|
||||||
|
const memoryFile = try allegro.openMemfile(@constCast(data), "r");
|
||||||
|
defer _ = allegro.fclose(memoryFile);
|
||||||
|
|
||||||
|
const bitmap = try allegro.loadBitmapF(memoryFile, ".png");
|
||||||
|
try self.assets.put(name, bitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(self: Textures, name: []const u8) ?allegro.Bitmap {
|
||||||
|
return self.assets.get(name);
|
||||||
|
}
|
||||||
|
};
|
43
src/engine/opaque_ptr.zig
Normal file
43
src/engine/opaque_ptr.zig
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
|
pub const OpaquePtr = struct {
|
||||||
|
allocator: Allocator,
|
||||||
|
object: usize = undefined,
|
||||||
|
virtualTable: VirtualTable = undefined,
|
||||||
|
|
||||||
|
const VirtualTable = struct {
|
||||||
|
destroy: *const fn (OpaquePtr) void,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn Object(comptime Type: type) type {
|
||||||
|
return struct {
|
||||||
|
ptr: *Type,
|
||||||
|
opaquePtr: OpaquePtr,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create(comptime Type: type, allocator: Allocator) !Object(Type) {
|
||||||
|
const ptr = try allocator.create(Type);
|
||||||
|
const opaq = OpaquePtr{
|
||||||
|
.allocator = allocator,
|
||||||
|
.object = @ptrToInt(ptr),
|
||||||
|
.virtualTable = .{
|
||||||
|
.destroy = struct {
|
||||||
|
fn destroy(self: OpaquePtr) void {
|
||||||
|
const object = @intToPtr(*Type, self.object);
|
||||||
|
self.allocator.destroy(object);
|
||||||
|
}
|
||||||
|
}.destroy,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return Object(Type){
|
||||||
|
.ptr = ptr,
|
||||||
|
.opaquePtr = opaq,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(self: OpaquePtr) void {
|
||||||
|
self.virtualTable.destroy(self);
|
||||||
|
}
|
||||||
|
};
|
30
src/engine/point.zig
Normal file
30
src/engine/point.zig
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
const PointF = @import("point_f.zig").PointF;
|
||||||
|
|
||||||
|
pub const Point = struct {
|
||||||
|
x: i64,
|
||||||
|
y: i64,
|
||||||
|
|
||||||
|
pub fn init(x: i64, y: i64) Point {
|
||||||
|
return Point{ .x = x, .y = y };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initUsize(x: usize, y: usize) Point {
|
||||||
|
return Point.init(@intCast(i64, x), @intCast(i64, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add(self: Point, other: Point) Point {
|
||||||
|
return Point{ .x = self.x + other.x, .y = self.y + other.y };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn float(self: Point) PointF {
|
||||||
|
return PointF{ .x = @intToFloat(f32, self.x), .y = @intToFloat(f32, self.y) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn multiply(self: Point, factor: i64) Point {
|
||||||
|
return Point{ .x = self.x * factor, .y = self.y * factor };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subtract(self: Point, other: Point) Point {
|
||||||
|
return Point{ .x = self.x - other.x, .y = self.y - other.y };
|
||||||
|
}
|
||||||
|
};
|
36
src/engine/point_f.zig
Normal file
36
src/engine/point_f.zig
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const Point = @import("point.zig").Point;
|
||||||
|
|
||||||
|
pub const PointF = struct {
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
|
||||||
|
pub fn init(x: f32, y: f32) PointF {
|
||||||
|
return PointF{ .x = x, .y = y };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add(self: PointF, other: PointF) PointF {
|
||||||
|
return PointF{ .x = self.x + other.x, .y = self.y + other.y };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ceil(self: PointF) PointF {
|
||||||
|
return PointF{ .x = std.math.ceil(self.x), .y = std.math.ceil(self.y) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn floor(self: PointF) PointF {
|
||||||
|
return PointF{ .x = std.math.floor(self.x), .y = std.math.floor(self.y) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn integer(self: PointF) Point {
|
||||||
|
return Point{ .x = @floatToInt(i64, self.x), .y = @floatToInt(i64, self.y) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn multiply(self: PointF, factor: f32) PointF {
|
||||||
|
return PointF{ .x = self.x * factor, .y = self.y * factor };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subtract(self: PointF, other: PointF) PointF {
|
||||||
|
return PointF{ .x = self.x - other.x, .y = self.y - other.y };
|
||||||
|
}
|
||||||
|
};
|
75
src/engine/rectangle.zig
Normal file
75
src/engine/rectangle.zig
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
const Point = @import("point.zig").Point;
|
||||||
|
|
||||||
|
pub const Rectangle = struct {
|
||||||
|
min: Point,
|
||||||
|
max: Point,
|
||||||
|
|
||||||
|
pub fn init(min: Point, max: Point) Rectangle {
|
||||||
|
if (min.x > max.x) unreachable;
|
||||||
|
if (min.y > max.y) unreachable;
|
||||||
|
|
||||||
|
return Rectangle{ .min = min, .max = max };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initAbsolute(x1: i64, y1: i64, x2: i64, y2: i64) Rectangle {
|
||||||
|
if (x1 < x2) {
|
||||||
|
if (y1 < y2) {
|
||||||
|
return Rectangle{
|
||||||
|
.min = Point{ .x = x1, .y = y1 },
|
||||||
|
.max = Point{ .x = x2, .y = y2 },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return Rectangle{
|
||||||
|
.min = Point{ .x = x1, .y = y2 },
|
||||||
|
.max = Point{ .x = x2, .y = y1 },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (y1 < y2) {
|
||||||
|
return Rectangle{
|
||||||
|
.min = Point{ .x = x2, .y = y1 },
|
||||||
|
.max = Point{ .x = x1, .y = y2 },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return Rectangle{
|
||||||
|
.min = Point{ .x = x2, .y = y2 },
|
||||||
|
.max = Point{ .x = x1, .y = y1 },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initRelative(x: i64, y: i64, w: i64, h: i64) Rectangle {
|
||||||
|
if (w < 0) {
|
||||||
|
if (h < 0) {
|
||||||
|
return Rectangle{
|
||||||
|
.min = Point{ .x = x + w, .y = y + h },
|
||||||
|
.max = Point{ .x = x, .y = y },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return Rectangle{
|
||||||
|
.min = Point{ .x = x + w, .y = y },
|
||||||
|
.max = Point{ .x = x, .y = y + h },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (h < 0) {
|
||||||
|
return Rectangle{
|
||||||
|
.min = Point{ .x = x, .y = y + h },
|
||||||
|
.max = Point{ .x = x + w, .y = y },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return Rectangle{
|
||||||
|
.min = Point{ .x = x, .y = y },
|
||||||
|
.max = Point{ .x = x + w, .y = y + h },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn center(self: Rectangle) Point {
|
||||||
|
return Point.init(@divTrunc(self.min.x + self.max.x, 2), @divTrunc(self.min.y + self.max.y, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn height(self: Rectangle) i64 {
|
||||||
|
return self.max.y - self.min.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn width(self: Rectangle) i64 {
|
||||||
|
return self.max.x - self.min.x;
|
||||||
|
}
|
||||||
|
};
|
75
src/engine/rectangle_f.zig
Normal file
75
src/engine/rectangle_f.zig
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
const PointF = @import("point_f.zig").PointF;
|
||||||
|
|
||||||
|
pub const RectangleF = struct {
|
||||||
|
min: PointF,
|
||||||
|
max: PointF,
|
||||||
|
|
||||||
|
pub fn init(min: PointF, max: PointF) RectangleF {
|
||||||
|
if (min.x > max.x) unreachable;
|
||||||
|
if (min.y > max.y) unreachable;
|
||||||
|
|
||||||
|
return RectangleF{ .min = min, .max = max };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initAbsolute(x1: f32, y1: f32, x2: f32, y2: f32) RectangleF {
|
||||||
|
if (x1 < x2) {
|
||||||
|
if (y1 < y2) {
|
||||||
|
return RectangleF{
|
||||||
|
.min = PointF{ .x = x1, .y = y1 },
|
||||||
|
.max = PointF{ .x = x2, .y = y2 },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return RectangleF{
|
||||||
|
.min = PointF{ .x = x1, .y = y2 },
|
||||||
|
.max = PointF{ .x = x2, .y = y1 },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (y1 < y2) {
|
||||||
|
return RectangleF{
|
||||||
|
.min = PointF{ .x = x2, .y = y1 },
|
||||||
|
.max = PointF{ .x = x1, .y = y2 },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return RectangleF{
|
||||||
|
.min = PointF{ .x = x2, .y = y2 },
|
||||||
|
.max = PointF{ .x = x1, .y = y1 },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initRelative(x: f32, y: f32, w: f32, h: f32) RectangleF {
|
||||||
|
if (w < 0) {
|
||||||
|
if (h < 0) {
|
||||||
|
return RectangleF{
|
||||||
|
.min = PointF{ .x = x + w, .y = y + h },
|
||||||
|
.max = PointF{ .x = x, .y = y },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return RectangleF{
|
||||||
|
.min = PointF{ .x = x + w, .y = y },
|
||||||
|
.max = PointF{ .x = x, .y = y + h },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (h < 0) {
|
||||||
|
return RectangleF{
|
||||||
|
.min = PointF{ .x = x, .y = y + h },
|
||||||
|
.max = PointF{ .x = x + w, .y = y },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return RectangleF{
|
||||||
|
.min = PointF{ .x = x, .y = y },
|
||||||
|
.max = PointF{ .x = x + w, .y = y + h },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn center(self: RectangleF) PointF {
|
||||||
|
return self.min.add(self.max).multiply(0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn height(self: RectangleF) f32 {
|
||||||
|
return self.max.y - self.min.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn width(self: RectangleF) f32 {
|
||||||
|
return self.max.x - self.min.x;
|
||||||
|
}
|
||||||
|
};
|
90
src/engine/scene.zig
Normal file
90
src/engine/scene.zig
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const OpaquePtr = @import("opaque_ptr.zig").OpaquePtr;
|
||||||
|
|
||||||
|
pub fn Scene(comptime Context: type, comptime Event: type) type {
|
||||||
|
return struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
object: usize = undefined,
|
||||||
|
virtualTable: VirtualTable = undefined,
|
||||||
|
opaquePtr: ?OpaquePtr = null,
|
||||||
|
|
||||||
|
const VirtualTable = struct {
|
||||||
|
enter: *const fn (Self, *Context) void,
|
||||||
|
exit: *const fn (Self, *Context) void,
|
||||||
|
handle: *const fn (Self, *Context, Event) anyerror!void,
|
||||||
|
update: *const fn (Self, *Context, f32) void,
|
||||||
|
render: *const fn (Self, *Context) void,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn enter(self: Self, ctx: *Context) void {
|
||||||
|
self.virtualTable.enter(self, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exit(self: Self, ctx: *Context) void {
|
||||||
|
self.virtualTable.exit(self, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle(self: Self, ctx: *Context, event: Event) !void {
|
||||||
|
try self.virtualTable.handle(self, ctx, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(self: Self, ctx: *Context, dt: f32) void {
|
||||||
|
self.virtualTable.update(self, ctx, dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(self: Self, ctx: *Context) void {
|
||||||
|
self.virtualTable.render(self, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn makeOpaque(comptime SceneType: type, object: *SceneType) Self {
|
||||||
|
return Self{ .object = @ptrToInt(object), .virtualTable = .{
|
||||||
|
.enter = struct {
|
||||||
|
fn enter(self: Self, ctx: *Context) void {
|
||||||
|
const scene = @intToPtr(*SceneType, self.object);
|
||||||
|
scene.enter(ctx);
|
||||||
|
}
|
||||||
|
}.enter,
|
||||||
|
.exit = struct {
|
||||||
|
fn exit(self: Self, ctx: *Context) void {
|
||||||
|
const scene = @intToPtr(*SceneType, self.object);
|
||||||
|
scene.exit(ctx);
|
||||||
|
}
|
||||||
|
}.exit,
|
||||||
|
.handle = struct {
|
||||||
|
fn handle(self: Self, ctx: *Context, event: Event) !void {
|
||||||
|
const scene = @intToPtr(*SceneType, self.object);
|
||||||
|
try scene.handle(ctx, event);
|
||||||
|
}
|
||||||
|
}.handle,
|
||||||
|
.update = struct {
|
||||||
|
fn update(self: Self, ctx: *Context, dt: f32) void {
|
||||||
|
const scene = @intToPtr(*SceneType, self.object);
|
||||||
|
scene.update(ctx, dt);
|
||||||
|
}
|
||||||
|
}.update,
|
||||||
|
.render = struct {
|
||||||
|
fn render(self: Self, ctx: *Context) void {
|
||||||
|
const scene = @intToPtr(*SceneType, self.object);
|
||||||
|
scene.render(ctx);
|
||||||
|
}
|
||||||
|
}.render,
|
||||||
|
} };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(comptime SceneType: type, allocator: std.mem.Allocator, build: ?*const fn (*SceneType) void) !Self {
|
||||||
|
const object = try OpaquePtr.create(SceneType, allocator);
|
||||||
|
var scene = Self.makeOpaque(SceneType, object.ptr);
|
||||||
|
if (build) |b| {
|
||||||
|
b(object.ptr);
|
||||||
|
}
|
||||||
|
return scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: Self) void {
|
||||||
|
if (self.opaquePtr) |ptr| {
|
||||||
|
ptr.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
54
src/engine/viewport.zig
Normal file
54
src/engine/viewport.zig
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
const PointF = @import("point_f.zig").PointF;
|
||||||
|
const RectangleF = @import("rectangle_f.zig").RectangleF;
|
||||||
|
|
||||||
|
pub const Viewport = struct {
|
||||||
|
unscaledWidth: i32,
|
||||||
|
unscaledHeight: i32,
|
||||||
|
|
||||||
|
actualWidth: i32,
|
||||||
|
actualHeight: i32,
|
||||||
|
|
||||||
|
scaledWidth: i32,
|
||||||
|
scaledHeight: i32,
|
||||||
|
bounds: RectangleF,
|
||||||
|
scale: f32,
|
||||||
|
|
||||||
|
pub fn init(width: i32, height: i32) Viewport {
|
||||||
|
return Viewport{
|
||||||
|
.unscaledWidth = width,
|
||||||
|
.unscaledHeight = height,
|
||||||
|
.actualWidth = width,
|
||||||
|
.actualHeight = height,
|
||||||
|
.scaledWidth = width,
|
||||||
|
.scaledHeight = height,
|
||||||
|
.bounds = RectangleF.initRelative(0, 0, @intToFloat(f32, width), @intToFloat(f32, height)),
|
||||||
|
.scale = 1.0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn center(self: Viewport) PointF {
|
||||||
|
return self.bounds.center();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(self: *Viewport, width: i32, height: i32) void {
|
||||||
|
self.actualWidth = width;
|
||||||
|
self.actualHeight = height;
|
||||||
|
|
||||||
|
const horizontalRatio = @intToFloat(f32, width) / @intToFloat(f32, self.unscaledWidth);
|
||||||
|
const verticalRatio = @intToFloat(f32, height) / @intToFloat(f32, self.unscaledHeight);
|
||||||
|
|
||||||
|
if (horizontalRatio < verticalRatio) {
|
||||||
|
self.scaledWidth = width;
|
||||||
|
self.scaledHeight = @floatToInt(i32, horizontalRatio * @intToFloat(f32, self.unscaledHeight));
|
||||||
|
const top = @divFloor(height - self.scaledHeight, 2);
|
||||||
|
self.bounds = RectangleF.initRelative(0, @intToFloat(f32, top), @intToFloat(f32, width), @intToFloat(f32, self.scaledHeight));
|
||||||
|
self.scale = horizontalRatio;
|
||||||
|
} else {
|
||||||
|
self.scaledWidth = @floatToInt(i32, verticalRatio * @intToFloat(f32, self.unscaledWidth));
|
||||||
|
self.scaledHeight = height;
|
||||||
|
const left = @divFloor(width - self.scaledWidth, 2);
|
||||||
|
self.bounds = RectangleF.initRelative(@intToFloat(f32, left), 0, @intToFloat(f32, self.scaledWidth), @intToFloat(f32, height));
|
||||||
|
self.scale = verticalRatio;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
98
src/main.zig
Normal file
98
src/main.zig
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const allegro = @import("allegro");
|
||||||
|
const engine = @import("engine.zig");
|
||||||
|
const Context = @import("context.zig").Context;
|
||||||
|
const Palette = @import("palette.zig").Palette;
|
||||||
|
const TitleScene = @import("title_scene.zig").TitleScene;
|
||||||
|
|
||||||
|
fn currentFile() []const u8 {
|
||||||
|
return @src().file;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sourceDir = std.fs.path.dirname(currentFile()).?;
|
||||||
|
const assetsDir = sourceDir ++ "/assets";
|
||||||
|
|
||||||
|
fn hexColor(hex: []const u8) allegro.Color {
|
||||||
|
return allegro.Color.initFromHex(hex);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
// Primary: #551485
|
||||||
|
// Secondary: #e44b50
|
||||||
|
// Tertiary: #479be6
|
||||||
|
// Neutral: #948f94
|
||||||
|
|
||||||
|
var arena = std.heap.ArenaAllocator.init(std.heap.c_allocator);
|
||||||
|
defer arena.deinit();
|
||||||
|
const allocator = arena.allocator();
|
||||||
|
|
||||||
|
var context = try Context.init(allocator);
|
||||||
|
defer context.deinit();
|
||||||
|
context.palette = Palette{
|
||||||
|
.primary = .{ .background = hexColor("#7d42ad"), .text = hexColor("#ffffff") },
|
||||||
|
.primaryContainer = .{ .background = hexColor("#f2daff"), .text = hexColor("#2e004e") },
|
||||||
|
.secondary = .{ .background = hexColor("#b32731"), .text = hexColor("#ffffff") },
|
||||||
|
.secondaryContainer = .{ .background = hexColor("#ffdad8"), .text = hexColor("#410006") },
|
||||||
|
.tertiary = .{ .background = hexColor("#0062a0"), .text = hexColor("#ffffff") },
|
||||||
|
.tertiaryContainer = .{ .background = hexColor("#d0e4ff"), .text = hexColor("#001d35") },
|
||||||
|
.background = .{ .background = hexColor("#fffbff"), .text = hexColor("#2b0052") },
|
||||||
|
.outline = hexColor("#7c757e"),
|
||||||
|
};
|
||||||
|
|
||||||
|
allegro.setNewBitmapFlags(allegro.NewBitmapFlags{ .MIN_LINEAR = true, .MAG_LINEAR = true });
|
||||||
|
try context.textures.addFromFile("opaque", assetsDir ++ "/images/opaque.png");
|
||||||
|
try context.textures.addFromFile("title_untitled", assetsDir ++ "/images/title_untitled.png");
|
||||||
|
allegro.convertMemoryBitmaps();
|
||||||
|
|
||||||
|
try context.fonts.addFromFileTTF("sub", assetsDir ++ "/fonts/Cabin-Regular.ttf", 16);
|
||||||
|
try context.fonts.addFromFileTTF("default", assetsDir ++ "/fonts/Cabin-Regular.ttf", 32);
|
||||||
|
|
||||||
|
try context.switchToScene(TitleScene, null);
|
||||||
|
|
||||||
|
var t = allegro.getTime();
|
||||||
|
while (!context.shouldQuit) {
|
||||||
|
const scene = if (context.scene) |scene| scene else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
while (!context.events.isEmpty()) {
|
||||||
|
var event: allegro.Event = undefined;
|
||||||
|
_ = context.events.get(&event);
|
||||||
|
switch (event.type) {
|
||||||
|
allegro.c.ALLEGRO_EVENT_DISPLAY_CLOSE => context.quit(),
|
||||||
|
allegro.c.ALLEGRO_EVENT_DISPLAY_RESIZE => {
|
||||||
|
context.resized(event.display.width, event.display.height);
|
||||||
|
_ = allegro.acknowledgeResize(allegro.Display{ .native = event.display.source.? });
|
||||||
|
},
|
||||||
|
allegro.c.ALLEGRO_EVENT_KEY_CHAR => {
|
||||||
|
switch (event.keyboard.keycode) {
|
||||||
|
allegro.c.ALLEGRO_KEY_ESCAPE => context.quit(),
|
||||||
|
allegro.c.ALLEGRO_KEY_F11 => context.toggleFullScreen(),
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
if (context.shouldQuit) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
try scene.handle(&context, &event);
|
||||||
|
}
|
||||||
|
|
||||||
|
const newT = allegro.getTime();
|
||||||
|
const deltaT = @floatCast(f32, newT - t);
|
||||||
|
t = newT;
|
||||||
|
scene.update(&context, deltaT);
|
||||||
|
|
||||||
|
scene.render(&context);
|
||||||
|
|
||||||
|
allegro.flipDisplay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "simple test" {
|
||||||
|
var list = std.ArrayList(i32).init(std.testing.allocator);
|
||||||
|
defer list.deinit(); // try commenting this out and see if zig detects the memory leak!
|
||||||
|
try list.append(42);
|
||||||
|
try std.testing.expectEqual(@as(i32, 42), list.pop());
|
||||||
|
}
|
36
src/main_menu_scene.zig
Normal file
36
src/main_menu_scene.zig
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
const allegro = @import("allegro");
|
||||||
|
const Context = @import("context.zig").Context;
|
||||||
|
|
||||||
|
pub const MainMenuScene = struct {
|
||||||
|
pub fn enter(self: *MainMenuScene, ctx: *Context) void {
|
||||||
|
_ = ctx;
|
||||||
|
_ = self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exit(self: *MainMenuScene, ctx: *Context) void {
|
||||||
|
_ = ctx;
|
||||||
|
_ = self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle(self: *MainMenuScene, ctx: *Context, event: *allegro.Event) !void {
|
||||||
|
_ = event;
|
||||||
|
_ = ctx;
|
||||||
|
_ = self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(self: *MainMenuScene, ctx: *Context, dt: f32) void {
|
||||||
|
_ = self;
|
||||||
|
_ = dt;
|
||||||
|
_ = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(self: *MainMenuScene, ctx: *Context) void {
|
||||||
|
_ = self;
|
||||||
|
allegro.clearToColor(ctx.palette.background.background);
|
||||||
|
|
||||||
|
const center = ctx.viewport.center();
|
||||||
|
ctx.textures.get("title_untitled").?.drawTintedCenteredScaled(ctx.palette.background.text, center.x, ctx.viewport.bounds.min.y + ctx.viewport.scale * 100, 0.5 * ctx.viewport.scale);
|
||||||
|
|
||||||
|
allegro.drawText(ctx.fonts.get("default").?, ctx.palette.background.text, center.x, ctx.viewport.bounds.min.y + ctx.viewport.scale * 200, allegro.DrawTextFlags.ALIGN_CENTER, "Play game");
|
||||||
|
}
|
||||||
|
};
|
14
src/palette.zig
Normal file
14
src/palette.zig
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
const allegro = @import("allegro");
|
||||||
|
|
||||||
|
pub const Palette = struct {
|
||||||
|
pub const Combination = struct { background: allegro.Color, text: allegro.Color };
|
||||||
|
|
||||||
|
primary: Combination,
|
||||||
|
primaryContainer: Combination,
|
||||||
|
secondary: Combination,
|
||||||
|
secondaryContainer: Combination,
|
||||||
|
tertiary: Combination,
|
||||||
|
tertiaryContainer: Combination,
|
||||||
|
background: Combination,
|
||||||
|
outline: allegro.Color,
|
||||||
|
};
|
5
src/scene.zig
Normal file
5
src/scene.zig
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const allegro = @import("allegro");
|
||||||
|
const engine = @import("engine.zig");
|
||||||
|
const Context = @import("context.zig").Context;
|
||||||
|
|
||||||
|
pub const Scene = engine.Scene(Context, *allegro.Event);
|
45
src/title_scene.zig
Normal file
45
src/title_scene.zig
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
const allegro = @import("allegro");
|
||||||
|
const Context = @import("context.zig").Context;
|
||||||
|
const MainMenuScene = @import("main_menu_scene.zig").MainMenuScene;
|
||||||
|
|
||||||
|
pub const TitleScene = struct {
|
||||||
|
offset: f32,
|
||||||
|
|
||||||
|
pub fn enter(self: *TitleScene, ctx: *Context) void {
|
||||||
|
_ = ctx;
|
||||||
|
_ = self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exit(self: *TitleScene, ctx: *Context) void {
|
||||||
|
_ = ctx;
|
||||||
|
_ = self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle(self: *TitleScene, ctx: *Context, event: *allegro.Event) !void {
|
||||||
|
switch (event.type) {
|
||||||
|
allegro.c.ALLEGRO_EVENT_KEY_CHAR => {
|
||||||
|
switch (event.keyboard.keycode) {
|
||||||
|
allegro.c.ALLEGRO_KEY_SPACE => try ctx.switchToScene(MainMenuScene, null),
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
_ = self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(self: *TitleScene, ctx: *Context, dt: f32) void {
|
||||||
|
_ = self;
|
||||||
|
_ = dt;
|
||||||
|
_ = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(self: *TitleScene, ctx: *Context) void {
|
||||||
|
_ = self;
|
||||||
|
allegro.clearToColor(ctx.palette.background.background);
|
||||||
|
ctx.textures.get("opaque").?.drawTintedScaled(ctx.palette.tertiaryContainer.background, ctx.viewport.bounds.min.x, ctx.viewport.bounds.min.y, ctx.viewport.bounds.width(), ctx.viewport.bounds.height(), allegro.DrawFlags{});
|
||||||
|
|
||||||
|
const center = ctx.viewport.center();
|
||||||
|
ctx.textures.get("title_untitled").?.drawTintedCenteredScaled(ctx.palette.background.text, center.x, center.y, ctx.viewport.scale);
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user