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