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) void { drawBitmap(self, x, y, DrawFlags{}); } 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 drawCenteredScaledUniform(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); } pub fn drawScaled(self: Bitmap, x: f32, y: f32, w: f32, h: f32) void { drawScaledBitmap(self, 0, 0, @intToFloat(f32, self.width()), @intToFloat(f32, self.height()), x, y, w, h, DrawFlags{}); } pub fn drawScaledUniform(self: Bitmap, x: f32, y: f32, s: f32) void { const sourceW = @intToFloat(f32, self.width()); const sourceH = @intToFloat(f32, self.height()); const scaledW = s * sourceW; const scaledH = s * sourceH; drawScaledBitmap(self, 0, 0, sourceW, sourceH, x, y, scaledW, scaledH, DrawFlags{}); } pub fn drawTinted(self: Bitmap, tint: Color, x: f32, y: f32) void { drawTintedBitmap(self, tint, x, y, DrawFlags{}); } 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); } pub fn drawTintedScaled(self: Bitmap, tint: Color, x: f32, y: f32, w: f32, h: f32) void { drawTintedScaledBitmap(self, tint, 0, 0, @intToFloat(f32, self.width()), @intToFloat(f32, self.height()), x, y, w, h, DrawFlags{}); } pub fn drawTintedScaledUniform(self: Bitmap, tint: Color, x: f32, y: f32, s: f32) void { const sourceW = @intToFloat(f32, self.width()); const sourceH = @intToFloat(f32, self.height()); const scaledW = s * sourceW; const scaledH = s * sourceH; drawTintedScaledBitmap(self, tint, 0, 0, sourceW, sourceH, x, y, scaledW, scaledH, DrawFlags{}); } pub fn height(self: Bitmap) i32 { return getBitmapHeight(self); } pub fn sub(self: Bitmap, x: i32, y: i32, w: i32, h: i32) !Bitmap { return createSubBitmap(self, x, y, w, h); } 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 createSubBitmap(bitmap: Bitmap, x: i32, y: i32, width: i32, height: i32) !Bitmap { const sub = c.al_create_sub_bitmap(bitmap.native, x, y, width, height); if (sub) |native| { return Bitmap{ .native = native }; } return error.FailedToCreateSubBitmap; } 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 saveBitmap(path: [*:0]const u8, bitmap: Bitmap) bool { return c.al_save_bitmap(path, bitmap.native); } pub fn saveBitmapF(file: File, ident: []const u8, bitmap: Bitmap) bool { return c.al_save_bitmap_f(file.native, &ident[0], bitmap.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(); }