Compare commits
No commits in common. "main" and "ed031c9b8c21e87ecb7797a0c2d2118d3b9a9cc9" have entirely different histories.
main
...
ed031c9b8c
|
@ -90,6 +90,3 @@ zig-out
|
|||
zig-cache
|
||||
zig-cache/h
|
||||
zig-cache/z
|
||||
|
||||
*.kra
|
||||
*.ini
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
[submodule "lib/SDL.zig"]
|
||||
path = lib/SDL.zig
|
||||
url = ../SDL.zig
|
||||
[submodule "lib/zgl"]
|
||||
path = lib/zgl
|
||||
url = https://github.com/ziglibs/zgl
|
||||
[submodule "lib/zlm"]
|
||||
path = lib/zlm
|
||||
url = https://github.com/ziglibs/zlm
|
14
build.zig
14
build.zig
|
@ -1,4 +1,5 @@
|
|||
const std = @import("std");
|
||||
const Sdk = @import("lib/SDL.zig/build.zig");
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
// Standard target options allows the person running `zig build` to choose
|
||||
|
@ -18,8 +19,17 @@ pub fn build(b: *std.Build) void {
|
|||
.optimize = optimize,
|
||||
});
|
||||
|
||||
exe.linkSystemLibrary("raylib");
|
||||
exe.linkSystemLibrary("c");
|
||||
const sdk = Sdk.init(b, null);
|
||||
sdk.link(exe, .dynamic);
|
||||
exe.linkSystemLibrary("sdl2_ttf");
|
||||
exe.linkSystemLibrary("sdl2_image");
|
||||
exe.linkSystemLibrary("gl");
|
||||
exe.linkSystemLibrary("epoxy");
|
||||
|
||||
const relative = std.Build.FileSource.relative;
|
||||
exe.addModule("zgl", b.createModule(.{ .source_file = relative("lib/zgl/zgl.zig") }));
|
||||
exe.addModule("zlm", b.createModule(.{ .source_file = relative("lib/zlm/zlm.zig") }));
|
||||
exe.addModule("sdl2", sdk.getWrapperModule());
|
||||
|
||||
b.installArtifact(exe);
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 36e192a74f3be878766e1aa3e6f13ba5f92650cb
|
|
@ -0,0 +1 @@
|
|||
Subproject commit b40eff53f384ced9481d1c8754651976de22588c
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 2dc8c0db2e92529bb618ca639bb891b6187fa579
|
BIN
res/cell.png
BIN
res/cell.png
Binary file not shown.
Before Width: | Height: | Size: 2.2 KiB |
|
@ -1,19 +1,17 @@
|
|||
const Self = @This();
|
||||
|
||||
const input = @import("input.zig");
|
||||
const SDL = @import("sdl2");
|
||||
|
||||
activate: bool = false,
|
||||
holding: bool = false,
|
||||
input: *const input.Input,
|
||||
scancode: SDL.Scancode, // SDL Keycode
|
||||
callback: *const anyopaque, // MUST be a function with void return
|
||||
|
||||
pub fn init(tmp_input: *const input.Input, callback: *const anyopaque) Self {
|
||||
pub fn init(scancode: SDL.Scancode, callback: *const anyopaque) Self {
|
||||
return Self{
|
||||
.input = tmp_input,
|
||||
.scancode = scancode,
|
||||
.callback = callback,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn call(self: Self, state: anytype) void {
|
||||
@call(.auto, @as(*const fn (@TypeOf(state)) void, @ptrCast(self.callback)), .{state});
|
||||
@call(.auto, @ptrCast(*const fn (@TypeOf(state)) void, self.callback), .{state});
|
||||
}
|
||||
|
|
|
@ -1,86 +0,0 @@
|
|||
const std = @import("std");
|
||||
const fs = std.fs;
|
||||
const io = std.io;
|
||||
|
||||
pub const Option = struct {
|
||||
key: []const u8,
|
||||
value: []const u8,
|
||||
};
|
||||
|
||||
pub const ConfigIterator = struct {
|
||||
filename: []const u8,
|
||||
file: fs.File,
|
||||
buf: [1024]u8,
|
||||
i: i32 = 0,
|
||||
|
||||
pub fn next(self: *ConfigIterator) ?Option {
|
||||
if (self.i >= 1024) {
|
||||
std.debug.print("WARNING: Maximum number of lines in config reached, ignoring the rest.\n", .{});
|
||||
return null;
|
||||
}
|
||||
|
||||
var reader = self.file.reader();
|
||||
var fbs = io.fixedBufferStream(&self.buf);
|
||||
var writer = fbs.writer();
|
||||
|
||||
reader.streamUntilDelimiter(writer, '\n', self.buf.len) catch |err| {
|
||||
if (err == error.EndOfStream) {
|
||||
return null;
|
||||
} else {
|
||||
std.debug.print("ConfigIterator Error: {any}\n", .{err});
|
||||
unreachable;
|
||||
}
|
||||
};
|
||||
|
||||
var line = fbs.getWritten();
|
||||
|
||||
var keyval = std.mem.split(u8, line, "=");
|
||||
|
||||
var result = Option{
|
||||
.key = keyval.next() orelse {
|
||||
std.debug.print("Config {s}: line {} with contents '{s}' is invalid. Skipping.\n", .{
|
||||
self.filename,
|
||||
self.i,
|
||||
line,
|
||||
});
|
||||
self.i += 1;
|
||||
return self.next();
|
||||
},
|
||||
.value = keyval.next() orelse {
|
||||
std.debug.print("Config {s}: line {} with contents '{s}' is invalid. Skipping.\n", .{
|
||||
self.filename,
|
||||
self.i,
|
||||
line,
|
||||
});
|
||||
self.i += 1;
|
||||
return self.next();
|
||||
},
|
||||
};
|
||||
|
||||
if (keyval.next() != null) {
|
||||
std.debug.print("Config {s}: line {} with contents '{s}' is invalid. Skipping.\n", .{
|
||||
self.filename,
|
||||
self.i,
|
||||
line,
|
||||
});
|
||||
self.i += 1;
|
||||
return self.next();
|
||||
}
|
||||
|
||||
self.i += 1;
|
||||
return result;
|
||||
}
|
||||
pub fn deinit(self: *ConfigIterator) void {
|
||||
self.file.close();
|
||||
}
|
||||
};
|
||||
|
||||
pub fn getConfigIterator(path: []const u8) !ConfigIterator {
|
||||
var iterator = ConfigIterator{
|
||||
.filename = path,
|
||||
.file = try fs.cwd().createFile(path, .{ .read = true, .truncate = false }),
|
||||
.buf = undefined,
|
||||
};
|
||||
|
||||
return iterator;
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
@import("../input.zig");
|
||||
|
||||
fn loadControls() void {
|
||||
|
||||
}
|
||||
|
||||
fn createControls() void {
|
||||
|
||||
}
|
||||
|
||||
pub const controls = config.init("coso.ini")I
|
69
src/Game.zig
69
src/Game.zig
|
@ -1,4 +1,5 @@
|
|||
const std = @import("std");
|
||||
const SDL = @import("sdl2");
|
||||
|
||||
const Grid = @import("Game/Grid.zig");
|
||||
const Piece = @import("Game/Piece.zig");
|
||||
|
@ -6,13 +7,10 @@ const Bag = @import("Game/Bag.zig");
|
|||
const Timer = @import("Timer.zig");
|
||||
const State = @import("flow.zig").State;
|
||||
const Action = @import("Action.zig");
|
||||
const input = @import("input.zig");
|
||||
|
||||
const Renderer = @import("Game/Renderer.zig");
|
||||
const movement = @import("Game/movement.zig");
|
||||
|
||||
pub const Score = u64;
|
||||
|
||||
const Self = @This();
|
||||
|
||||
// Codes to access action list
|
||||
|
@ -38,16 +36,14 @@ held: ?Piece.Type,
|
|||
piece: Piece,
|
||||
shadow: Piece,
|
||||
|
||||
score: Score = 0,
|
||||
|
||||
action_list: ActionList = .{
|
||||
.right = Action.init(&input.game_right, actionRight), // Right
|
||||
.left = Action.init(&input.game_left, actionLeft), // Left
|
||||
.down = Action.init(&input.game_down, actionDown), // Down
|
||||
.hard = Action.init(&input.game_drop, actionHard), // Instant Drop
|
||||
.swap = Action.init(&input.game_swap_piece, actionSwap), // Swap Piece
|
||||
.rot_r = Action.init(&input.game_rotate_r, actionRotR), // Rotate
|
||||
.rot_l = Action.init(&input.game_rotate_l, actionRotL), // Rotate
|
||||
.right = Action.init(SDL.Scancode.d, actionRight), // Right
|
||||
.left = Action.init(SDL.Scancode.a, actionLeft), // Left
|
||||
.down = Action.init(SDL.Scancode.s, actionDown), // Down
|
||||
.hard = Action.init(SDL.Scancode.w, actionHard), // Instant Drop
|
||||
.swap = Action.init(SDL.Scancode.space, actionSwap), // Swap Piece
|
||||
.rot_r = Action.init(SDL.Scancode.right, actionRotR), // Rotate
|
||||
.rot_l = Action.init(SDL.Scancode.left, actionRotL), // Rotate
|
||||
},
|
||||
|
||||
timer_down: Timer,
|
||||
|
@ -56,7 +52,6 @@ timer_left_das: Timer,
|
|||
timer_right_arr: Timer,
|
||||
timer_right_das: Timer,
|
||||
timer_gravity: Timer,
|
||||
timer_line_clear: Timer,
|
||||
|
||||
needs_reinit: bool = false,
|
||||
|
||||
|
@ -70,13 +65,12 @@ pub fn init(renderer: *Renderer.Renderer) Self {
|
|||
.held = null,
|
||||
.renderer = Renderer.init(renderer),
|
||||
|
||||
.timer_down = Timer.init(0.05),
|
||||
.timer_left_arr = Timer.init(0.05),
|
||||
.timer_left_das = Timer.init(0.2),
|
||||
.timer_right_arr = Timer.init(0.05),
|
||||
.timer_right_das = Timer.init(0.2),
|
||||
.timer_gravity = Timer.init(0.3),
|
||||
.timer_line_clear = Timer.init(1),
|
||||
.timer_down = Timer.init(50),
|
||||
.timer_left_arr = Timer.init(50),
|
||||
.timer_left_das = Timer.init(200),
|
||||
.timer_right_arr = Timer.init(50),
|
||||
.timer_right_das = Timer.init(200),
|
||||
.timer_gravity = Timer.init(200),
|
||||
};
|
||||
|
||||
// Get a piece from the bag
|
||||
|
@ -87,10 +81,6 @@ pub fn init(renderer: *Renderer.Renderer) Self {
|
|||
|
||||
// Main Game loop
|
||||
pub fn tick(self: *Self) State {
|
||||
if (self.timer_line_clear.started and !self.timer_line_clear.finished()) {
|
||||
self.renderer.render(self.*);
|
||||
return self.state;
|
||||
}
|
||||
|
||||
// TIMERS
|
||||
// Dropping a piece
|
||||
|
@ -178,16 +168,17 @@ pub fn tick(self: *Self) State {
|
|||
}
|
||||
|
||||
// KEY EVENTS
|
||||
var key_state = SDL.getKeyboardState();
|
||||
|
||||
const action_fields = std.meta.fields(ActionList);
|
||||
inline for (action_fields) |field| {
|
||||
// REVIEW: Is this necessary?
|
||||
std.debug.print("\n{any}", .{field.name});
|
||||
const action = &@field(self.action_list, field.name);
|
||||
|
||||
if (action.input.isDown() and !action.*.holding) {
|
||||
if (key_state.isPressed(action.*.scancode) and !action.*.holding) {
|
||||
action.*.holding = true;
|
||||
action.*.activate = true;
|
||||
}
|
||||
if (!action.input.isDown()) {
|
||||
if (!key_state.isPressed(action.*.scancode)) {
|
||||
action.*.holding = false;
|
||||
}
|
||||
|
||||
|
@ -201,7 +192,7 @@ pub fn tick(self: *Self) State {
|
|||
// Update Shadow
|
||||
{
|
||||
self.shadow = movement.shadow(self.grid, self.piece);
|
||||
self.shadow.color[3] /= 4;
|
||||
self.shadow.color.a /= 4;
|
||||
}
|
||||
|
||||
// Check for a top out
|
||||
|
@ -215,25 +206,7 @@ pub fn tick(self: *Self) State {
|
|||
}
|
||||
}
|
||||
|
||||
// Check for empty lines. If there are, then start the clearing sequence
|
||||
if (!self.timer_line_clear.started) {
|
||||
if (self.grid.updateLinesToClear()) {
|
||||
self.timer_line_clear.start();
|
||||
}
|
||||
}
|
||||
// Don't go and clear them until the timer has finished
|
||||
else if (self.timer_line_clear.finished()) {
|
||||
const clear_score = self.grid.clearLines();
|
||||
if (clear_score > 0) {
|
||||
self.timer_line_clear.stop();
|
||||
self.score += clear_score;
|
||||
} else {
|
||||
std.debug.print("WARNING: Clear line timer stopped but there was nothign to clear. This situation isn't valid\n", .{});
|
||||
}
|
||||
}
|
||||
// NOTE: If for some reason game doesn't stop and another line has been cleared
|
||||
// before the timer reached the end, that line will be processed right after
|
||||
// the timer stops. Behaviour shouldn't get any funkier than that.
|
||||
self.grid.clearLines();
|
||||
|
||||
self.renderer.render(self.*);
|
||||
|
||||
|
|
|
@ -10,17 +10,17 @@ prng: std.rand.DefaultPrng,
|
|||
pub fn init() Self {
|
||||
var ret = Self{
|
||||
.contents = undefined,
|
||||
.prng = std.rand.DefaultPrng.init(@as(u64, @intCast(std.time.milliTimestamp()))),
|
||||
.prng = std.rand.DefaultPrng.init(@intCast(u64, std.time.milliTimestamp())),
|
||||
};
|
||||
// We must fill all of the array
|
||||
for (ret.contents[0..7], 0..) |_, i| {
|
||||
ret.contents[i] = @as(Piece.Type, @enumFromInt(i));
|
||||
ret.contents[i] = @intToEnum(Piece.Type, i);
|
||||
}
|
||||
// Then we shuffle
|
||||
ret.prng.random().shuffle(?Piece.Type, ret.contents[0..7]);
|
||||
|
||||
for (ret.contents[7..14], 0..) |_, i| {
|
||||
ret.contents[i + 7] = @as(Piece.Type, @enumFromInt(i));
|
||||
ret.contents[i + 7] = @intToEnum(Piece.Type, i);
|
||||
}
|
||||
// Then we shuffle
|
||||
ret.updateSeed();
|
||||
|
@ -46,7 +46,7 @@ pub fn pop(self: *Self) Piece {
|
|||
// Get more pieces if needed
|
||||
if (self.contents[7] == null) {
|
||||
for (self.contents[7..14], 0..) |_, i| {
|
||||
self.contents[i + 7] = @as(Piece.Type, @enumFromInt(i));
|
||||
self.contents[i + 7] = @intToEnum(Piece.Type, i);
|
||||
}
|
||||
self.updateSeed();
|
||||
self.prng.random().shuffle(?Piece.Type, self.contents[7..14]);
|
||||
|
@ -56,5 +56,5 @@ pub fn pop(self: *Self) Piece {
|
|||
}
|
||||
|
||||
fn updateSeed(self: *Self) void {
|
||||
self.prng.seed(@as(u64, @intCast(std.time.milliTimestamp())));
|
||||
self.prng.seed(@intCast(u64, std.time.milliTimestamp()));
|
||||
}
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
const std = @import("std");
|
||||
const SDL = @import("sdl2");
|
||||
|
||||
const color = @import("../color.zig");
|
||||
const Color = @import("../color.zig");
|
||||
|
||||
const Self = @This();
|
||||
|
||||
free: bool,
|
||||
color: color.Color,
|
||||
color: SDL.Color,
|
||||
|
||||
pub fn init() Self {
|
||||
return Self{
|
||||
.free = true,
|
||||
.color = color.dark_grey,
|
||||
.color = Color.dark_grey,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ pub const buffer = 10;
|
|||
|
||||
cells: [nrows][ncolumns]Cell,
|
||||
topped: bool = false,
|
||||
lines_to_clear: [nrows]bool = .{false} ** nrows,
|
||||
|
||||
pub fn init() Self {
|
||||
var self = Self{
|
||||
|
@ -31,44 +30,20 @@ pub fn init() Self {
|
|||
return self;
|
||||
}
|
||||
|
||||
pub fn updateLinesToClear(self: *Self) bool {
|
||||
var ret: bool = false;
|
||||
|
||||
// Look at each row
|
||||
pub fn clearLines(self: *Self) void {
|
||||
for (self.cells, 0..) |_, y| {
|
||||
// Look at each cell in the line
|
||||
for (self.cells[y], 0..) |cell_x, x| {
|
||||
if (cell_x.free) {
|
||||
// It is free, this line isn't to be cleared
|
||||
break;
|
||||
} else {
|
||||
// Reached the end of the column?
|
||||
if (x == self.cells[y].len - 1) {
|
||||
self.lines_to_clear[y] = true;
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
pub fn clearLines(self: *Self) u8 {
|
||||
var ncleared: u8 = 0;
|
||||
|
||||
// Go line by line, checking if any of them needs to be cleared
|
||||
for (self.lines_to_clear, 0..) |_, y| {
|
||||
if (self.lines_to_clear[y]) {
|
||||
// Delete current row and bring the others down
|
||||
for (self.cells[1..y], 0..) |_, i| {
|
||||
self.cells[y - i] = self.cells[y - i - 1];
|
||||
}
|
||||
ncleared += 1;
|
||||
}
|
||||
}
|
||||
|
||||
self.lines_to_clear = .{false} ** nrows;
|
||||
|
||||
return ncleared;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
const SDL = @import("sdl2");
|
||||
const std = @import("std");
|
||||
|
||||
const Grid = @import("Grid.zig");
|
||||
|
@ -50,7 +51,7 @@ dropped: bool = false,
|
|||
swapped: bool = false,
|
||||
|
||||
piece_type: Type,
|
||||
color: color.Color,
|
||||
color: SDL.Color,
|
||||
|
||||
pub fn init(piece_type: Type) Self {
|
||||
return Self{
|
||||
|
@ -58,7 +59,7 @@ pub fn init(piece_type: Type) Self {
|
|||
.col = (Grid.ncolumns / 2) - (ncols / 2),
|
||||
.piece_type = piece_type,
|
||||
|
||||
.timer_dropped = Timer.init(0.5),
|
||||
.timer_dropped = Timer.init(500),
|
||||
|
||||
.structure = switch (piece_type) {
|
||||
Type.o => .{
|
||||
|
@ -132,21 +133,21 @@ pub fn rotate(self: Self, dir: Rot) Self {
|
|||
|
||||
if (dir == Rot.right) {
|
||||
// Cicle through rotation stage
|
||||
new_piece.rot_stage = @as(RotStage, @enumFromInt(@mod((@intFromEnum(new_piece.rot_stage) + 1), 4)));
|
||||
new_piece.rot_stage = @intToEnum(RotStage, @mod((@enumToInt(new_piece.rot_stage) + 1), 4));
|
||||
// Rotate structure CW
|
||||
inline for (sequences) |seq| {
|
||||
inline for (seq, 0..) |_, i| {
|
||||
const refi = @mod((@as(i32, @intCast(i)) - 1), 4);
|
||||
const refi = @mod((@intCast(i32, i) - 1), 4);
|
||||
new_piece.structure[seq[i][0]][seq[i][1]] = self.structure[seq[refi][0]][seq[refi][1]];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Cicle through rotation stage
|
||||
new_piece.rot_stage = @as(RotStage, @enumFromInt(@mod((@intFromEnum(new_piece.rot_stage) - 1), 4)));
|
||||
new_piece.rot_stage = @intToEnum(RotStage, @mod((@enumToInt(new_piece.rot_stage) - 1), 4));
|
||||
// Rotate structure CCW
|
||||
inline for (sequences) |seq| {
|
||||
inline for (seq, 0..) |_, i| {
|
||||
const refi = @mod((@as(i32, @intCast(i)) + 1), 4);
|
||||
const refi = @mod((@intCast(i32, i) + 1), 4);
|
||||
new_piece.structure[seq[i][0]][seq[i][1]] = self.structure[seq[refi][0]][seq[refi][1]];
|
||||
}
|
||||
}
|
||||
|
@ -156,21 +157,21 @@ pub fn rotate(self: Self, dir: Rot) Self {
|
|||
|
||||
if (dir == Rot.right) {
|
||||
// Cicle through rotation stage
|
||||
new_piece.rot_stage = @as(RotStage, @enumFromInt(@mod((@intFromEnum(new_piece.rot_stage) + 1), 4)));
|
||||
new_piece.rot_stage = @intToEnum(RotStage, @mod((@enumToInt(new_piece.rot_stage) + 1), 4));
|
||||
// Rotate structure CW
|
||||
inline for (sequences) |seq| {
|
||||
inline for (seq, 0..) |_, i| {
|
||||
const refi = @mod((@as(i32, @intCast(i)) - 1), 4);
|
||||
const refi = @mod((@intCast(i32, i) - 1), 4);
|
||||
new_piece.structure[seq[i][0]][seq[i][1]] = self.structure[seq[refi][0]][seq[refi][1]];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Cicle through rotation stage
|
||||
new_piece.rot_stage = @as(RotStage, @enumFromInt(@mod((@intFromEnum(new_piece.rot_stage) - 1), 4)));
|
||||
new_piece.rot_stage = @intToEnum(RotStage, @mod((@enumToInt(new_piece.rot_stage) - 1), 4));
|
||||
// Rotate structure CCW
|
||||
inline for (sequences) |seq| {
|
||||
inline for (seq, 0..) |_, i| {
|
||||
const refi = @mod((@as(i32, @intCast(i)) + 1), 4);
|
||||
const refi = @mod((@intCast(i32, i) + 1), 4);
|
||||
new_piece.structure[seq[i][0]][seq[i][1]] = self.structure[seq[refi][0]][seq[refi][1]];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
const std = @import("std");
|
||||
const SDL = @import("sdl2");
|
||||
|
||||
const Game = @import("../Game.zig");
|
||||
const Bag = @import("Bag.zig");
|
||||
const Grid = @import("Grid.zig");
|
||||
|
@ -13,7 +14,6 @@ renderer: *Renderer,
|
|||
grid_cell_size: i32,
|
||||
grid_pos_x: i32,
|
||||
grid_pos_y: i32,
|
||||
cell_texture: Renderer.Texture,
|
||||
|
||||
pub fn init(renderer: *Renderer) Self {
|
||||
var wsize = renderer.getOutputSize();
|
||||
|
@ -26,7 +26,6 @@ pub fn init(renderer: *Renderer) Self {
|
|||
.grid_pos_x = grid_pos_x,
|
||||
.grid_pos_y = grid_pos_y,
|
||||
.grid_cell_size = grid_cell_size,
|
||||
.cell_texture = Renderer.Texture.init("res/cell.png"),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -34,31 +33,36 @@ pub fn renderBag(self: *Self, game: Game) void {
|
|||
const pos_x = self.grid_pos_x + ((Grid.ncolumns + 1) * self.grid_cell_size);
|
||||
const pos_y = self.grid_pos_y + (Grid.buffer * self.grid_cell_size);
|
||||
|
||||
var r: u8 = 0;
|
||||
var g: u8 = 0;
|
||||
var b: u8 = 0;
|
||||
var a: u8 = 255;
|
||||
|
||||
for (game.bag.contents[0..5], 0..) |_, i| {
|
||||
if (game.bag.contents[i]) |piece_type| {
|
||||
var piece = Piece.init(piece_type);
|
||||
|
||||
for (piece.structure, 0..) |_, y| {
|
||||
for (piece.structure[y], 0..) |_, x| {
|
||||
const new_x = pos_x + @as(i32, @intCast(x)) * self.grid_cell_size;
|
||||
const new_y = pos_y + (@as(i32, @intCast(y)) + @as(i32, @intCast(i * piece.structure.len))) * self.grid_cell_size;
|
||||
|
||||
if (piece.structure[y][x]) {
|
||||
self.cell_texture.drawTo(new_x, new_y, self.grid_cell_size, self.grid_cell_size, piece.color);
|
||||
r = piece.color.r;
|
||||
g = piece.color.g;
|
||||
b = piece.color.b;
|
||||
a = piece.color.a;
|
||||
} else {
|
||||
const alpha = 50;
|
||||
|
||||
self.renderer.setColor([_]u8{
|
||||
piece.color[0] -| 30, // r
|
||||
piece.color[1] -| 30, // g
|
||||
piece.color[2] -| 30, // b
|
||||
alpha,
|
||||
});
|
||||
self.renderer.fillRectangle(new_x, new_y, self.grid_cell_size, self.grid_cell_size);
|
||||
|
||||
self.renderer.setColor(.{ piece.color[0], piece.color[1], piece.color[2], alpha });
|
||||
self.renderer.fillRectangle(new_x + 1, new_y + 1, self.grid_cell_size - 2, self.grid_cell_size - 2);
|
||||
r = piece.color.r;
|
||||
g = piece.color.g;
|
||||
b = piece.color.b;
|
||||
a = 50;
|
||||
}
|
||||
|
||||
const new_x = pos_x + @intCast(i32, x) * self.grid_cell_size;
|
||||
const new_y = pos_y + (@intCast(i32, y) + @intCast(i32, i * piece.structure.len)) * self.grid_cell_size;
|
||||
|
||||
self.renderer.setColor(r, g, b, a);
|
||||
self.renderer.fillRectangle(new_x, new_y, self.grid_cell_size, self.grid_cell_size);
|
||||
self.renderer.setColor(r -| 30, g -| 30, b -| 30, a);
|
||||
self.renderer.drawRectangle(new_x, new_y, self.grid_cell_size, self.grid_cell_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -69,30 +73,35 @@ pub fn renderHeld(self: *Self, game: Game) void {
|
|||
const pos_x = self.grid_pos_x - (5 * self.grid_cell_size);
|
||||
const pos_y = self.grid_pos_y + (Grid.buffer * self.grid_cell_size);
|
||||
|
||||
var r: u8 = 0;
|
||||
var g: u8 = 0;
|
||||
var b: u8 = 0;
|
||||
var a: u8 = 255;
|
||||
|
||||
if (game.held) |held_type| {
|
||||
var held = Piece.init(held_type);
|
||||
|
||||
for (held.structure, 0..) |_, y| {
|
||||
for (held.structure[y], 0..) |_, x| {
|
||||
const new_x = pos_x + @as(i32, @intCast(x)) * self.grid_cell_size;
|
||||
const new_y = pos_y + @as(i32, @intCast(y)) * self.grid_cell_size;
|
||||
|
||||
if (held.structure[y][x]) {
|
||||
self.cell_texture.drawTo(new_x, new_y, self.grid_cell_size, self.grid_cell_size, held.color);
|
||||
r = held.color.r;
|
||||
g = held.color.g;
|
||||
b = held.color.b;
|
||||
a = held.color.a;
|
||||
} else {
|
||||
const alpha = 50;
|
||||
|
||||
self.renderer.setColor([_]u8{
|
||||
held.color[0] -| 30, // r
|
||||
held.color[1] -| 30, // g
|
||||
held.color[2] -| 30, // b
|
||||
alpha,
|
||||
});
|
||||
self.renderer.fillRectangle(new_x, new_y, self.grid_cell_size, self.grid_cell_size);
|
||||
|
||||
self.renderer.setColor(.{ held.color[0], held.color[1], held.color[2], alpha });
|
||||
self.renderer.fillRectangle(new_x + 1, new_y + 1, self.grid_cell_size - 2, self.grid_cell_size - 2);
|
||||
r = held.color.r;
|
||||
g = held.color.g;
|
||||
b = held.color.b;
|
||||
a = 50;
|
||||
}
|
||||
|
||||
const new_x = pos_x + @intCast(i32, x) * self.grid_cell_size;
|
||||
const new_y = pos_y + @intCast(i32, y) * self.grid_cell_size;
|
||||
|
||||
self.renderer.setColor(r, g, b, a);
|
||||
self.renderer.fillRectangle(new_x, new_y, self.grid_cell_size, self.grid_cell_size);
|
||||
self.renderer.setColor(r -| 30, g -| 30, b -| 30, a);
|
||||
self.renderer.drawRectangle(new_x, new_y, self.grid_cell_size, self.grid_cell_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -104,7 +113,6 @@ pub fn render(self: *Self, game: Game) void {
|
|||
renderPiece(self, game.shadow);
|
||||
renderBag(self, game);
|
||||
renderHeld(self, game);
|
||||
renderScore(self, game.score);
|
||||
}
|
||||
|
||||
pub fn renderPiece(self: *Self, piece: Piece) void {
|
||||
|
@ -118,10 +126,18 @@ pub fn renderPiece(self: *Self, piece: Piece) void {
|
|||
continue;
|
||||
}
|
||||
|
||||
const new_x = pos_x + (@as(i32, @intCast(x)) + piece.col) * self.grid_cell_size;
|
||||
const new_y = pos_y + (@as(i32, @intCast(y)) + piece.row) * self.grid_cell_size;
|
||||
var r = piece.color.r;
|
||||
var g = piece.color.g;
|
||||
var b = piece.color.b;
|
||||
var a = piece.color.a;
|
||||
|
||||
self.cell_texture.drawTo(new_x, new_y, self.grid_cell_size, self.grid_cell_size, piece.color);
|
||||
const new_x = pos_x + (@intCast(i32, x) + piece.col) * self.grid_cell_size;
|
||||
const new_y = pos_y + (@intCast(i32, y) + piece.row) * self.grid_cell_size;
|
||||
|
||||
self.renderer.setColor(r, g, b, a);
|
||||
self.renderer.fillRectangle(new_x, new_y, self.grid_cell_size, self.grid_cell_size);
|
||||
self.renderer.setColor(r -| 30, g -| 30, b -| 30, a);
|
||||
self.renderer.drawRectangle(new_x, new_y, self.grid_cell_size, self.grid_cell_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -129,37 +145,23 @@ pub fn renderPiece(self: *Self, piece: Piece) void {
|
|||
pub fn renderGrid(self: *Self, grid: Grid) void {
|
||||
const pos_x = self.grid_pos_x;
|
||||
const pos_y = self.grid_pos_y;
|
||||
|
||||
const lg = color.light_grey;
|
||||
|
||||
var visible = grid.cells[Grid.buffer..];
|
||||
for (visible, 0..) |_, y| {
|
||||
for (visible[y], 0..) |_, x| {
|
||||
const new_x = pos_x + @as(i32, @intCast(x)) * self.grid_cell_size;
|
||||
const new_y = pos_y + (@as(i32, @intCast(y)) + Grid.buffer) * self.grid_cell_size;
|
||||
var r = visible[y][x].color.r;
|
||||
var g = visible[y][x].color.g;
|
||||
var b = visible[y][x].color.b;
|
||||
var a = visible[y][x].color.a;
|
||||
|
||||
// Background
|
||||
self.renderer.setColor(color.light_grey);
|
||||
const new_x = pos_x + @intCast(i32, x) * self.grid_cell_size;
|
||||
const new_y = pos_y + (@intCast(i32, y) + Grid.buffer) * self.grid_cell_size;
|
||||
|
||||
self.renderer.setColor(r, g, b, a);
|
||||
self.renderer.fillRectangle(new_x, new_y, self.grid_cell_size, self.grid_cell_size);
|
||||
|
||||
if (visible[y][x].free) {
|
||||
// Not dropped
|
||||
self.renderer.setColor(visible[y][x].color);
|
||||
self.renderer.fillRectangle(new_x + 1, new_y + 1, self.grid_cell_size - 2, self.grid_cell_size - 2);
|
||||
} else {
|
||||
// Dropped
|
||||
self.cell_texture.drawTo(new_x, new_y, self.grid_cell_size, self.grid_cell_size, visible[y][x].color);
|
||||
}
|
||||
self.renderer.setColor(lg.r, lg.g, lg.b, lg.a);
|
||||
self.renderer.drawRectangle(new_x, new_y, self.grid_cell_size, self.grid_cell_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn renderScore(self: *Self, score: Game.Score) void {
|
||||
|
||||
const s_size = self.renderer.getOutputSize();
|
||||
|
||||
var buffer: [32]u8 = undefined;
|
||||
var score_string = std.fmt.bufPrintZ(&buffer, "Score: {d:0>16}", .{score}) catch "Score: " ++ "9" ** 16;
|
||||
|
||||
self.renderer.setColor(.{0,0,0,255});
|
||||
self.renderer.drawText(score_string, s_size.width - 400, 50, 20);
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
const Score = @Type(u64);
|
|
@ -68,8 +68,8 @@ pub fn drop(grid: Grid, piece: Piece) Grid {
|
|||
for (piece.structure, 0..) |_, y| {
|
||||
for (piece.structure[y], 0..) |_, x| {
|
||||
if (piece.structure[y][x]) {
|
||||
new_grid.cells[@as(usize, @intCast(piece.row + @as(i32, @intCast(y))))][@as(usize, @intCast(piece.col + @as(i32, @intCast(x))))].free = false;
|
||||
new_grid.cells[@as(usize, @intCast(piece.row + @as(i32, @intCast(y))))][@as(usize, @intCast(piece.col + @as(i32, @intCast(x))))].color = piece.color;
|
||||
new_grid.cells[@intCast(usize, piece.row + @intCast(i32, y))][@intCast(usize, piece.col + @intCast(i32, x))].free = false;
|
||||
new_grid.cells[@intCast(usize, piece.row + @intCast(i32, y))][@intCast(usize, piece.col + @intCast(i32, x))].color = piece.color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -86,11 +86,11 @@ fn checkCollision(grid: Grid, piece: Piece) bool {
|
|||
for (piece.structure, 0..) |_, y| {
|
||||
for (piece.structure[y], 0..) |_, x| {
|
||||
if (piece.structure[y][x] and
|
||||
((@as(i32, @intCast(x)) + piece.col > Grid.ncolumns - 1) or
|
||||
(@as(i32, @intCast(x)) + piece.col < 0) or
|
||||
(@as(i32, @intCast(y)) + piece.row > Grid.nrows - 1) or
|
||||
(@as(i32, @intCast(y)) + piece.row < 0) or
|
||||
(!grid.cells[@as(usize, @intCast(piece.row + @as(i32, @intCast(y))))][@as(usize, @intCast(piece.col + @as(i32, @intCast(x))))].free)))
|
||||
((@intCast(i32, x) + piece.col > Grid.ncolumns - 1) or
|
||||
(@intCast(i32, x) + piece.col < 0) or
|
||||
(@intCast(i32, y) + piece.row > Grid.nrows - 1) or
|
||||
(@intCast(i32, y) + piece.row < 0) or
|
||||
(!grid.cells[@intCast(usize, piece.row + @intCast(i32, y))][@intCast(usize, piece.col + @intCast(i32, x))].free)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ fn checkTTwist(grid: Grid, piece: Piece) bool {
|
|||
var row = piece.row + rows[i];
|
||||
var col = piece.col + cols[i];
|
||||
if ((row > 0 and row < Grid.nrows and col > 0 and col < Grid.ncolumns) and
|
||||
!grid.cells[@as(usize, @intCast(row))][@as(usize, @intCast(col))].free)
|
||||
!grid.cells[@intCast(usize, row)][@intCast(usize, col)].free)
|
||||
{
|
||||
std.debug.print("Hit\n", .{});
|
||||
diagonals += 1;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const std = @import("std");
|
||||
//const SDL = @import("sdl2");
|
||||
const SDL = @import("sdl2");
|
||||
const range = @import("utils.zig").range;
|
||||
|
||||
const MenuSelection = @import("MainMenu/MenuSelection.zig");
|
||||
|
@ -9,8 +9,6 @@ const Renderer = @import("MainMenu/Renderer.zig");
|
|||
const State = @import("flow.zig").State;
|
||||
const Action = @import("Action.zig");
|
||||
|
||||
const input = @import("input.zig");
|
||||
|
||||
const Self = @This();
|
||||
|
||||
const ActionList = struct {
|
||||
|
@ -22,11 +20,11 @@ const ActionList = struct {
|
|||
};
|
||||
|
||||
action_list: ActionList = .{
|
||||
.right = Action.init(&input.menu_right, actionTabRight), // Tab Right
|
||||
.left = Action.init(&input.menu_left, actionTabLeft), // Tab left
|
||||
.down = Action.init(&input.menu_down, actionSelDown), // Go down
|
||||
.up = Action.init(&input.menu_up, actionSelUp), // Go up
|
||||
.select = Action.init(&input.menu_accept, actionSelect), // Select
|
||||
.right = Action.init(SDL.Scancode.right, actionTabRight), // Tab Right
|
||||
.left = Action.init(SDL.Scancode.left, actionTabLeft), // Tab left
|
||||
.down = Action.init(SDL.Scancode.down, actionSelDown), // Go down
|
||||
.up = Action.init(SDL.Scancode.up, actionSelUp), // Go up
|
||||
.select = Action.init(SDL.Scancode.@"return", actionSelect), // Select
|
||||
},
|
||||
|
||||
tab_list: [3]MenuTab = .{
|
||||
|
@ -41,9 +39,8 @@ tab_list: [3]MenuTab = .{
|
|||
MenuTab.init("Online", .{ 105, 179, 86 }, &.{
|
||||
MenuSelection.init("Play", play),
|
||||
MenuSelection.init("Print", print),
|
||||
// FIXME: Crashes upon trying to render them
|
||||
//MenuSelection.init("Print", print),
|
||||
//MenuSelection.init("Print", print),
|
||||
MenuSelection.init("Print", print),
|
||||
MenuSelection.init("Print", print),
|
||||
}),
|
||||
},
|
||||
|
||||
|
@ -68,14 +65,14 @@ pub fn getSel(self: Self, offset: i32) MenuSelection {
|
|||
}
|
||||
|
||||
pub fn getSelIdx(self: Self, offset: i32) usize {
|
||||
const len = @as(i32, @intCast(self.getTab().contents.len));
|
||||
const sel = @as(i32, @intCast(self.getTab().sel));
|
||||
const len = @intCast(i32, self.getTab().contents.len);
|
||||
const sel = @intCast(i32, self.getTab().sel);
|
||||
|
||||
var ret: i32 = undefined;
|
||||
if (offset < 0) {
|
||||
ret = sel;
|
||||
|
||||
for (range(@as(usize, @intCast(-offset)))) |_| {
|
||||
for (range(@intCast(usize, -offset))) |_| {
|
||||
ret -= 1;
|
||||
if (ret < 0) {
|
||||
ret = len - 1;
|
||||
|
@ -89,7 +86,7 @@ pub fn getSelIdx(self: Self, offset: i32) usize {
|
|||
//std.debug.print("len {},offset {},ret {}, sel {}\n", .{ len, offset, ret, sel });
|
||||
}
|
||||
|
||||
return @as(usize, @intCast(ret));
|
||||
return @intCast(usize, ret);
|
||||
}
|
||||
|
||||
pub fn getTab(self: Self) MenuTab {
|
||||
|
@ -104,17 +101,16 @@ pub fn tick(self: *Self) State {
|
|||
|
||||
//const sel = self.getSel();
|
||||
//const tab = self.getTab();
|
||||
var key_state = SDL.getKeyboardState();
|
||||
|
||||
const action_fields = std.meta.fields(ActionList);
|
||||
inline for (action_fields) |field| {
|
||||
// REVIEW: Is this necessary?
|
||||
const action = &@field(self.action_list, field.name);
|
||||
|
||||
if (action.input.isDown() and !action.*.holding) {
|
||||
if (key_state.isPressed(action.*.scancode) and !action.*.holding) {
|
||||
action.*.holding = true;
|
||||
action.*.activate = true;
|
||||
}
|
||||
if (!action.input.isDown()) {
|
||||
if (!key_state.isPressed(action.*.scancode)) {
|
||||
action.*.holding = false;
|
||||
}
|
||||
|
||||
|
@ -124,7 +120,6 @@ pub fn tick(self: *Self) State {
|
|||
action.*.call(self);
|
||||
}
|
||||
}
|
||||
|
||||
//std.debug.print(
|
||||
//\\Tab: {s}
|
||||
//\\Selection: {s}
|
||||
|
|
|
@ -32,10 +32,12 @@ pub fn render(self: Self, main_menu: MainMenu) void {
|
|||
};
|
||||
|
||||
const wsize = self.renderer.getOutputSize();
|
||||
const screen_width = @intCast(i32, wsize.width);
|
||||
const screen_height = @intCast(i32, wsize.height);
|
||||
|
||||
for (tabs, 0..) |u_tab, u_tab_i| {
|
||||
//const tab = @intCast(i32, u_tab);
|
||||
const tab_i = @as(i32, @intCast(u_tab_i));
|
||||
const tab_i = @intCast(i32, u_tab_i);
|
||||
const curr_tab = main_menu.tab_list[u_tab];
|
||||
|
||||
// Auxiliary variables to claculate the center of the screen
|
||||
|
@ -45,12 +47,12 @@ pub fn render(self: Self, main_menu: MainMenu) void {
|
|||
// Current selection vertical offset
|
||||
const sel_y_offset = y_spacing * 12;
|
||||
// Number of items below selection
|
||||
const n_sel_below = @as(usize, @intCast(@divExact((wsize.height - sel_y_offset), (height + y_spacing))));
|
||||
const n_sel_below = @intCast(usize, @divExact((screen_height - sel_y_offset), (height + y_spacing)));
|
||||
// Number of items below selection
|
||||
const n_sel_above = @as(usize, @intCast(@divExact((sel_y_offset), (height + y_spacing))));
|
||||
const n_sel_above = @intCast(usize, @divExact((sel_y_offset), (height + y_spacing)));
|
||||
|
||||
// Move it from the left to the center
|
||||
const centering = @divExact((wsize.width - (total_width + total_spacing)), 2);
|
||||
const centering = @divExact((screen_width - (total_width + total_spacing)), 2);
|
||||
|
||||
const x = tab_i * (width + x_spacing) + centering;
|
||||
|
||||
|
@ -62,13 +64,13 @@ pub fn render(self: Self, main_menu: MainMenu) void {
|
|||
|
||||
// Current selection
|
||||
{
|
||||
const y = @as(i32, @intCast(sel_y_offset));
|
||||
const y = @intCast(i32, sel_y_offset);
|
||||
|
||||
// TODO: The shadow should be static, it is easier like this rn tho
|
||||
|
||||
if (tab_i == 1) {
|
||||
// Shadow
|
||||
self.renderer.setColor(.{ 0, 0, 0, 30 });
|
||||
self.renderer.setColor(0, 0, 0, 30);
|
||||
self.renderer.fillRectangleEx(x + 10, y + 10, width, height, skew);
|
||||
}
|
||||
|
||||
|
@ -76,53 +78,51 @@ pub fn render(self: Self, main_menu: MainMenu) void {
|
|||
}
|
||||
|
||||
for (range(n_sel_below), 0..) |_, i| {
|
||||
const aux_sel: i32 = @as(i32, @intCast(i + 1));
|
||||
const aux_sel: i32 = @intCast(i32, i + 1);
|
||||
const curr_sel: usize = main_menu.getSelIdx(aux_sel);
|
||||
const y = @as(i32, @intCast(sel_y_offset + ((y_spacing + height) * (aux_sel))));
|
||||
const y = @intCast(i32, sel_y_offset + ((y_spacing + height) * (aux_sel)));
|
||||
self.renderMenu(x - ((skew + 8) * aux_sel), y, curr_tab, curr_sel, alpha, false);
|
||||
}
|
||||
|
||||
for (range(n_sel_above), 0..) |_, i| {
|
||||
const aux_sel: i32 = -@as(i32, @intCast(i + 1));
|
||||
const aux_sel: i32 = -@intCast(i32, i + 1);
|
||||
const curr_sel: usize = main_menu.getSelIdx(aux_sel);
|
||||
const y = @as(i32, @intCast(sel_y_offset + ((y_spacing + height) * (aux_sel))));
|
||||
const y = @intCast(i32, sel_y_offset + ((y_spacing + height) * (aux_sel)));
|
||||
self.renderMenu(x - ((skew + 8) * aux_sel), y, curr_tab, curr_sel, alpha, false);
|
||||
}
|
||||
|
||||
// Tab header
|
||||
self.renderer.setColor(.{ curr_tab.color[0], curr_tab.color[1], curr_tab.color[2], alpha });
|
||||
self.renderer.setColor(curr_tab.color[0], curr_tab.color[1], curr_tab.color[2], alpha);
|
||||
self.renderer.fillRectangleEx(x - 25, 10, width + 50, height + 50, skew);
|
||||
}
|
||||
|
||||
// TODO: Set the Color depending on the Main Menu color
|
||||
self.renderer.setColor(.{ 232, 217, 166, 127 });
|
||||
self.renderer.setColorF(0.91, 0.85, 0.65, 0.50);
|
||||
self.renderer.fillRectangleEx(-150, 0, @divTrunc(wsize.width, 3), wsize.height, skew);
|
||||
self.renderer.fillRectangleEx(wsize.width - 300, 0, @divTrunc(wsize.width, 3), wsize.height, skew);
|
||||
self.renderer.fillRectangleEx(@intCast(i32, screen_width) - 300, 0, @divTrunc(wsize.width, 3), wsize.height, skew);
|
||||
}
|
||||
|
||||
fn renderMenu(self: Self, x: i32, y: i32, tab: MenuTab, sel: usize, a: u8, selected: bool) void {
|
||||
// White background
|
||||
self.renderer.setColor(.{ 255, 255, 255, a });
|
||||
self.renderer.setColor(255, 255, 255, a);
|
||||
self.renderer.fillRectangleEx(x, y, width, height, skew);
|
||||
|
||||
//_ = sel;
|
||||
if (selected) {
|
||||
// Set color if selected
|
||||
self.renderer.setColor(.{ tab.color[0], tab.color[1], tab.color[2], a });
|
||||
self.renderer.setColor(tab.color[0], tab.color[1], tab.color[2], a);
|
||||
} else {
|
||||
// Set black color, not selected
|
||||
self.renderer.setColor(.{ 0, 0, 0, a });
|
||||
self.renderer.setColor(0, 0, 0, a);
|
||||
}
|
||||
|
||||
const margin = 20;
|
||||
|
||||
self.renderer.drawText(
|
||||
tab.contents[sel].name,
|
||||
x + margin,
|
||||
y + margin,
|
||||
height - margin * 2,
|
||||
);
|
||||
//self.renderer.setColorF(1, 1, 1, 1);
|
||||
|
||||
//self.renderer.fillRectangleEx(x + margin, y + margin, width - margin * 2 - 12, height - margin * 2, skew);
|
||||
var text = Renderer.Texture.fromText(tab.contents[sel].name, height - margin * 2);
|
||||
self.renderer.renderTexture(text, x + margin, y + margin);
|
||||
|
||||
//self.renderer.fillRectangleEx(x + margin, y + margin, width - margin * 2, height - margin * 2, skew);
|
||||
self.renderer.fillRectangleEx(x + width - 6, y, 6, height, skew);
|
||||
self.renderer.fillRectangleEx(x + width - 12, y, 3, height, skew);
|
||||
}
|
||||
|
|
283
src/Renderer.zig
283
src/Renderer.zig
|
@ -1,35 +1,177 @@
|
|||
const std = @import("std");
|
||||
const rl = @import("raylib.zig");
|
||||
const sdl = @import("sdl2");
|
||||
const zlm = @import("zlm");
|
||||
const gl = @import("zgl");
|
||||
const m = zlm.SpecializeOn(f32);
|
||||
|
||||
const Self = @This();
|
||||
const colors = @import("color.zig");
|
||||
|
||||
color: colors.Color = .{ 0, 0, 0, 0 },
|
||||
window: sdl.Window,
|
||||
context: sdl.gl.Context,
|
||||
buffer: gl.Buffer,
|
||||
color: [4]f32 = .{ 0, 0, 0, 0 },
|
||||
|
||||
// There's a vbo for each shader program
|
||||
vbo: [max_objects]f32 = .{0.0} ** max_objects,
|
||||
vbo_index: usize = 0,
|
||||
|
||||
// The index of the program is the enum converted to int
|
||||
textures: [max_objects]Texture = .{undefined} ** max_objects,
|
||||
|
||||
const max_objects: usize = 16384;
|
||||
const quadSize: usize = 9 * 6;
|
||||
|
||||
pub fn init() !Self {
|
||||
rl.ConfigFlag.msaa_4x_hint.set();
|
||||
rl.initWindow(1280, 720, "USG", 120);
|
||||
fn glGetProcAddress(p: []const u8, proc: [:0]const u8) ?*const anyopaque {
|
||||
_ = p;
|
||||
return sdl.c.SDL_GL_GetProcAddress(@ptrCast([*c]const u8, proc));
|
||||
}
|
||||
|
||||
return Self{};
|
||||
pub fn init() !Self {
|
||||
try sdl.init(.{ .video = true, .audio = true, .events = true });
|
||||
try sdl.ttf.init();
|
||||
|
||||
try sdl.gl.setAttribute(.{ .context_major_version = 3 });
|
||||
try sdl.gl.setAttribute(.{ .context_minor_version = 3 });
|
||||
try sdl.gl.setAttribute(.{ .multisamplebuffers = true });
|
||||
try sdl.gl.setAttribute(.{ .multisamplesamples = 4 });
|
||||
|
||||
const window = try sdl.createWindow(
|
||||
"USG",
|
||||
.{ .centered = {} },
|
||||
.{ .centered = {} },
|
||||
1280,
|
||||
720,
|
||||
.{ .context = .opengl, .vis = .shown },
|
||||
);
|
||||
|
||||
const proc: []const u8 = undefined;
|
||||
try gl.loadExtensions(proc, glGetProcAddress);
|
||||
|
||||
const ctx = try sdl.gl.createContext(window);
|
||||
sdl.gl.setSwapInterval(.immediate) catch {
|
||||
std.debug.print("WARNING: Unable to configure the swap interval.\n", .{});
|
||||
};
|
||||
|
||||
// Activate blending and configure it
|
||||
gl.enable(.blend);
|
||||
gl.blendFunc(.src_alpha, .one_minus_src_alpha);
|
||||
|
||||
var buf = gl.Buffer.gen();
|
||||
buf.bind(.array_buffer);
|
||||
|
||||
var renderer = Self{ .window = window, .context = ctx, .buffer = buf };
|
||||
|
||||
// Load the shader programs according to the names in the enum
|
||||
_ = renderer.loadProgram("texture").use();
|
||||
|
||||
var vertex_array = gl.VertexArray.gen();
|
||||
vertex_array.bind();
|
||||
|
||||
gl.vertexAttribPointer(0, 2, .float, false, @sizeOf(f32) * 9, @sizeOf(f32) * 0);
|
||||
gl.enableVertexAttribArray(0);
|
||||
|
||||
gl.vertexAttribPointer(1, 4, .float, false, @sizeOf(f32) * 9, @sizeOf(f32) * 2);
|
||||
gl.enableVertexAttribArray(1);
|
||||
|
||||
gl.vertexAttribPointer(2, 2, .float, false, @sizeOf(f32) * 9, @sizeOf(f32) * 6);
|
||||
gl.enableVertexAttribArray(2);
|
||||
|
||||
gl.vertexAttribPointer(3, 1, .float, false, @sizeOf(f32) * 9, @sizeOf(f32) * 8);
|
||||
gl.enableVertexAttribArray(3);
|
||||
|
||||
gl.clearColor(0.91, 0.85, 0.65, 1.00);
|
||||
|
||||
return renderer;
|
||||
}
|
||||
|
||||
fn loadProgram(self: Self, comptime name: []const u8) gl.Program {
|
||||
var program = gl.Program.create();
|
||||
|
||||
const vs = gl.Shader.create(.vertex);
|
||||
defer vs.delete();
|
||||
const fs = gl.Shader.create(.fragment);
|
||||
defer fs.delete();
|
||||
|
||||
vs.source(1, &.{@embedFile("shaders/" ++ name ++ ".vert")});
|
||||
fs.source(1, &.{@embedFile("shaders/" ++ name ++ ".frag")});
|
||||
|
||||
vs.compile();
|
||||
fs.compile();
|
||||
|
||||
program.attach(vs);
|
||||
defer program.detach(vs);
|
||||
program.attach(fs);
|
||||
defer program.detach(fs);
|
||||
|
||||
program.link();
|
||||
|
||||
// Get the matrix that converts coordinates to 1:1 on the screen from the OpenGL default
|
||||
if (program.uniformLocation("mvp")) |mvpLocation| {
|
||||
const wsize = self.window.getSize();
|
||||
const xunit = @intToFloat(f32, wsize.width);
|
||||
const yunit = @intToFloat(f32, wsize.height);
|
||||
|
||||
const ortho = m.Mat4.createOrthogonal(0.0, xunit, yunit, 0.0, 0.0, 100.0);
|
||||
|
||||
program.use();
|
||||
gl.uniformMatrix4fv(mvpLocation, false, &.{ortho.fields});
|
||||
}
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
pub fn render(self: *Self) void {
|
||||
_ = self;
|
||||
rl.drawFPS(10, 10);
|
||||
// TODO: Submit with SubData instead to not pass the whole buffer
|
||||
self.buffer.data(f32, &self.vbo, .static_draw);
|
||||
|
||||
rl.endDrawing();
|
||||
rl.beginDrawing();
|
||||
var i: usize = 0;
|
||||
const amount = self.vbo_index / quadSize;
|
||||
while (i < amount) : (i += 1) {
|
||||
gl.bindTexture(self.textures[i].texture, .@"2d");
|
||||
gl.drawArrays(.triangles, i * 6, 6);
|
||||
}
|
||||
self.vbo_index = 0;
|
||||
|
||||
rl.clearBackground(.{ 232, 216, 166, 255 });
|
||||
// Clear the vbo, this really shouldn't be necessary as the index is set to zero,
|
||||
// but otherwise it leads to bugs
|
||||
self.vbo = .{0.0} ** max_objects;
|
||||
|
||||
sdl.gl.swapWindow(self.window);
|
||||
gl.clear(.{ .color = true });
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self) void {
|
||||
_ = self;
|
||||
gl.disableVertexAttribArray(0);
|
||||
gl.disableVertexAttribArray(1);
|
||||
gl.disableVertexAttribArray(2);
|
||||
gl.disableVertexAttribArray(3);
|
||||
sdl.quit();
|
||||
sdl.ttf.quit();
|
||||
self.window.destroy();
|
||||
sdl.gl.deleteContext(self.context);
|
||||
}
|
||||
|
||||
rl.closeWindow();
|
||||
pub fn setColorF(self: *Self, r: f32, g: f32, b: f32, a: f32) void {
|
||||
self.*.color = .{ r, g, b, a };
|
||||
}
|
||||
|
||||
pub fn setColor(self: *Self, r: i32, g: i32, b: i32, a: i32) void {
|
||||
self.*.color = .{
|
||||
@intToFloat(f32, r) / 255.0,
|
||||
@intToFloat(f32, g) / 255.0,
|
||||
@intToFloat(f32, b) / 255.0,
|
||||
@intToFloat(f32, a) / 255.0,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn drawRectangle(self: *Self, x: i32, y: i32, w: i32, h: i32) void {
|
||||
//const indices = [_]u8{ 0, 1, 1, 2, 2, 3, 3, 0 };
|
||||
//self.renderRectangle(x, y, w, h, .lines, &indices);
|
||||
_ = x;
|
||||
_ = y;
|
||||
_ = self;
|
||||
_ = w;
|
||||
_ = h;
|
||||
}
|
||||
|
||||
pub fn fillRectangle(self: *Self, x: i32, y: i32, w: i32, h: i32) void {
|
||||
|
@ -37,53 +179,108 @@ pub fn fillRectangle(self: *Self, x: i32, y: i32, w: i32, h: i32) void {
|
|||
}
|
||||
|
||||
pub fn fillRectangleEx(self: *Self, x: i32, y: i32, w: i32, h: i32, skew_x: i32) void {
|
||||
var xf: f32 = @floatFromInt(x);
|
||||
var yf: f32 = @floatFromInt(y);
|
||||
var wf: f32 = @floatFromInt(w);
|
||||
var hf: f32 = @floatFromInt(h);
|
||||
|
||||
const skew_x_offset = @as(f32, @floatFromInt(skew_x)) * hf / 100;
|
||||
|
||||
const upLeft = [_]f32{ xf + skew_x_offset, yf };
|
||||
const upRight = [_]f32{ xf + wf + skew_x_offset, yf };
|
||||
const downLeft = [_]f32{ xf - skew_x_offset, yf + hf };
|
||||
const downRight = [_]f32{ xf + wf - skew_x_offset, yf + hf };
|
||||
|
||||
rl.drawTriangle(upLeft, downLeft, upRight, self.color);
|
||||
rl.drawTriangle(downLeft, downRight, upRight, self.color);
|
||||
renderRectangle(self, x, y, w, h, skew_x, 0);
|
||||
}
|
||||
|
||||
pub fn drawText(self: Self, text: [:0]const u8, x: i32, y: i32, size: i32) void {
|
||||
rl.drawText(text, x, y, size, self.color);
|
||||
pub fn renderTexture(self: *Self, texture: Texture, x: i32, y: i32) void {
|
||||
self.textures[self.vbo_index / quadSize] = texture;
|
||||
renderRectangle(self, x, y, @intCast(i32, texture.width), @intCast(i32, texture.height), 0, 1);
|
||||
}
|
||||
|
||||
pub fn setColor(self: *Self, color: colors.Color) void {
|
||||
self.color = color;
|
||||
fn renderRectangle(self: *Self, x: i32, y: i32, w: i32, h: i32, skew_x: i32, unit: f32) void {
|
||||
var xf = @intToFloat(f32, x);
|
||||
var yf = @intToFloat(f32, y);
|
||||
var wf = @intToFloat(f32, w);
|
||||
var hf = @intToFloat(f32, h);
|
||||
|
||||
const skew_x_offset = @intToFloat(f32, skew_x) * hf / 100;
|
||||
|
||||
const i = self.vbo_index;
|
||||
const vertex_data = [_]f32{
|
||||
xf + skew_x_offset, yf, // up-left
|
||||
self.color[0], self.color[1],
|
||||
self.color[2], self.color[3],
|
||||
0, 0,
|
||||
unit,
|
||||
xf + wf + skew_x_offset, yf, // up-right
|
||||
self.color[0], self.color[1],
|
||||
self.color[2], self.color[3],
|
||||
1, 0,
|
||||
unit,
|
||||
xf - skew_x_offset, yf + hf, // down-left
|
||||
self.color[0], self.color[1],
|
||||
self.color[2], self.color[3],
|
||||
0, 1,
|
||||
unit,
|
||||
xf + wf - skew_x_offset, yf + hf, // down-right
|
||||
self.color[0], self.color[1],
|
||||
self.color[2], self.color[3],
|
||||
1, 1,
|
||||
unit,
|
||||
xf + wf + skew_x_offset, yf, // up-right
|
||||
self.color[0], self.color[1],
|
||||
self.color[2], self.color[3],
|
||||
1, 0,
|
||||
unit,
|
||||
xf - skew_x_offset, yf + hf, // down-left
|
||||
self.color[0], self.color[1],
|
||||
self.color[2], self.color[3],
|
||||
0, 1,
|
||||
unit,
|
||||
};
|
||||
std.mem.copy(f32, self.vbo[i..], &vertex_data);
|
||||
self.vbo_index += vertex_data.len;
|
||||
}
|
||||
|
||||
pub const OutputSize = struct { width: i32, height: i32 };
|
||||
pub const OutputSize = struct { width: c_int, height: c_int };
|
||||
pub fn getOutputSize(self: Self) OutputSize {
|
||||
_ = self;
|
||||
var wsize = self.window.getSize();
|
||||
return OutputSize{
|
||||
.width = rl.getScreenWidth(),
|
||||
.height = rl.getScreenHeight(),
|
||||
.width = wsize.width,
|
||||
.height = wsize.height,
|
||||
};
|
||||
}
|
||||
|
||||
pub const Texture = struct {
|
||||
texture: rl.Texture,
|
||||
texture: gl.Texture,
|
||||
width: usize,
|
||||
height: usize,
|
||||
|
||||
pub fn init(path: [*]const u8) Texture {
|
||||
return .{
|
||||
.texture = rl.Texture.load(path),
|
||||
pub fn init(data: [*]const u8, width: usize, height: usize) Texture {
|
||||
var tex = gl.genTexture();
|
||||
//defer gl.Texture.delete(tex);
|
||||
gl.bindTexture(tex, .@"2d");
|
||||
|
||||
gl.textureImage2D(.@"2d", 0, .rgba, width, height, .rgba, .unsigned_byte, data);
|
||||
|
||||
gl.texParameter(.@"2d", .wrap_s, .clamp_to_edge);
|
||||
gl.texParameter(.@"2d", .wrap_r, .clamp_to_edge);
|
||||
gl.texParameter(.@"2d", .min_filter, .linear);
|
||||
gl.texParameter(.@"2d", .mag_filter, .linear);
|
||||
|
||||
return Texture{
|
||||
.texture = tex,
|
||||
.width = width,
|
||||
.height = height,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn drawTo(self: Texture, x: i32, y: i32, w: i32, h: i32, tint: [4]u8) void {
|
||||
self.texture.drawTo(x, y, w, h, tint);
|
||||
pub fn fromText(text: [:0]const u8, size: c_int) Texture {
|
||||
var font = sdl.ttf.openFont("res/fonts/MarginaliaRegular-8XlZ.ttf", size) catch unreachable;
|
||||
defer font.close();
|
||||
|
||||
var surface = font.renderTextBlended(text, sdl.Color.white) catch unreachable;
|
||||
defer surface.destroy();
|
||||
|
||||
const width = @intCast(usize, surface.ptr.w);
|
||||
const height = @intCast(usize, surface.ptr.h);
|
||||
var newsurf = sdl.c.SDL_ConvertSurfaceFormat(surface.ptr, @enumToInt(sdl.PixelFormatEnum.argb8888), 0) orelse unreachable;
|
||||
const data = @ptrCast([*]const u8, newsurf.pixels);
|
||||
|
||||
return Texture.init(data, width, height);
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Texture) void {
|
||||
self.texture.unload();
|
||||
gl.Texture.delete(self.texture);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
const SDL = @import("sdl2");
|
||||
|
||||
const Self = @This();
|
||||
|
||||
const getTime = @import("raylib.zig").getTime;
|
||||
|
||||
started: bool,
|
||||
initial: f64,
|
||||
progress: f64,
|
||||
target: f64,
|
||||
initial: u64,
|
||||
progress: u64,
|
||||
target: u64,
|
||||
|
||||
pub fn init(target: f64) Self {
|
||||
pub fn init(target: u64) Self {
|
||||
return Self{
|
||||
.started = false,
|
||||
.initial = 0,
|
||||
|
@ -19,12 +19,12 @@ pub fn init(target: f64) Self {
|
|||
pub fn start(self: *Self) void {
|
||||
self.started = true;
|
||||
self.progress = 0;
|
||||
self.initial = getTime();
|
||||
self.initial = SDL.getTicks64();
|
||||
}
|
||||
|
||||
pub fn finished(self: *Self) bool {
|
||||
if (self.started) {
|
||||
self.progress = getTime() - self.initial;
|
||||
self.progress = SDL.getTicks64() - self.initial;
|
||||
if (self.progress >= self.target) {
|
||||
return true;
|
||||
} else return false;
|
||||
|
@ -35,7 +35,7 @@ pub fn finished(self: *Self) bool {
|
|||
|
||||
pub fn reset(self: *Self) void {
|
||||
self.progress = 0;
|
||||
self.initial = getTime();
|
||||
self.initial = SDL.getTicks64();
|
||||
}
|
||||
|
||||
pub fn stop(self: *Self) void {
|
||||
|
|
|
@ -1,13 +1,68 @@
|
|||
pub const Color = [4]u8;
|
||||
const SDL = @import("sdl2");
|
||||
|
||||
pub const yellow = Color{ 255, 208, 95, 255 };
|
||||
pub const brown = Color{ 180, 130, 90, 255 };
|
||||
pub const cyan = Color{ 138, 167, 172, 255 };
|
||||
pub const orange = Color{ 222, 154, 40, 255 };
|
||||
pub const blue = Color{ 112, 123, 136, 255 };
|
||||
pub const green = Color{ 142, 146, 87, 255 };
|
||||
pub const red = Color{ 229, 93, 77, 255 };
|
||||
pub const purple = Color{ 180, 171, 189, 255 };
|
||||
pub const pink = Color{ 230, 115, 170, 255 };
|
||||
pub const dark_grey = Color{ 40, 40, 40, 255 };
|
||||
pub const light_grey = Color{ 80, 80, 80, 255 };
|
||||
pub const yellow = SDL.Color{
|
||||
.r = 232,
|
||||
.g = 216,
|
||||
.b = 165,
|
||||
.a = 255,
|
||||
};
|
||||
pub const brown = SDL.Color{
|
||||
.r = 180,
|
||||
.g = 130,
|
||||
.b = 90,
|
||||
.a = 255,
|
||||
};
|
||||
pub const cyan = SDL.Color{
|
||||
.r = 138,
|
||||
.g = 167,
|
||||
.b = 172,
|
||||
.a = 255,
|
||||
};
|
||||
pub const orange = SDL.Color{
|
||||
.r = 222,
|
||||
.g = 154,
|
||||
.b = 40,
|
||||
.a = 255,
|
||||
};
|
||||
pub const blue = SDL.Color{
|
||||
.r = 112,
|
||||
.g = 123,
|
||||
.b = 136,
|
||||
.a = 255,
|
||||
};
|
||||
pub const green = SDL.Color{
|
||||
.r = 142,
|
||||
.g = 146,
|
||||
.b = 87,
|
||||
.a = 255,
|
||||
};
|
||||
pub const red = SDL.Color{
|
||||
.r = 229,
|
||||
.g = 93,
|
||||
.b = 77,
|
||||
.a = 255,
|
||||
};
|
||||
pub const purple = SDL.Color{
|
||||
.r = 180,
|
||||
.g = 171,
|
||||
.b = 189,
|
||||
.a = 255,
|
||||
};
|
||||
pub const pink = SDL.Color{
|
||||
.r = 230,
|
||||
.g = 115,
|
||||
.b = 170,
|
||||
.a = 255,
|
||||
};
|
||||
pub const dark_grey = SDL.Color{
|
||||
.r = 40,
|
||||
.g = 40,
|
||||
.b = 40,
|
||||
.a = 255,
|
||||
};
|
||||
pub const light_grey = SDL.Color{
|
||||
.r = 80,
|
||||
.g = 80,
|
||||
.b = 80,
|
||||
.a = 255,
|
||||
};
|
||||
|
|
101
src/input.zig
101
src/input.zig
|
@ -1,101 +0,0 @@
|
|||
const Self = @This();
|
||||
|
||||
const rl = @import("raylib.zig");
|
||||
const std = @import("std");
|
||||
const config = @import("Config/config.zig");
|
||||
|
||||
pub const Input = struct {
|
||||
name: []const u8,
|
||||
code: i32,
|
||||
default: i32,
|
||||
|
||||
pub fn isDown(self: Input) bool {
|
||||
return rl.isKeyDown(self.code);
|
||||
}
|
||||
pub fn isJustPressed(self: Input) bool {
|
||||
return rl.isKeyPressed(self.code);
|
||||
}
|
||||
pub fn isJustReleased(self: Input) bool {
|
||||
return rl.isKeyReleased(self.code);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
pub fn loadConfig() void {
|
||||
var iter = config.getConfigIterator("input.ini") catch {
|
||||
std.debug.print("Error loading input config, using defaults...\n", .{});
|
||||
return;
|
||||
};
|
||||
|
||||
while (iter.next()) |option| {
|
||||
inline for (comptime getInputNames()) |name| {
|
||||
if (std.mem.eql(u8, option.key, name)) {
|
||||
if (rl.getValueFromInputName(option.value)) |value| {
|
||||
@field(Self, name).code = value;
|
||||
} else {
|
||||
std.debug.print("Invalid input value '{s}' in config, ignoring.\n", .{option.value});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn init(comptime name: []const u8, comptime key_code: []const u8) Input {
|
||||
return Input{
|
||||
.name = name,
|
||||
.code = rl.getKeyCode(key_code),
|
||||
.default = rl.getKeyCode(key_code),
|
||||
};
|
||||
}
|
||||
|
||||
pub var menu_right = init("Menu Right", "RIGHT");
|
||||
pub var menu_left = init("Menu Left", "LEFT");
|
||||
pub var menu_down = init("Menu Down", "DOWN");
|
||||
pub var menu_up = init("Menu Up", "UP");
|
||||
pub var menu_accept = init("Menu Accept", "ENTER");
|
||||
pub var menu_cancel = init("Menu Cancel", "BACKSPACE");
|
||||
|
||||
pub var game_right = init("Move Right", "D");
|
||||
pub var game_left = init("Move Left", "A");
|
||||
pub var game_down = init("Move Down", "S");
|
||||
pub var game_drop = init("Drop Piece", "W");
|
||||
pub var game_swap_piece = init("Swap Piece", "SPACE");
|
||||
pub var game_rotate_r = init("Rotate Piece Clockwise", "RIGHT");
|
||||
pub var game_rotate_l = init("Rotate Piece Counterclockwise", "LEFT");
|
||||
|
||||
// Get the names of the Input(s) defined in this file with introspection
|
||||
fn getInputNames() [getInputCount()][]const u8 {
|
||||
comptime {
|
||||
const decls = std.meta.declarations(Self);
|
||||
|
||||
var ret: [getInputCount()][]const u8 = undefined;
|
||||
|
||||
var i: usize = 0;
|
||||
inline for (decls) |i_decl| {
|
||||
const field = @field(Self, i_decl.name);
|
||||
|
||||
if (@TypeOf(field) == Input) {
|
||||
ret[i] = i_decl.name;
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
// With reflection count the amount of declarations of type "Input"
|
||||
fn getInputCount() usize {
|
||||
comptime {
|
||||
const decls = std.meta.declarations(Self);
|
||||
|
||||
var i: usize = 0;
|
||||
inline for (decls) |i_decl| {
|
||||
const field = @field(Self, i_decl.name);
|
||||
|
||||
if (@TypeOf(field) == Input) i += 1;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
27
src/main.zig
27
src/main.zig
|
@ -1,18 +1,13 @@
|
|||
const std = @import("std");
|
||||
// TODO: Get this from a input class, not from rl directly
|
||||
const shouldClose = @import("raylib.zig").windowShouldClose;
|
||||
const SDL = @import("sdl2");
|
||||
|
||||
const Renderer = @import("Renderer.zig");
|
||||
const Game = @import("Game.zig");
|
||||
const MainMenu = @import("MainMenu.zig");
|
||||
const config = @import("Config/config.zig");
|
||||
|
||||
const State = @import("flow.zig").State;
|
||||
const input = @import("input.zig");
|
||||
|
||||
pub fn main() !void {
|
||||
input.loadConfig();
|
||||
|
||||
var renderer = try Renderer.init();
|
||||
defer renderer.deinit();
|
||||
|
||||
|
@ -21,7 +16,18 @@ pub fn main() !void {
|
|||
|
||||
var current_state: State = main_menu.state;
|
||||
|
||||
while (!shouldClose()) {
|
||||
try SDL.image.init(.{ .jpg = true });
|
||||
|
||||
mainLoop: while (true) {
|
||||
const start = SDL.getTicks64();
|
||||
|
||||
while (SDL.pollEvent()) |ev| {
|
||||
switch (ev) {
|
||||
.quit => break :mainLoop,
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
if (game.needs_reinit) {
|
||||
game = Game.init(&renderer);
|
||||
}
|
||||
|
@ -36,5 +42,12 @@ pub fn main() !void {
|
|||
};
|
||||
|
||||
renderer.render();
|
||||
|
||||
const delay = SDL.getTicks64() - start;
|
||||
|
||||
//std.debug.print("{} ms\n", .{delay});
|
||||
if (delay < 17) {
|
||||
SDL.delay(17 - @intCast(u32, delay));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
279
src/raylib.zig
279
src/raylib.zig
|
@ -1,279 +0,0 @@
|
|||
pub const c = @cImport({
|
||||
@cInclude("raylib.h");
|
||||
});
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const InputCode = struct {
|
||||
name: []const u8 = "",
|
||||
value: i32 = 0,
|
||||
};
|
||||
|
||||
// zig fmt: off
|
||||
const input_codes = [_]InputCode{
|
||||
.{ .name = "NULL" , .value = 0, },
|
||||
.{ .name = "APOSTROPHE" , .value = 39, },
|
||||
.{ .name = "COMMA" , .value = 44, },
|
||||
.{ .name = "MINUS" , .value = 45, },
|
||||
.{ .name = "PERIOD" , .value = 46, },
|
||||
.{ .name = "SLASH" , .value = 47, },
|
||||
.{ .name = "ZERO" , .value = 48, },
|
||||
.{ .name = "ONE" , .value = 49, },
|
||||
.{ .name = "TWO" , .value = 50, },
|
||||
.{ .name = "THREE" , .value = 51, },
|
||||
.{ .name = "FOUR" , .value = 52, },
|
||||
.{ .name = "FIVE" , .value = 53, },
|
||||
.{ .name = "SIX" , .value = 54, },
|
||||
.{ .name = "SEVEN" , .value = 55, },
|
||||
.{ .name = "EIGHT" , .value = 56, },
|
||||
.{ .name = "NINE" , .value = 57, },
|
||||
.{ .name = "SEMICOLON" , .value = 59, },
|
||||
.{ .name = "EQUAL" , .value = 61, },
|
||||
.{ .name = "A" , .value = 65, },
|
||||
.{ .name = "B" , .value = 66, },
|
||||
.{ .name = "C" , .value = 67, },
|
||||
.{ .name = "D" , .value = 68, },
|
||||
.{ .name = "E" , .value = 69, },
|
||||
.{ .name = "F" , .value = 70, },
|
||||
.{ .name = "G" , .value = 71, },
|
||||
.{ .name = "H" , .value = 72, },
|
||||
.{ .name = "I" , .value = 73, },
|
||||
.{ .name = "J" , .value = 74, },
|
||||
.{ .name = "K" , .value = 75, },
|
||||
.{ .name = "L" , .value = 76, },
|
||||
.{ .name = "M" , .value = 77, },
|
||||
.{ .name = "N" , .value = 78, },
|
||||
.{ .name = "O" , .value = 79, },
|
||||
.{ .name = "P" , .value = 80, },
|
||||
.{ .name = "Q" , .value = 81, },
|
||||
.{ .name = "R" , .value = 82, },
|
||||
.{ .name = "S" , .value = 83, },
|
||||
.{ .name = "T" , .value = 84, },
|
||||
.{ .name = "U" , .value = 85, },
|
||||
.{ .name = "V" , .value = 86, },
|
||||
.{ .name = "W" , .value = 87, },
|
||||
.{ .name = "X" , .value = 88, },
|
||||
.{ .name = "Y" , .value = 89, },
|
||||
.{ .name = "Z" , .value = 90, },
|
||||
.{ .name = "LEFT_BRACKET" , .value = 91, },
|
||||
.{ .name = "BACKSLASH" , .value = 92, },
|
||||
.{ .name = "RIGHT_BRACKET" , .value = 93, },
|
||||
.{ .name = "GRAVE" , .value = 96, },
|
||||
.{ .name = "SPACE" , .value = 32, },
|
||||
.{ .name = "ESCAPE" , .value = 256, },
|
||||
.{ .name = "ENTER" , .value = 257, },
|
||||
.{ .name = "TAB" , .value = 258, },
|
||||
.{ .name = "BACKSPACE" , .value = 259, },
|
||||
.{ .name = "INSERT" , .value = 260, },
|
||||
.{ .name = "DELETE" , .value = 261, },
|
||||
.{ .name = "RIGHT" , .value = 262, },
|
||||
.{ .name = "LEFT" , .value = 263, },
|
||||
.{ .name = "DOWN" , .value = 264, },
|
||||
.{ .name = "UP" , .value = 265, },
|
||||
.{ .name = "PAGE_UP" , .value = 266, },
|
||||
.{ .name = "PAGE_DOWN" , .value = 267, },
|
||||
.{ .name = "HOME" , .value = 268, },
|
||||
.{ .name = "END" , .value = 269, },
|
||||
.{ .name = "CAPS_LOCK" , .value = 280, },
|
||||
.{ .name = "SCROLL_LOCK" , .value = 281, },
|
||||
.{ .name = "NUM_LOCK" , .value = 282, },
|
||||
.{ .name = "PRINT_SCREEN" , .value = 283, },
|
||||
.{ .name = "PAUSE" , .value = 284, },
|
||||
.{ .name = "F1" , .value = 290, },
|
||||
.{ .name = "F2" , .value = 291, },
|
||||
.{ .name = "F3" , .value = 292, },
|
||||
.{ .name = "F4" , .value = 293, },
|
||||
.{ .name = "F5" , .value = 294, },
|
||||
.{ .name = "F6" , .value = 295, },
|
||||
.{ .name = "F7" , .value = 296, },
|
||||
.{ .name = "F8" , .value = 297, },
|
||||
.{ .name = "F9" , .value = 298, },
|
||||
.{ .name = "F10" , .value = 299, },
|
||||
.{ .name = "F11" , .value = 300, },
|
||||
.{ .name = "F12" , .value = 301, },
|
||||
.{ .name = "LEFT_SHIFT" , .value = 340, },
|
||||
.{ .name = "LEFT_CONTROL" , .value = 341, },
|
||||
.{ .name = "LEFT_ALT" , .value = 342, },
|
||||
.{ .name = "LEFT_SUPER" , .value = 343, },
|
||||
.{ .name = "RIGHT_SHIFT" , .value = 344, },
|
||||
.{ .name = "RIGHT_CONTROL" , .value = 345, },
|
||||
.{ .name = "RIGHT_ALT" , .value = 346, },
|
||||
.{ .name = "RIGHT_SUPER" , .value = 347, },
|
||||
.{ .name = "KB_MENU" , .value = 348, },
|
||||
.{ .name = "KP_0" , .value = 320, },
|
||||
.{ .name = "KP_1" , .value = 321, },
|
||||
.{ .name = "KP_2" , .value = 322, },
|
||||
.{ .name = "KP_3" , .value = 323, },
|
||||
.{ .name = "KP_4" , .value = 324, },
|
||||
.{ .name = "KP_5" , .value = 325, },
|
||||
.{ .name = "KP_6" , .value = 326, },
|
||||
.{ .name = "KP_7" , .value = 327, },
|
||||
.{ .name = "KP_8" , .value = 328, },
|
||||
.{ .name = "KP_9" , .value = 329, },
|
||||
.{ .name = "KP_DECIMAL" , .value = 330, },
|
||||
.{ .name = "KP_DIVIDE" , .value = 331, },
|
||||
.{ .name = "KP_MULTIPLY" , .value = 332, },
|
||||
.{ .name = "KP_SUBTRACT" , .value = 333, },
|
||||
.{ .name = "KP_ADD" , .value = 334, },
|
||||
.{ .name = "KP_ENTER" , .value = 335, },
|
||||
.{ .name = "KP_EQUAL" , .value = 336, },
|
||||
.{ .name = "BACK" , .value = 4, },
|
||||
.{ .name = "MENU" , .value = 82, },
|
||||
.{ .name = "VOLUME_UP" , .value = 24, },
|
||||
.{ .name = "VOLUME_DOWN" , .value = 25, },
|
||||
};
|
||||
// zig fmt: on
|
||||
|
||||
pub fn getValueFromInputName(name: []const u8) ?i32 {
|
||||
for (input_codes) |ic| {
|
||||
if (std.mem.eql(u8, ic.name, name)) {
|
||||
return ic.value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn initWindow(width: i32, height: i32, title: [*c]const u8, fps: i32) void {
|
||||
c.InitWindow(width, height, title);
|
||||
c.SetTargetFPS(fps);
|
||||
}
|
||||
|
||||
pub fn windowShouldClose() bool {
|
||||
return c.WindowShouldClose();
|
||||
}
|
||||
|
||||
pub fn closeWindow() void {
|
||||
c.CloseWindow();
|
||||
}
|
||||
|
||||
pub fn beginDrawing() void {
|
||||
c.BeginDrawing();
|
||||
}
|
||||
|
||||
pub fn endDrawing() void {
|
||||
c.EndDrawing();
|
||||
}
|
||||
|
||||
pub fn getKeyCode(comptime name: []const u8) i32 {
|
||||
const full_name = "KEY_" ++ name;
|
||||
|
||||
if (!@hasDecl(c, full_name)) {
|
||||
@compileError(full_name ++ " keycode does not exist.");
|
||||
}
|
||||
|
||||
return @field(c, full_name);
|
||||
}
|
||||
|
||||
pub fn isKeyPressed(key: i32) bool {
|
||||
return c.IsKeyPressed(key);
|
||||
}
|
||||
|
||||
pub fn isKeyDown(key: i32) bool {
|
||||
return c.IsKeyDown(key);
|
||||
}
|
||||
|
||||
pub fn isKeyReleased(key: i32) bool {
|
||||
return c.IsKeyReleased(key);
|
||||
}
|
||||
|
||||
pub fn drawText(text: [*c]const u8, x: i32, y: i32, fontSize: i32, color: [4]u8) void {
|
||||
c.DrawText(text, x, y, fontSize, .{ .r = color[0], .g = color[1], .b = color[2], .a = color[3] });
|
||||
}
|
||||
|
||||
pub fn setConfigFlags(flag: u32) void {
|
||||
c.SetConfigFlags(flag);
|
||||
}
|
||||
|
||||
// Call before initializing the window
|
||||
pub const ConfigFlag = enum(u32) {
|
||||
vsync_hint = 0x00000040, // set to try enabling v-sync on gpu
|
||||
fullscreen_mode = 0x00000002, // set to run program in fullscreen
|
||||
window_resizable = 0x00000004, // set to allow resizable window
|
||||
window_undecorated = 0x00000008, // set to disable window decoration (frame and buttons)
|
||||
window_hidden = 0x00000080, // set to hide window
|
||||
window_minimized = 0x00000200, // set to minimize window (iconify)
|
||||
window_maximized = 0x00000400, // set to maximize window (expanded to monitor)
|
||||
window_unfocused = 0x00000800, // set to window non focused
|
||||
window_topmost = 0x00001000, // set to window always on top
|
||||
window_always_run = 0x00000100, // set to allow windows running while minimized
|
||||
window_transparent = 0x00000010, // set to allow transparent framebuffer
|
||||
window_highdpi = 0x00002000, // set to support highdpi
|
||||
window_mouse_passthrough = 0x00004000, // set to support mouse passthrough, only supported when flag_window_undecorated
|
||||
borderless_windowed_mode = 0x00008000, // set to run program in borderless windowed mode
|
||||
msaa_4x_hint = 0x00000020, // set to try enabling msaa 4x
|
||||
interlaced_hint = 0x00010000, // set to try enabling interlaced video format (for v3d)
|
||||
|
||||
pub fn set(self: ConfigFlag) void {
|
||||
setConfigFlags(@intFromEnum(self));
|
||||
}
|
||||
};
|
||||
|
||||
pub fn clearBackground(color: [4]u8) void {
|
||||
c.ClearBackground(.{ .r = color[0], .g = color[1], .b = color[2], .a = color[3] });
|
||||
}
|
||||
|
||||
pub fn drawTriangle(v1: [2]f32, v2: [2]f32, v3: [2]f32, color: [4]u8) void {
|
||||
c.DrawTriangle(
|
||||
.{ .x = v1[0], .y = v1[1] },
|
||||
.{ .x = v2[0], .y = v2[1] },
|
||||
.{ .x = v3[0], .y = v3[1] },
|
||||
.{ .r = color[0], .g = color[1], .b = color[2], .a = color[3] },
|
||||
);
|
||||
}
|
||||
|
||||
pub const Texture = struct {
|
||||
texture: c.Texture2D,
|
||||
|
||||
pub fn load(file_name: [*c]const u8) Texture {
|
||||
const aux = .{
|
||||
.texture = c.LoadTexture(file_name),
|
||||
};
|
||||
c.SetTextureFilter(aux.texture, c.TEXTURE_FILTER_BILINEAR);
|
||||
return aux;
|
||||
}
|
||||
|
||||
pub fn drawTo(self: Texture, x: i32, y: i32, w: i32, h: i32, tint: [4]u8) void {
|
||||
const srcRec: c.Rectangle = .{
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = @floatFromInt(self.texture.width),
|
||||
.height = @floatFromInt(self.texture.height),
|
||||
};
|
||||
|
||||
const dstRec: c.Rectangle = .{
|
||||
.x = @floatFromInt(x),
|
||||
.y = @floatFromInt(y),
|
||||
.width = @floatFromInt(w),
|
||||
.height = @floatFromInt(h),
|
||||
};
|
||||
|
||||
c.DrawTexturePro(
|
||||
self.texture,
|
||||
srcRec,
|
||||
dstRec,
|
||||
.{ .x = 0, .y = 0 },
|
||||
0,
|
||||
.{ .r = tint[0], .g = tint[1], .b = tint[2], .a = tint[3] },
|
||||
);
|
||||
}
|
||||
|
||||
pub fn unload(self: Texture) void {
|
||||
c.UnloadTexture(self.texture);
|
||||
}
|
||||
};
|
||||
|
||||
pub fn getScreenWidth() i32 {
|
||||
return c.GetScreenWidth();
|
||||
}
|
||||
|
||||
pub fn getScreenHeight() i32 {
|
||||
return c.GetScreenHeight();
|
||||
}
|
||||
|
||||
pub fn getTime() f64 {
|
||||
return c.GetTime();
|
||||
}
|
||||
|
||||
pub fn drawFPS(x: i32, y: i32) void {
|
||||
c.DrawFPS(x, y);
|
||||
}
|
Loading…
Reference in New Issue