From 84c90c4665031bd7f2c6d12092f04837ea417c90 Mon Sep 17 00:00:00 2001 From: Colby Date: Mon, 1 Aug 2016 20:21:06 +1000 Subject: [PATCH] re-enable drawing sprites and windows --- lib/waterfoul/gpu.rb | 132 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/lib/waterfoul/gpu.rb b/lib/waterfoul/gpu.rb index 7a152ee..57c06c2 100644 --- a/lib/waterfoul/gpu.rb +++ b/lib/waterfoul/gpu.rb @@ -29,6 +29,7 @@ module Waterfoul @vblank_line = 0 @auxillary_modeclock = 0 @screen_enabled = true + @window_line = 0 end def step(cycles = 1) @@ -53,6 +54,7 @@ module Waterfoul @modeclock = 0 @mode = 0 @auxillary_modeclock = 0 + @window_line = 0 reset_current_line update_stat_mode compare_lylc @@ -92,6 +94,7 @@ module Waterfoul @mode = V_BLANK_STATE @auxillary_modeclock = @modeclock @vblank = true + @window_line = 0 Interrupt.request_interrupt(Interrupt::INTERRUPT_VBLANK) end @@ -120,6 +123,8 @@ module Waterfoul def scanline render_bg + render_window + render_sprites end def update_stat_mode @@ -128,6 +133,133 @@ module Waterfoul $mmu.write_byte 0xFF41, new_stat end + def render_window + line = current_line + line_width = line * Screen::SCREEN_WIDTH + # dont render if the window is outside the bounds of the screen or + # if the LCDC window enable bit flag is not set + return if @window_line > 143 || !IO::LCDControl.window_enabled? + + window_pos_x = $mmu.read_byte(0xFF4B) - 7 + window_pos_y = $mmu.read_byte(0xFF4A) + + # don't render if the window is outside the bounds of the screen + return if window_pos_x > 159 || window_pos_y > 143 || window_pos_y > line + + map_select = IO::LCDControl.window_map_select + tiles_select = IO::LCDControl.bg_tile_select + + line_adjusted = @window_line + y_offset = (line_adjusted / 8) * 32 + tile_line = line_adjusted % 8 + tile_line_offset = tile_line * 2 + + 0.upto(31) do |x| + tile = 0 + if tiles == 0x8800 + tile = signed_value $mmu.read_byte(map_select + y_offset + x) + tile += 128 + else + tile = $mmu.read_byte map_select + y_offset + x + end + + line_pixel_offset = x * 8 + tile_select_offset = tile * 16 + tile_address = tiles_select + tile_select_offset + tile_line_offset + + byte_1 = $mmu.read_byte tile_address + byte_2 = $mmu.read_byte (tile_address + 1) + + 0.upto(7) do |pixelx| + buffer_addr = line_pixel_offset + pixelx + wx + + next if buffer_addr < 0 || buffer_addr >= SCREEN_WIDTH + + shift 0x1 << (7 - pixelx) + + pixel = 0 + if (byte_1 & shift == shift) && (byte_2 & shift == shift) + pixel = 3 + elsif (byte_1 & shift == 0x0) && (byte_2 & shift == shift) + pixel = 1 + elsif (byte_1 & shift == shift) && (byte_2 & shift == 0x0) + pixel = 2 + elsif (byte_1 & shift == 0x0) && (byte_2 & shift == 0x00) + pixel = 0 + end + + position = line_width + buffer_addr + @framebuffer[position] = pixel + end + end + @window_line += 1 + end + + def render_sprites + line = current_line + line_width = line * Screen::SCREEN_WIDTH + + return unless IO::LCDControl.obj_display + + sprite_size = IO::LCDControl.obj_size + + 39.downto(0) do |sprite| + sprite_offset = sprite * 4 + + sprite_y = $mmu.read_byte(0xFE00 + sprite_offset) - 16 + next if sprite_y > line || (sprite_y + sprite_size) <= line + + sprite_x = $mmu.read_byte(0xFE00 + sprite_offset + 1) - 8 + next if sprite_x < -7 || sprite_x >= SCREEN_WIDTH + + sprite_tile_offset = ($mmu.read_byte(0xFE00 + sprite_offset + 2) & (sprite_size == 16 ? 0xFE : 0xFF)) * 16 + sprite_flags = $mmu.read_byte(0xFE00 + sprite_offset + 3) + x_flip = sprite_flags & 0x20 == 0x20 ? true : false + y_flip = sprite_flags & 0x40 == 0x40 ? true : false + #above_bg = sprite_flags & 0x80 == 0x80 ? true : false + + tiles = 0x8000 + pixel_y = y_flip ? (sprite_size == 16 ? 15 : 7) - (line - sprite_y) : line - sprite_y + + pixel_y_2 = 0 + offset = 0 + + if sprite_size == 16 && (pixel_y >= 8) + pixel_y_2 = (pixel_y - 8) * 2 + offset = 16 + else + pixel_y_2 = pixel_y * 2 + end + + tile_address = tiles + sprite_tile_offset + pixel_y_2 + offset + + byte_1 = $mmu.read_byte tile_address + byte_2 = $mmu.read_byte (tile_address + 1) + + 0.upto(7) do |pixelx| + shift = 0x1 << (x_flip ? pixelx : 7 - pixelx) + pixel = 0 + + if (byte_1 & shift == shift) && (byte_2 & shift == shift) + pixel = 3 + elsif (byte_1 & shift == 0x0) && (byte_2 & shift == shift) + pixel = 1 + elsif (byte_1 & shift == shift) && (byte_2 & shift == 0x0) + pixel = 2 + elsif (byte_1 & shift == 0x0) && (byte_2 & shift == 0x00) + pixel = 0 + end + + buffer_x = sprite_x + pixelx + next if buffer_x < 0 || buffer_x >= Screen::SCREEN_WIDTH + + position = line_width + buffer_x + + @framebuffer[position] = pixel + end + end + end + def render_bg line = current_line line_width = line * Screen::SCREEN_WIDTH