[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