game-2026-01-18/src/engine/screen_scaler.zig

68 lines
1.7 KiB
Zig

const Gfx = @import("./graphics.zig");
const Math = @import("./math.zig");
const Vec2 = Math.Vec2;
const rgb = Math.rgb;
const ScreenScalar = @This();
// TODO: Implement a fractional pixel perfect scalar
// Based on this video: https://www.youtube.com/watch?v=d6tp43wZqps
// And this blog: https://colececil.dev/blog/2017/scaling-pixel-art-without-destroying-it/
window_size: Vec2,
translation: Vec2,
scale: f32,
pub fn push(window_size: Vec2, canvas_size: Vec2) ScreenScalar {
// TODO: Render to a lower resolution instead of scaling.
// To avoid pixel bleeding in spritesheet artifacts
const scale = @floor(@min(
window_size.x / canvas_size.x,
window_size.y / canvas_size.y,
));
var translation: Vec2 = Vec2.sub(window_size, canvas_size.multiplyScalar(scale)).multiplyScalar(0.5);
translation.x = @round(translation.x);
translation.y = @round(translation.y);
Gfx.pushTransform(translation, .init(scale, scale));
return ScreenScalar{
.window_size = window_size,
.translation = translation,
.scale = scale
};
}
pub fn pop(self: ScreenScalar) void {
Gfx.popTransform();
const bg_color = rgb(0, 0, 0);
const filler_size = self.translation;
Gfx.drawRectangle(
.init(0, 0),
.init(self.window_size.x, filler_size.y),
bg_color
);
Gfx.drawRectangle(
.init(0, self.window_size.y - filler_size.y),
.init(self.window_size.x, filler_size.y),
bg_color
);
Gfx.drawRectangle(
.init(0, 0),
.init(filler_size.x, self.window_size.y),
bg_color
);
Gfx.drawRectangle(
.init(self.window_size.x - filler_size.x, 0),
.init(filler_size.x, self.window_size.y),
bg_color
);
}