[pypy-svn] r62623 - pypy/trunk/pypy/lang/gameboy
tverwaes at codespeak.net
tverwaes at codespeak.net
Fri Mar 6 02:25:22 CET 2009
Author: tverwaes
Date: Fri Mar 6 02:25:18 2009
New Revision: 62623
Added:
pypy/trunk/pypy/lang/gameboy/video_meta.py
Modified:
pypy/trunk/pypy/lang/gameboy/constants.py
pypy/trunk/pypy/lang/gameboy/gameboy.py
pypy/trunk/pypy/lang/gameboy/gameboy_implementation.py
pypy/trunk/pypy/lang/gameboy/video.py
pypy/trunk/pypy/lang/gameboy/video_sprite.py
Log:
small refactorings + adding possibility of visualizing meta-data at runtime.
This will for now show what's in tile_data_0,1 and the 40 sprites.
Sprites will have while block in between when small sprites are selected.
Otherwise big sprites are joined together
Modified: pypy/trunk/pypy/lang/gameboy/constants.py
==============================================================================
--- pypy/trunk/pypy/lang/gameboy/constants.py (original)
+++ pypy/trunk/pypy/lang/gameboy/constants.py Fri Mar 6 02:25:18 2009
@@ -11,6 +11,7 @@
GAMEBOY_SCREEN_HEIGHT = 144
SPRITE_SIZE = 8
+MAX_SPRITES = 40
#___________________________________________________________________________
# CATRIGE TYPES
Modified: pypy/trunk/pypy/lang/gameboy/gameboy.py
==============================================================================
--- pypy/trunk/pypy/lang/gameboy/gameboy.py (original)
+++ pypy/trunk/pypy/lang/gameboy/gameboy.py Fri Mar 6 02:25:18 2009
@@ -21,14 +21,14 @@
def __init__(self):
self.create_drivers()
- self.create_gamboy_elements()
+ self.create_gameboy_elements()
def create_drivers(self):
self.joypad_driver = JoypadDriver()
self.video_driver = VideoDriver()
self.sound_driver = SoundDriver()
- def create_gamboy_elements(self):
+ def create_gameboy_elements(self):
self.clock = Clock()
self.ram = RAM()
self.cartridge_manager = CartridgeManager(self.clock)
Modified: pypy/trunk/pypy/lang/gameboy/gameboy_implementation.py
==============================================================================
--- pypy/trunk/pypy/lang/gameboy/gameboy_implementation.py (original)
+++ pypy/trunk/pypy/lang/gameboy/gameboy_implementation.py Fri Mar 6 02:25:18 2009
@@ -5,10 +5,12 @@
from pypy.lang.gameboy.video import VideoDriver
from pypy.lang.gameboy.sound import SoundDriver
from pypy.lang.gameboy.timer import Clock
+from pypy.lang.gameboy.video_meta import TileDataWindow, SpriteWindow
from pypy.lang.gameboy import constants
import time
use_rsdl = True
+show_metadata = False # Extends the window with windows visualizing meta-data
if use_rsdl:
from pypy.rlib.rsdl import RSDL, RSDL_helper
@@ -24,6 +26,7 @@
GameBoy.__init__(self)
self.is_running = False
self.penalty = 0.0
+ self.sync_time = time.time()
if use_rsdl:
self.init_sdl()
@@ -34,7 +37,7 @@
def create_drivers(self):
self.clock = Clock()
self.joypad_driver = JoypadDriverImplementation()
- self.video_driver = VideoDriverImplementation()
+ self.video_driver = VideoDriverImplementation(self)
self.sound_driver = SoundDriverImplementation()
def mainLoop(self):
@@ -51,16 +54,14 @@
return 0
def emulate_cycle(self):
- # self.joypad_driver.button_up(True)
X = 1<<6 # About 1<<6 to make sure we have a clean distrubution of about
# 1<<6 frames per second
- start_time = time.time()
self.handle_events()
# Come back to this cycle every 1/X seconds
self.emulate(constants.GAMEBOY_CLOCK / X)
# if use_rsdl:
# RSDL.Delay(100)
- spent = time.time() - start_time
+ spent = time.time() - self.sync_time
left = (1.0/X) + self.penalty - spent
if left > 0:
time.sleep(left)
@@ -68,6 +69,7 @@
else:
self.penalty = left
# print "WARNING: Going too slow: ", spent, " ", left
+ self.sync_time = time.time()
def handle_execution_error(self, error):
@@ -106,30 +108,48 @@
COLOR_MAP = [0xFFFFFF, 0xCCCCCC, 0x666666, 0x000000]
- def __init__(self):
+ def __init__(self, gameboy):
VideoDriver.__init__(self)
+
+ self.create_pixels()
+ if show_metadata:
+ self.create_meta_windows(gameboy)
self.create_screen()
- self.map = []
def create_screen(self):
if use_rsdl:
self.screen = RSDL.SetVideoMode(self.width, self.height, 32, 0)
-
+
+ def create_meta_windows(self, gameboy):
+ self.meta_windows = [TileDataWindow(gameboy),
+ SpriteWindow(gameboy)]
+
+ for window in self.meta_windows:
+ window.set_origin(self.width, 0)
+ self.height = max(self.height, window.height)
+ self.width += window.width
+
def update_display(self):
if use_rsdl:
RSDL.LockSurface(self.screen)
+ if show_metadata:
+ for meta_window in self.meta_windows:
+ meta_window.draw()
self.draw_pixels()
RSDL.UnlockSurface(self.screen)
RSDL.Flip(self.screen)
else:
- print '\x1b[H\x1b[2J'
+ print '\x1b[H\x1b[2J' # Clear screen
self.draw_ascii_pixels()
-
+
+ def draw_pixel(self, x, y, color):
+ color = VideoDriverImplementation.COLOR_MAP[color]
+ RSDL_helper.set_pixel(self.screen, x, y, color)
+
def draw_pixels(self):
- for y in range(self.height):
- for x in range(self.width):
- color = VideoDriverImplementation.COLOR_MAP[self.get_pixel_color(x, y)]
- RSDL_helper.set_pixel(self.screen, x, y, color)
+ for y in range(constants.GAMEBOY_SCREEN_HEIGHT):
+ for x in range(constants.GAMEBOY_SCREEN_WIDTH):
+ self.draw_pixel(x, y, self.pixels[y][x])
def draw_ascii_pixels(self):
str = []
@@ -137,17 +157,9 @@
str.append("\n")
for x in range(self.width):
if y%2 == 0 or True:
- str.append(self.get_pixel_color(x, y, string=True))
+ str.append(["#", "%", "+", "."][self.pixels[y][x]])
print "".join(str)
- @specialize.arg(3)
- def get_pixel_color(self, x, y, string=False):
- if string:
- return ["#", "%", "+", ".", " "][self.get_pixel_color(x, y)]
- else:
- return self.pixels[y][x]
-
-
# JOYPAD DRIVER ----------------------------------------------------------------
class JoypadDriverImplementation(JoypadDriver):
Modified: pypy/trunk/pypy/lang/gameboy/video.py
==============================================================================
--- pypy/trunk/pypy/lang/gameboy/video.py (original)
+++ pypy/trunk/pypy/lang/gameboy/video.py Fri Mar 6 02:25:18 2009
@@ -93,13 +93,13 @@
# -----------------------------------------------------------------------
def create_sprites(self):
- self.sprites = [None] * 40
- for i in range(40):
+ self.sprites = [None] * MAX_SPRITES
+ for i in range(MAX_SPRITES):
self.sprites[i] = Sprite(self)
def update_all_sprites(self):
# TODO: TEST!
- for i in range(40):
+ for i in range(MAX_SPRITES):
address = i * 4
self.sprites[i].set_data(self.oam[address + 0],
self.oam[address + 1],
@@ -112,12 +112,15 @@
def update_sprite_size(self):
for sprite in self.sprites:
sprite.big_size = self.control.big_sprites
-
+
+ def get_sprite_at(self, sprite_index):
+ return self.sprites[sprite_index]
+
def get_sprite(self, address):
address -= OAM_ADDR
# address divided by 4 gives the correct sprite, each sprite has 4
# bytes of attributes
- return self.sprites[ int(math.floor(address / 4)) ]
+ return self.get_sprite_at(address / 4)
# -----------------------------------------------------------------------
@@ -447,11 +450,11 @@
# graphics handling --------------------------------------------------------
def draw_frame(self):
- self.driver.update_display()
+ self.driver.update_gb_display()
def clear_frame(self):
- self.driver.clear_pixels()
- self.driver.update_display()
+ self.driver.clear_gb_pixels()
+ self.driver.update_gb_display()
def draw_line(self):
if self.control.background_and_window_lower_tile_data_selected:
@@ -482,14 +485,14 @@
lastx = SPRITE_SIZE + GAMEBOY_SCREEN_WIDTH + SPRITE_SIZE
for index in range(count):
sprite = self.shown_sprites[index]
- sprite.draw(lastx)
+ sprite.draw(self.line, self.line_y, lastx)
lastx = sprite.x
def scan_sprites(self):
# search active shown_sprites
count = 0
for sprite in self.sprites:
- if sprite.is_shown_on_current_line():
+ if sprite.is_shown_on_line(self.line_y):
self.shown_sprites[count] = sprite
count += 1
if count >= SPRITES_PER_LINE:
@@ -544,21 +547,20 @@
class VideoDriver(object):
def __init__(self):
- self.width = int(GAMEBOY_SCREEN_WIDTH)
- self.height = int(GAMEBOY_SCREEN_HEIGHT)
- self.clear_pixels()
-
- def clear_pixels(self):
- self.pixels = [[0] * self.width for i in range(self.height)]
+ self.width = GAMEBOY_SCREEN_WIDTH
+ self.height = GAMEBOY_SCREEN_HEIGHT
+
+ def clear_gb_pixels(self):
+ for y in range(GAMEBOY_SCREEN_HEIGHT):
+ for x in range(GAMEBOY_SCREEN_WIDTH):
+ self.draw_gb_pixel(x, y, 0)
def draw_gb_pixel(self, x, y, color):
self.pixels[y][x] = color
- def get_width(self):
- return self.width
-
- def get_height(self):
- return self.height
-
- def update_display(self):
- self.clear_pixels()
+ def update_gb_display(self):
+ self.update_display()
+
+ def create_pixels(self):
+ self.pixels = [[0] * self.width
+ for i in range(self.height)]
Added: pypy/trunk/pypy/lang/gameboy/video_meta.py
==============================================================================
--- (empty file)
+++ pypy/trunk/pypy/lang/gameboy/video_meta.py Fri Mar 6 02:25:18 2009
@@ -0,0 +1,80 @@
+from pypy.lang.gameboy.constants import SPRITE_SIZE, MAX_SPRITES
+
+# Metadata visualizing windows.
+
+class VideoMetaWindow(object):
+ def __init__(self, gameboy, x, y):
+ self.width = x
+ self.height = y
+ self.screen = [[0] * x for i in range(y)]
+ self.gameboy = gameboy
+ self.x = 0
+ self.y = 0
+
+ def get_screen(self):
+ return self.screen
+
+ def set_origin(self, x, y):
+ self.x = x
+ self.y = y
+
+ def draw(self):
+ self.update_screen()
+ self.draw_on_driver()
+
+ def update_screen(self):
+ raise Exception("Not implemented")
+
+ def draw_on_driver(self):
+ for y in range(self.height):
+ line = self.screen[y]
+ for x in range(self.width):
+ self.gameboy.video_driver.draw_pixel(x + self.x,
+ y + self.y,
+ self.gameboy.video.palette[self.screen[y][x]])
+
+ def clear_screen(self):
+ for line in self.screen:
+ for x in range(len(line)):
+ line[x] = 0
+
+class TileDataWindow(VideoMetaWindow):
+ def __init__(self, gameboy):
+ self.tiles_x = 24
+ self.tiles_y = 16
+ VideoMetaWindow.__init__(self, gameboy,
+ self.tiles_x * SPRITE_SIZE,
+ self.tiles_y * SPRITE_SIZE)
+
+ def update_screen(self):
+ for y_id in range(self.tiles_y):
+ for x_id in range(self.tiles_x):
+ tile = self.gameboy.video.get_tile_at(x_id * self.tiles_y + y_id)
+ for y_offset in range(SPRITE_SIZE):
+ line = self.screen[y_offset + y_id * SPRITE_SIZE]
+ tile.draw(line, x_id * SPRITE_SIZE, y_offset)
+
+class SpriteWindow(VideoMetaWindow):
+ def __init__(self, gameboy):
+ self.sprites_y = 8
+ self.sprites_x = MAX_SPRITES / self.sprites_y
+ VideoMetaWindow.__init__(self, gameboy,
+ self.sprites_x * SPRITE_SIZE,
+ self.sprites_y * SPRITE_SIZE * 2) # Double sprites
+
+ def update_screen(self):
+ self.clear_screen()
+ for y_id in range(self.sprites_y):
+ for x_id in range(self.sprites_x):
+ sprite = self.gameboy.video.get_sprite_at(y_id * self.sprites_x + x_id)
+ for y_offset in range(SPRITE_SIZE * (1 + sprite.big_size)):
+ line = self.screen[y_offset + y_id * SPRITE_SIZE * 2]
+ tile = sprite.get_tile_for_relative_line(y_offset)
+ if sprite.y_flipped:
+ y_offset = SPRITE_SIZE - 1 - y_offset
+ tile.draw(line, x_id * SPRITE_SIZE, y_offset)
+
+ for x in range(SPRITE_SIZE):
+ x += x_id * SPRITE_SIZE
+ line[x] = line[x] << 1 # Colors of sprites are in
+ # another range of the palette.
Modified: pypy/trunk/pypy/lang/gameboy/video_sprite.py
==============================================================================
--- pypy/trunk/pypy/lang/gameboy/video_sprite.py (original)
+++ pypy/trunk/pypy/lang/gameboy/video_sprite.py Fri Mar 6 02:25:18 2009
@@ -130,8 +130,9 @@
value += self.rest_attributes_and_flags
return value
- def get_width(self):
- return SPRITE_SIZE
+ # Unused.
+ #def get_width(self):
+ # return SPRITE_SIZE
def get_height(self):
if self.big_size:
@@ -148,9 +149,11 @@
address &= 0xFE
return address
- def get_tile_for_current_line(self):
- lower = self.current_line_y() < SPRITE_SIZE
- if lower ^ (self.big_size and self.y_flipped):
+ def get_tile_for_current_line(self, y):
+ return self.get_tile_for_relative_line(self.current_line_y(y))
+
+ def get_tile_for_relative_line(self, y):
+ if (y < SPRITE_SIZE) ^ (self.big_size and self.y_flipped):
return self.get_tile()
else:
return self.get_lower_tile()
@@ -172,24 +175,26 @@
self.hidden = False
return self.hidden
- def intersects_current_line(self):
- y = self.current_line_y()
+ def intersects_current_line(self, line_y):
+ y = self.current_line_y(line_y)
return y >= 0 and y < self.get_height()
- def is_shown_on_current_line(self):
- return not self.hidden and self.intersects_current_line()
+ def is_shown_on_line(self, line_y):
+ return not self.hidden and self.intersects_current_line(line_y)
- def current_line_y(self):
- return (self.video.line_y - self.y) + 2 * SPRITE_SIZE
+ def current_line_y(self, y):
+ return (y - self.y) + 2 * SPRITE_SIZE
- def get_draw_y(self):
- y = self.current_line_y()
+ def get_draw_y(self, line_y):
+ y = self.current_line_y(line_y)
if self.y_flipped:
y = self.get_height() - 1 - y
return y
- def draw(self, lastx):
- self.get_tile_for_current_line().draw_for_sprite(self, self.video.line, lastx)
+ def draw(self, line, line_y, lastx):
+ tile = self.get_tile_for_current_line(line_y)
+ draw_y = self.get_draw_y(line_y)
+ tile.draw_for_sprite(self, line, draw_y, lastx)
# -----------------------------------------------------------------------------
@@ -201,8 +206,8 @@
def draw(self, line, x, y):
pattern = self.get_pattern_at(y << 1)
for i in range(SPRITE_SIZE):
- value = (pattern >> (SPRITE_SIZE - 1 - i)) & 0x0101
- line[x + i] = value
+ color = (pattern >> (SPRITE_SIZE - 1 - i)) & 0x0101
+ line[x + i] = color
def set_tile_data(self, data):
self.data = data
@@ -220,13 +225,13 @@
return self.get_data_at(address) +\
(self.get_data_at(address + 1) << 8)
- def draw_for_sprite(self, sprite, line, lastx):
+ def draw_for_sprite(self, sprite, line, y, lastx):
if sprite.x_flipped:
convert, offset = 1, 0 # 0-7
else:
convert, offset = -1, SPRITE_SIZE # 7-0
- y = sprite.get_draw_y() << 1
+ y = y << 1 # 2 bytes per line
pattern = self.get_pattern_at(y) << 1
mask = (sprite.palette_number << 2) +\
(sprite.object_behind_background << 3)
More information about the Pypy-commit
mailing list