home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 13 / MA_Cover_13.bin / source / c / gbe / vram.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-11-13  |  27.9 KB  |  898 lines

  1. /*
  2.  *  gbe - gameboy emulator
  3.  *  Copyright (C) 1999  Chuck Mason, Steven Fuller
  4.  *
  5.  *  This program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2 of the License, or
  8.  *  (at your option) any later version.
  9.  *
  10.  *  This program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *  GNU General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with this program; if not, write to the Free Software
  17.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  18.  *
  19.  *
  20.  *  Chuck Mason <chuckjr@sinclair.net>
  21.  *  Steven Fuller <relnev@atdot.org>
  22.  */
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26.  
  27. #include "rom.h"
  28. #include "vram.h"
  29. #include "mem.h"
  30. #include "regs.h"
  31. #include "cpu.h"
  32. #include "data.h"
  33. #include "amiga.h"
  34. #include "joypad.h"
  35.  
  36. #define GAMEBOY_WIDTH (160 * gameboy_screen_mul)
  37. #define GAMEBOY_HEIGHT (144 * gameboy_screen_mul)
  38. #define GAMEBOY_TILEWIDTH 20
  39. #define GAMEBOY_TILEHEIGHT 18;
  40.  
  41.                          /* LIGHTEST -------> DARKEST */
  42. static unsigned short int colors16[4] = { 0x6318, 0x4210, 0x2108, 0x0000 };
  43.  
  44. static unsigned short int colors8[4]  = { 219, 146, 73, 0 };
  45. static unsigned short int *colors;
  46.  
  47. typedef struct _graphics_mode {
  48.      int (*init)(char *);
  49.      int (*close)();
  50.      int (*create)(char *, int, int);
  51.      int (*plot)(int, int, int);
  52.      int (*blit)();
  53.      int (*update)();
  54. } graphics_mode;
  55.  
  56. graphics_mode graphic_modes[] = {
  57. #ifdef BUILD_AMIGA
  58.      {
  59.           gbe_init_amiga,
  60.           gbe_close_amiga,
  61.           gbe_create_window_amiga,
  62.           gbe_plot_amiga,
  63.           gbe_blit_amiga,
  64.           gbe_poll_events_amiga
  65.      },
  66. #endif
  67. };
  68.  
  69. unsigned char graphic_sel = 0;     /* 0 AmigaOS */
  70.  
  71. short int (*fix_gbc_color) (short int color);
  72.  
  73. /* Changes 0BBBBBGGGGGRRRRR to RRRGGGBB */
  74. short int fix_gbc_color8(short int color)
  75. {
  76.      short int res = 0;
  77.      unsigned char r, g, b;
  78.      
  79.      r = (color & 0x001c) <<  3; /* 3 bits */
  80.      g = (color & 0x0380) >>  5; /* 3 bits */
  81.      b = (color & 0x6000) >> 13; /* 2 bits */
  82.      
  83.      res = r | g | b;
  84.  
  85.      return res;
  86. }
  87.  
  88. /* Changes 0BBBBBGGGGGRRRRR to 0RRRRRGGGGGBBBBB */
  89. short int fix_gbc_color16(short int color)
  90. {
  91.      short int res = 0;
  92.      short r, g, b;
  93.      
  94.      r = (color & 0x001f) << 10; /* 5 bits */
  95.      g = (color & 0x03e0);       /* 5 bits */
  96.      b = (color & 0x7c00) >> 10; /* 5 bits */
  97.      
  98.      res = r | g | b;
  99.  
  100.      return res;
  101. }
  102.  
  103. void vram_set_color(int x, int c)
  104. {
  105.      colors16[x] = colors8[x] = c;
  106. }
  107.  
  108. void vram_plot(int x, int y, int color)
  109. {
  110. #if 0
  111.      int nx, ny;
  112.      int i, j;
  113. #endif
  114.  
  115.      if(x >= 160 || y >= 144)
  116.           return;
  117. #if 0
  118.      nx = x * gameboy_screen_mul;
  119.      ny = y * gameboy_screen_mul;
  120.      
  121.      for(i = 0; i < gameboy_screen_mul; i++) {
  122.           for(j = 0; j < gameboy_screen_mul; j++) {
  123.                graphic_modes[graphic_sel].plot(nx+j, ny+i, color);
  124.           }
  125.      }
  126. #else
  127.      graphic_modes[graphic_sel].plot(x, y, color);
  128. #endif
  129. }
  130.  
  131.  
  132. void vram_plot_line_sprites(int current_line)
  133. {
  134.      /* Sprite tiles are always at $8000-$8FFF */
  135.      char *tiles; 
  136.      char *sprptr;
  137.      int sprcnt;
  138.      int sprsize;   
  139.      int cntperline = 0;
  140.      tiles = video_ram;
  141.      sprptr = &sprite_oam[0xA0];
  142.      
  143.      sprsize = (LCDCONT & 0x04) ? 16 : 8;    
  144.      
  145.      for(sprcnt = 40; sprcnt > 0; sprcnt--) {
  146.           unsigned char x, xoff, yoff;
  147.           unsigned char y;
  148.           unsigned char tile, attr;
  149.           unsigned char sprcolors;
  150.           unsigned char yflip, xflip;
  151.           
  152.           attr = *--sprptr;
  153.           tile = *--sprptr;
  154.              x = *--sprptr;
  155.              y = *--sprptr;
  156.                          
  157.           if(x < 8) {
  158.                xoff = 8 - x;  
  159.                x = 0;
  160.           } else {
  161.                xoff = 0;
  162.                x -= 8;
  163.           }
  164.           
  165.      
  166.           if(y == 0)     /* dont show sprite i guess */
  167.                continue; 
  168.                
  169.           y -= 16;
  170.           yoff = 0;
  171.           
  172.           if(x >= 160)
  173.                continue;
  174.  
  175.           sprcolors = (attr & 0x10) ? OBJ1PAL : OBJ0PAL;
  176.           yflip = (attr & 0x40) ? 1 : 0;
  177.           xflip = (attr & 0x20) ? 1 : 0;
  178.  
  179.           if(sprsize == 16)
  180.                tile = tile & 0xFE; /* 8x16 ignores LS bit */
  181.           
  182.           if(abs(current_line - y) < sprsize && current_line >= y) {
  183.                int nx;
  184.                char *tileptr = &tiles[tile * 16];
  185.                
  186.                if(!yflip)
  187.                     tileptr += (abs(current_line - y)) * 2;
  188.                else
  189.                     tileptr += ((sprsize - 1) - abs(current_line - y)) * 2;
  190.  
  191.                cntperline++;
  192.                
  193.                for(nx = xoff; nx < 8; nx++) {
  194.                     int bit1, bit2, color;
  195.                     int wbit = 0;
  196.                     
  197.                     if(!xflip)
  198.                          wbit = nx;
  199.                     else
  200.                          wbit = 7 - nx;
  201.                          
  202.                     bit1  = (*tileptr       & (0x80 >> wbit)) ? 1 : 0;
  203.                     bit2  = (*(tileptr + 1) & (0x80 >> wbit)) ? 1 : 0;
  204.                     color = (bit2 << 1) | bit1;
  205.  
  206.                     switch(color) {
  207.                          case 0:
  208.                               break;    /* transparency */
  209.                               vram_plot(x + nx, current_line, colors[(sprcolors & 0x03)]);
  210.                               break;
  211.                          case 1:
  212.                               vram_plot(x + nx, current_line, colors[(sprcolors & 0x0C) >> 2]);
  213.                               break;
  214.                          case 2:
  215.                               vram_plot(x + nx, current_line, colors[(sprcolors & 0x30) >> 4]);
  216.                               break;
  217.                          case 3:
  218.                               vram_plot(x + nx, current_line, colors[(sprcolors & 0xC0) >> 6]);
  219.                               break;
  220.                     }
  221.                }              
  222.           }
  223.      }
  224. }
  225.  
  226. void vram_plot_line_sprites_color(int current_line)
  227. {
  228.      /* Sprite tiles are always at $8000-$8FFF */
  229.      char *tiles; 
  230.      char *sprptr;
  231.      int sprcnt;
  232.      int sprsize;   
  233.      int cntperline = 0;
  234.      tiles = video_ram;
  235.      sprptr = &sprite_oam[0xA0];
  236.      
  237.      sprsize = (LCDCONT & 0x04) ? 16 : 8;    
  238.      
  239.      for(sprcnt = 40; sprcnt > 0; sprcnt--) {
  240.           unsigned char x, xoff, yoff;
  241.           unsigned char y;
  242.           unsigned char tile, attr;
  243.           unsigned char sprcolors;
  244.           unsigned char yflip, xflip;
  245.           unsigned char palette;
  246.           unsigned char bank;
  247.           
  248.           attr = *--sprptr;
  249.           tile = *--sprptr;
  250.              x = *--sprptr;
  251.              y = *--sprptr;
  252.                          
  253.           if(x < 8) {
  254.                xoff = 8 - x;  
  255.                x = 0;
  256.           } else {
  257.                xoff = 0;
  258.                x -= 8;
  259.           }
  260.           
  261.      
  262.           if(y == 0)     /* dont show sprite i guess */
  263.                continue; 
  264.                
  265.           y -= 16;
  266.           yoff = 0;
  267.           
  268.           if(x >= 160)
  269.                continue;
  270.  
  271.           sprcolors = (attr & 0x10) ? OBJ1PAL : OBJ0PAL;
  272.           yflip = (attr & 0x40) ? 1 : 0;
  273.           xflip = (attr & 0x20) ? 1 : 0;
  274.           palette = (attr & 0x07);
  275.           bank = (attr & 0x08) ? 1 : 0;
  276.           
  277.           if(sprsize == 16)
  278.                tile = tile & 0xFE; /* 8x16 ignores LS bit */
  279.           
  280.           if(abs(current_line - y) < sprsize && current_line >= y) {
  281.                int nx;
  282.                char *tileptr = &tiles[tile * 16 + (bank * 0x2000)];
  283.                
  284.                if(!yflip)
  285.                     tileptr += (abs(current_line - y)) * 2;
  286.                else
  287.                     tileptr += ((sprsize - 1) - abs(current_line - y)) * 2;
  288.  
  289.                cntperline++;
  290.                
  291.                for(nx = xoff; nx < 8; nx++) {
  292.                     int bit1, bit2, color;
  293.                     int wbit = 0;
  294.                     
  295.                     if(!xflip)
  296.                          wbit = nx;
  297.                     else
  298.                          wbit = 7 - nx;
  299.                          
  300.                     bit1  = (*tileptr       & (0x80 >> wbit)) ? 1 : 0;
  301.                     bit2  = (*(tileptr + 1) & (0x80 >> wbit)) ? 1 : 0;
  302.                     color = (bit2 << 1) | bit1;
  303.  
  304.                     switch(color) {
  305.                          case 0:
  306.                               break;    /* transparency */
  307.                          case 1:
  308.                               vram_plot(x + nx, current_line, fix_gbc_color(obj_palettes[palette][1]));
  309.                               break;
  310.                          case 2:
  311.                               vram_plot(x + nx, current_line, fix_gbc_color(obj_palettes[palette][2]));
  312.                               break;
  313.                          case 3:
  314.                               vram_plot(x + nx, current_line, fix_gbc_color(obj_palettes[palette][3]));
  315.                               break;
  316.                     }
  317.                }              
  318.           }
  319.      }
  320. }
  321.  
  322. void vram_plot_line(unsigned char *table, int current_line)
  323. {
  324.      char *tiles, *tileptr;
  325.      int signnosign = 0;
  326.      
  327.      int x, y;
  328.      
  329.      if((LCDCONT & 0x10)) {
  330.           signnosign = 0;
  331.           tiles = &video_ram[0];
  332.      } else {
  333.           signnosign = 1;
  334.           tiles = &video_ram[0x1000];
  335.      }
  336.  
  337.      
  338.      for(y = current_line, x = 0; x < 160; x += 8) {
  339.           int bit1, bit2;
  340.           int color;
  341.           int nx;
  342.           signed char tile;
  343.           unsigned char scrolled_y = SCROLLY + y;
  344.           unsigned char scrolled_x = SCROLLX + x;
  345.           
  346.           // tile     = table[( (scrolled_y / 8) * 32 ) + (scrolled_x / 8)];     /* Find Tile # */
  347.           tile    = table[( (scrolled_y >> 3) << 5 ) + (scrolled_x >> 3)];
  348.      
  349.           if(signnosign && (tile & 0x80)) {
  350.                /*tileptr  = &tiles[tile * 16];*/
  351.                tileptr    = &tiles[tile << 4];
  352.           } else {
  353.                unsigned char t = tile;            /* Lets make it an actual variable,
  354.                                          * an odd reason, casting didn't work */
  355.                // tileptr  = &tiles[t * 16];       /* File Tile Data from # */
  356.                tileptr    = &tiles[t << 4];
  357.           }
  358.           
  359.           tileptr += (scrolled_y % 8) * 2;             /* Get Y Offset of Tile */
  360.           
  361.           for(nx = 0; nx < 8; nx++) {
  362.                /*bit1  = (*tileptr       & (0x80 >> (nx + (scrolled_x % 8)))) ? 1 : 0;
  363.                bit2  = (*(tileptr + 1) & (0x80 >> (nx + (scrolled_x % 8)))) ? 1 : 0; */
  364.                bit1  = (*tileptr       & (0x80 >> (nx + (scrolled_x & 0x07)))) ? 1 : 0;
  365.                bit2  = (*(tileptr + 1) & (0x80 >> (nx + (scrolled_x & 0x07)))) ? 1 : 0;
  366.                color = (bit2 << 1) | bit1;
  367.  
  368.                switch(color) {
  369.                     case 0:
  370.                          vram_plot(x + nx, y, colors[(BGRDPAL & 0x03)]);
  371.                          break;
  372.                     case 1:
  373.                          vram_plot(x + nx, y, colors[(BGRDPAL & 0x0C) >> 2]);
  374.                          break;
  375.                     case 2:
  376.                          vram_plot(x + nx, y, colors[(BGRDPAL & 0x30) >> 4]);
  377.                          break;
  378.                     case 3:
  379.                          vram_plot(x + nx, y, colors[(BGRDPAL & 0xC0) >> 6]);
  380.                          break;
  381.                }
  382.                /*
  383.                if((nx == 7 - (scrolled_x % 8)) && (scrolled_x % 8)) {
  384.                     x -= (scrolled_x % 8);
  385.                     break;
  386.                }*/
  387.                if((nx == 7 - (scrolled_x & 0x07)) && (scrolled_x & 0x07)) {
  388.                     x -= (scrolled_x & 0x07);
  389.                     break;
  390.                }
  391.           }
  392.      }
  393. }
  394.  
  395. void vram_plot_line_color(unsigned char *table, int current_line)
  396. {
  397.      char *tiles, *tileptr;
  398.      unsigned char attr;
  399.      unsigned char pal;
  400.      
  401.      int signnosign = 0;
  402.      
  403.      int x, y;
  404.      
  405.      if((LCDCONT & 0x10)) {
  406.           signnosign = 0;
  407.           tiles = &video_ram[0];
  408.      } else {
  409.           signnosign = 1;
  410.           tiles = &video_ram[0x1000];
  411.      }
  412.  
  413.      
  414.      for(y = current_line, x = 0; x < 160; x += 8) {
  415.           int bit1, bit2;
  416.           int color;
  417.           int nx;
  418.           signed char tile;
  419.           unsigned char scrolled_y = SCROLLY + y;
  420.           unsigned char scrolled_x = SCROLLX + x;
  421.           
  422.           tile     = table[( (scrolled_y / 8) * 32 ) + (scrolled_x / 8)];  /* Find Tile # */
  423.           attr     = table[0x2000 + ( (scrolled_y / 8) * 32 ) + (scrolled_x / 8)]; /* Find attrs */
  424.           pal      = attr & 0x07;
  425.           
  426.           if(attr & 0x08) { /* Using bank 1 */
  427.                if(signnosign && (tile & 0x80)) {
  428.                     tileptr = &tiles[0x2000 + tile * 16];
  429.                } else {
  430.                     unsigned char t = tile;
  431.                     tileptr = &tiles[0x2000 + t * 16];
  432.                }
  433.           } else {
  434.                if(signnosign && (tile & 0x80)) {
  435.                     tileptr  = &tiles[tile * 16];
  436.                } else {
  437.                     unsigned char t = tile;            /* Lets make it an actual variable,
  438.                                          * an odd reason, casting didn't work */
  439.                     tileptr  = &tiles[t * 16];         /* File Tile Data from # */
  440.                }
  441.           }
  442.           
  443.           tileptr += (scrolled_y % 8) * 2;             /* Get Y Offset of Tile */
  444.           
  445.           for(nx = 0; nx < 8; nx++) {
  446.                bit1  = (*tileptr       & (0x80 >> (nx + (scrolled_x % 8)))) ? 1 : 0;
  447.                bit2  = (*(tileptr + 1) & (0x80 >> (nx + (scrolled_x % 8)))) ? 1 : 0;
  448.                color = (bit2 << 1) | bit1;
  449.  
  450.                switch(color) {
  451.                     case 0:
  452.                          vram_plot(x + nx, y, fix_gbc_color(bkg_palettes[pal][0]));
  453.                          break;
  454.                     case 1:
  455.                          vram_plot(x + nx, y, fix_gbc_color(bkg_palettes[pal][1]));
  456.                          break;
  457.                     case 2:
  458.                          vram_plot(x + nx, y, fix_gbc_color(bkg_palettes[pal][2]));
  459.                          break;
  460.                     case 3:
  461.                          vram_plot(x + nx, y, fix_gbc_color(bkg_palettes[pal][3]));
  462.                          break;
  463.                }
  464.                if((nx == 7 - (scrolled_x % 8)) && (scrolled_x % 8)) {
  465.                     x -= (scrolled_x % 8);
  466.                     break;
  467.                }
  468.           }
  469.      }
  470. }
  471.  
  472. int vram_plot_line_window(int current_line)
  473. {
  474.      static int window_current_line = 0;     /* This is for the Windows "static" line */
  475.      static int last_current_line = 0;
  476.      
  477.      unsigned char *tableptr, *tiles, *tileptr;
  478.      int signnosign;
  479.      
  480.      signnosign = 0;
  481.           
  482.      if(current_line == 0)    /* Reset window to top of window or smth */
  483.           window_current_line = 0;
  484.      else if(last_current_line > current_line)
  485.           window_current_line = 0;
  486.           
  487.      last_current_line = current_line;
  488.                
  489.      if(WNDPOSX >= 166)  /* X >= 166 disables window */
  490.           return 0;
  491.           
  492.      if((LCDCONT & 0x40))     /* The table refs to tiles */
  493.           tableptr = &video_ram[0x1C00];
  494.      else
  495.           tableptr = &video_ram[0x1800];
  496.      
  497.      if((LCDCONT & 0x10)) {   /* Actual tiles, (same as background) */
  498.           signnosign = 0;
  499.           tiles = video_ram;
  500.      } else {
  501.           signnosign = 1;
  502.           tiles = &video_ram[0x1000];
  503.      }
  504.      
  505.      
  506.      /* The idea is this:
  507.         display in the window (because its only 160x144 (close enuf)) from line
  508.           window_current_line
  509.         onto the screen at line
  510.           current_line
  511.         its an odd concept but the idea is this:
  512.           say your window has only 4 rows of tiles in it.. if you were to display the entire
  513.           window, it would cover the background.. but if youwere to disable the window at scanline
  514.           16, the first 2 tiles would have been displayed, and you re-enabled the window
  515.           at line 124 (2 tiles from bottom), then the next 2 tiles in the window
  516.           are displayed at that line.. it's a pretty cool concept, but a bitch
  517.           to emulate.
  518.      */
  519.  
  520.      if(current_line >= WNDPOSY) { /* Draw this portion single line :) */
  521.           int y = window_current_line;
  522.           int x;
  523.  
  524.           for(x = 0; x < 160; x += 8) {
  525.                unsigned char tile;
  526.                int nx, bit1, bit2, color;
  527.                     
  528.                tile = tableptr[((y / 8) * 32) + (x / 8)];
  529.                
  530.                if(signnosign && (tile & 0x80)) {
  531.                     signed char t;
  532.                     t = tile;
  533.                     tileptr = &tiles[t * 16];
  534.                } else
  535.                     tileptr = &tiles[tile * 16];
  536.                     
  537.                tileptr += (y % 8) * 2;
  538.                
  539.                for(nx = 0; nx < 8; nx++) {
  540.                     bit1  = (*tileptr       & (0x80 >> (nx + (x % 8)))) ? 1 : 0;
  541.                     bit2  = (*(tileptr + 1) & (0x80 >> (nx + (x % 8)))) ? 1 : 0;
  542.                     color = (bit2 << 1) | bit1;
  543.  
  544.                     switch(color) {
  545.                          case 0:
  546.                               vram_plot(x + nx + (WNDPOSX > 0 ? WNDPOSX-7 : WNDPOSX), y + WNDPOSY, colors[(BGRDPAL & 0x03)]);
  547.                               break;
  548.                          case 1:
  549.                               vram_plot(x + nx + (WNDPOSX > 0 ? WNDPOSX-7 : WNDPOSX), y + WNDPOSY, colors[(BGRDPAL & 0x0C) >> 2]);
  550.                               break;
  551.                          case 2:
  552.                               vram_plot(x + nx + (WNDPOSX > 0 ? WNDPOSX-7 : WNDPOSX), y + WNDPOSY, colors[(BGRDPAL & 0x30) >> 4]);
  553.                               break;
  554.                          case 3:
  555.                               vram_plot(x + nx + (WNDPOSX > 0 ? WNDPOSX-7 : WNDPOSX), y + WNDPOSY, colors[(BGRDPAL & 0xC0) >> 6]);
  556.                               break;
  557.                     }
  558.                     if((nx == 7 - (x % 8)) && (x % 8)) {
  559.                          x -= (x % 8);
  560.                          break;
  561.                     }
  562.                }
  563.                
  564.           }
  565.           window_current_line++;
  566.           return 1;
  567.      } else
  568.           return 0;
  569. }
  570.  
  571. int vram_plot_line_window_color(int current_line)
  572. {
  573.      static int window_current_line = 0;     /* This is for the Windows "static" line */
  574.      static int last_current_line = 0;
  575.      
  576.      unsigned char *tableptr, *tiles, *tileptr;
  577.      int signnosign;
  578.      
  579.      signnosign = 0;
  580.           
  581.      if(current_line == 0)    /* Reset window to top of window or smth */
  582.           window_current_line = 0;
  583.      else if(last_current_line > current_line)
  584.           window_current_line = 0;
  585.           
  586.      last_current_line = current_line;
  587.                
  588.      if(WNDPOSX >= 166)  /* X >= 166 disables window */
  589.           return 0;
  590.           
  591.      if((LCDCONT & 0x40))     /* The table refs to tiles */
  592.           tableptr = &video_ram[0x1C00];
  593.      else
  594.           tableptr = &video_ram[0x1800];
  595.      
  596.      if((LCDCONT & 0x10)) {   /* Actual tiles, (same as background) */
  597.           signnosign = 0;
  598.           tiles = video_ram;
  599.      } else {
  600.           signnosign = 1;
  601.           tiles = &video_ram[0x1000];
  602.      }
  603.      
  604.      
  605.      /* The idea is this:
  606.         display in the window (because its only 160x144 (close enuf)) from line
  607.           window_current_line
  608.         onto the screen at line
  609.           current_line
  610.         its an odd concept but the idea is this:
  611.           say your window has only 4 rows of tiles in it.. if you were to display the entire
  612.           window, it would cover the background.. but if youwere to disable the window at scanline
  613.           16, the first 2 tiles would have been displayed, and you re-enabled the window
  614.           at line 124 (2 tiles from bottom), then the next 2 tiles in the window
  615.           are displayed at that line.. it's a pretty cool concept, but a bitch
  616.           to emulate.
  617.      */
  618.  
  619.      if(current_line >= WNDPOSY) { /* Draw this portion single line :) */
  620.           int y = window_current_line;
  621.           int x;
  622.  
  623.           for(x = 0; x < 160; x += 8) {
  624.                unsigned char tile;
  625.                int nx, bit1, bit2, color;
  626.                     
  627.                tile = tableptr[((y / 8) * 32) + (x / 8)];
  628.                
  629.                if(signnosign && (tile & 0x80)) {
  630.                     signed char t;
  631.                     t = tile;
  632.                     tileptr = &tiles[t * 16];
  633.                } else
  634.                     tileptr = &tiles[tile * 16];
  635.                     
  636.                tileptr += (y % 8) * 2;
  637.                
  638.                for(nx = 0; nx < 8; nx++) {
  639.                     bit1  = (*tileptr       & (0x80 >> (nx + (x % 8)))) ? 1 : 0;
  640.                     bit2  = (*(tileptr + 1) & (0x80 >> (nx + (x % 8)))) ? 1 : 0;
  641.                     color = (bit2 << 1) | bit1;
  642.  
  643.                     switch(color) {
  644.                          case 0:
  645.                               vram_plot(x + nx + (WNDPOSX > 0 ? WNDPOSX-7 : WNDPOSX), y + WNDPOSY, colors[(BGRDPAL & 0x03)]);
  646.                               break;
  647.                          case 1:
  648.                               vram_plot(x + nx + (WNDPOSX > 0 ? WNDPOSX-7 : WNDPOSX), y + WNDPOSY, colors[(BGRDPAL & 0x0C) >> 2]);
  649.                               break;
  650.                          case 2:
  651.                               vram_plot(x + nx + (WNDPOSX > 0 ? WNDPOSX-7 : WNDPOSX), y + WNDPOSY, colors[(BGRDPAL & 0x30) >> 4]);
  652.                               break;
  653.                          case 3:
  654.                               vram_plot(x + nx + (WNDPOSX > 0 ? WNDPOSX-7 : WNDPOSX), y + WNDPOSY, colors[(BGRDPAL & 0xC0) >> 6]);
  655.                               break;
  656.                     }
  657.                     if((nx == 7 - (x % 8)) && (x % 8)) {
  658.                          x -= (x % 8);
  659.                          break;
  660.                     }
  661.                }
  662.                
  663.           }
  664.           window_current_line++;
  665.           return 1;
  666.      } else
  667.           return 0;
  668. }
  669.  
  670. void vram_plot_screen()
  671. {
  672.      char *table;
  673.      int i;
  674.      
  675.      if(CURLINE >= 144)
  676.           return;
  677.  
  678.      if(LCDCONT & 0x20) {
  679.           if(!color_gameboy)
  680.                i = vram_plot_line_window(CURLINE);
  681.           else
  682.                i = vram_plot_line_window_color(CURLINE);
  683.      } else
  684.           i = 0;
  685.  
  686.      if(LCDCONT & 0x01) {          
  687.           if((LCDCONT & 0x08))
  688.                table = &video_ram[0x1C00];
  689.           else
  690.                table = &video_ram[0x1800];
  691.  
  692.           if(i == 0) {
  693.                if(!color_gameboy)
  694.                     vram_plot_line(table, CURLINE);
  695.                else
  696.                     vram_plot_line_color(table, CURLINE);
  697.           }
  698.      }
  699.  
  700.  
  701.      if(LCDCONT & 0x02) {
  702.           if(!color_gameboy)
  703.                vram_plot_line_sprites(CURLINE);
  704.           else
  705.                vram_plot_line_sprites_color(CURLINE);
  706.      }
  707. }
  708.  
  709. void gbe_init_gfx()
  710. {
  711.      int bitdepth;
  712.      
  713.      if(!(bitdepth = graphic_modes[graphic_sel].init(NULL))) {
  714.           exit(1);
  715.      }
  716.  
  717.      if(!graphic_modes[graphic_sel].create("gbe", GAMEBOY_WIDTH, GAMEBOY_HEIGHT)) {
  718.           exit(1);
  719.      }
  720.  
  721.      if(bitdepth == 2) {
  722.           colors = colors16;
  723.           fix_gbc_color = fix_gbc_color16;
  724.      }
  725.      else {
  726.           colors = colors8;
  727.           fix_gbc_color = fix_gbc_color8;
  728.      }
  729.  
  730.      return;
  731. }
  732.  
  733. void gbe_close_gfx()
  734. {
  735.      graphic_modes[graphic_sel].close();
  736. }
  737.  
  738. void vram_blit()
  739. {
  740.      graphic_modes[graphic_sel].blit();
  741. }
  742.  
  743. void vram_sysupdate()
  744. {
  745.      joypad_update();
  746.      graphic_modes[graphic_sel].update();
  747. }
  748.  
  749. /* HBlank interrupt */
  750. void gameboy_hblank()
  751. {
  752.      static int last_scanline = 0;
  753. /*     static int did_vbl = 0;  */
  754.      
  755.      DIVIDER += 18; /* unanomous value */
  756.      IFLAGS &= 0xC0;
  757.           
  758.      if(CURLINE < 144) {
  759.           LCDSTAT &= 0xFC;
  760.      } else if(CURLINE >= 144) {
  761.           LCDSTAT = (LCDSTAT & 0xFC) | 0x01;
  762.                
  763.      }
  764.  
  765.      if(TIMCONT & 0x04) {
  766.           switch(TIMCONT & 0x03) {
  767.                case 0:
  768.                     if((CURLINE - last_scanline) >= 3) {
  769.                          TIMECNT++;
  770.                          last_scanline = CURLINE;
  771.                     }
  772.                     break;
  773.                case 1:
  774.                     if((CURLINE - last_scanline) >= 16) {
  775.                          if(TIMECNT <= (255 - 28))
  776.                               TIMECNT = 0;
  777.                          else
  778.                               TIMECNT += 28;
  779.                          last_scanline = CURLINE;
  780.                     }
  781.                     break;
  782.                case 2:
  783.                     if((CURLINE - last_scanline) >= 64) {
  784.                          if(TIMECNT <= (255 - 7))
  785.                               TIMECNT = 0;
  786.                          else
  787.                               TIMECNT += 7;
  788.                          last_scanline = CURLINE;
  789.                     }
  790.                     break;
  791.                case 3:
  792.                     TIMECNT += 2;
  793.                     if(TIMECNT == 1)
  794.                          TIMECNT = 0;
  795.                     break;
  796.                default:
  797.                     printf("unknown frequency\n");
  798.                     break;
  799.           }
  800.      }
  801.  
  802.  
  803.      if(gameboy_proc->PC.uw != VBLANK_INT &&
  804.         CURLINE == CMPLINE && CURLINE <= 144 && (LCDSTAT & 0x44)) {   
  805.           IFLAGS |= 0x02;          /* LCDC int */
  806.           if((IENABLE & 0x02) && (gameboy_proc->IFF & 0x01)) {
  807.                gameboy_proc->IFF &= ~0x01;
  808.                gameboy_stack_write_word(gameboy_proc->PC.uw);
  809.                gameboy_proc->PC.uw = 0x48;
  810.           }
  811.      }
  812.  
  813.      if(CURLINE < 155) {
  814.           vram_sysupdate();
  815.           vram_plot_screen();
  816.           if(CURLINE == 0x90) 
  817.                gameboy_vblank();
  818.           CURLINE++;
  819.      } else if(CURLINE == 155) {
  820.           CURLINE = 0;
  821.           last_scanline = 0;
  822.      }
  823.  
  824.      if(gameboy_proc->PC.uw != VBLANK_INT && 
  825.         gameboy_proc->PC.uw != 0x48       && 
  826.         TIMECNT == 0                    && 
  827.         TIMCONT & 0x04) {
  828.           IFLAGS |= 0x04;
  829.           TIMEMOD = 0xFF;          /* TIMEMOD is loaded??? */
  830.           if((IENABLE & 0x04) && (gameboy_proc->IFF & 0x01)) {
  831.                gameboy_proc->IFF &= ~0x01;
  832.                gameboy_stack_write_word(gameboy_proc->PC.uw);
  833.                gameboy_proc->PC.uw = 0x50;
  834.           }
  835.      }
  836.      
  837.  
  838.  
  839.      if((SIOCONT & 0x80) && 
  840.         gameboy_proc->PC.uw != VBLANK_INT &&
  841.         gameboy_proc->PC.uw != 0x48 &&
  842.         gameboy_proc->PC.uw != 0x50 &&
  843.         CURLINE > 144) {
  844.           SIOCONT &= 0x7F;
  845.           SIODATA = 0;
  846.           IFLAGS |= 0x08;
  847.      
  848.           if((IENABLE & 0x80) && (gameboy_proc->IFF & 0x01)) {
  849.           printf("int tho!\n");
  850.                gameboy_proc->IFF &= ~0x01;
  851.                gameboy_stack_write_word(gameboy_proc->PC.uw);
  852.                gameboy_proc->PC.uw = 0x58;
  853.                return;
  854.           }
  855.      }
  856. }
  857.  
  858. void gameboy_vblank()
  859. {
  860.      /* Docs say this:
  861.         The IME (aka gameboy_proc->IFF) flag is reset by DI and 
  862.         prohibits all interrupts.  It is set by EI and acknoledges the 
  863.         interrupt setting by the IE (IENABLE, $FFFF) register.
  864.         
  865.         1. When an interrupt is generated, the IF (IFLAGS, $FF0F)
  866.            flag will be set.
  867.         2. If the IME flag is set & the corresponding IE flag is
  868.            set, the following 3 steps are performed:
  869.         3. Reset the IME flag and prevelt all interrupts.
  870.         4. The PC (program counter) is pushed onto the stack.
  871.         5. Jump to the starting address of the interrupt.
  872.         
  873.         Resetting of the IF register, which was the cause of the
  874.         interrupt, is done by hardware.
  875.      */
  876.  
  877.      IFLAGS |= 0x01;     /* Step 1 */
  878.      if((IENABLE & 0x01) && (gameboy_proc->IFF & 0x01)) {   /* Step 2 */
  879.           gameboy_proc->IFF &= ~0x01;             /* Step 3 */
  880.           gameboy_stack_write_word(gameboy_proc->PC.uw);    /* Step 4 */
  881.           gameboy_proc->PC.uw = VBLANK_INT;       /* Step 5 */
  882.      }
  883.  
  884.      if(LCDCONT & 0x80)
  885.           vram_blit();
  886.           
  887. }
  888.  
  889. void gameboy_do_dma()
  890. {
  891.      unsigned short int address = (DMACONT << 8) & 0xFFF;
  892.      unsigned char bank = DMACONT >> 4;
  893.  
  894.      if(gameboy_memory[bank])
  895.           memcpy(sprite_oam, &gameboy_memory[bank][address], 0xA0);
  896.      DMACONT = 0xE0;
  897. }
  898.