mirror of
https://github.com/mattrberry/crab.git
synced 2025-01-19 10:26:44 +01:00
a rough start to getting affine background working
This commit is contained in:
parent
4247cf139d
commit
d8f03b8ff6
2 changed files with 91 additions and 1 deletions
|
@ -11,6 +11,8 @@ class PPU
|
||||||
getter bgcnt = Array(Reg::BGCNT).new 4 { Reg::BGCNT.new 0 }
|
getter bgcnt = Array(Reg::BGCNT).new 4 { Reg::BGCNT.new 0 }
|
||||||
getter bghofs = Array(Reg::BGOFS).new 4 { Reg::BGOFS.new 0 }
|
getter bghofs = Array(Reg::BGOFS).new 4 { Reg::BGOFS.new 0 }
|
||||||
getter bgvofs = Array(Reg::BGOFS).new 4 { Reg::BGOFS.new 0 }
|
getter bgvofs = Array(Reg::BGOFS).new 4 { Reg::BGOFS.new 0 }
|
||||||
|
getter bgaff = Array(Array(Reg::BGAFF)).new 2 { Array(Reg::BGAFF).new 4 { Reg::BGAFF.new 0 } }
|
||||||
|
getter bgref = Array(Array(Reg::BGREF)).new 2 { Array(Reg::BGREF).new 4 { Reg::BGREF.new 0 } }
|
||||||
getter win0h = Reg::WINH.new 0
|
getter win0h = Reg::WINH.new 0
|
||||||
getter win1h = Reg::WINH.new 0
|
getter win1h = Reg::WINH.new 0
|
||||||
getter win0V = Reg::WINV.new 0
|
getter win0V = Reg::WINV.new 0
|
||||||
|
@ -83,7 +85,16 @@ class PPU
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
240.times { |idx| scanline[idx] = @pram.to_unsafe.as(UInt16*)[scanline[idx]] }
|
240.times { |idx| scanline[idx] = @pram.to_unsafe.as(UInt16*)[scanline[idx]] }
|
||||||
when 1, 2
|
when 1
|
||||||
|
4.times do |priority|
|
||||||
|
render_sprites(scanline, row, priority)
|
||||||
|
2.times do |bg|
|
||||||
|
render_background(scanline, row, bg) if @bgcnt[bg].priority == priority
|
||||||
|
end
|
||||||
|
render_affine(scanline, row, 2) if @bgcnt[2].priority == priority
|
||||||
|
end
|
||||||
|
240.times { |idx| scanline[idx] = @pram.to_unsafe.as(UInt16*)[scanline[idx]] }
|
||||||
|
when 2
|
||||||
puts "Unsupported background mode: #{@dispcnt.bg_mode}"
|
puts "Unsupported background mode: #{@dispcnt.bg_mode}"
|
||||||
when 3
|
when 3
|
||||||
240.times do |col|
|
240.times do |col|
|
||||||
|
@ -191,6 +202,39 @@ class PPU
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def render_affine(scanline : Slice(UInt16), row : Int, bg : Int) : Nil
|
||||||
|
return unless bit?(@dispcnt.value, 8 + bg)
|
||||||
|
|
||||||
|
pa, pb, pc, pd = @bgaff[bg - 2].map { |p| p.value.to_i16! }
|
||||||
|
aff_x, aff_y = @bgref[bg - 2].map { |p| (p.value << 4).to_i32! >> 4 }
|
||||||
|
|
||||||
|
size = 16 << @bgcnt[bg].screen_size # tiles, always a square
|
||||||
|
size_pixels = size << 3
|
||||||
|
|
||||||
|
screen_base = 0x800_u32 * @bgcnt[bg].screen_base_block
|
||||||
|
character_base = @bgcnt[bg].character_base_block.to_u32 * 0x4000
|
||||||
|
240.times do |col|
|
||||||
|
next if scanline[col] > 0
|
||||||
|
|
||||||
|
x = (aff_x >> 8) + pa
|
||||||
|
y = (aff_y >> 8) + pc
|
||||||
|
|
||||||
|
if @bgcnt[bg].affine_wrap
|
||||||
|
puts "Wrap not supported yet (bg:#{bg})".colorize.fore(:red)
|
||||||
|
end
|
||||||
|
next unless 0 <= x < size_pixels && 0 <= y < size_pixels
|
||||||
|
|
||||||
|
screen_entry = @vram[screen_base + (y >> 3) * size + (x >> 3)]
|
||||||
|
|
||||||
|
tile_id = bits(screen_entry, 0..9)
|
||||||
|
y = (y & 7) ^ (7 * (screen_entry >> 11 & 1))
|
||||||
|
x = (x & 7) ^ (7 * (screen_entry >> 10 & 1))
|
||||||
|
|
||||||
|
pal_idx = @vram[character_base + tile_id * 0x40 + y * 8 + x]
|
||||||
|
scanline[col] = pal_idx.to_u16
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def read_io(io_addr : Int) : Byte
|
def read_io(io_addr : Int) : Byte
|
||||||
case io_addr
|
case io_addr
|
||||||
when 0x000..0x001 then @dispcnt.read_byte(io_addr & 1)
|
when 0x000..0x001 then @dispcnt.read_byte(io_addr & 1)
|
||||||
|
@ -205,6 +249,15 @@ class PPU
|
||||||
else
|
else
|
||||||
@bghofs[bg_num].read_byte(io_addr & 1)
|
@bghofs[bg_num].read_byte(io_addr & 1)
|
||||||
end
|
end
|
||||||
|
when 0x020..0x03F
|
||||||
|
bg_num = (io_addr & 0x10) >> 4 # (bg 0/1 represents bg 2/3, since those are the only aff bgs)
|
||||||
|
offs = io_addr & 0xF
|
||||||
|
if offs >= 8
|
||||||
|
offs -= 8
|
||||||
|
@bgref[bg_num][offs >> 2].read_byte(offs & 3)
|
||||||
|
else
|
||||||
|
@bgaff[bg_num][offs >> 1].read_byte(offs & 1)
|
||||||
|
end
|
||||||
when 0x040 then 0xFF_u8 & @win0h.value
|
when 0x040 then 0xFF_u8 & @win0h.value
|
||||||
when 0x041 then 0xFF_u8 & @win0h.value >> 8
|
when 0x041 then 0xFF_u8 & @win0h.value >> 8
|
||||||
when 0x042 then 0xFF_u8 & @win1h.value
|
when 0x042 then 0xFF_u8 & @win1h.value
|
||||||
|
@ -243,6 +296,15 @@ class PPU
|
||||||
else
|
else
|
||||||
@bghofs[bg_num].write_byte(io_addr & 1, value)
|
@bghofs[bg_num].write_byte(io_addr & 1, value)
|
||||||
end
|
end
|
||||||
|
when 0x020..0x03F
|
||||||
|
bg_num = (io_addr & 0x10) >> 4 # (bg 0/1 represents bg 2/3, since those are the only aff bgs)
|
||||||
|
offs = io_addr & 0xF
|
||||||
|
if offs >= 8
|
||||||
|
offs -= 8
|
||||||
|
@bgref[bg_num][offs >> 2].read_byte(offs & 3)
|
||||||
|
else
|
||||||
|
@bgaff[bg_num][offs >> 1].read_byte(offs & 1)
|
||||||
|
end
|
||||||
when 0x040 then @win0h.value = (@win0h.value & 0xFF00) | value
|
when 0x040 then @win0h.value = (@win0h.value & 0xFF00) | value
|
||||||
when 0x041 then @win0h.value = (@win0h.value & 0x00FF) | value.to_u16 << 8
|
when 0x041 then @win0h.value = (@win0h.value & 0x00FF) | value.to_u16 << 8
|
||||||
when 0x042 then @win1h.value = (@win1h.value & 0xFF00) | value
|
when 0x042 then @win1h.value = (@win1h.value & 0xFF00) | value
|
||||||
|
|
|
@ -12,6 +12,19 @@ module Reg
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
module Base32
|
||||||
|
def read_byte(byte_num : Int) : Byte
|
||||||
|
(@value >> (8 * byte_num)).to_u8!
|
||||||
|
end
|
||||||
|
|
||||||
|
def write_byte(byte_num : Int, byte : Byte) : Byte
|
||||||
|
shift = 8 * byte_num
|
||||||
|
mask = ~(0xFF_u32 << shift)
|
||||||
|
@value = (@value & mask) | byte.to_u32 << shift
|
||||||
|
byte
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
####################
|
####################
|
||||||
# APU
|
# APU
|
||||||
|
|
||||||
|
@ -103,6 +116,21 @@ module Reg
|
||||||
num offset, 9
|
num offset, 9
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class BGAFF < BitField(UInt16)
|
||||||
|
include Base16
|
||||||
|
bool sign
|
||||||
|
num integer, 7
|
||||||
|
num fraction, 8
|
||||||
|
end
|
||||||
|
|
||||||
|
class BGREF < BitField(UInt32)
|
||||||
|
include Base32
|
||||||
|
num not_used, 4, lock: true
|
||||||
|
bool sign
|
||||||
|
num integer, 19
|
||||||
|
num fraction, 8
|
||||||
|
end
|
||||||
|
|
||||||
class WINH < BitField(UInt16)
|
class WINH < BitField(UInt16)
|
||||||
include Base16
|
include Base16
|
||||||
num x1, 8
|
num x1, 8
|
||||||
|
|
Loading…
Reference in a new issue