DGen/SDL
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ras-drawplane.h
Go to the documentation of this file.
1 /*
2  * Looks up a vertical scroll value and sets some related variables.
3  */
4 #undef LOOKUP_YSCROLL_REC
5 #define LOOKUP_YSCROLL_REC(rec_no) \
6  do { \
7  yscroll_amount = get_word(vsram + rec_no * 2) & 0x7ff; \
8  \
9  /* interlace ? */ \
10  if (reg[12] & 2) \
11  yscroll_amount >>= 1; \
12  \
13  /* Offset for the line */ \
14  yscroll_amount += line; \
15  \
16  yoff = ((yscroll_amount >> 3) & (ysize - 1)); \
17  tile_line = (tiles + ((xsize * yoff) & 0x1fff)); \
18  scan = (yscroll_amount & 7); \
19  } \
20  while (0)
21 
22 {
23  int xsize, ysize;
24  int x, scan = 0, w, xstart;
25  static int sizes[4] = { 32, 64, 64, 128 };
26  unsigned which;
27  unsigned char *where, *hscroll_rec_ptr, *tiles, *tile_line = NULL;
30  uint8_t two_cell_vscroll = 0;
31 
32  /*
33  * when VSCR bit is set in register 11, this is 'per 2-cell'
34  * vertical scrolling as opposed to full screen vscrolling.
35  */
36  two_cell_vscroll = ((reg[11] >> 2) & 0x1);
37 
38 #if PLANE == 0
39  // Plane 0 is only where the window isn't
40  // This should make Herzog Zwei split screen work perfectly, and clean
41  // up those little glitches on Sonic 3's level select.
42  if (reg[18] & 0x80) {
43  // Window goes down, plane 0 goes up! :)
44  if ((line >> 3) >= (reg[18] & 0x1f))
45  return;
46  }
47  else {
48  // Window goes up, plane 0 goes down
49  if ((line >> 3) < (reg[18] & 0x1f))
50  return;
51  }
52 #endif
53 
54  /*
55  * Get the vertical/horizontal scroll plane sizes
56  *
57  * 0b00: 32 cell
58  * 0b01: 64 cell
59  * 0b10: prohibited, but unlicensed games use this
60  * turns out to be 64.
61  * 0b11: 128 cell
62  */
63  xsize = (sizes[(reg[16] & 3)] << 1);
64  ysize = sizes[((reg[16] >> 4) & 3)];
65 
66  /*
67  * Here we compute pointer to the beginning of the hscroll table.
68  * The base address of the table is stored in reg[13] << 10.
69  */
70 #if PLANE == 0
71  hscroll_rec_ptr = (vram + ((reg[13] << 10) & 0xfc00));
72  tiles = (vram + (reg[2] << 10));
73 #else // PLANE == 1
74  hscroll_rec_ptr = (vram + ((reg[13] << 10) & 0xfc00) + 2);
75  tiles = (vram + (reg[4] << 13));
76 #endif
77 
78  // Wide or narrow?
79  if (reg[12] & 1) {
80  w = 40;
81  xstart = -8;
82  }
83  else {
84  w = 32;
85  xstart = 24;
86  }
87 
88  /*
89  * Lookup the horizontal offset.
90  * See Charles MacDonald's genvdp.txt for explanation.
91  */
92  switch (reg[11] & 3) {
93  case 0:
94  // full screen
95  // NOP - pointer in the right place
96  break;
97  case 1:
98  // invalid, but populous uses it
99  hscroll_rec_ptr += ((line & 7) << 2);
100  break;
101  case 2:
102  // per tile
103  hscroll_rec_ptr += ((line & ~7) << 2);
104  break;
105  case 3:
106  // per line
107  hscroll_rec_ptr += (line << 2);
108  break;
109  }
110 
111  hscroll_amount = get_word(hscroll_rec_ptr);
112  xoff_mask = xsize - 1;
113  xoff = ((-(hscroll_amount>>3) - 1)<<1) & xoff_mask;
114  where = dest + (xstart + (hscroll_amount & 7)) * (int) Bpp;
115 
116  /*
117  * If this is not column vscroll mode, we look up the
118  * whole screen vertical scroll value once and once only.
119  */
120  if (two_cell_vscroll == 0)
121  LOOKUP_YSCROLL_REC(PLANE);
122 
123  /*
124  * Loop cells, we draw 2 more cells than expected (-1 and w) because
125  * previously off-screen cells can be horizontally scrolled on-screen.
126  */
127  for (x = -1; (x <= w); x++) {
128  /*
129  * If we are in 2-cell vscroll mode then lookup the amount by
130  * which we should scroll this tile.
131  *
132  * If we are not in 2-cell vscroll then we looked up the value
133  * for the whole screen vscroll earlier.
134  *
135  * We lookup vscroll values on even x values and this is the
136  * vscroll value for the next two cells. Note that cell -1 is
137  * a special case as we never looked up the vscroll value for
138  * cell -2.
139  */
140  if ((two_cell_vscroll) && ((x % 2 == 0) || (x == -1))) {
141 
142  /*
143  * Note that the underflow and overflow of the table
144  * for cell -1 and cell w is intentional.
145  *
146  * http://gendev.spritesmind.net/forum/viewtopic.php?t=737&postdays=0&postorder=asc&start=30
147  */
148  uint8_t cell_index = (uint8_t) x % w;
149  int vscroll_rec_no = 2 * (cell_index / 2);
150 
151  /*
152  * The records alternate, PLANE A, PLANE B, PLANE A,
153  * ...
154  */
155 #if PLANE == 1
156  vscroll_rec_no++;
157 #endif
158  LOOKUP_YSCROLL_REC(vscroll_rec_no);
159  }
160 
161 #if PLANE == 0
162  if (reg[17] & 0x80) {
163  // Don't draw where the window will be
164  if (x >= ((reg[17] & 0x1f) << 1))
165  goto skip;
166  }
167  else {
168  // + 1 so scroll layers in Sonic look right
169  if ((x + 1) < ((reg[17] & 0x1f) << 1))
170  goto skip;
171  }
172 #endif
173  which = get_word(tile_line + xoff);
174 
175 #if (FRONT == 0) && (PLANE == 1)
176  draw_tile_solid(which, scan, where);
177 #elif FRONT == 1
178  if (which >> 15)
179  draw_tile(which, scan, where);
180 #else
181  if (!(which >> 15))
182  draw_tile(which, scan, where);
183 #endif
184 
185 #if PLANE == 0
186  skip:
187 #endif
188  where += Bpp_times8;
189  xoff = ((xoff + 2) & xoff_mask);
190  }
191 }