2025-05-27 22:59:15 -06:00
|
|
|
pub fn main() !void {
|
|
|
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
|
|
|
defer _ = gpa.deinit();
|
|
|
|
const allocator = gpa.allocator();
|
|
|
|
|
2025-05-28 11:05:36 -06:00
|
|
|
raylib.SetConfigFlags(raylib.FLAG_VSYNC_HINT); // | raylib.FLAG_WINDOW_RESIZABLE);
|
2025-05-27 22:59:15 -06:00
|
|
|
raylib.InitWindow(@intFromFloat(screen_width), @intFromFloat(screen_height), "ReX");
|
|
|
|
defer raylib.CloseWindow();
|
|
|
|
|
2025-05-28 11:05:36 -06:00
|
|
|
raylib.SetWindowMinSize(480, 272);
|
|
|
|
raylib.SetWindowMaxSize(1920, 1080);
|
|
|
|
scales.recalculate();
|
|
|
|
|
|
|
|
global_font = raylib.LoadFontEx("font/SCE-PS3-RD-R-LATIN.TTF", 32, 0, 250);
|
2025-05-28 11:59:55 -06:00
|
|
|
raylib.SetTextureFilter(global_font.texture, raylib.TEXTURE_FILTER_BILINEAR);
|
2025-05-28 11:05:36 -06:00
|
|
|
|
|
|
|
var background = Background.init();
|
|
|
|
var column = Column.init(
|
|
|
|
allocator,
|
|
|
|
raylib.LoadTextureFromImage(raylib.GenImageChecked(64, 64, 8, 8, raylib.BLACK, raylib.WHITE)),
|
|
|
|
"Game",
|
|
|
|
);
|
|
|
|
defer column.deinit();
|
|
|
|
|
2025-05-28 11:59:55 -06:00
|
|
|
var item1 = Item.init(
|
2025-05-28 11:05:36 -06:00
|
|
|
raylib.LoadTexture("menu/game/CometCrash/ICON0.PNG"),
|
|
|
|
"Comet Crash",
|
2025-05-28 15:42:45 -06:00
|
|
|
"3/1/2025 23:11",
|
2025-05-28 11:05:36 -06:00
|
|
|
);
|
2025-05-28 11:59:55 -06:00
|
|
|
var item2 = Item.init(
|
|
|
|
raylib.LoadTexture("menu/game/LBP1/ICON0.PNG"),
|
|
|
|
"LittleBigPlanet",
|
2025-05-28 15:42:45 -06:00
|
|
|
"3/1/2025 23:15",
|
2025-05-28 11:59:55 -06:00
|
|
|
);
|
|
|
|
var item3 = Item.init(
|
|
|
|
raylib.LoadTexture("menu/game/LBP2/ICON0.PNG"),
|
|
|
|
"LittleBigPlanet 2",
|
2025-05-28 15:42:45 -06:00
|
|
|
"3/1/2025 23:26",
|
2025-05-28 11:59:55 -06:00
|
|
|
);
|
|
|
|
var item4 = Item.init(
|
|
|
|
raylib.LoadTexture("menu/game/LBP3/ICON0.PNG"),
|
|
|
|
"LittleBigPlanet 3",
|
2025-05-28 15:42:45 -06:00
|
|
|
"3/1/2025 23:48",
|
2025-05-28 11:59:55 -06:00
|
|
|
);
|
|
|
|
try column.appendItem(&item1);
|
|
|
|
try column.appendItem(&item2);
|
|
|
|
try column.appendItem(&item3);
|
|
|
|
try column.appendItem(&item4);
|
2025-05-27 22:59:15 -06:00
|
|
|
|
|
|
|
raylib.SetTargetFPS(120);
|
|
|
|
while (!raylib.WindowShouldClose()) {
|
|
|
|
if (raylib.IsWindowResized()) {
|
|
|
|
screen_width = @floatFromInt(raylib.GetScreenWidth());
|
|
|
|
screen_height = @floatFromInt(raylib.GetScreenHeight());
|
2025-05-28 11:05:36 -06:00
|
|
|
scales.recalculate();
|
2025-05-27 22:59:15 -06:00
|
|
|
}
|
2025-05-28 11:05:36 -06:00
|
|
|
if (raylib.IsKeyPressed('D')) debug_draw = !debug_draw;
|
2025-05-28 11:59:55 -06:00
|
|
|
if (raylib.IsKeyPressed('Z')) item1.setLarge(!item1.large);
|
2025-05-28 07:07:58 -06:00
|
|
|
if (raylib.IsKeyPressed('S')) raylib.TakeScreenshot("screenshot.png");
|
2025-05-27 22:59:15 -06:00
|
|
|
|
2025-05-30 16:30:27 -06:00
|
|
|
column.updatePositions();
|
|
|
|
|
2025-05-27 22:59:15 -06:00
|
|
|
raylib.BeginDrawing();
|
|
|
|
defer raylib.EndDrawing();
|
|
|
|
|
2025-05-28 11:05:36 -06:00
|
|
|
background.draw();
|
|
|
|
column.draw();
|
2025-05-27 22:59:15 -06:00
|
|
|
|
|
|
|
raylib.DrawFPS(1, 1);
|
|
|
|
|
2025-05-30 16:30:27 -06:00
|
|
|
const debug_text = try std.fmt.allocPrint(allocator,
|
|
|
|
\\screen size = {d}x{d}
|
|
|
|
\\selected = {d}
|
|
|
|
, .{
|
|
|
|
screen_width,
|
|
|
|
screen_height,
|
|
|
|
column.selected,
|
|
|
|
});
|
2025-05-27 22:59:15 -06:00
|
|
|
defer allocator.free(debug_text);
|
|
|
|
raylib.DrawText(@ptrCast(debug_text), 80, 2, 8, raylib.GREEN);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-05-28 11:05:36 -06:00
|
|
|
var debug_draw = true;
|
|
|
|
|
2025-05-27 22:59:15 -06:00
|
|
|
var global_font: raylib.Font = undefined;
|
|
|
|
|
|
|
|
var screen_width: f32 = 480;
|
|
|
|
var screen_height: f32 = 272;
|
|
|
|
|
|
|
|
var scales: Scales = undefined;
|
|
|
|
|
2025-05-28 07:07:58 -06:00
|
|
|
/// Cached scaling and positioning values for dynamic window resizing.
|
2025-05-27 22:59:15 -06:00
|
|
|
pub const Scales = struct {
|
2025-05-28 11:05:36 -06:00
|
|
|
item_icon_small_width: f32,
|
|
|
|
item_icon_small_height: f32,
|
2025-05-28 11:59:55 -06:00
|
|
|
item_icon_large_width: f32,
|
|
|
|
item_icon_large_height: f32,
|
2025-05-27 22:59:15 -06:00
|
|
|
item_title_font_size: f32,
|
|
|
|
item_subtitle_font_size: f32,
|
|
|
|
|
|
|
|
column_icon_scale: f32,
|
|
|
|
column_title_font_size: f32,
|
|
|
|
column_position_center: raylib.Vector2,
|
|
|
|
column_position_spacing: f32,
|
2025-05-28 11:59:55 -06:00
|
|
|
column_item_spacing: f32,
|
2025-05-30 16:30:27 -06:00
|
|
|
column_item_start: f32,
|
2025-05-27 22:59:15 -06:00
|
|
|
|
2025-05-28 07:07:58 -06:00
|
|
|
/// Recalculate scales after screen resize.
|
2025-05-27 22:59:15 -06:00
|
|
|
pub fn recalculate(self: *Scales) void {
|
2025-05-28 11:05:36 -06:00
|
|
|
self.item_icon_small_width = 67;
|
|
|
|
self.item_icon_small_height = 48;
|
2025-05-28 11:59:55 -06:00
|
|
|
self.item_icon_large_width = 67;
|
|
|
|
self.item_icon_large_height = 48;
|
2025-05-28 15:42:45 -06:00
|
|
|
self.item_title_font_size = 18;
|
|
|
|
self.item_subtitle_font_size = 12;
|
2025-05-27 22:59:15 -06:00
|
|
|
|
2025-05-28 08:44:41 -06:00
|
|
|
self.column_icon_scale = 0.75;
|
|
|
|
self.column_title_font_size = 13;
|
2025-05-27 22:59:15 -06:00
|
|
|
self.column_position_center = .{
|
|
|
|
.x = std.math.lerp(0.0, screen_width, 0.18),
|
|
|
|
.y = std.math.lerp(0.0, screen_height, 0.15),
|
|
|
|
};
|
|
|
|
self.column_position_spacing = 64;
|
2025-05-28 11:59:55 -06:00
|
|
|
self.column_item_spacing = 16;
|
2025-05-30 16:30:27 -06:00
|
|
|
self.column_item_start = 117.8;
|
2025-05-27 22:59:15 -06:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
pub const Column = struct {
|
|
|
|
icon: raylib.Texture2D,
|
|
|
|
title: []const u8,
|
|
|
|
|
|
|
|
items: std.ArrayList(*Item),
|
2025-05-30 16:30:27 -06:00
|
|
|
selected: usize = 0,
|
|
|
|
start_y: f32 = undefined,
|
2025-05-27 22:59:15 -06:00
|
|
|
|
|
|
|
pub fn init(allocator: Allocator, icon: raylib.Texture2D, title: []const u8) Column {
|
|
|
|
raylib.SetTextureFilter(icon, raylib.TEXTURE_FILTER_BILINEAR);
|
|
|
|
return .{
|
|
|
|
.icon = icon,
|
|
|
|
.title = title,
|
|
|
|
.items = .init(allocator),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn deinit(self: *Column) void {
|
|
|
|
self.items.deinit();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn draw(self: *Column) void {
|
2025-05-28 11:05:36 -06:00
|
|
|
var icon = Image{
|
|
|
|
.texture = self.icon,
|
|
|
|
.box = .{
|
|
|
|
.x = scales.column_position_center.x,
|
|
|
|
.y = scales.column_position_center.y,
|
|
|
|
.w = 67,
|
|
|
|
.h = 48,
|
|
|
|
},
|
|
|
|
};
|
2025-05-27 22:59:15 -06:00
|
|
|
|
2025-05-28 15:42:45 -06:00
|
|
|
var title = Text{
|
|
|
|
.string = self.title,
|
|
|
|
.font_size = scales.column_title_font_size,
|
|
|
|
.font_spacing = 1,
|
|
|
|
.box = .{
|
|
|
|
.x = icon.box.x - 8,
|
|
|
|
.y = icon.box.y + icon.box.h + 6,
|
|
|
|
.w = icon.box.w + 16,
|
|
|
|
.h = scales.column_title_font_size,
|
|
|
|
},
|
|
|
|
.align_h = .center,
|
2025-05-27 22:59:15 -06:00
|
|
|
};
|
|
|
|
|
2025-05-30 16:30:27 -06:00
|
|
|
// self.start_y = scales.column_position_center.y + icon.box.h + title.box.h + scales.column_item_spacing;
|
|
|
|
for (self.items.items) |item| item.draw();
|
2025-05-27 22:59:15 -06:00
|
|
|
|
2025-05-28 11:05:36 -06:00
|
|
|
icon.draw();
|
2025-05-28 15:42:45 -06:00
|
|
|
title.draw();
|
2025-05-27 22:59:15 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn appendItem(self: *Column, item: *Item) !void {
|
|
|
|
try self.items.append(item);
|
2025-05-30 16:30:27 -06:00
|
|
|
self.refresh();
|
2025-05-27 22:59:15 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn insertItem(self: *Column, idx: usize, item: *Item) !void {
|
|
|
|
try self.items.insert(idx, item);
|
2025-05-30 16:30:27 -06:00
|
|
|
self.refresh();
|
2025-05-27 22:59:15 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn removeItem(self: *Column, idx: usize) void {
|
|
|
|
_ = try self.items.orderedRemove(idx);
|
2025-05-30 16:30:27 -06:00
|
|
|
self.refresh();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn updatePositions(self: *Column) void {
|
|
|
|
const up = raylib.IsKeyPressed(raylib.KEY_UP) or raylib.IsKeyPressedRepeat(raylib.KEY_UP);
|
|
|
|
const down = raylib.IsKeyPressed(raylib.KEY_DOWN) or raylib.IsKeyPressedRepeat(raylib.KEY_DOWN);
|
|
|
|
if (up and self.selected > 0) self.selected -= 1;
|
|
|
|
if (down and self.selected < self.items.items.len - 1) self.selected += 1;
|
|
|
|
|
|
|
|
if (up or down) self.refresh();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn refresh(self: *Column) void {
|
|
|
|
var y = scales.column_item_start;
|
|
|
|
for (self.items.items[self.selected..]) |item| {
|
|
|
|
item.setPosition(.{ .x = scales.column_position_center.x, .y = y });
|
|
|
|
y += scales.item_icon_small_height + scales.column_item_spacing;
|
|
|
|
}
|
2025-05-27 22:59:15 -06:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
pub const Item = struct {
|
|
|
|
position: raylib.Vector2 = .{ .x = 0, .y = 0 },
|
2025-05-28 11:05:36 -06:00
|
|
|
// icon_scale: f32,
|
|
|
|
// start_scale: f32,
|
2025-05-30 16:30:27 -06:00
|
|
|
time: f32 = 0.0,
|
|
|
|
start_position: raylib.Vector2 = .{ .x = 0, .y = 0 },
|
2025-05-27 22:59:15 -06:00
|
|
|
|
|
|
|
icon: raylib.Texture2D,
|
|
|
|
title: []const u8,
|
|
|
|
subtitle: []const u8,
|
2025-05-28 11:59:55 -06:00
|
|
|
large: bool = false,
|
2025-05-27 22:59:15 -06:00
|
|
|
|
|
|
|
pub fn init(texture: raylib.Texture2D, title: []const u8, subtitle: []const u8) Item {
|
|
|
|
raylib.SetTextureFilter(texture, raylib.TEXTURE_FILTER_BILINEAR);
|
|
|
|
return .{
|
|
|
|
.icon = texture,
|
|
|
|
.title = title,
|
|
|
|
.subtitle = subtitle,
|
2025-05-28 11:05:36 -06:00
|
|
|
// .icon_scale = scales.item_icon_small_scale,
|
|
|
|
// .start_scale = scales.item_icon_small_scale,
|
2025-05-27 22:59:15 -06:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn draw(self: *Item) void {
|
2025-05-30 16:30:27 -06:00
|
|
|
self.time += raylib.GetFrameTime();
|
2025-05-28 11:05:36 -06:00
|
|
|
// self.icon_scale = std.math.lerp(
|
|
|
|
// self.start_scale,
|
|
|
|
// if (self.large) scales.item_icon_large_scale else scales.item_icon_small_scale,
|
|
|
|
// easeOutExpo(self.time / 0.333),
|
|
|
|
// );
|
2025-05-30 16:30:27 -06:00
|
|
|
const position = raylib.Vector2Lerp(
|
|
|
|
self.start_position,
|
|
|
|
self.position,
|
|
|
|
easeOutExpo(self.time / 0.333),
|
|
|
|
);
|
2025-05-28 11:05:36 -06:00
|
|
|
|
|
|
|
var icon = Image{
|
|
|
|
.texture = self.icon,
|
|
|
|
.box = .{
|
2025-05-30 16:30:27 -06:00
|
|
|
.x = position.x - scales.item_icon_small_width / 2.0 + 67.0 / 2.0,
|
|
|
|
.y = position.y,
|
2025-05-28 11:05:36 -06:00
|
|
|
.w = scales.item_icon_small_width,
|
|
|
|
.h = scales.item_icon_small_height,
|
|
|
|
},
|
2025-05-28 08:44:41 -06:00
|
|
|
};
|
2025-05-28 11:05:36 -06:00
|
|
|
|
2025-05-28 15:42:45 -06:00
|
|
|
var title = Text{
|
|
|
|
.string = self.title,
|
|
|
|
.box = .{
|
|
|
|
.x = icon.box.x + 8 + icon.box.w,
|
|
|
|
.y = icon.box.y,
|
|
|
|
.w = 300,
|
|
|
|
.h = icon.box.h / 2.0 - 2,
|
|
|
|
},
|
|
|
|
.font_size = scales.item_title_font_size,
|
|
|
|
.font_spacing = 1,
|
|
|
|
.align_v = .right,
|
|
|
|
};
|
|
|
|
|
|
|
|
var subtitle = Text{
|
|
|
|
.string = self.subtitle,
|
|
|
|
.box = .{
|
|
|
|
.x = icon.box.x + 8 + icon.box.w,
|
|
|
|
.y = icon.box.y + icon.box.h / 2.0 + 1,
|
|
|
|
.w = 200,
|
|
|
|
.h = icon.box.h / 2.0 - 2,
|
|
|
|
},
|
|
|
|
.font_size = scales.item_subtitle_font_size,
|
|
|
|
.font_spacing = 1,
|
|
|
|
.align_v = .left,
|
2025-05-27 22:59:15 -06:00
|
|
|
};
|
|
|
|
|
2025-05-28 11:05:36 -06:00
|
|
|
icon.draw();
|
2025-05-28 15:42:45 -06:00
|
|
|
title.draw();
|
|
|
|
subtitle.draw();
|
2025-05-27 22:59:15 -06:00
|
|
|
}
|
|
|
|
|
2025-05-28 11:59:55 -06:00
|
|
|
pub fn setLarge(self: *Item, large: bool) void {
|
|
|
|
self.large = large;
|
2025-05-28 11:05:36 -06:00
|
|
|
// self.time = 0;
|
|
|
|
// self.start_scale = self.icon_scale;
|
2025-05-27 22:59:15 -06:00
|
|
|
}
|
|
|
|
|
2025-05-30 16:30:27 -06:00
|
|
|
pub fn setPosition(self: *Item, position: raylib.Vector2) void {
|
|
|
|
self.start_position = self.position;
|
|
|
|
self.position = position;
|
|
|
|
self.time = 0;
|
|
|
|
}
|
|
|
|
|
2025-05-27 22:59:15 -06:00
|
|
|
fn easeOutExpo(x: f32) f32 {
|
|
|
|
return 1.0 - std.math.pow(f32, 2, -10 * std.math.clamp(x, 0.0, 1.0));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/// Draws the dynamic gradient background.
|
|
|
|
// TODO shift based on time of day
|
|
|
|
// TODO image wallpaper
|
|
|
|
// TODO slideshow wallpaper
|
|
|
|
// TODO animated image wallpaper
|
|
|
|
pub const Background = struct {
|
|
|
|
top_left: Color,
|
|
|
|
top_right: Color,
|
|
|
|
bottom_right: Color,
|
|
|
|
bottom_left: Color,
|
|
|
|
|
|
|
|
pub fn init() Background {
|
|
|
|
var self: Background = undefined;
|
|
|
|
self.setColors(NIGHT_08);
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn setColors(self: *Background, colors: [4]Color) void {
|
|
|
|
self.top_left = colors[0];
|
|
|
|
self.bottom_right = colors[1];
|
|
|
|
self.top_right = colors[2];
|
|
|
|
self.bottom_left = colors[3];
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn draw(self: *Background) void {
|
|
|
|
raylib.DrawRectangleGradientEx(
|
|
|
|
.{
|
|
|
|
.x = 0,
|
|
|
|
.y = 0,
|
|
|
|
.width = screen_width,
|
|
|
|
.height = screen_height,
|
|
|
|
},
|
|
|
|
self.top_left.toRaylib(),
|
|
|
|
self.bottom_left.toRaylib(),
|
|
|
|
self.top_right.toRaylib(),
|
|
|
|
self.bottom_right.toRaylib(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub const Color = struct {
|
|
|
|
r: f32,
|
|
|
|
g: f32,
|
|
|
|
b: f32,
|
|
|
|
|
|
|
|
fn toRaylib(self: Color) raylib.Color {
|
|
|
|
return .{
|
|
|
|
.r = @intFromFloat(self.r * 255.0),
|
|
|
|
.g = @intFromFloat(self.g * 255.0),
|
|
|
|
.b = @intFromFloat(self.b * 255.0),
|
|
|
|
.a = 255,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
pub const DAY_06 = [4]Color{
|
|
|
|
.{ .r = 0.408, .g = 0.333, .b = 0.643 },
|
|
|
|
.{ .r = 0.518, .g = 0.365, .b = 0.855 },
|
|
|
|
.{ .r = 0.761, .g = 0.510, .b = 0.851 },
|
|
|
|
.{ .r = 0.569, .g = 0.325, .b = 0.620 },
|
|
|
|
};
|
|
|
|
|
|
|
|
pub const DAY_08 = [4]Color{
|
|
|
|
.{ .r = 0.243, .g = 0.608, .b = 0.831 },
|
|
|
|
.{ .r = 0.039, .g = 0.690, .b = 0.878 },
|
|
|
|
.{ .r = 0.016, .g = 0.306, .b = 0.694 },
|
|
|
|
.{ .r = 0.000, .g = 0.027, .b = 0.310 },
|
|
|
|
};
|
|
|
|
|
|
|
|
pub const NIGHT_08 = [4]Color{
|
|
|
|
.{ .r = 0.000, .g = 0.145, .b = 0.349 },
|
|
|
|
.{ .r = 0.000, .g = 0.008, .b = 0.106 },
|
|
|
|
.{ .r = 0.251, .g = 0.494, .b = 0.576 },
|
|
|
|
.{ .r = 0.008, .g = 0.537, .b = 0.612 },
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2025-05-28 10:02:30 -06:00
|
|
|
pub const BoundingBox = struct {
|
|
|
|
x: f32 = 0,
|
|
|
|
y: f32 = 0,
|
|
|
|
w: f32,
|
|
|
|
h: f32,
|
|
|
|
};
|
|
|
|
|
|
|
|
/// A texture within a bounding box. Positions and scales based on configurable parameters.
|
2025-05-28 11:59:55 -06:00
|
|
|
/// Will not crop texture if using `Mode.original`.
|
2025-05-28 10:02:30 -06:00
|
|
|
pub const Image = struct {
|
|
|
|
box: BoundingBox,
|
|
|
|
texture: raylib.Texture2D,
|
|
|
|
|
|
|
|
mode: Mode = .fit,
|
|
|
|
align_w: Align = .center,
|
|
|
|
align_h: Align = .center,
|
|
|
|
|
|
|
|
pub fn draw(self: *Image) void {
|
|
|
|
const width: f32 = @floatFromInt(self.texture.width);
|
|
|
|
const height: f32 = @floatFromInt(self.texture.height);
|
|
|
|
const width_scale: f32 = if (width == 0) 0.0 else self.box.w / width;
|
|
|
|
const height_scale: f32 = if (height == 0) 0.0 else self.box.h / height;
|
|
|
|
const scale = switch (self.mode) {
|
|
|
|
.original => 1.0,
|
|
|
|
.fit => @min(width_scale, height_scale),
|
|
|
|
.fill => @max(width_scale, height_scale),
|
|
|
|
};
|
|
|
|
const position = raylib.Vector2{
|
|
|
|
.x = switch (self.align_w) {
|
|
|
|
.left => 0,
|
|
|
|
.center => self.box.x + self.box.w / 2.0 - (width * scale) / 2.0,
|
|
|
|
.right => self.box.x + self.box.w - width * scale,
|
|
|
|
},
|
|
|
|
.y = switch (self.align_h) {
|
|
|
|
.left => 0,
|
|
|
|
.center => self.box.y + self.box.h / 2.0 - (height * scale) / 2.0,
|
|
|
|
.right => self.box.y + self.box.h - height * scale,
|
|
|
|
},
|
|
|
|
};
|
2025-05-28 11:05:36 -06:00
|
|
|
if (debug_draw)
|
|
|
|
raylib.DrawRectangleLines(
|
|
|
|
@intFromFloat(self.box.x),
|
|
|
|
@intFromFloat(self.box.y),
|
|
|
|
@intFromFloat(self.box.w),
|
|
|
|
@intFromFloat(self.box.h),
|
|
|
|
raylib.MAROON,
|
|
|
|
)
|
|
|
|
else
|
|
|
|
raylib.DrawTextureEx(self.texture, position, 0, scale, raylib.WHITE);
|
2025-05-28 10:02:30 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
pub const Mode = enum { original, fit, fill };
|
|
|
|
pub const Align = enum { left, center, right };
|
|
|
|
};
|
|
|
|
|
2025-05-28 15:42:45 -06:00
|
|
|
/// Draws a string inside a bounding box.
|
|
|
|
// TODO ellipsize text
|
|
|
|
// TODO clip text and scroll
|
|
|
|
pub const Text = struct {
|
|
|
|
box: BoundingBox,
|
|
|
|
string: []const u8,
|
|
|
|
font_size: f32,
|
|
|
|
font_spacing: f32,
|
|
|
|
|
|
|
|
align_h: Align = .left,
|
|
|
|
align_v: Align = .left,
|
|
|
|
|
|
|
|
pub fn draw(self: *Text) void {
|
|
|
|
const size = raylib.MeasureTextEx(
|
|
|
|
global_font,
|
|
|
|
@ptrCast(self.string),
|
|
|
|
self.font_size,
|
|
|
|
self.font_spacing,
|
|
|
|
);
|
|
|
|
if (debug_draw)
|
|
|
|
raylib.DrawRectangleLines(
|
|
|
|
@intFromFloat(self.box.x),
|
|
|
|
@intFromFloat(self.box.y),
|
|
|
|
@intFromFloat(self.box.w),
|
|
|
|
@intFromFloat(self.box.h),
|
|
|
|
raylib.GREEN,
|
|
|
|
)
|
|
|
|
else
|
|
|
|
raylib.DrawTextEx(
|
|
|
|
global_font,
|
|
|
|
@ptrCast(self.string),
|
|
|
|
.{
|
|
|
|
.x = switch (self.align_h) {
|
|
|
|
.left => self.box.x,
|
|
|
|
.center => self.box.x + self.box.w / 2.0 - size.x / 2.0,
|
|
|
|
.right => self.box.x + self.box.w - size.x,
|
|
|
|
},
|
|
|
|
.y = switch (self.align_v) {
|
|
|
|
.left => self.box.y,
|
|
|
|
.center => self.box.y + self.box.h / 2.0 - size.y / 2.0,
|
|
|
|
.right => self.box.y + self.box.h - size.y,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
self.font_size,
|
|
|
|
self.font_spacing,
|
|
|
|
raylib.WHITE,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub const Align = enum { left, center, right };
|
|
|
|
};
|
|
|
|
|
2025-05-28 07:07:58 -06:00
|
|
|
/// Create ortho camera looking down at the XY plane, with a fovy of 1 for UV-like positioning.
|
2025-05-27 22:59:15 -06:00
|
|
|
fn createCamera() raylib.Camera3D {
|
|
|
|
var camera = raylib.Camera3D{};
|
|
|
|
|
|
|
|
camera.position.x = 0;
|
|
|
|
camera.position.y = 10;
|
|
|
|
camera.position.z = 0;
|
|
|
|
|
|
|
|
// camera pointing down, oriented correctly
|
|
|
|
// TODO this works but looks weird. do better.
|
|
|
|
camera.target.x = 0;
|
|
|
|
camera.target.y = 0;
|
|
|
|
camera.target.z = -0.000000000000001;
|
|
|
|
|
|
|
|
camera.up.x = 0;
|
|
|
|
camera.up.y = 1;
|
|
|
|
camera.up.z = 0;
|
|
|
|
|
|
|
|
camera.fovy = 1;
|
|
|
|
camera.projection = raylib.CAMERA_ORTHOGRAPHIC;
|
|
|
|
|
|
|
|
return camera;
|
|
|
|
}
|
|
|
|
|
|
|
|
const std = @import("std");
|
|
|
|
const Allocator = std.mem.Allocator;
|
|
|
|
|
|
|
|
const c = @import("c.zig");
|
|
|
|
const raylib = c.raylib;
|