/ MCUME_teensy / teensygen / render.c
render.c
   1  /*
   2          only update window clip on window change (?)
   3          fix leftmost window/nta render and window bug
   4          sprite masking isn't right in sonic/micromachines 2, but
   5          seems ok in galaxy force 2
   6  */
   7  
   8  
   9  #include "shared.h"
  10  #include "platform_config.h"
  11  
  12  #ifdef HAS_T4_VGA 
  13  #include "vga_t_dma.h"
  14  #endif
  15  extern void emu_DrawLine16(unsigned short *src, int width , int height, int line); 
  16  extern void emu_printf(char * text);
  17  
  18  
  19  #ifdef ALIGN_LONG
  20  
  21  /* Or change the names if you depend on these from elsewhere.. */
  22  #undef READ_LONG
  23  #undef WRITE_LONG
  24  
  25  
  26  
  27         if(reg[12] & 8)
  28          {
  29              int j;
  30              for(j = 0; j < 3; j += 1)
  31              {
  32                  color = &vdp_palette[j][data];
  33                  set_color((j << 6), color);
  34              }
  35          }
  36          else
  37          {
  38              color = &vdp_palette[1][data];
  39              set_color(0x00, color);
  40              set_color(0x40, color);
  41              set_color(0x80, color);
  42          }
  43    
  44  
  45  
  46  static __inline__ uint32 READ_LONG(void *address)
  47  {
  48      if ((uint32)address & 3)
  49  	{
  50  #ifdef LSB_FIRST  /* little endian version */
  51          return ( *((uint8 *)address) +
  52                  (*((uint8 *)address+1) << 8)  +
  53                  (*((uint8 *)address+2) << 16) +
  54                  (*((uint8 *)address+3) << 24) );
  55  #else             /* big endian version */
  56          return ( *((uint8 *)address+3) +
  57                  (*((uint8 *)address+2) << 8)  +
  58                  (*((uint8 *)address+1) << 16) +
  59                  (*((uint8 *)address)   << 24) );
  60  #endif  /* LSB_FIRST */
  61  	}
  62  	else
  63          return *(uint32 *)address;
  64  }
  65  
  66  static __inline__ void WRITE_LONG(void *address, uint32 data)
  67  {
  68      if ((uint32)address & 3)
  69  	{
  70  #ifdef LSB_FIRST
  71              *((uint8 *)address) =    data;
  72              *((uint8 *)address+1) = (data >> 8);
  73              *((uint8 *)address+2) = (data >> 16);
  74              *((uint8 *)address+3) = (data >> 24);
  75  #else
  76              *((uint8 *)address+3) =  data;
  77              *((uint8 *)address+2) = (data >> 8);
  78              *((uint8 *)address+1) = (data >> 16);
  79              *((uint8 *)address)   = (data >> 24);
  80  #endif /* LSB_FIRST */
  81  		return;
  82    	}
  83    	else
  84          *(uint32 *)address = data;
  85  }
  86  
  87  #endif  /* ALIGN_LONG */
  88  
  89  #ifdef ALIGN_LONG
  90  /* Draw a single 8-pixel column */
  91  #define DRAW_COLUMN(ATTR, LINE) \
  92      atex = atex_table[(ATTR >> 13) & 7]; \
  93      src = (uint32 *)&bg_pattern_cache[(ATTR & 0x0FFF) << 6 | (LINE)]; \
  94      WRITE_LONG(dst, READ_LONG(src) | atex); \
  95      dst++; \
  96      src++; \
  97      WRITE_LONG(dst, READ_LONG(src) | atex); \
  98      dst++; \
  99      src++; \
 100      ATTR >>= 16; \
 101      atex = atex_table[(ATTR >> 13) & 7]; \
 102      src = (uint32 *)&bg_pattern_cache[(ATTR & 0x0FFF) << 6 | (LINE)]; \
 103      WRITE_LONG(dst, READ_LONG(src) | atex); \
 104      dst++; \
 105      src++; \
 106      WRITE_LONG(dst, READ_LONG(src) | atex); \
 107      dst++; \
 108      src++;
 109  
 110  
 111  /* Draw a single 16-pixel column */
 112  #define DRAW_COLUMN_IM2(ATTR, LINE) \
 113      atex = atex_table[(ATTR >> 13) & 7]; \
 114      offs = (ATTR & 0x03FF) << 7 | (ATTR & 0x0800) << 6 | (LINE); \
 115      if(ATTR & 0x1000) offs ^= 0x40; \
 116      src = (uint32 *)&bg_pattern_cache[offs]; \
 117      WRITE_LONG(dst, READ_LONG(src) | atex); \
 118      dst++; \
 119      src++; \
 120      WRITE_LONG(dst, READ_LONG(src) | atex); \
 121      dst++; \
 122      src++; \
 123      ATTR >>= 16; \
 124      atex = atex_table[(ATTR >> 13) & 7]; \
 125      offs = (ATTR & 0x03FF) << 7 | (ATTR & 0x0800) << 6 | (LINE); \
 126      if(ATTR & 0x1000) offs ^= 0x40; \
 127      src = (uint32 *)&bg_pattern_cache[offs]; \
 128      WRITE_LONG(dst, READ_LONG(src) | atex); \
 129      dst++; \
 130      src++; \
 131      WRITE_LONG(dst, READ_LONG(src) | atex); \
 132      dst++; \
 133      src++; 
 134  
 135  #else
 136  
 137  #define DRAW_COLUMN(ATTR, LINE) \
 138      atex = atex_table[(ATTR >> 13) & 7]; \
 139      src = (uint32 *)&bg_pattern_cache[(ATTR & 0x0FFF) << 6 | (LINE)]; \
 140      *dst++ = (*src++ | atex); \
 141      *dst++ = (*src++ | atex); \
 142      ATTR >>= 16; \
 143      atex = atex_table[(ATTR >> 13) & 7]; \
 144      src = (uint32 *)&bg_pattern_cache[(ATTR & 0x0FFF) << 6 | (LINE)]; \
 145      *dst++ = (*src++ | atex); \
 146      *dst++ = (*src++ | atex);
 147  
 148  #define DRAW_COLUMN_IM2(ATTR, LINE) \
 149      atex = atex_table[(ATTR >> 13) & 7]; \
 150      offs = (ATTR & 0x03FF) << 7 | (ATTR & 0x0800) << 6 | (LINE); \
 151      if(ATTR & 0x1000) offs ^= 0x40; \
 152      src = (uint32 *)&bg_pattern_cache[offs]; \
 153      *dst++ = (*src++ | atex); \
 154      *dst++ = (*src++ | atex); \
 155      ATTR >>= 16; \
 156      atex = atex_table[(ATTR >> 13) & 7]; \
 157      offs = (ATTR & 0x03FF) << 7 | (ATTR & 0x0800) << 6 | (LINE); \
 158      if(ATTR & 0x1000) offs ^= 0x40; \
 159      src = (uint32 *)&bg_pattern_cache[offs]; \
 160      *dst++ = (*src++ | atex); \
 161      *dst++ = (*src++ | atex);
 162  
 163  
 164  
 165  #endif /* ALIGN_LONG */
 166  
 167  
 168  
 169  /*
 170      gcc complains about this:
 171          *lb++ = table[(*lb << 8) |(*src++ | palette)]; 
 172      .. claiming the result on lb is undefined.
 173      So we manually advance lb and use constant offsets into the line buffer.
 174  */
 175  #define DRAW_SPRITE_TILE \
 176      lb[0] = table[(lb[0] << 8) |(*src++ | palette)]; \
 177      lb[1] = table[(lb[1] << 8) |(*src++ | palette)]; \
 178      lb[2] = table[(lb[2] << 8) |(*src++ | palette)]; \
 179      lb[3] = table[(lb[3] << 8) |(*src++ | palette)]; \
 180      lb[4] = table[(lb[4] << 8) |(*src++ | palette)]; \
 181      lb[5] = table[(lb[5] << 8) |(*src++ | palette)]; \
 182      lb[6] = table[(lb[6] << 8) |(*src++ | palette)]; \
 183      lb[7] = table[(lb[7] << 8) |(*src++ | palette)]
 184  
 185  /* Pixel creation macros, input is four bits each */
 186  
 187  /* 3:3:2 RGB */
 188  #define MAKE_PIXEL_8(r,g,b)  ((r) <<  5 | (g) << 2 | ((b) >> 1))
 189  
 190  /* 5:6:5 RGB */
 191  #define MAKE_PIXEL_16(r,g,b) ((r) << 12 | (g) << 7 | (b) << 1)
 192  
 193  /* Clip data */
 194  static clip_t clip[2];
 195  
 196  /* Attribute expansion table */
 197  static const uint32 atex_table[] = {
 198      0x00000000, 0x10101010, 0x20202020, 0x30303030,
 199      0x40404040, 0x50505050, 0x60606060, 0x70707070
 200  };
 201  
 202  /* Sprite name look-up table */
 203  static uint8 name_lut[0x400];
 204  
 205  /* Sprite line buffer data */
 206  static uint8 object_index_count;
 207  
 208  struct {
 209      uint16 ypos;
 210      uint16 xpos;
 211      uint16 attr;
 212      uint8 size;
 213      uint8 index;
 214  }object_info[20];
 215  
 216  /* Pixel look-up tables and table base address */
 217  static uint8 *lut[5];
 218  #include "genlut.h"
 219  
 220  /* 16-bit pixel remapping data */
 221  static uint16 pixel_16[0x100];
 222  static uint16 pixel_16_lut[3][0x200];
 223  
 224  /* Line buffers */
 225  static uint8 tmp_buf[0x400];                   /* Temporary buffer */
 226  static uint8 bg_buf[0x400];                    /* Merged background buffer */
 227  static uint8 nta_buf[0x400];                   /* Plane A / Window line buffer */
 228  static uint8 ntb_buf[0x400];                   /* Plane B line buffer */
 229  static uint8 obj_buf[0x400];                   /* Object layer line buffer */
 230  
 231  static uint16 line_buf[0x400];
 232  
 233  
 234  
 235  /*--------------------------------------------------------------------------*/
 236  /* Init, reset, shutdown routines                                           */
 237  /*--------------------------------------------------------------------------*/
 238  
 239  int render_init(void)
 240  {
 241      int i;
 242  
 243      /* Pixel look-up tables */
 244      lut[0] = (uint8 *)(lut_base);
 245      for(i = 1; i < LUT_MAX; i += 1)
 246      {
 247          lut[i] = lut[0] + (i * LUT_SIZE);
 248      }
 249  
 250      /* Make pixel data tables */
 251      for(i = 0; i < 0x200; i += 1)
 252      {
 253          int r, g, b;
 254          
 255          r = (i >> 6) & 7;
 256          g = (i >> 3) & 7;
 257          b = (i >> 0) & 7;
 258  
 259          pixel_16_lut[0][i] = MAKE_PIXEL_16(r,g,b);
 260          pixel_16_lut[1][i] = MAKE_PIXEL_16(r<<1,g<<1,b<<1);
 261          pixel_16_lut[2][i] = MAKE_PIXEL_16(r|8,g|8,b|8);
 262      }
 263  
 264  
 265      /* Set up color update function */
 266      color_update = color_update_16;
 267  
 268      /* Make sprite name look-up table */
 269      make_name_lut();
 270  
 271      return (1);
 272  }
 273  
 274  void make_name_lut(void)
 275  {
 276      int col, row;
 277      int vcol, vrow;
 278      int width, height;
 279      int flipx, flipy;
 280      int i, name;
 281  
 282      memset(name_lut, 0, sizeof(name_lut));
 283  
 284      for(i = 0; i < 0x400; i += 1)
 285      {
 286          vcol = col = i & 3;
 287          vrow = row = (i >> 2) & 3;
 288          height = (i >> 4) & 3;
 289          width = (i >> 6) & 3;
 290          flipx = (i >> 8) & 1;
 291          flipy = (i >> 9) & 1;
 292  
 293          if(flipx)
 294              vcol = (width - col);
 295          if(flipy)
 296              vrow = (height - row);
 297  
 298          name = vrow + (vcol * (height + 1));
 299  
 300          if((row > height) || col > width)
 301              name = -1;
 302  
 303          name_lut[i] = name;        
 304      }
 305  }
 306  
 307  
 308  
 309  void render_reset(void)
 310  {
 311      memset(&clip, 0, sizeof(clip));
 312  
 313      memset(bg_buf, 0, sizeof(bg_buf));
 314      memset(tmp_buf, 0, sizeof(tmp_buf));
 315      memset(nta_buf, 0, sizeof(nta_buf));
 316      memset(ntb_buf, 0, sizeof(ntb_buf));
 317      memset(obj_buf, 0, sizeof(obj_buf));
 318  
 319      //memset(&pixel_8, 0, sizeof(pixel_8));
 320      memset(&pixel_16, 0, sizeof(pixel_16));
 321  }
 322  
 323  
 324  void render_shutdown(void)
 325  {
 326  }
 327  
 328  /*--------------------------------------------------------------------------*/
 329  /* Line render function                                                     */
 330  /*--------------------------------------------------------------------------*/
 331  
 332  void render_line(int line)
 333  {
 334  //    uint8 *lb = (gbitmap.remap == 1) ? tmp_buf : &gbitmap.data[(line * gbitmap.pitch)];
 335      uint8 *lb = tmp_buf;
 336  
 337      if((reg[1] & 0x40) == 0x00)
 338      {
 339          /* Use the overscan color to clear the screen */
 340          memset(&lb[gbitmap.viewport.x], 0x40 | border, gbitmap.viewport.w);
 341      }
 342      else
 343      {
 344          update_bg_pattern_cache();
 345          window_clip(line);
 346  
 347          if(im2_flag)
 348          {
 349              render_ntx_im2(0, line, nta_buf);
 350              render_ntx_im2(1, line, ntb_buf);
 351          }
 352          else
 353          {
 354              if(reg[0x0B] & 4)
 355              {
 356                  render_ntx_vs(0, line, nta_buf);
 357                  render_ntx_vs(1, line, ntb_buf);
 358              }
 359              else
 360              {
 361                  render_ntx(0, line, nta_buf);
 362                  render_ntx(1, line, ntb_buf);
 363              }
 364          }
 365  
 366          if(im2_flag)
 367                render_ntw_im2(line, nta_buf);
 368          else
 369                render_ntw(line, nta_buf);
 370  
 371          if(reg[12] & 8)
 372          {
 373              merge(&nta_buf[0x20], &ntb_buf[0x20], &bg_buf[0x20], lut[2], (reg[12] & 1) ? 320 : 256);
 374              memset(&obj_buf[0x20], 0, (reg[12] & 1) ? 320 : 256);
 375  
 376              if(im2_flag)
 377                  render_obj_im2(line, obj_buf, lut[3]);
 378              else
 379                  render_obj(line, obj_buf, lut[3]);
 380  
 381              merge(&obj_buf[0x20], &bg_buf[0x20], &lb[0x20], lut[4], (reg[12] & 1) ? 320 : 256);
 382          }
 383          else
 384          {
 385              merge(&nta_buf[0x20], &ntb_buf[0x20], &lb[0x20], lut[0], (reg[12] & 1) ? 320 : 256);
 386              if(im2_flag)
 387                  render_obj_im2(line, lb, lut[1]);
 388              else
 389                  render_obj(line, lb, lut[1]);
 390          }
 391      }
 392  
 393      if(reg[0] & 0x20)
 394      {
 395          memset(&lb[gbitmap.viewport.x], 0x40 | border, 0x08);
 396      }
 397  
 398  
 399      int width = (reg[12] & 1) ? 320 : 256;
 400      remap_16(lb+0x20, line_buf, pixel_16, width);
 401      emu_DrawLine16(line_buf, width ,256, line); 
 402  }
 403  /*--------------------------------------------------------------------------*/
 404  /* Window rendering                                                         */
 405  /*--------------------------------------------------------------------------*/
 406  
 407  void render_ntw(int line, uint8 *buf)
 408  {
 409      int column, v_line, width;
 410      uint32 *nt, *src, *dst, atex, atbuf;
 411  
 412      v_line = (line & 7) << 3;
 413      width = (reg[12] & 1) ? 7 : 6;
 414  
 415      nt = (uint32 *)&vram[ntwb | ((line >> 3) << width)];
 416      dst = (uint32 *)&buf[0x20 + (clip[1].left << 4)];
 417  
 418      for(column = clip[1].left; column < clip[1].right; column += 1)
 419      {
 420          atbuf = nt[column];
 421          DRAW_COLUMN(atbuf, v_line)
 422      }
 423  }
 424  
 425  void render_ntw_im2(int line, uint8 *buf)
 426  {
 427      int column, v_line, width;
 428      uint32 *nt, *src, *dst, atex, atbuf, offs;
 429  
 430      v_line = ((line & 7) << 1 | ((status >> 4) & 1)) << 3;
 431      width = (reg[12] & 1) ? 7 : 6;
 432  
 433      nt = (uint32 *)&vram[ntwb | ((line >> 3) << width)];
 434      dst = (uint32 *)&buf[0x20 + (clip[1].left << 4)];
 435  
 436      for(column = clip[1].left; column < clip[1].right; column += 1)
 437      {
 438          atbuf = nt[column];
 439          DRAW_COLUMN_IM2(atbuf, v_line)
 440      }
 441  }
 442  
 443  /*--------------------------------------------------------------------------*/
 444  /* Background plane rendering                                               */
 445  /*--------------------------------------------------------------------------*/
 446  
 447  void render_ntx(int which, int line, uint8 *buf)
 448  {
 449      int column;
 450      int start, end;
 451      int index;
 452      int shift;
 453      int nametable_row_mask = (playfield_col_mask >> 1);
 454      int v_line;
 455      uint32 atex, atbuf, *src, *dst;
 456      uint16 xascroll, xbscroll, xscroll;
 457      int y_scroll;
 458      uint32 *nt;
 459      int vsr_shift;
 460      uint32 *vs;
 461      uint16 table;
 462  
 463  
 464  
 465  
 466      table = (which) ? ntbb : ntab;
 467  
 468      get_hscroll(line, &xascroll, &xbscroll);
 469      xscroll = (which) ? xbscroll : xascroll;
 470  
 471      shift = (xscroll & 0x0F);
 472      index = ((playfield_col_mask + 1) >> 1) - ((xscroll >> 4) & nametable_row_mask);
 473  
 474      if(which)
 475      {
 476          start = 0;
 477          end = (reg[0x0C] & 1) ? 20 : 16;
 478      }
 479      else
 480      {
 481  // Looks correct if clip[0].left has 1 subtracted
 482  // Otherwise window has gap between endpoint and where the first normal
 483  // nta column starts
 484  
 485          if(clip[0].enable == 0) return;
 486          start = clip[0].left;
 487          end = clip[0].right;
 488          index = (index + clip[0].left) & nametable_row_mask;
 489      }
 490  
 491      vsr_shift = (which) ? 16 : 0;
 492      vs = (uint32 *)&vsram[0];
 493  
 494      y_scroll = (vs[0] >> vsr_shift) & 0xFFFF;
 495  
 496  //    int dy = line & 0x7; 
 497  //    int rev_line = (line & 0x1f8) + (dy^7);
 498  
 499      y_scroll = (line + (y_scroll & 0x3FF)) & playfield_row_mask;
 500  
 501      int dy = y_scroll & 0x7; 
 502      int y_scroll2 = (y_scroll & 0x1f8) + (dy^7);
 503  
 504  
 505  
 506  
 507      v_line = (y_scroll & 7) << 3;
 508      int v_line2 = (y_scroll2 & 7) << 3;
 509      
 510      nt = (uint32 *)&vram[table + (((y_scroll >> 3) << playfield_shift) & y_mask)];
 511  
 512      if(shift)
 513      {
 514          dst = (uint32 *)&buf[0x20-(0x10-shift)];
 515          atbuf = nt[(index-1) & nametable_row_mask];
 516          //DRAW_COLUMN(atbuf, v_line)
 517         // JMH
 518          if (atbuf & 0x1000) {
 519              DRAW_COLUMN(atbuf, v_line2);
 520          }
 521          else  {
 522              DRAW_COLUMN(atbuf, v_line);
 523          }  
 524       }
 525      buf = (buf + 0x20 + shift);
 526      dst = (uint32 *)&buf[start<<4];
 527  
 528  
 529  
 530      for(column = start; column < end; column += 1, index += 1)
 531      {
 532          atbuf = nt[index & nametable_row_mask];
 533          // JMH
 534          if (atbuf & 0x1000) {
 535              DRAW_COLUMN(atbuf, v_line2);
 536          }
 537          else  
 538          {
 539              DRAW_COLUMN(atbuf, v_line);
 540          }  
 541      }
 542  
 543  }
 544  
 545  
 546  void render_ntx_im2(int which, int line, uint8 *buf)
 547  {
 548      int column;
 549      int start, end;
 550      int index;
 551      int shift;
 552      int nametable_row_mask = (playfield_col_mask >> 1);
 553      int v_line;
 554      uint32 atex, atbuf, *src, *dst;
 555      uint16 xascroll, xbscroll, xscroll;
 556      int y_scroll;
 557      uint32 *nt;
 558      int vsr_shift;
 559      uint32 *vs;
 560      uint16 table;
 561      uint32 offs;
 562  
 563      table = (which) ? ntbb : ntab;
 564  
 565      get_hscroll(line, &xascroll, &xbscroll);
 566      xscroll = (which) ? xbscroll : xascroll;
 567  
 568      shift = (xscroll & 0x0F);
 569      index = ((playfield_col_mask + 1) >> 1) - ((xscroll >> 4) & nametable_row_mask);
 570  
 571      if(which)
 572      {
 573          start = 0;
 574          end = (reg[0x0C] & 1) ? 20 : 16;
 575      }
 576      else
 577      {
 578          if(clip[0].enable == 0) return;
 579          start = clip[0].left;
 580          end = clip[0].right;
 581          index = (index + clip[0].left) & nametable_row_mask;
 582      }
 583  
 584      vsr_shift = (which) ? 16 : 0;
 585      vs = (uint32 *)&vsram[0];
 586  
 587      y_scroll = (vs[0] >> vsr_shift) & 0xFFFF;
 588      y_scroll = (line + ((y_scroll >> 1) & 0x3FF)) & playfield_row_mask;
 589      v_line = (((y_scroll & 7) << 1) | ((status >> 4) & 1)) << 3;
 590      nt = (uint32 *)&vram[table + (((y_scroll >> 3) << playfield_shift) & y_mask)];
 591  
 592      if(shift)
 593      {
 594          dst = (uint32 *)&buf[0x20-(0x10-shift)];
 595          atbuf = nt[(index-1) & nametable_row_mask];
 596          DRAW_COLUMN_IM2(atbuf, v_line)
 597      }
 598      buf = (buf + 0x20 + shift);
 599      dst = (uint32 *)&buf[start<<4];
 600  
 601      for(column = start; column < end; column += 1, index += 1)
 602      {
 603          atbuf = nt[index & nametable_row_mask];
 604          DRAW_COLUMN_IM2(atbuf, v_line)
 605      }
 606  }
 607  
 608  
 609  void render_ntx_vs(int which, int line, uint8 *buf)
 610  {
 611      int column;
 612      int start, end;
 613      int index;
 614      int shift;
 615      int nametable_row_mask = (playfield_col_mask >> 1);
 616      int v_line;
 617      uint32 atex, atbuf, *src, *dst;
 618      uint16 xascroll, xbscroll, xscroll;
 619      int y_scroll;
 620      uint32 *nt;
 621      int vsr_shift;
 622      uint32 *vs;
 623      uint16 table;
 624  
 625      table = (which) ? ntbb : ntab;
 626  
 627      get_hscroll(line, &xascroll, &xbscroll);
 628      xscroll = (which) ? xbscroll : xascroll;
 629      shift = (xscroll & 0x0F);
 630      index = ((playfield_col_mask + 1) >> 1) - ((xscroll >> 4) & nametable_row_mask);
 631  
 632      if(which)
 633      {
 634          start = 0;
 635          end = (reg[0x0C] & 1) ? 20 : 16;
 636      }
 637      else
 638      {
 639          if(clip[0].enable == 0) return;
 640          start = clip[0].left;
 641          end = clip[0].right;
 642          index = (index + clip[0].left) & nametable_row_mask;
 643      }
 644  
 645      vsr_shift = (which) ? 16 : 0;
 646      vs = (uint32 *)&vsram[0];
 647      end = (reg[0x0C] & 1) ? 20 : 16;
 648  
 649      if(shift)
 650      {
 651          dst = (uint32 *)&buf[0x20-(0x10-shift)];
 652          y_scroll = (line & playfield_row_mask);
 653          v_line = (y_scroll & 7) << 3;
 654          nt = (uint32 *)&vram[table + (((y_scroll >> 3) << playfield_shift) & y_mask)];
 655          atbuf = nt[(index-1) & nametable_row_mask];
 656          DRAW_COLUMN(atbuf, v_line)
 657      }
 658  
 659      buf = (buf + 0x20 + shift);
 660      dst = (uint32 *)&buf[start << 4];
 661  
 662      for(column = start; column < end; column += 1, index += 1)
 663      {
 664          y_scroll = (vs[column] >> vsr_shift) & 0xFFFF;
 665          y_scroll = (line + (y_scroll & 0x3FF)) & playfield_row_mask;
 666          v_line = (y_scroll & 7) << 3;
 667          nt = (uint32 *)&vram[table + (((y_scroll >> 3) << playfield_shift) & y_mask)];
 668          atbuf = nt[index & nametable_row_mask];
 669          DRAW_COLUMN(atbuf, v_line)
 670      }
 671  }
 672  /*--------------------------------------------------------------------------*/
 673  /* Helper functions (cache update, hscroll, window clip)                    */
 674  /*--------------------------------------------------------------------------*/
 675  
 676  void update_bg_pattern_cache(void)
 677  {
 678      int i;
 679      uint8 x, y, c;
 680      uint16 name;
 681  
 682      if(!bg_list_index) return;
 683  
 684      for(i = 0; i < bg_list_index; i += 1)
 685      {
 686          name = bg_name_list[i];
 687          bg_name_list[i] = 0;
 688  
 689          for(y = 0; y < 8; y += 1)
 690          {
 691              if(bg_name_dirty[name] & (1 << y))
 692              {
 693                  uint8 *dst = &bg_pattern_cache[name << 6];
 694                  uint32 bp = *(uint32 *)&vram[(name << 5) | (y << 2)];
 695  
 696                  for(x = 0; x < 8; x += 1)
 697                  {
 698                      c = (bp >> ((x ^ 3) << 2)) & 0x0F;
 699                      dst[0x00000 | (y << 3) | (x)] = (c);
 700                      dst[0x20000 | (y << 3) | (x ^ 7)] = (c);
 701                      //dst[0x40000 | ((y ^ 7) << 3) | (x)] = (c);
 702                      //dst[0x60000 | ((y ^ 7) << 3) | (x ^ 7)] = (c);
 703                  }
 704              }
 705          }
 706          bg_name_dirty[name] = 0;
 707      }
 708      bg_list_index = 0;
 709  }
 710  
 711  void get_hscroll(int line, uint16 *scrolla, uint16 *scrollb)
 712  {
 713      switch(reg[11] & 3)
 714      {
 715          case 0: /* Full-screen */
 716              *scrolla = *(uint16 *)&vram[hscb + 0];
 717              *scrollb = *(uint16 *)&vram[hscb + 2];
 718              break;
 719  
 720          case 1: /* First 8 lines */
 721              *scrolla = *(uint16 *)&vram[hscb + ((line & 7) << 2) + 0];
 722              *scrollb = *(uint16 *)&vram[hscb + ((line & 7) << 2) + 2];
 723              break;
 724  
 725          case 2: /* Every 8 lines */
 726              *scrolla = *(uint16 *)&vram[hscb + ((line & ~7) << 2) + 0];
 727              *scrollb = *(uint16 *)&vram[hscb + ((line & ~7) << 2) + 2];
 728              break;
 729  
 730          case 3: /* Every line */
 731              *scrolla = *(uint16 *)&vram[hscb + (line << 2) + 0];
 732              *scrollb = *(uint16 *)&vram[hscb + (line << 2) + 2];
 733              break;
 734      }
 735  
 736      *scrolla &= 0x03FF;
 737      *scrollb &= 0x03FF;
 738  }
 739  
 740  void window_clip(int line)
 741  {
 742      /* Window size and invert flags */
 743      int hp = (reg[17] & 0x1F);
 744      int hf = (reg[17] >> 7) & 1;
 745      int vp = (reg[18] & 0x1F) << 3;
 746      int vf = (reg[18] >> 7) & 1;
 747  
 748      /* Display size  */
 749      int sw = (reg[12] & 1) ? 20 : 16;
 750  
 751      /* Clear clipping data */
 752      memset(&clip, 0, sizeof(clip));
 753  
 754      /* Check if line falls within window range */
 755      if(vf == (line >= vp))
 756      {
 757          /* Window takes up entire line */
 758          clip[1].right = sw;
 759          clip[1].enable = 1;
 760      }
 761      else
 762      {
 763          /* Perform horizontal clipping; the results are applied in reverse
 764             if the horizontal inversion flag is set */
 765          int a = hf;
 766          int w = hf ^ 1;
 767  
 768          if(hp)
 769          {
 770              if(hp > sw)
 771              {
 772                  /* Plane W takes up entire line */
 773                  clip[w].right = sw;
 774                  clip[w].enable = 1;
 775              }
 776              else
 777              {
 778                  /* Window takes left side, Plane A takes right side */
 779                  clip[w].right = hp;
 780                  clip[a].left = hp;
 781                  clip[a].right = sw;
 782                  clip[0].enable = clip[1].enable = 1;
 783              }
 784          }
 785          else
 786          {
 787              /* Plane A takes up entire line */
 788              clip[a].right = sw;
 789              clip[a].enable = 1;
 790          }
 791      }
 792  }
 793  
 794  
 795  
 796  
 797  
 798  
 799  
 800  /*--------------------------------------------------------------------------*/
 801  /* Remap functions                                                          */
 802  /*--------------------------------------------------------------------------*/
 803  void remap_16(uint8 *src, uint16 *dst, uint16 *table, int length)
 804  {
 805      int count;
 806      for(count = 0; count < length; count += 1)
 807      {
 808          *dst++ = table[*src++];
 809      }
 810  }
 811  
 812  
 813  /*--------------------------------------------------------------------------*/
 814  /* Merge functions                                                          */
 815  /*--------------------------------------------------------------------------*/
 816  
 817  void merge(uint8 *srca, uint8 *srcb, uint8 *dst, uint8 *table, int width)
 818  {
 819      int i;
 820      for(i = 0; i < width; i += 1)
 821      {
 822          uint8 a = srca[i];
 823          uint8 b = srcb[i];
 824          uint8 c = table[(b << 8) | (a)];
 825          dst[i] = c;
 826      }
 827  }
 828  
 829  
 830  void color_update_16(int index, uint16 data)
 831  {
 832      if(reg[12] & 8)
 833      {
 834          pixel_16[0x00 | index] = pixel_16_lut[0][data];
 835          pixel_16[0x40 | index] = pixel_16_lut[1][data];
 836          pixel_16[0x80 | index] = pixel_16_lut[2][data];
 837      }
 838      else
 839      {
 840          uint16 temp = pixel_16_lut[1][data];
 841          pixel_16[0x00 | index] = temp;
 842          pixel_16[0x40 | index] = temp;
 843          pixel_16[0x80 | index] = temp;
 844      }
 845  }
 846  
 847  
 848  /*--------------------------------------------------------------------------*/
 849  /* Object render functions                                                  */
 850  /*--------------------------------------------------------------------------*/
 851  
 852  void parse_satb(int line)
 853  {
 854      static uint8 sizetab[] = {8, 16, 24, 32};
 855      uint8 *p, *q, link = 0;
 856      uint16 ypos;
 857  
 858      int count;
 859      int height;
 860  
 861      int limit = (reg[12] & 1) ? 20 : 16;
 862      int total = (reg[12] & 1) ? 80 : 64;
 863  
 864      object_index_count = 0;
 865  
 866      for(count = 0; count < total; count += 1)
 867      {
 868          q = &sat[link << 3];
 869          p = &vram[satb + (link << 3)];
 870  
 871          ypos = *(uint16 *)&q[0];
 872  
 873          if(im2_flag)
 874              ypos = (ypos >> 1) & 0x1FF;
 875          else
 876              ypos &= 0x1FF;
 877  
 878          height = sizetab[q[3] & 3];
 879  
 880          if((line >= ypos) && (line < (ypos + height)))
 881          {
 882              object_info[object_index_count].ypos = *(uint16 *)&q[0];
 883              object_info[object_index_count].xpos = *(uint16 *)&p[6];
 884  
 885              // using xpos from internal satb stops sprite x
 886              // scrolling in bloodlin.bin,
 887              // but this seems to go against the test prog
 888  //          object_info[object_index_count].xpos = *(uint16 *)&q[6];
 889              object_info[object_index_count].attr = *(uint16 *)&p[4];
 890              object_info[object_index_count].size = q[3];
 891              object_info[object_index_count].index = count;
 892  
 893              object_index_count += 1;
 894  
 895              if(object_index_count == limit)
 896              {
 897                  if(vint_pending == 0)
 898                      status |= 0x40;
 899                  return;
 900              }
 901          }
 902  
 903          link = q[2] & 0x7F;
 904          if(link == 0) break;
 905      }
 906  }
 907  
 908  void render_obj(int line, uint8 *buf, uint8 *table)
 909  {
 910      uint16 ypos;
 911      uint16 attr;
 912      uint16 xpos;
 913      uint8 sizetab[] = {8, 16, 24, 32};
 914      uint8 size;
 915      uint8 *src;
 916  
 917      int count;
 918      int pixellimit = (reg[12] & 1) ? 320 : 256;
 919      int pixelcount = 0;
 920      int width;
 921      int height;
 922      int v_line;
 923      int column;
 924      int sol_flag = 0;
 925      int left = 0x80;
 926      int right = 0x80 + ((reg[12] & 1) ? 320 : 256);
 927  
 928      uint8 *s, *lb;
 929      uint16 name, index;
 930      uint8 palette;
 931  
 932      int attr_mask, nt_row;
 933  
 934      if(object_index_count == 0) return;
 935  
 936      for(count = 0; count < object_index_count; count += 1)
 937      {
 938          size = object_info[count].size & 0x0f;
 939          xpos = object_info[count].xpos;
 940          xpos &= 0x1ff;
 941  
 942          width = sizetab[(size >> 2) & 3];
 943  
 944          if(xpos != 0) sol_flag = 1;
 945          else
 946          if(xpos == 0 && sol_flag) return;
 947  
 948          if(pixelcount > pixellimit) return;
 949          pixelcount += width;
 950  
 951          if(((xpos + width) >= left) && (xpos < right))
 952          {
 953              ypos = object_info[count].ypos;
 954              ypos &= 0x1ff;
 955  
 956              attr = object_info[count].attr;
 957  //            attr_mask = (attr & 0x1800);
 958              attr_mask = (attr & 0x800);
 959  
 960              height = sizetab[size & 3];
 961              palette = (attr >> 9) & 0x70;
 962  
 963              v_line = (line - ypos);
 964              nt_row = (v_line >> 3) & 3;
 965  
 966              if (attr & 0x1000) {
 967                  v_line = ((v_line & 7)^0x07) << 3;
 968              }
 969              else {
 970                  v_line = ((v_line & 7)) << 3;                
 971              }
 972  
 973              name = (attr & 0x07FF);
 974              s = &name_lut[((attr >> 3) & 0x300) | (size << 4) | (nt_row << 2)];
 975  
 976              lb = (uint8 *)&buf[0x20 + (xpos - 0x80)];
 977  
 978              width >>= 3;
 979              for(column = 0; column < width; column += 1, lb+=8)
 980              {
 981                  index = attr_mask | ((name + s[column]) & 0x07FF);
 982                  src = &bg_pattern_cache[(index << 6) | (v_line)];
 983                  DRAW_SPRITE_TILE;
 984              }
 985          }
 986      }
 987  }
 988  
 989  void render_obj_im2(int line, uint8 *buf, uint8 *table)
 990  {
 991      uint16 ypos;
 992      uint16 attr;
 993      uint16 xpos;
 994      uint8 sizetab[] = {8, 16, 24, 32};
 995      uint8 size;
 996      uint8 *src;
 997  
 998      int count;
 999      int pixellimit = (reg[12] & 1) ? 320 : 256;
1000      int pixelcount = 0;
1001      int width;
1002      int height;
1003      int v_line;
1004      int column;
1005      int sol_flag = 0;
1006      int left = 0x80;
1007      int right = 0x80 + ((reg[12] & 1) ? 320 : 256);
1008  
1009      uint8 *s, *lb;
1010      uint16 name, index;
1011      uint8 palette;
1012      uint32 offs;
1013  
1014      int attr_mask, nt_row;
1015  
1016      if(object_index_count == 0) return;
1017  
1018      for(count = 0; count < object_index_count; count += 1)
1019      {
1020          size = object_info[count].size & 0x0f;
1021          xpos = object_info[count].xpos;
1022          xpos &= 0x1ff;
1023  
1024          width = sizetab[(size >> 2) & 3];
1025  
1026          if(xpos != 0) sol_flag = 1;
1027          else
1028          if(xpos == 0 && sol_flag) return;
1029  
1030          if(pixelcount > pixellimit) return;
1031          pixelcount += width;
1032  
1033          if(((xpos + width) >= left) && (xpos < right))
1034          {
1035              ypos = object_info[count].ypos;
1036              ypos = (ypos >> 1) & 0x1ff;
1037  
1038              attr = object_info[count].attr;
1039  //            attr_mask = (attr & 0x1800);
1040              attr_mask = (attr & 0x800);
1041  
1042              height = sizetab[size & 3];
1043              palette = (attr >> 9) & 0x70;
1044  
1045              v_line = (line - ypos);
1046              nt_row = (v_line >> 3) & 3;
1047              v_line = ((((v_line & 7)/*^0x07*/) << 1) | ((status >> 4) & 1)) << 3;            
1048  
1049              name = (attr & 0x03FF);
1050              s = &name_lut[((attr >> 3) & 0x300) | (size << 4) | (nt_row << 2)];
1051  
1052              lb = (uint8 *)&buf[0x20 + (xpos - 0x80)];
1053  
1054              width >>= 3;
1055              for(column = 0; column < width; column += 1, lb+=8)
1056              {
1057                  index = (name + s[column]) & 0x3ff;
1058                  offs = index << 7 | attr_mask << 6 | v_line;
1059                  if(attr & 0x1000) offs ^= 0x40;
1060                  src = &bg_pattern_cache[offs];
1061                  DRAW_SPRITE_TILE;
1062              }
1063          }
1064      }
1065  }