Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
9837 turbocat 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;
28
	int xoff, yoff, xoff_mask;
29
	int hscroll_amount, yscroll_amount = 0;
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
}