Compare commits
3 Commits
06ee31980e
...
102eb0c1e6
Author | SHA1 | Date | |
---|---|---|---|
102eb0c1e6 | |||
dda533f557 | |||
29e9d3c288 |
@ -428,8 +428,6 @@ const u8WriteKind = enum { Hi, Lo };
|
|||||||
|
|
||||||
/// Write-only
|
/// Write-only
|
||||||
pub const WinH = extern union {
|
pub const WinH = extern union {
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
x2: Bitfield(u16, 0, 8),
|
x2: Bitfield(u16, 0, 8),
|
||||||
x1: Bitfield(u16, 8, 8),
|
x1: Bitfield(u16, 8, 8),
|
||||||
raw: u16,
|
raw: u16,
|
||||||
@ -442,13 +440,6 @@ pub const WinV = extern union {
|
|||||||
y2: Bitfield(u16, 0, 8),
|
y2: Bitfield(u16, 0, 8),
|
||||||
y1: Bitfield(u16, 8, 8),
|
y1: Bitfield(u16, 8, 8),
|
||||||
raw: u16,
|
raw: u16,
|
||||||
|
|
||||||
pub fn set(self: *Self, comptime K: u8WriteKind, value: u8) void {
|
|
||||||
self.raw = switch (K) {
|
|
||||||
.Hi => (@as(u16, value) << 8) | self.raw & 0xFF,
|
|
||||||
.Lo => (self.raw & 0xFF00) | value,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const WinIn = extern union {
|
pub const WinIn = extern union {
|
||||||
|
@ -9,7 +9,6 @@ const dma = @import("bus/dma.zig");
|
|||||||
const Oam = @import("ppu/Oam.zig");
|
const Oam = @import("ppu/Oam.zig");
|
||||||
const Palette = @import("ppu/Palette.zig");
|
const Palette = @import("ppu/Palette.zig");
|
||||||
const Vram = @import("ppu/Vram.zig");
|
const Vram = @import("ppu/Vram.zig");
|
||||||
const EventKind = @import("scheduler.zig").EventKind;
|
|
||||||
const Scheduler = @import("scheduler.zig").Scheduler;
|
const Scheduler = @import("scheduler.zig").Scheduler;
|
||||||
const Arm7tdmi = @import("cpu.zig").Arm7tdmi;
|
const Arm7tdmi = @import("cpu.zig").Arm7tdmi;
|
||||||
const FrameBuffer = @import("../util.zig").FrameBuffer;
|
const FrameBuffer = @import("../util.zig").FrameBuffer;
|
||||||
@ -20,7 +19,6 @@ const log = std.log.scoped(.PPU);
|
|||||||
const getHalf = util.getHalf;
|
const getHalf = util.getHalf;
|
||||||
const setHalf = util.setHalf;
|
const setHalf = util.setHalf;
|
||||||
const setQuart = util.setQuart;
|
const setQuart = util.setQuart;
|
||||||
const pollDmaOnBlank = @import("bus/dma.zig").pollDmaOnBlank;
|
|
||||||
|
|
||||||
pub const width = 240;
|
pub const width = 240;
|
||||||
pub const height = 160;
|
pub const height = 160;
|
||||||
@ -265,8 +263,7 @@ pub const Ppu = struct {
|
|||||||
scanline: Scanline,
|
scanline: Scanline,
|
||||||
|
|
||||||
pub fn init(allocator: Allocator, sched: *Scheduler) !Self {
|
pub fn init(allocator: Allocator, sched: *Scheduler) !Self {
|
||||||
// Queue first Hblank
|
sched.push(.Draw, 240 * 4); // Add first PPU Event to Scheduler
|
||||||
sched.push(.Draw, 240 * 4);
|
|
||||||
|
|
||||||
const sprites = try allocator.create([128]?Sprite);
|
const sprites = try allocator.create([128]?Sprite);
|
||||||
std.mem.set(?Sprite, sprites, null);
|
std.mem.set(?Sprite, sprites, null);
|
||||||
@ -326,20 +323,16 @@ pub const Ppu = struct {
|
|||||||
// Only consider enabled Sprites
|
// Only consider enabled Sprites
|
||||||
if (attr0.is_affine.read() or !attr0.disabled.read()) {
|
if (attr0.is_affine.read() or !attr0.disabled.read()) {
|
||||||
const attr1 = @bitCast(Attr1, self.oam.read(u16, i + 2));
|
const attr1 = @bitCast(Attr1, self.oam.read(u16, i + 2));
|
||||||
|
const sprite_height = spriteDimensions(attr0.shape.read(), attr1.size.read())[1];
|
||||||
|
|
||||||
// When fetching sprites we only care about ones that could be rendered
|
// When fetching sprites we only care about ones that could be rendered
|
||||||
// on this scanline
|
// on this scanline
|
||||||
const iy = @bitCast(i8, y);
|
var y_pos: i32 = attr0.y.read();
|
||||||
|
if (y_pos >= 160) y_pos -= 256; // fleroviux's solution to negative positions
|
||||||
const start = attr0.y.read();
|
|
||||||
const istart = @bitCast(i8, start);
|
|
||||||
|
|
||||||
const end = start +% spriteDimensions(attr0.shape.read(), attr1.size.read())[1];
|
|
||||||
const iend = @bitCast(i8, end);
|
|
||||||
|
|
||||||
// Sprites are expected to be able to wraparound, we perform the same check
|
// Sprites are expected to be able to wraparound, we perform the same check
|
||||||
// for unsigned and signed values so that we handle all valid sprite positions
|
// for unsigned and signed values so that we handle all valid sprite positions
|
||||||
if ((start <= y and y < end) or (istart <= iy and iy < iend)) {
|
if (y_pos <= y and y < (y_pos + sprite_height)) {
|
||||||
for (self.scanline_sprites) |*maybe_sprite| {
|
for (self.scanline_sprites) |*maybe_sprite| {
|
||||||
if (maybe_sprite.* == null) {
|
if (maybe_sprite.* == null) {
|
||||||
maybe_sprite.* = Sprite.init(attr0, attr1, @bitCast(Attr2, self.oam.read(u16, i + 4)));
|
maybe_sprite.* = Sprite.init(attr0, attr1, @bitCast(Attr2, self.oam.read(u16, i + 4)));
|
||||||
@ -366,8 +359,6 @@ pub const Ppu = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn drawAffineSprite(self: *Self, sprite: AffineSprite) void {
|
fn drawAffineSprite(self: *Self, sprite: AffineSprite) void {
|
||||||
const iy = @bitCast(i8, self.vcount.scanline.read());
|
|
||||||
|
|
||||||
const is_8bpp = sprite.is8bpp();
|
const is_8bpp = sprite.is8bpp();
|
||||||
const tile_id: u32 = sprite.tileId();
|
const tile_id: u32 = sprite.tileId();
|
||||||
const obj_mapping = self.dispcnt.obj_mapping.read();
|
const obj_mapping = self.dispcnt.obj_mapping.read();
|
||||||
@ -376,25 +367,22 @@ pub const Ppu = struct {
|
|||||||
|
|
||||||
const char_base = 0x4000 * 4;
|
const char_base = 0x4000 * 4;
|
||||||
|
|
||||||
|
const y = self.vcount.scanline.read();
|
||||||
|
|
||||||
var i: u9 = 0;
|
var i: u9 = 0;
|
||||||
while (i < sprite.width) : (i += 1) {
|
while (i < sprite.width) : (i += 1) {
|
||||||
const x = (sprite.x() +% i) % width;
|
const x = (sprite.x() +% i) % width;
|
||||||
const ix = @bitCast(i9, x);
|
|
||||||
|
|
||||||
if (!shouldDrawSprite(self.bld.cnt, &self.scanline, x)) continue;
|
if (!shouldDrawSprite(self.bld.cnt, &self.scanline, x)) continue;
|
||||||
|
|
||||||
const sprite_start = sprite.x();
|
var x_pos: i32 = sprite.x();
|
||||||
const isprite_start = @bitCast(i9, sprite_start);
|
if (x_pos >= 240) x_pos -= 512;
|
||||||
const sprite_end = sprite_start +% sprite.width;
|
|
||||||
const isprite_end = @bitCast(i9, sprite_end);
|
|
||||||
|
|
||||||
const condition = (sprite_start <= x and x < sprite_end) or (isprite_start <= ix and ix < isprite_end);
|
if (!(x_pos <= x and x < (x_pos + sprite.width))) continue;
|
||||||
if (!condition) continue;
|
|
||||||
|
|
||||||
// Sprite is within bounds and therefore should be rendered
|
// Sprite is within bounds and therefore should be rendered
|
||||||
// std.math.absInt is branchless
|
// std.math.absInt is branchless
|
||||||
const tile_x = @bitCast(u9, std.math.absInt(ix - @bitCast(i9, sprite.x())) catch unreachable);
|
const tile_x = @bitCast(u32, @as(i32, std.math.absInt(@as(i32, x) - x_pos) catch unreachable));
|
||||||
const tile_y = @bitCast(u8, std.math.absInt(iy -% @bitCast(i8, sprite.y())) catch unreachable);
|
const tile_y = @bitCast(u32, @as(i32, std.math.absInt(@bitCast(i8, y) -% @bitCast(i8, sprite.y())) catch unreachable));
|
||||||
|
|
||||||
const row = @truncate(u3, tile_y);
|
const row = @truncate(u3, tile_y);
|
||||||
const col = @truncate(u3, tile_x);
|
const col = @truncate(u3, tile_x);
|
||||||
@ -416,8 +404,6 @@ pub const Ppu = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn drawSprite(self: *Self, sprite: Sprite) void {
|
fn drawSprite(self: *Self, sprite: Sprite) void {
|
||||||
const iy = @bitCast(i8, self.vcount.scanline.read());
|
|
||||||
|
|
||||||
const is_8bpp = sprite.is8bpp();
|
const is_8bpp = sprite.is8bpp();
|
||||||
const tile_id: u32 = sprite.tileId();
|
const tile_id: u32 = sprite.tileId();
|
||||||
const obj_mapping = self.dispcnt.obj_mapping.read();
|
const obj_mapping = self.dispcnt.obj_mapping.read();
|
||||||
@ -426,31 +412,27 @@ pub const Ppu = struct {
|
|||||||
|
|
||||||
const char_base = 0x4000 * 4;
|
const char_base = 0x4000 * 4;
|
||||||
|
|
||||||
|
const y = self.vcount.scanline.read();
|
||||||
|
|
||||||
var i: u9 = 0;
|
var i: u9 = 0;
|
||||||
while (i < sprite.width) : (i += 1) {
|
while (i < sprite.width) : (i += 1) {
|
||||||
const x = (sprite.x() +% i) % width;
|
const x = (sprite.x() +% i) % width;
|
||||||
const ix = @bitCast(i9, x);
|
|
||||||
|
|
||||||
if (!shouldDrawSprite(self.bld.cnt, &self.scanline, x)) continue;
|
if (!shouldDrawSprite(self.bld.cnt, &self.scanline, x)) continue;
|
||||||
|
|
||||||
const sprite_start = sprite.x();
|
var x_pos: i32 = sprite.x();
|
||||||
const isprite_start = @bitCast(i9, sprite_start);
|
if (x_pos >= 240) x_pos -= 512;
|
||||||
const sprite_end = sprite_start +% sprite.width;
|
|
||||||
const isprite_end = @bitCast(i9, sprite_end);
|
|
||||||
|
|
||||||
const condition = (sprite_start <= x and x < sprite_end) or (isprite_start <= ix and ix < isprite_end);
|
if (!(x_pos <= x and x < (x_pos + sprite.width))) continue;
|
||||||
if (!condition) continue;
|
|
||||||
|
|
||||||
// Sprite is within bounds and therefore should be rendered
|
// Sprite is within bounds and therefore should be rendered
|
||||||
// std.math.absInt is branchless
|
const x_diff: i32 = std.math.absInt(@as(i32, x) - x_pos) catch unreachable;
|
||||||
const x_diff = @bitCast(u9, std.math.absInt(ix - @bitCast(i9, sprite.x())) catch unreachable);
|
const y_diff: i32 = std.math.absInt(@bitCast(i8, y) -% @bitCast(i8, sprite.y())) catch unreachable;
|
||||||
const y_diff = @bitCast(u8, std.math.absInt(iy -% @bitCast(i8, sprite.y())) catch unreachable);
|
|
||||||
|
|
||||||
// Note that we flip the tile_pos not the (tile_pos % 8) like we do for
|
// Note that we flip the tile_pos not the (tile_pos % 8) like we do for
|
||||||
// Background Tiles. By doing this we mirror the entire sprite instead of
|
// Background Tiles. By doing this we mirror the entire sprite instead of
|
||||||
// just a specific tile (see how sprite.width and sprite.height are involved)
|
// just a specific tile (see how sprite.width and sprite.height are involved)
|
||||||
const tile_y = y_diff ^ if (sprite.vFlip()) (sprite.height - 1) else 0;
|
const tile_x = @intCast(u9, x_diff) ^ if (sprite.hFlip()) (sprite.width - 1) else 0;
|
||||||
const tile_x = x_diff ^ if (sprite.hFlip()) (sprite.width - 1) else 0;
|
const tile_y = @intCast(u8, y_diff) ^ if (sprite.vFlip()) (sprite.height - 1) else 0;
|
||||||
|
|
||||||
const row = @truncate(u3, tile_y);
|
const row = @truncate(u3, tile_y);
|
||||||
const col = @truncate(u3, tile_x);
|
const col = @truncate(u3, tile_x);
|
||||||
@ -980,24 +962,35 @@ const Window = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn inRange(self: *const Self, comptime id: u1, x: u9, y: u8) bool {
|
fn inRange(self: *const Self, comptime id: u1, x: u9, y: u8) bool {
|
||||||
const h = self.h[id];
|
const winh = self.h[id];
|
||||||
const v = self.v[id];
|
const winv = self.v[id];
|
||||||
|
|
||||||
const y1 = v.y1.read();
|
if (isYInRange(winv, y)) {
|
||||||
const y2 = if (y1 > v.y2.read()) 160 else std.math.min(160, v.y2.read());
|
const x1 = winh.x1.read();
|
||||||
|
const x2 = winh.x2.read();
|
||||||
if (y1 <= y and y < y2) {
|
|
||||||
// Within Y bounds
|
|
||||||
const x1 = h.x1.read();
|
|
||||||
const x2 = if (x1 > h.x2.read()) 240 else std.math.min(240, h.x2.read());
|
|
||||||
|
|
||||||
// Within X Bounds
|
// Within X Bounds
|
||||||
return x1 <= x and x < x2;
|
return if (x1 < x2) blk: {
|
||||||
|
break :blk x >= x1 and x < x2;
|
||||||
|
} else blk: {
|
||||||
|
break :blk x >= x1 or x < x2;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fn isYInRange(winv: io.WinV, y: u9) bool {
|
||||||
|
const y1 = winv.y1.read();
|
||||||
|
const y2 = winv.y2.read();
|
||||||
|
|
||||||
|
if (y1 < y2) {
|
||||||
|
return y >= y1 and y < y2;
|
||||||
|
} else {
|
||||||
|
return y >= y1 or y < y2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn setH(self: *Self, value: u32) void {
|
pub fn setH(self: *Self, value: u32) void {
|
||||||
self.h[0].raw = @truncate(u16, value);
|
self.h[0].raw = @truncate(u16, value);
|
||||||
self.h[1].raw = @truncate(u16, value >> 16);
|
self.h[1].raw = @truncate(u16, value >> 16);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user