2021-12-29 21:09:00 +00:00
|
|
|
const std = @import("std");
|
2022-03-17 01:28:24 +00:00
|
|
|
const Log2Int = std.math.Log2Int;
|
2021-12-29 21:09:00 +00:00
|
|
|
|
2022-03-17 01:28:24 +00:00
|
|
|
pub inline fn sext(comptime bits: comptime_int, value: u32) u32 {
|
2022-03-01 00:38:50 +00:00
|
|
|
comptime std.debug.assert(bits <= 32);
|
|
|
|
const amount = 32 - bits;
|
2022-01-01 09:41:50 +00:00
|
|
|
|
2022-03-01 00:38:50 +00:00
|
|
|
return @bitCast(u32, @bitCast(i32, value << amount) >> amount);
|
2021-12-29 21:09:00 +00:00
|
|
|
}
|
2022-03-14 11:54:48 +00:00
|
|
|
|
2022-03-17 01:28:24 +00:00
|
|
|
/// See https://godbolt.org/z/W3en9Eche
|
2022-04-08 05:13:41 +00:00
|
|
|
pub inline fn rotr(comptime T: type, x: T, r: anytype) T {
|
|
|
|
if (@typeInfo(T).Int.signedness == .signed)
|
|
|
|
@compileError("cannot rotate signed integer");
|
2022-03-17 01:28:24 +00:00
|
|
|
|
2022-04-08 05:13:41 +00:00
|
|
|
const ar = @intCast(Log2Int(T), @mod(r, @typeInfo(T).Int.bits));
|
|
|
|
return x >> ar | x << (1 +% ~ar);
|
2022-03-17 01:28:24 +00:00
|
|
|
}
|
|
|
|
|
2022-03-14 11:54:48 +00:00
|
|
|
pub const FpsAverage = struct {
|
|
|
|
const Self = @This();
|
|
|
|
|
|
|
|
total: u64,
|
|
|
|
sample_count: u64,
|
|
|
|
|
|
|
|
pub fn init() Self {
|
2022-03-18 12:41:06 +00:00
|
|
|
return .{ .total = 0, .sample_count = 1 };
|
2022-03-14 11:54:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn add(self: *Self, sample: u64) void {
|
2022-03-14 23:38:29 +00:00
|
|
|
if (self.sample_count == 600) return self.reset(sample);
|
2022-03-14 11:54:48 +00:00
|
|
|
|
|
|
|
self.total += sample;
|
|
|
|
self.sample_count += 1;
|
|
|
|
}
|
|
|
|
|
2022-03-22 13:39:42 +00:00
|
|
|
pub fn calc(self: *const Self) f64 {
|
|
|
|
return @intToFloat(f64, std.time.ns_per_s) / (@intToFloat(f64, self.total) / @intToFloat(f64, self.sample_count));
|
2022-03-14 11:54:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn reset(self: *Self, sample: u64) void {
|
|
|
|
self.total = sample;
|
|
|
|
self.sample_count = 1;
|
|
|
|
}
|
|
|
|
};
|
2022-03-18 09:27:37 +00:00
|
|
|
|
|
|
|
pub fn intToBytes(comptime T: type, value: anytype) [@sizeOf(T)]u8 {
|
|
|
|
comptime std.debug.assert(@typeInfo(T) == .Int);
|
|
|
|
|
|
|
|
var result: [@sizeOf(T)]u8 = undefined;
|
|
|
|
|
|
|
|
var i: Log2Int(T) = 0;
|
|
|
|
while (i < result.len) : (i += 1) result[i] = @truncate(u8, value >> i * @bitSizeOf(u8));
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2022-03-22 17:41:18 +00:00
|
|
|
|
|
|
|
/// The Title from the GBA Cartridge may be null padded to a maximum
|
|
|
|
/// length of 12 bytes.
|
|
|
|
///
|
|
|
|
/// This function returns a slice of everything just before the first
|
|
|
|
/// `\0`
|
|
|
|
pub fn correctTitle(title: [12]u8) []const u8 {
|
|
|
|
var len = title.len;
|
|
|
|
for (title) |char, i| {
|
|
|
|
if (char == 0) {
|
|
|
|
len = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return title[0..len];
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Copies a Title and returns either an identical or similar
|
|
|
|
/// array consisting of ASCII that won't make any file system angry
|
|
|
|
///
|
2022-03-22 17:54:37 +00:00
|
|
|
/// e.g. POKEPIN R/S to POKEPIN R_S
|
2022-03-22 17:41:18 +00:00
|
|
|
pub fn safeTitle(title: [12]u8) [12]u8 {
|
|
|
|
var result: [12]u8 = title;
|
|
|
|
|
|
|
|
for (result) |*char| {
|
2022-03-22 17:54:37 +00:00
|
|
|
if (char.* == '/' or char.* == '\\') char.* = '_';
|
2022-03-22 17:41:18 +00:00
|
|
|
if (char.* == 0) break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn fixTitle(alloc: std.mem.Allocator, title: [12]u8) ![]u8 {
|
|
|
|
var len: usize = 12;
|
|
|
|
for (title) |char, i| {
|
|
|
|
if (char == 0) {
|
|
|
|
len = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const buf = try alloc.alloc(u8, len);
|
|
|
|
std.mem.copy(u8, buf, title[0..len]);
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|