forked from KolibriOS/kolibrios
ea1a60faa3
git-svn-id: svn://kolibrios.org@9837 a494cfbc-eb01-0410-851d-a64ba20cac60
192 lines
4.6 KiB
C
192 lines
4.6 KiB
C
/*
|
|
* 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);
|
|
}
|
|
}
|