2 * Looks up a vertical scroll value and sets some related variables.
4 #undef LOOKUP_YSCROLL_REC
5 #define LOOKUP_YSCROLL_REC(rec_no) \
7 yscroll_amount = get_word(vsram + rec_no * 2) & 0x7ff; \
11 yscroll_amount >>= 1; \
13 /* Offset for the line */ \
14 yscroll_amount += line; \
16 yoff = ((yscroll_amount >> 3) & (ysize - 1)); \
17 tile_line = (tiles + ((xsize * yoff) & 0x1fff)); \
18 scan = (yscroll_amount & 7); \
24 int x
, scan
= 0, w
, xstart
;
25 static int sizes
[4] = { 32, 64, 64, 128 };
27 unsigned char *where
, *hscroll_rec_ptr
, *tiles
, *tile_line
= NULL
;
28 int xoff
, yoff
, xoff_mask
;
29 int hscroll_amount
, yscroll_amount
= 0;
30 uint8_t two_cell_vscroll
= 0;
33 * when VSCR bit is set in register 11, this is 'per 2-cell'
34 * vertical scrolling as opposed to full screen vscrolling.
36 two_cell_vscroll
= ((reg
[11] >> 2) & 0x1);
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.
43 // Window goes down, plane 0 goes up! :)
44 if ((line
>> 3) >= (reg
[18] & 0x1f))
48 // Window goes up, plane 0 goes down
49 if ((line
>> 3) < (reg
[18] & 0x1f))
55 * Get the vertical/horizontal scroll plane sizes
59 * 0b10: prohibited, but unlicensed games use this
63 xsize
= (sizes
[(reg
[16] & 3)] << 1);
64 ysize
= sizes
[((reg
[16] >> 4) & 3)];
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.
71 hscroll_rec_ptr
= (vram
+ ((reg
[13] << 10) & 0xfc00));
72 tiles
= (vram
+ (reg
[2] << 10));
74 hscroll_rec_ptr
= (vram
+ ((reg
[13] << 10) & 0xfc00) + 2);
75 tiles
= (vram
+ (reg
[4] << 13));
89 * Lookup the horizontal offset.
90 * See Charles MacDonald's genvdp.txt for explanation.
92 switch (reg
[11] & 3) {
95 // NOP - pointer in the right place
98 // invalid, but populous uses it
99 hscroll_rec_ptr
+= ((line
& 7) << 2);
103 hscroll_rec_ptr
+= ((line
& ~7) << 2);
107 hscroll_rec_ptr
+= (line
<< 2);
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
;
117 * If this is not column vscroll mode, we look up the
118 * whole screen vertical scroll value once and once only.
120 if (two_cell_vscroll
== 0)
121 LOOKUP_YSCROLL_REC(PLANE
);
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.
127 for (x
= -1; (x
<= w
); x
++) {
129 * If we are in 2-cell vscroll mode then lookup the amount by
130 * which we should scroll this tile.
132 * If we are not in 2-cell vscroll then we looked up the value
133 * for the whole screen vscroll earlier.
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
140 if ((two_cell_vscroll
) && ((x
% 2 == 0) || (x
== -1))) {
143 * Note that the underflow and overflow of the table
144 * for cell -1 and cell w is intentional.
146 * http://gendev.spritesmind.net/forum/viewtopic.php?t=737&postdays=0&postorder=asc&start=30
148 uint8_t cell_index
= (uint8_t) x
% w
;
149 int vscroll_rec_no
= 2 * (cell_index
/ 2);
152 * The records alternate, PLANE A, PLANE B, PLANE A,
158 LOOKUP_YSCROLL_REC(vscroll_rec_no
);
162 if (reg
[17] & 0x80) {
163 // Don't draw where the window will be
164 if (x
>= ((reg
[17] & 0x1f) << 1))
168 // + 1 so scroll layers in Sonic look right
169 if ((x
+ 1) < ((reg
[17] & 0x1f) << 1))
173 which
= get_word(tile_line
+ xoff
);
175 #if (FRONT == 0) && (PLANE == 1)
176 draw_tile_solid(which
, scan
, where
);
179 draw_tile(which
, scan
, where
);
182 draw_tile(which
, scan
, where
);
189 xoff
= ((xoff
+ 2) & xoff_mask
);