init (messy)
This commit is contained in:
commit
18bff3cc00
10 changed files with 926 additions and 0 deletions
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
* text=auto eol=lf
|
16
.gitignore
vendored
Normal file
16
.gitignore
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
# Zig-specific build artifacts
|
||||||
|
.zig-cache/
|
||||||
|
zig-cache/
|
||||||
|
zig-out/
|
||||||
|
/release/
|
||||||
|
/debug/
|
||||||
|
/build/
|
||||||
|
/build-*/
|
||||||
|
/docgen_tmp/
|
||||||
|
|
||||||
|
# Temporary project-specific dirs
|
||||||
|
vsh/
|
||||||
|
dumped/
|
||||||
|
menu/
|
||||||
|
font/
|
||||||
|
reference/
|
46
build.zig
Normal file
46
build.zig
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn build(b: *std.Build) void {
|
||||||
|
const target = b.standardTargetOptions(.{});
|
||||||
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
|
const raylib = b.dependency("raylib", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.shared = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const exe_mod = b.createModule(.{
|
||||||
|
.root_source_file = b.path("src/main.zig"),
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
|
||||||
|
exe_mod.strip = false;
|
||||||
|
exe_mod.linkLibrary(raylib.artifact("raylib"));
|
||||||
|
|
||||||
|
const exe = b.addExecutable(.{
|
||||||
|
.name = "rex",
|
||||||
|
.root_module = exe_mod,
|
||||||
|
});
|
||||||
|
|
||||||
|
b.installArtifact(exe);
|
||||||
|
|
||||||
|
const run_cmd = b.addRunArtifact(exe);
|
||||||
|
run_cmd.step.dependOn(b.getInstallStep());
|
||||||
|
if (b.args) |args| {
|
||||||
|
run_cmd.addArgs(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const run_step = b.step("run", "Run the app");
|
||||||
|
run_step.dependOn(&run_cmd.step);
|
||||||
|
|
||||||
|
const exe_unit_tests = b.addTest(.{
|
||||||
|
.root_module = exe_mod,
|
||||||
|
});
|
||||||
|
|
||||||
|
const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
|
||||||
|
|
||||||
|
const test_step = b.step("test", "Run unit tests");
|
||||||
|
test_step.dependOn(&run_exe_unit_tests.step);
|
||||||
|
}
|
17
build.zig.zon
Normal file
17
build.zig.zon
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
.{
|
||||||
|
.name = .rex,
|
||||||
|
.version = "0.0.0",
|
||||||
|
.fingerprint = 0xee6003c042470dd0,
|
||||||
|
.minimum_zig_version = "0.14.0",
|
||||||
|
.dependencies = .{
|
||||||
|
.raylib = .{
|
||||||
|
.url = "git+https://github.com/raysan5/raylib#8d9c1cecb7f53aef720e2ee0d1558ffc39fa7eef",
|
||||||
|
.hash = "raylib-5.5.0-whq8uKXONARKPKfYVo14WktbUTIM3OYxdVPOPTdsQejc",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.paths = .{
|
||||||
|
"build.zig",
|
||||||
|
"build.zig.zon",
|
||||||
|
"src",
|
||||||
|
},
|
||||||
|
}
|
20
build.zig.zon2json-lock
Normal file
20
build.zig.zon2json-lock
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"raylib-5.5.0-whq8uKXONARKPKfYVo14WktbUTIM3OYxdVPOPTdsQejc": {
|
||||||
|
"name": "raylib",
|
||||||
|
"url": "git+https://github.com/raysan5/raylib#8d9c1cecb7f53aef720e2ee0d1558ffc39fa7eef",
|
||||||
|
"hash": "sha256-NCUpCi5Kjs/mC97pAeRpPO4/1e5vaMZ2xEWrAXZV2Vs=",
|
||||||
|
"rev": "8d9c1cecb7f53aef720e2ee0d1558ffc39fa7eef"
|
||||||
|
},
|
||||||
|
"N-V-__8AABHMqAWYuRdIlflwi8gksPnlUMQBiSxAqQAAZFms": {
|
||||||
|
"name": "xcode_frameworks",
|
||||||
|
"url": "git+https://github.com/hexops/xcode-frameworks#9a45f3ac977fd25dff77e58c6de1870b6808c4a7",
|
||||||
|
"hash": "sha256-xveFYoQu0BT+ZtEsyca/zdQ/so9jPK56SeX3xmF3iro=",
|
||||||
|
"rev": "9a45f3ac977fd25dff77e58c6de1870b6808c4a7"
|
||||||
|
},
|
||||||
|
"N-V-__8AALRTBQDo_pUJ8IQ-XiIyYwDKQVwnr7-7o5kvPDGE": {
|
||||||
|
"name": "emsdk",
|
||||||
|
"url": "git+https://github.com/emscripten-core/emsdk#3.1.50",
|
||||||
|
"hash": "sha256-YUwb8yfz26Tfz4wyN13MBsdyA40ygJwfxHWt4eFMvQE=",
|
||||||
|
"rev": "e2627e265d940db5ea58dffa63e490375bfc92e5"
|
||||||
|
}
|
||||||
|
}
|
78
flake.lock
generated
Normal file
78
flake.lock
generated
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731533236,
|
||||||
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1747273150,
|
||||||
|
"narHash": "sha256-8Vp3dEOmH4Idj0wnj66uJZbi4xiIgKxx+d6gD9KIBzc=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "7f8abfe980eb2ec5f3257c34aa4b4f0c3ca7002e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"zig2nix": "zig2nix"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"zig2nix": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1747273718,
|
||||||
|
"narHash": "sha256-cB0Abljln7nvmou3fecVKtIQZc0B8DpYBrw6CKbovgQ=",
|
||||||
|
"owner": "Cloudef",
|
||||||
|
"repo": "zig2nix",
|
||||||
|
"rev": "ea9a1a0f86a7addf8dedb03a38215b14c6f429b3",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "Cloudef",
|
||||||
|
"repo": "zig2nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
90
flake.nix
Normal file
90
flake.nix
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
{
|
||||||
|
description = "Zig project flake";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
zig2nix.url = "github:Cloudef/zig2nix";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { zig2nix, ... }: let
|
||||||
|
flake-utils = zig2nix.inputs.flake-utils;
|
||||||
|
in (flake-utils.lib.eachDefaultSystem (system: let
|
||||||
|
# Zig flake helper
|
||||||
|
# Check the flake.nix in zig2nix project for more options:
|
||||||
|
# <https://github.com/Cloudef/zig2nix/blob/master/flake.nix>
|
||||||
|
env = zig2nix.outputs.zig-env.${system} {};
|
||||||
|
in with builtins; with env.pkgs.lib; rec {
|
||||||
|
# Produces clean binaries meant to be ship'd outside of nix
|
||||||
|
# nix build .#foreign
|
||||||
|
packages.foreign = env.package {
|
||||||
|
src = cleanSource ./.;
|
||||||
|
|
||||||
|
# Packages required for compiling
|
||||||
|
nativeBuildInputs = with env.pkgs; [];
|
||||||
|
|
||||||
|
# Packages required for linking
|
||||||
|
buildInputs = with env.pkgs; [
|
||||||
|
raylib
|
||||||
|
wayland
|
||||||
|
wayland-scanner
|
||||||
|
libxkbcommon
|
||||||
|
xorg.libXcursor
|
||||||
|
xorg.libXext
|
||||||
|
xorg.libXfixes
|
||||||
|
xorg.libXi
|
||||||
|
xorg.libXinerama
|
||||||
|
xorg.libXrandr
|
||||||
|
xorg.libXrender
|
||||||
|
];
|
||||||
|
|
||||||
|
# Smaller binaries and avoids shipping glibc.
|
||||||
|
zigPreferMusl = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# nix build .
|
||||||
|
packages.default = packages.foreign.override (attrs: {
|
||||||
|
# Prefer nix friendly settings.
|
||||||
|
zigPreferMusl = false;
|
||||||
|
|
||||||
|
# Executables required for runtime
|
||||||
|
# These packages will be added to the PATH
|
||||||
|
zigWrapperBins = with env.pkgs; [];
|
||||||
|
|
||||||
|
# Libraries required for runtime
|
||||||
|
# These packages will be added to the LD_LIBRARY_PATH
|
||||||
|
zigWrapperLibs = attrs.buildInputs or [];
|
||||||
|
});
|
||||||
|
|
||||||
|
# For bundling with nix bundle for running outside of nix
|
||||||
|
# example: https://github.com/ralismark/nix-appimage
|
||||||
|
apps.bundle = {
|
||||||
|
type = "app";
|
||||||
|
program = "${packages.foreign}/bin/default";
|
||||||
|
};
|
||||||
|
|
||||||
|
# nix run .
|
||||||
|
apps.default = env.app [] "zig build run -- \"$@\"";
|
||||||
|
|
||||||
|
# nix run .#build
|
||||||
|
apps.build = env.app [] "zig build \"$@\"";
|
||||||
|
|
||||||
|
# nix run .#test
|
||||||
|
apps.test = env.app [] "zig build test -- \"$@\"";
|
||||||
|
|
||||||
|
# nix run .#docs
|
||||||
|
apps.docs = env.app [] "zig build docs -- \"$@\"";
|
||||||
|
|
||||||
|
# nix run .#zig2nix
|
||||||
|
apps.zig2nix = env.app [] "zig2nix \"$@\"";
|
||||||
|
|
||||||
|
# nix develop
|
||||||
|
devShells.default = env.mkShell {
|
||||||
|
# Packages required for compiling, linking and running
|
||||||
|
# Libraries added here will be automatically added to the LD_LIBRARY_PATH and PKG_CONFIG_PATH
|
||||||
|
nativeBuildInputs = []
|
||||||
|
++ packages.default.nativeBuildInputs
|
||||||
|
++ packages.default.buildInputs
|
||||||
|
++ packages.default.zigWrapperBins
|
||||||
|
++ packages.default.zigWrapperLibs;
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
}
|
4
src/c.zig
Normal file
4
src/c.zig
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
pub const raylib = @cImport({
|
||||||
|
@cInclude("raylib.h");
|
||||||
|
@cInclude("raymath.h");
|
||||||
|
});
|
302
src/main.zig
Normal file
302
src/main.zig
Normal file
|
@ -0,0 +1,302 @@
|
||||||
|
pub fn main() !void {
|
||||||
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
defer _ = gpa.deinit();
|
||||||
|
const allocator = gpa.allocator();
|
||||||
|
|
||||||
|
raylib.SetConfigFlags(raylib.FLAG_VSYNC_HINT | raylib.FLAG_WINDOW_RESIZABLE);
|
||||||
|
raylib.InitWindow(@intFromFloat(screen_width), @intFromFloat(screen_height), "ReX");
|
||||||
|
defer raylib.CloseWindow();
|
||||||
|
|
||||||
|
raylib.SetWindowMinSize(480, 272);
|
||||||
|
raylib.SetWindowMaxSize(1920, 1080);
|
||||||
|
scales.recalculate();
|
||||||
|
|
||||||
|
global_font = raylib.LoadFontEx("font/SCE-PS3-RD-R-LATIN.TTF", 32, 0, 250);
|
||||||
|
raylib.SetTextureFilter(global_font.texture, raylib.TEXTURE_FILTER_TRILINEAR);
|
||||||
|
|
||||||
|
// const camera = createCamera();
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
var item = Item.init(
|
||||||
|
raylib.LoadTexture("menu/game/CometCrash/ICON0.PNG"),
|
||||||
|
"Comet Crash",
|
||||||
|
"",
|
||||||
|
);
|
||||||
|
try column.appendItem(&item);
|
||||||
|
|
||||||
|
raylib.SetTargetFPS(120);
|
||||||
|
while (!raylib.WindowShouldClose()) {
|
||||||
|
if (raylib.IsWindowResized()) {
|
||||||
|
screen_width = @floatFromInt(raylib.GetScreenWidth());
|
||||||
|
screen_height = @floatFromInt(raylib.GetScreenHeight());
|
||||||
|
scales.recalculate();
|
||||||
|
}
|
||||||
|
if (raylib.IsKeyPressed('Z')) item.setBig(!item.big);
|
||||||
|
|
||||||
|
raylib.BeginDrawing();
|
||||||
|
defer raylib.EndDrawing();
|
||||||
|
|
||||||
|
background.draw();
|
||||||
|
column.draw();
|
||||||
|
|
||||||
|
// {
|
||||||
|
// raylib.BeginMode3D(camera);
|
||||||
|
// defer raylib.EndMode3D();
|
||||||
|
// }
|
||||||
|
|
||||||
|
raylib.DrawFPS(1, 1);
|
||||||
|
|
||||||
|
const debug_text = try std.fmt.allocPrint(allocator, "screen size = {d}x{d}", .{ screen_width, screen_height });
|
||||||
|
defer allocator.free(debug_text);
|
||||||
|
raylib.DrawText(@ptrCast(debug_text), 80, 2, 8, raylib.GREEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var global_font: raylib.Font = undefined;
|
||||||
|
|
||||||
|
var screen_width: f32 = 480;
|
||||||
|
var screen_height: f32 = 272;
|
||||||
|
|
||||||
|
var scales: Scales = undefined;
|
||||||
|
|
||||||
|
pub const Scales = struct {
|
||||||
|
item_icon_scale: f32,
|
||||||
|
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,
|
||||||
|
|
||||||
|
pub fn recalculate(self: *Scales) void {
|
||||||
|
self.item_icon_scale = screen_height * 0.72 / screen_height;
|
||||||
|
|
||||||
|
self.column_icon_scale = screen_height * 0.75 / screen_height;
|
||||||
|
self.column_title_font_size = screen_height * 13 / screen_height;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Column = struct {
|
||||||
|
icon: raylib.Texture2D,
|
||||||
|
title: []const u8,
|
||||||
|
|
||||||
|
items: std.ArrayList(*Item),
|
||||||
|
|
||||||
|
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 {
|
||||||
|
const icon_position = scales.column_position_center;
|
||||||
|
const icon_scale = scales.column_icon_scale;
|
||||||
|
const icon_width = @as(f32, @floatFromInt(self.icon.width)) * icon_scale;
|
||||||
|
const icon_height = @as(f32, @floatFromInt(self.icon.height)) * icon_scale;
|
||||||
|
|
||||||
|
const title_font_size = scales.column_title_font_size;
|
||||||
|
const title_font_spacing = 1.0;
|
||||||
|
const title_size = raylib.MeasureTextEx(global_font, @ptrCast(self.title), title_font_size, title_font_spacing);
|
||||||
|
const title_position = raylib.Vector2{
|
||||||
|
.x = icon_position.x + icon_width / 2.0 - title_size.x / 2.0,
|
||||||
|
.y = icon_position.y + icon_height + 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
var y: f32 = scales.column_position_center.y + icon_height + title_size.y + 32;
|
||||||
|
for (self.items.items) |item| {
|
||||||
|
item.position = .{ .x = scales.column_position_center.x, .y = y };
|
||||||
|
// item.draw();
|
||||||
|
y += 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
raylib.DrawTextureEx(self.icon, icon_position, 0, icon_scale, raylib.WHITE);
|
||||||
|
raylib.DrawTextEx(global_font, @ptrCast(self.title), title_position, title_font_size, title_font_spacing, raylib.WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn appendItem(self: *Column, item: *Item) !void {
|
||||||
|
try self.items.append(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insertItem(self: *Column, idx: usize, item: *Item) !void {
|
||||||
|
try self.items.insert(idx, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn removeItem(self: *Column, idx: usize) void {
|
||||||
|
_ = try self.items.orderedRemove(idx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Item = struct {
|
||||||
|
time: f32 = 0.0,
|
||||||
|
start_scale: f32,
|
||||||
|
position: raylib.Vector2 = .{ .x = 0, .y = 0 },
|
||||||
|
scale: f32,
|
||||||
|
|
||||||
|
icon: raylib.Texture2D,
|
||||||
|
title: []const u8,
|
||||||
|
subtitle: []const u8,
|
||||||
|
big: bool = true,
|
||||||
|
|
||||||
|
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,
|
||||||
|
.scale = scales.item_icon_scale,
|
||||||
|
.start_scale = scales.item_icon_scale,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(self: *Item) void {
|
||||||
|
self.time += raylib.GetFrameTime();
|
||||||
|
self.scale = std.math.lerp(
|
||||||
|
self.start_scale,
|
||||||
|
if (self.big) scales.item_icon_scale else scales.item_icon_scale * 0.5,
|
||||||
|
easeOutExpo(self.time / 0.333),
|
||||||
|
);
|
||||||
|
|
||||||
|
const title_pos = raylib.Vector2{
|
||||||
|
.x = self.position.x + 16 + @as(f32, @floatFromInt(self.icon.width)) * self.scale,
|
||||||
|
.y = (self.position.y + @as(f32, @floatFromInt(self.icon.height)) * self.scale) / 2.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
raylib.DrawTextureEx(self.icon, self.position, 0, self.scale, raylib.WHITE);
|
||||||
|
raylib.DrawTextEx(global_font, @ptrCast(self.title), title_pos, 18.0, 1, raylib.WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setBig(self: *Item, big: bool) void {
|
||||||
|
self.big = big;
|
||||||
|
self.time = 0;
|
||||||
|
self.start_scale = self.scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 },
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
352
src/rco.zig
Normal file
352
src/rco.zig
Normal file
|
@ -0,0 +1,352 @@
|
||||||
|
pub fn main() !void {
|
||||||
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
defer _ = gpa.deinit();
|
||||||
|
const allocator = gpa.allocator();
|
||||||
|
|
||||||
|
var rco_file = try std.fs.cwd().openFile("vsh/resource/explore_plugin_game.rco", .{});
|
||||||
|
defer rco_file.close();
|
||||||
|
|
||||||
|
var rco = try RcoFile.init(allocator, rco_file);
|
||||||
|
defer rco.deinit();
|
||||||
|
|
||||||
|
try rco_file.seekTo(rco.toc_main_tree_offset.?);
|
||||||
|
const packed_size = try rco_file.reader().readInt(u32, .big);
|
||||||
|
const unpacked_size = try rco_file.reader().readInt(u32, .big);
|
||||||
|
const longest_text_size = try rco_file.reader().readInt(u32, .big);
|
||||||
|
std.debug.print("{d} {d} {d}\n", .{ packed_size, unpacked_size, longest_text_size });
|
||||||
|
|
||||||
|
const packed_buf = try allocator.alloc(u8, packed_size);
|
||||||
|
defer allocator.free(packed_buf);
|
||||||
|
_ = try rco_file.readAll(packed_buf);
|
||||||
|
|
||||||
|
var fb = std.io.fixedBufferStream(packed_buf);
|
||||||
|
var al = std.ArrayList(u8).init(allocator);
|
||||||
|
defer al.deinit();
|
||||||
|
|
||||||
|
try std.compress.zlib.decompress(fb.reader(), al.writer());
|
||||||
|
if (al.items.len != unpacked_size) return error.DecompressedSizeDoesNotMatch;
|
||||||
|
|
||||||
|
var nfb = std.io.fixedBufferStream(al.items);
|
||||||
|
|
||||||
|
while (nfb.pos < try nfb.getEndPos()) {
|
||||||
|
try parseTocEntry(nfb.reader());
|
||||||
|
}
|
||||||
|
|
||||||
|
std.debug.print("{any}\n", .{rco});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parseTocEntry(reader: anytype) !void {
|
||||||
|
const entry_type: TocEntryType = @enumFromInt(try reader.readInt(u16, .big));
|
||||||
|
try reader.skipBytes(2, .{});
|
||||||
|
const entry_label_offset = try reader.readInt(u32, .big);
|
||||||
|
const attributes_offset = try reader.readInt(u32, .big);
|
||||||
|
const children_offset = try reader.readInt(u32, .big);
|
||||||
|
const children_number = try reader.readInt(u32, .big);
|
||||||
|
const next_sibling_offset = try reader.readInt(u32, .big);
|
||||||
|
const prev_sibling_offset = try reader.readInt(u32, .big);
|
||||||
|
const parent_offset = try reader.readInt(u32, .big);
|
||||||
|
try reader.skipBytes(8, .{});
|
||||||
|
|
||||||
|
_ = .{ entry_label_offset, attributes_offset, children_offset, children_number, next_sibling_offset, prev_sibling_offset, parent_offset };
|
||||||
|
|
||||||
|
std.log.debug("Found TOC Entry: {any}", .{entry_type});
|
||||||
|
|
||||||
|
switch (entry_type) {
|
||||||
|
.MainTree,
|
||||||
|
.ScriptTree,
|
||||||
|
.TextTree,
|
||||||
|
.ImageTree,
|
||||||
|
.ModelTree,
|
||||||
|
.SoundTree,
|
||||||
|
.FontTree,
|
||||||
|
.ObjectTree,
|
||||||
|
.AnimTree,
|
||||||
|
=> {},
|
||||||
|
|
||||||
|
.Text => {
|
||||||
|
const text = try RcoFile.Text.init(reader);
|
||||||
|
std.debug.print("Text: {any}\n", .{text});
|
||||||
|
},
|
||||||
|
|
||||||
|
.Image => {
|
||||||
|
const image = try RcoFile.ImageTree.Image.init(reader);
|
||||||
|
std.debug.print("Image: {any}\n", .{image});
|
||||||
|
},
|
||||||
|
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const TocEntryType = enum(u16) {
|
||||||
|
MainTree = 0x0101,
|
||||||
|
|
||||||
|
ScriptTree = 0x0200,
|
||||||
|
|
||||||
|
TextTree = 0x0300,
|
||||||
|
Text = 0x0301,
|
||||||
|
|
||||||
|
ImageTree = 0x0400,
|
||||||
|
Image = 0x0401,
|
||||||
|
|
||||||
|
ModelTree = 0x0500,
|
||||||
|
Model = 0x0501,
|
||||||
|
|
||||||
|
SoundTree = 0x0600,
|
||||||
|
Sound = 0x0601,
|
||||||
|
|
||||||
|
FontTree = 0x0700,
|
||||||
|
Font = 0x0701,
|
||||||
|
|
||||||
|
ObjectTree = 0x0800,
|
||||||
|
Page = 0x0801,
|
||||||
|
Plane = 0x0802,
|
||||||
|
Button = 0x0803,
|
||||||
|
XMenu,
|
||||||
|
XMList,
|
||||||
|
Progress,
|
||||||
|
Scroll,
|
||||||
|
MList,
|
||||||
|
MItem,
|
||||||
|
_object_unk1 = 0x080B,
|
||||||
|
XItem,
|
||||||
|
TextObject,
|
||||||
|
ModelObject,
|
||||||
|
Spin,
|
||||||
|
Action,
|
||||||
|
ItemSpin,
|
||||||
|
Group,
|
||||||
|
LList,
|
||||||
|
LItem,
|
||||||
|
Edit,
|
||||||
|
Clock,
|
||||||
|
IList,
|
||||||
|
IItem,
|
||||||
|
Icon,
|
||||||
|
UButton,
|
||||||
|
_object_unk2 = 0x081B,
|
||||||
|
CheckboxGroup,
|
||||||
|
CheckboxItem,
|
||||||
|
Meter,
|
||||||
|
EditBox = 0x081F,
|
||||||
|
|
||||||
|
AnimTree = 0x0900,
|
||||||
|
Anim = 0x0901,
|
||||||
|
MoveTo = 0x0902,
|
||||||
|
Recolour = 0x0903,
|
||||||
|
Rotate = 0x0904,
|
||||||
|
Resize = 0x0905,
|
||||||
|
Fade = 0x0906,
|
||||||
|
Delay = 0x0907,
|
||||||
|
FireEvent = 0x0908,
|
||||||
|
Lock = 0x0909,
|
||||||
|
Unlock = 0x090A,
|
||||||
|
SlideOut = 0x090B,
|
||||||
|
|
||||||
|
_,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const RcoFile = struct {
|
||||||
|
allocator: Allocator,
|
||||||
|
file: std.fs.File,
|
||||||
|
|
||||||
|
compression: Compression,
|
||||||
|
|
||||||
|
toc_main_tree_offset: ?u32,
|
||||||
|
toc_script_tree_offset: ?u32,
|
||||||
|
toc_text_tree_offset: ?u32,
|
||||||
|
toc_sound_tree_offset: ?u32,
|
||||||
|
toc_model_tree_offset: ?u32,
|
||||||
|
toc_image_tree_offset: ?u32,
|
||||||
|
toc_font_tree_offset: ?u32,
|
||||||
|
toc_object_tree_offset: ?u32,
|
||||||
|
toc_anim_tree_offset: ?u32,
|
||||||
|
|
||||||
|
pub fn parse(self: *RcoFile) !void {
|
||||||
|
const rco_header = try self.file.reader().readStructEndian(RcoHeader, .big);
|
||||||
|
self.compression = @enumFromInt(rco_header.prf_compress);
|
||||||
|
self.toc_main_tree_offset = parseOffset(rco_header.toc_main_tree_offset);
|
||||||
|
self.toc_script_tree_offset = parseOffset(rco_header.toc_script_tree_offset);
|
||||||
|
self.toc_text_tree_offset = parseOffset(rco_header.toc_text_tree_offset);
|
||||||
|
self.toc_sound_tree_offset = parseOffset(rco_header.toc_sound_tree_offset);
|
||||||
|
self.toc_model_tree_offset = parseOffset(rco_header.toc_model_tree_offset);
|
||||||
|
self.toc_image_tree_offset = parseOffset(rco_header.toc_image_tree_offset);
|
||||||
|
self.toc_font_tree_offset = parseOffset(rco_header.toc_font_tree_offset);
|
||||||
|
self.toc_object_tree_offset = parseOffset(rco_header.toc_object_tree_offset);
|
||||||
|
self.toc_anim_tree_offset = parseOffset(rco_header.toc_anim_tree_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(allocator: Allocator, file: std.fs.File) !RcoFile {
|
||||||
|
var self: RcoFile = undefined;
|
||||||
|
self.allocator = allocator;
|
||||||
|
self.file = file;
|
||||||
|
try self.parse();
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(_: *RcoFile) void {}
|
||||||
|
|
||||||
|
fn parseOffset(offset: u32) ?u32 {
|
||||||
|
return if (offset == std.math.maxInt(u32)) null else offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format(
|
||||||
|
self: RcoFile,
|
||||||
|
comptime _: []const u8,
|
||||||
|
_: std.fmt.FormatOptions,
|
||||||
|
writer: anytype,
|
||||||
|
) !void {
|
||||||
|
try writer.writeAll("RcoFile{\n");
|
||||||
|
try writer.print(" .compression = {any},\n", .{self.compression});
|
||||||
|
try self.fmtField("toc_main_tree_offset", writer);
|
||||||
|
try self.fmtField("toc_script_tree_offset", writer);
|
||||||
|
try self.fmtField("toc_text_tree_offset", writer);
|
||||||
|
try self.fmtField("toc_sound_tree_offset", writer);
|
||||||
|
try self.fmtField("toc_model_tree_offset", writer);
|
||||||
|
try self.fmtField("toc_image_tree_offset", writer);
|
||||||
|
try self.fmtField("toc_font_tree_offset", writer);
|
||||||
|
try self.fmtField("toc_object_tree_offset", writer);
|
||||||
|
try self.fmtField("toc_anim_tree_offset", writer);
|
||||||
|
try writer.writeAll("}");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fn fmtField(self: RcoFile, comptime field_name: []const u8, writer: anytype) !void {
|
||||||
|
const field = @field(self, field_name);
|
||||||
|
const format_string = std.fmt.comptimePrint(" .{s} = {{s}}{{?X}},\n", .{field_name});
|
||||||
|
try writer.print(format_string, .{
|
||||||
|
if (field != null) "0x" else "",
|
||||||
|
field,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const Compression = enum(u32) {
|
||||||
|
none = 0,
|
||||||
|
zlib = 0x10,
|
||||||
|
rlz = 0x20,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Text = struct {
|
||||||
|
language: Language,
|
||||||
|
encoding: Encoding,
|
||||||
|
number_of: u32,
|
||||||
|
|
||||||
|
pub const Language = enum(u16) {
|
||||||
|
Japanese = 0,
|
||||||
|
English_US = 1,
|
||||||
|
French = 2,
|
||||||
|
Spanish_Spain = 3,
|
||||||
|
German = 4,
|
||||||
|
Italian = 5,
|
||||||
|
Dutch = 6,
|
||||||
|
Portuguese_Portugal = 7,
|
||||||
|
Russian = 8,
|
||||||
|
Korean = 9,
|
||||||
|
Chinese_Traditional = 10,
|
||||||
|
Chinese_Simplified = 11,
|
||||||
|
Finnish = 12,
|
||||||
|
Swedish = 13,
|
||||||
|
Danish = 14,
|
||||||
|
Norwegian = 15,
|
||||||
|
Polish = 16,
|
||||||
|
Portuguese_Brazil = 17,
|
||||||
|
English_UK = 18,
|
||||||
|
Turkish = 19,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Encoding = enum(u16) {
|
||||||
|
utf8 = 0,
|
||||||
|
utf16 = 1,
|
||||||
|
utf32 = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const String = extern struct {
|
||||||
|
label_offset: u32,
|
||||||
|
string_length: u32,
|
||||||
|
string_offset: u32,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ImageTree = struct {
|
||||||
|
pub const Image = struct {
|
||||||
|
format: Format,
|
||||||
|
compression: Image.Compression,
|
||||||
|
size: u32,
|
||||||
|
offset: u32,
|
||||||
|
uncompressed_size: ?u32,
|
||||||
|
|
||||||
|
pub fn init(reader: anytype) !Image {
|
||||||
|
var self: Image = undefined;
|
||||||
|
self.format = @enumFromInt(try reader.readInt(u16, .big));
|
||||||
|
self.compression = @enumFromInt(try reader.readInt(u16, .big));
|
||||||
|
self.size = try reader.readInt(u32, .big);
|
||||||
|
self.offset = try reader.readInt(u32, .big);
|
||||||
|
try reader.skipBytes(4, .{});
|
||||||
|
self.uncompressed_size = if (self.compression == .none) null else try reader.readInt(u32, .big);
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const Format = enum(u16) {
|
||||||
|
png = 0,
|
||||||
|
jpeg = 1,
|
||||||
|
tiff = 2,
|
||||||
|
gif = 3,
|
||||||
|
bmp = 4,
|
||||||
|
gim = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Compression = enum(u16) {
|
||||||
|
none = 0,
|
||||||
|
zlib = 1,
|
||||||
|
rlz = 2,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const RcoHeader = extern struct {
|
||||||
|
prf_signature: [4]u8,
|
||||||
|
prf_version: [4]u8,
|
||||||
|
prf_unk: u32 = 0,
|
||||||
|
prf_compress: u32,
|
||||||
|
|
||||||
|
toc_main_tree_offset: u32,
|
||||||
|
toc_script_tree_offset: u32,
|
||||||
|
toc_text_tree_offset: u32,
|
||||||
|
toc_sound_tree_offset: u32,
|
||||||
|
toc_model_tree_offset: u32,
|
||||||
|
toc_image_tree_offset: u32,
|
||||||
|
toc_unk: u32 = std.math.maxInt(u32),
|
||||||
|
toc_font_tree_offset: u32,
|
||||||
|
toc_object_tree_offset: u32,
|
||||||
|
toc_anim_tree_offset: u32,
|
||||||
|
|
||||||
|
str_text_table_offset: u32,
|
||||||
|
str_text_table_length: u32,
|
||||||
|
str_text_label_offset: u32,
|
||||||
|
str_text_label_length: u32,
|
||||||
|
str_text_event_offset: u32,
|
||||||
|
str_text_event_length: u32,
|
||||||
|
|
||||||
|
ptr_text_table_offset: u32,
|
||||||
|
ptr_text_table_length: u32,
|
||||||
|
ptr_image_table_offset: u32,
|
||||||
|
ptr_image_table_length: u32,
|
||||||
|
ptr_model_table_offset: u32,
|
||||||
|
ptr_model_table_length: u32,
|
||||||
|
ptr_sound_table_offset: u32,
|
||||||
|
ptr_sound_table_length: u32,
|
||||||
|
ptr_object_table_offset: u32,
|
||||||
|
ptr_object_table_length: u32,
|
||||||
|
ptr_anim_table_offset: u32,
|
||||||
|
ptr_anim_table_length: u32,
|
||||||
|
|
||||||
|
dat_image_table_offset: u32,
|
||||||
|
dat_image_table_length: u32,
|
||||||
|
dat_sound_table_offset: u32,
|
||||||
|
dat_sound_table_length: u32,
|
||||||
|
dat_model_table_offset: u32,
|
||||||
|
dat_model_table_length: u32,
|
||||||
|
dat_unk: [3]u32 = [_]u32{std.math.maxInt(u32)} ** 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const Allocator = std.mem.Allocator;
|
Loading…
Add table
Add a link
Reference in a new issue