Import Debian changes 1.23-11
[debian-dgen.git] / ras.cpp
blob8c2e4d3525463c3d16afd5fd0d2f995f5227b39a
1 // DGen/SDL v1.16+
2 // New raster effects engine
3 // I'd like to thank the Mac folks for giving me a good template to work from.
4 // This is just a cheap rehash of their code, except friendlier to other bit
5 // depths. :) I also put in a few little optimizations, like blank checking
6 // and especially the sprites.
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include "md.h"
12 // This is marked each time the palette is updated. Handy for the 8bpp
13 // implementation, so we don't waste time changing the palette unnecessarily.
14 int pal_dirty;
16 // Macros, to route draw_tile and draw_tile_solid to the right handler
17 #define draw_tile(which, line, where) \
18 switch(Bpp)\
20 case 1:\
21 draw_tile1((which),(line),(where)); break;\
22 case 2:\
23 draw_tile2((which),(line),(where)); break;\
24 case 3:\
25 draw_tile3((which),(line),(where)); break;\
26 case 4:\
27 draw_tile4((which),(line),(where)); break;\
30 #define draw_tile_solid(which, line, where) \
31 switch(Bpp)\
33 case 1:\
34 draw_tile1_solid((which),(line),(where)); break;\
35 case 2:\
36 draw_tile2_solid((which),(line),(where)); break;\
37 case 3:\
38 draw_tile3_solid((which),(line),(where)); break;\
39 case 4:\
40 draw_tile4_solid((which),(line),(where)); break;\
43 // Silly utility function, get a big-endian word
44 #ifdef WORDS_BIGENDIAN
45 static inline int get_word(unsigned char *where)
46 { return (int)(*(unsigned short*)where); }
47 #else
48 static inline int get_word(unsigned char *where)
49 { return (where[0] << 8) | where[1]; }
50 #endif
52 // Tile pixel masks
53 #ifdef WORDS_BIGENDIAN
54 # define PIXEL0 (0xf0000000)
55 # define PIXEL1 (0x0f000000)
56 # define PIXEL2 (0x00f00000)
57 # define PIXEL3 (0x000f0000)
58 # define PIXEL4 (0x0000f000)
59 # define PIXEL5 (0x00000f00)
60 # define PIXEL6 (0x000000f0)
61 # define PIXEL7 (0x0000000f)
62 # define SHIFT0 (28)
63 # define SHIFT1 (24)
64 # define SHIFT2 (20)
65 # define SHIFT3 (16)
66 # define SHIFT4 (12)
67 # define SHIFT5 ( 8)
68 # define SHIFT6 ( 4)
69 # define SHIFT7 ( 0)
70 #else // WORDS_BIGENDIAN
71 # define PIXEL0 (0x000000f0)
72 # define PIXEL1 (0x0000000f)
73 # define PIXEL2 (0x0000f000)
74 # define PIXEL3 (0x00000f00)
75 # define PIXEL4 (0x00f00000)
76 # define PIXEL5 (0x000f0000)
77 # define PIXEL6 (0xf0000000)
78 # define PIXEL7 (0x0f000000)
79 # define SHIFT0 ( 4)
80 # define SHIFT1 ( 0)
81 # define SHIFT2 (12)
82 # define SHIFT3 ( 8)
83 # define SHIFT4 (20)
84 # define SHIFT5 (16)
85 # define SHIFT6 (28)
86 # define SHIFT7 (24)
87 #endif // WORDS_BIGENDIAN
89 #ifdef ASM_TILES
90 extern "C" {
91 void _asm_tiles_init(unsigned char *vram,
92 unsigned char *reg,
93 unsigned *highpal);
95 void _drawtile1(int which, int line, unsigned char *where);
96 void _drawtile1_solid(int which, int line, unsigned char *where);
97 void _drawtile2(int which, int line, unsigned char *where);
98 void _drawtile2_solid(int which, int line, unsigned char *where);
99 void _drawtile3(int which, int line, unsigned char *where);
100 void _drawtile3_solid(int which, int line, unsigned char *where);
101 void _drawtile4(int which, int line, unsigned char *where);
102 void _drawtile4_solid(int which, int line, unsigned char *where);
105 // Pass off these calls to assembler counterparts
106 inline void md_vdp::draw_tile1_solid(int which, int line, unsigned char *where)
107 { _drawtile1_solid(which, line, where); }
109 inline void md_vdp::draw_tile1(int which, int line, unsigned char *where)
110 { _drawtile1(which, line, where); }
112 inline void md_vdp::draw_tile2_solid(int which, int line, unsigned char *where)
113 { _drawtile2_solid(which, line, where); }
115 inline void md_vdp::draw_tile2(int which, int line, unsigned char *where)
116 { _drawtile2(which, line, where); }
118 inline void md_vdp::draw_tile3_solid(int which, int line, unsigned char *where)
119 { _drawtile3_solid(which, line, where); }
121 inline void md_vdp::draw_tile3(int which, int line, unsigned char *where)
122 { _drawtile3(which, line, where); }
124 inline void md_vdp::draw_tile4_solid(int which, int line, unsigned char *where)
125 { _drawtile4_solid(which, line, where); }
127 inline void md_vdp::draw_tile4(int which, int line, unsigned char *where)
128 { _drawtile4(which, line, where); }
130 #else // ASM_TILES
132 // Blit tile solidly, for 1 byte-per-pixel
133 inline void md_vdp::draw_tile1_solid(int which, int line, unsigned char *where)
135 unsigned tile, pal;
137 pal = (which >> 9 & 0x30); // Determine which 16-color palette
139 if(which & 0x1000) // y flipped
140 line ^= 7; // take from the bottom, instead of the top
142 if(reg[12] & 2) // interlace
143 tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
144 else
145 tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
147 // Blit the tile!
148 if(which & 0x800) // x flipped
150 *(where ) = ((tile & PIXEL7)>>SHIFT7) | pal;
151 *(where+1) = ((tile & PIXEL6)>>SHIFT6) | pal;
152 *(where+2) = ((tile & PIXEL5)>>SHIFT5) | pal;
153 *(where+3) = ((tile & PIXEL4)>>SHIFT4) | pal;
154 *(where+4) = ((tile & PIXEL3)>>SHIFT3) | pal;
155 *(where+5) = ((tile & PIXEL2)>>SHIFT2) | pal;
156 *(where+6) = ((tile & PIXEL1)>>SHIFT1) | pal;
157 *(where+7) = ((tile & PIXEL0)>>SHIFT0) | pal;
158 } else {
159 *(where ) = ((tile & PIXEL0)>>SHIFT0) | pal;
160 *(where+1) = ((tile & PIXEL1)>>SHIFT1) | pal;
161 *(where+2) = ((tile & PIXEL2)>>SHIFT2) | pal;
162 *(where+3) = ((tile & PIXEL3)>>SHIFT3) | pal;
163 *(where+4) = ((tile & PIXEL4)>>SHIFT4) | pal;
164 *(where+5) = ((tile & PIXEL5)>>SHIFT5) | pal;
165 *(where+6) = ((tile & PIXEL6)>>SHIFT6) | pal;
166 *(where+7) = ((tile & PIXEL7)>>SHIFT7) | pal;
170 // Blit tile, leaving color zero transparent, for 1 byte per pixel
171 inline void md_vdp::draw_tile1(int which, int line, unsigned char *where)
173 unsigned tile, pal;
175 pal = (which >> 9 & 0x30); // Determine which 16-color palette
177 if(which & 0x1000) // y flipped
178 line ^= 7; // take from the bottom, instead of the top
180 if(reg[12] & 2) // interlace
181 tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
182 else
183 tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
184 // If the tile is all 0's, why waste the time?
185 if(!tile) return;
187 // Blit the tile!
188 if(which & 0x800) // x flipped
190 if(tile & PIXEL7) *(where ) = ((tile & PIXEL7)>>SHIFT7) | pal;
191 if(tile & PIXEL6) *(where+1) = ((tile & PIXEL6)>>SHIFT6) | pal;
192 if(tile & PIXEL5) *(where+2) = ((tile & PIXEL5)>>SHIFT5) | pal;
193 if(tile & PIXEL4) *(where+3) = ((tile & PIXEL4)>>SHIFT4) | pal;
194 if(tile & PIXEL3) *(where+4) = ((tile & PIXEL3)>>SHIFT3) | pal;
195 if(tile & PIXEL2) *(where+5) = ((tile & PIXEL2)>>SHIFT2) | pal;
196 if(tile & PIXEL1) *(where+6) = ((tile & PIXEL1)>>SHIFT1) | pal;
197 if(tile & PIXEL0) *(where+7) = ((tile & PIXEL0)>>SHIFT0) | pal;
198 } else {
199 if(tile & PIXEL0) *(where ) = ((tile & PIXEL0)>>SHIFT0) | pal;
200 if(tile & PIXEL1) *(where+1) = ((tile & PIXEL1)>>SHIFT1) | pal;
201 if(tile & PIXEL2) *(where+2) = ((tile & PIXEL2)>>SHIFT2) | pal;
202 if(tile & PIXEL3) *(where+3) = ((tile & PIXEL3)>>SHIFT3) | pal;
203 if(tile & PIXEL4) *(where+4) = ((tile & PIXEL4)>>SHIFT4) | pal;
204 if(tile & PIXEL5) *(where+5) = ((tile & PIXEL5)>>SHIFT5) | pal;
205 if(tile & PIXEL6) *(where+6) = ((tile & PIXEL6)>>SHIFT6) | pal;
206 if(tile & PIXEL7) *(where+7) = ((tile & PIXEL7)>>SHIFT7) | pal;
210 // Blit tile solidly, for 2 byte-per-pixel
211 inline void md_vdp::draw_tile2_solid(int which, int line, unsigned char *where)
213 unsigned tile, temp, *pal;
214 unsigned short *wwhere = (unsigned short*)where;
216 pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
217 temp = *pal; *pal = highpal[reg[7]&0x3f]; // Get background color
219 if(which & 0x1000) // y flipped
220 line ^= 7; // take from the bottom, instead of the top
222 if(reg[12] & 2) // interlace
223 tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
224 else
225 tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
227 // Blit the tile!
228 if(which & 0x800) // x flipped
230 *(wwhere ) = pal[((tile & PIXEL7)>>SHIFT7)];
231 *(wwhere+1) = pal[((tile & PIXEL6)>>SHIFT6)];
232 *(wwhere+2) = pal[((tile & PIXEL5)>>SHIFT5)];
233 *(wwhere+3) = pal[((tile & PIXEL4)>>SHIFT4)];
234 *(wwhere+4) = pal[((tile & PIXEL3)>>SHIFT3)];
235 *(wwhere+5) = pal[((tile & PIXEL2)>>SHIFT2)];
236 *(wwhere+6) = pal[((tile & PIXEL1)>>SHIFT1)];
237 *(wwhere+7) = pal[((tile & PIXEL0)>>SHIFT0)];
238 } else {
239 *(wwhere ) = pal[((tile & PIXEL0)>>SHIFT0)];
240 *(wwhere+1) = pal[((tile & PIXEL1)>>SHIFT1)];
241 *(wwhere+2) = pal[((tile & PIXEL2)>>SHIFT2)];
242 *(wwhere+3) = pal[((tile & PIXEL3)>>SHIFT3)];
243 *(wwhere+4) = pal[((tile & PIXEL4)>>SHIFT4)];
244 *(wwhere+5) = pal[((tile & PIXEL5)>>SHIFT5)];
245 *(wwhere+6) = pal[((tile & PIXEL6)>>SHIFT6)];
246 *(wwhere+7) = pal[((tile & PIXEL7)>>SHIFT7)];
248 // Restore the original color
249 *pal = temp;
252 // Blit tile, leaving color zero transparent, for 2 byte per pixel
253 inline void md_vdp::draw_tile2(int which, int line, unsigned char *where)
255 unsigned tile, *pal;
256 unsigned short *wwhere = (unsigned short*)where;
258 pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
260 if(which & 0x1000) // y flipped
261 line ^= 7; // take from the bottom, instead of the top
263 if(reg[12] & 2) // interlace
264 tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
265 else
266 tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
267 // If the tile is all 0's, why waste the time?
268 if(!tile) return;
270 // Blit the tile!
271 if(which & 0x800) // x flipped
273 if(tile & PIXEL7) *(wwhere ) = pal[((tile & PIXEL7)>>SHIFT7)];
274 if(tile & PIXEL6) *(wwhere+1) = pal[((tile & PIXEL6)>>SHIFT6)];
275 if(tile & PIXEL5) *(wwhere+2) = pal[((tile & PIXEL5)>>SHIFT5)];
276 if(tile & PIXEL4) *(wwhere+3) = pal[((tile & PIXEL4)>>SHIFT4)];
277 if(tile & PIXEL3) *(wwhere+4) = pal[((tile & PIXEL3)>>SHIFT3)];
278 if(tile & PIXEL2) *(wwhere+5) = pal[((tile & PIXEL2)>>SHIFT2)];
279 if(tile & PIXEL1) *(wwhere+6) = pal[((tile & PIXEL1)>>SHIFT1)];
280 if(tile & PIXEL0) *(wwhere+7) = pal[((tile & PIXEL0)>>SHIFT0)];
281 } else {
282 if(tile & PIXEL0) *(wwhere ) = pal[((tile & PIXEL0)>>SHIFT0)];
283 if(tile & PIXEL1) *(wwhere+1) = pal[((tile & PIXEL1)>>SHIFT1)];
284 if(tile & PIXEL2) *(wwhere+2) = pal[((tile & PIXEL2)>>SHIFT2)];
285 if(tile & PIXEL3) *(wwhere+3) = pal[((tile & PIXEL3)>>SHIFT3)];
286 if(tile & PIXEL4) *(wwhere+4) = pal[((tile & PIXEL4)>>SHIFT4)];
287 if(tile & PIXEL5) *(wwhere+5) = pal[((tile & PIXEL5)>>SHIFT5)];
288 if(tile & PIXEL6) *(wwhere+6) = pal[((tile & PIXEL6)>>SHIFT6)];
289 if(tile & PIXEL7) *(wwhere+7) = pal[((tile & PIXEL7)>>SHIFT7)];
293 inline void md_vdp::draw_tile3_solid(int which, int line, unsigned char *where)
295 unsigned tile;
296 unsigned char *pal;
298 pal = ((unsigned char*)highpal) + (which >> 7 & 0xc0); // Determine 16-color palette
300 if(which & 0x1000) // y flipped
301 line ^= 7; // take from the bottom, instead of the top
303 if(reg[12] & 2) // interlace
304 tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
305 else
306 tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
308 // Blit the tile (this is UGLY! Do you know of a better way? :P)
309 if(which & 0x800)
311 *(where ) = pal[((tile & 0x0f000000)>>22)+1];
312 *(where+1 ) = pal[((tile & 0x0f000000)>>22)+2];
313 *(where+2 ) = pal[((tile & 0x0f000000)>>22) ];
314 *(where+3 ) = pal[((tile & 0xf0000000)>>26)+1];
315 *(where+4 ) = pal[((tile & 0xf0000000)>>26)+2];
316 *(where+5 ) = pal[((tile & 0xf0000000)>>26) ];
317 *(where+6 ) = pal[((tile & 0x000f0000)>>14)+1];
318 *(where+7 ) = pal[((tile & 0x000f0000)>>14)+2];
319 *(where+8 ) = pal[((tile & 0x000f0000)>>14) ];
320 *(where+9 ) = pal[((tile & 0x00f00000)>>18)+1];
321 *(where+10) = pal[((tile & 0x00f00000)>>18)+2];
322 *(where+11) = pal[((tile & 0x00f00000)>>18) ];
323 *(where+12) = pal[((tile & 0x00000f00)>> 6)+1];
324 *(where+13) = pal[((tile & 0x00000f00)>> 6)+2];
325 *(where+14) = pal[((tile & 0x00000f00)>> 6) ];
326 *(where+15) = pal[((tile & 0x0000f000)>>10)+1];
327 *(where+16) = pal[((tile & 0x0000f000)>>10)+2];
328 *(where+17) = pal[((tile & 0x0000f000)>>10) ];
329 *(where+18) = pal[((tile & 0x0000000f)<< 2)+1];
330 *(where+19) = pal[((tile & 0x0000000f)<< 2)+2];
331 *(where+20) = pal[((tile & 0x0000000f)<< 2) ];
332 *(where+21) = pal[((tile & 0x000000f0)>> 2)+1];
333 *(where+22) = pal[((tile & 0x000000f0)>> 2)+2];
334 *(where+23) = pal[((tile & 0x000000f0)>> 2) ];
335 } else {
336 *(where ) = pal[((tile & 0x000000f0)>> 2)+1];
337 *(where+ 1) = pal[((tile & 0x000000f0)>> 2)+2];
338 *(where+ 2) = pal[((tile & 0x000000f0)>> 2) ];
339 *(where+ 3) = pal[((tile & 0x0000000f)<< 2)+1];
340 *(where+ 4) = pal[((tile & 0x0000000f)<< 2)+2];
341 *(where+ 5) = pal[((tile & 0x0000000f)<< 2) ];
342 *(where+ 6) = pal[((tile & 0x0000f000)>>10)+1];
343 *(where+ 7) = pal[((tile & 0x0000f000)>>10)+2];
344 *(where+ 8) = pal[((tile & 0x0000f000)>>10) ];
345 *(where+ 9) = pal[((tile & 0x00000f00)>> 6)+1];
346 *(where+10) = pal[((tile & 0x00000f00)>> 6)+2];
347 *(where+11) = pal[((tile & 0x00000f00)>> 6) ];
348 *(where+12) = pal[((tile & 0x00f00000)>>18)+1];
349 *(where+13) = pal[((tile & 0x00f00000)>>18)+2];
350 *(where+14) = pal[((tile & 0x00f00000)>>18) ];
351 *(where+15) = pal[((tile & 0x000f0000)>>14)+1];
352 *(where+16) = pal[((tile & 0x000f0000)>>14)+2];
353 *(where+17) = pal[((tile & 0x000f0000)>>14) ];
354 *(where+18) = pal[((tile & 0xf0000000)>>26)+1];
355 *(where+19) = pal[((tile & 0xf0000000)>>26)+2];
356 *(where+20) = pal[((tile & 0xf0000000)>>26) ];
357 *(where+21) = pal[((tile & 0x0f000000)>>22)+1];
358 *(where+22) = pal[((tile & 0x0f000000)>>22)+2];
359 *(where+23) = pal[((tile & 0x0f000000)>>22) ];
363 inline void md_vdp::draw_tile3(int which, int line, unsigned char *where)
365 unsigned tile;
366 unsigned char *pal;
368 pal = ((unsigned char*)highpal) + (which >> 7 & 0xc0); // Determine 16-color palette
370 if(which & 0x1000) // y flipped
371 line ^= 7; // take from the bottom, instead of the top
373 if(reg[12] & 2) // interlace
374 tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
375 else
376 tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
377 // If it's empty, why waste the time?
378 if(!tile) return;
380 // Blit the tile (this is UGLY! Do you know of a better way? :P)
381 if(which & 0x800)
383 // The numbers are a little wierd, because of little endian. *gag*
384 // <SARCASM>Thanks Intel!</SARCASM>
385 if(tile & 0x0f000000) { *(where ) = pal[((tile & 0x0f000000)>>22)+1];
386 *(where+1 ) = pal[((tile & 0x0f000000)>>22)+2];
387 *(where+2 ) = pal[((tile & 0x0f000000)>>22) ]; }
388 if(tile & 0xf0000000) { *(where+3 ) = pal[((tile & 0xf0000000)>>26)+1];
389 *(where+4 ) = pal[((tile & 0xf0000000)>>26)+2];
390 *(where+5 ) = pal[((tile & 0xf0000000)>>26) ]; }
391 if(tile & 0x000f0000) { *(where+6 ) = pal[((tile & 0x000f0000)>>14)+1];
392 *(where+7 ) = pal[((tile & 0x000f0000)>>14)+2];
393 *(where+8 ) = pal[((tile & 0x000f0000)>>14) ]; }
394 if(tile & 0x00f00000) { *(where+9 ) = pal[((tile & 0x00f00000)>>18)+1];
395 *(where+10) = pal[((tile & 0x00f00000)>>18)+2];
396 *(where+11) = pal[((tile & 0x00f00000)>>18) ]; }
397 if(tile & 0x00000f00) { *(where+12) = pal[((tile & 0x00000f00)>> 6)+1];
398 *(where+13) = pal[((tile & 0x00000f00)>> 6)+2];
399 *(where+14) = pal[((tile & 0x00000f00)>> 6) ]; }
400 if(tile & 0x0000f000) { *(where+15) = pal[((tile & 0x0000f000)>>10)+1];
401 *(where+16) = pal[((tile & 0x0000f000)>>10)+2];
402 *(where+17) = pal[((tile & 0x0000f000)>>10) ]; }
403 if(tile & 0x0000000f) { *(where+18) = pal[((tile & 0x0000000f)<< 2)+1];
404 *(where+19) = pal[((tile & 0x0000000f)<< 2)+2];
405 *(where+20) = pal[((tile & 0x0000000f)<< 2) ]; }
406 if(tile & 0x000000f0) { *(where+21) = pal[((tile & 0x000000f0)>> 2)+1];
407 *(where+22) = pal[((tile & 0x000000f0)>> 2)+2];
408 *(where+23) = pal[((tile & 0x000000f0)>> 2) ]; }
409 } else {
410 if(tile & 0x000000f0) { *(where ) = pal[((tile & 0x000000f0)>> 2)+1];
411 *(where+ 1) = pal[((tile & 0x000000f0)>> 2)+2];
412 *(where+ 2) = pal[((tile & 0x000000f0)>> 2) ]; }
413 if(tile & 0x0000000f) { *(where+ 3) = pal[((tile & 0x0000000f)<< 2)+1];
414 *(where+ 4) = pal[((tile & 0x0000000f)<< 2)+2];
415 *(where+ 5) = pal[((tile & 0x0000000f)<< 2) ]; }
416 if(tile & 0x0000f000) { *(where+ 6) = pal[((tile & 0x0000f000)>>10)+1];
417 *(where+ 7) = pal[((tile & 0x0000f000)>>10)+2];
418 *(where+ 8) = pal[((tile & 0x0000f000)>>10) ]; }
419 if(tile & 0x00000f00) { *(where+ 9) = pal[((tile & 0x00000f00)>> 6)+1];
420 *(where+10) = pal[((tile & 0x00000f00)>> 6)+2];
421 *(where+11) = pal[((tile & 0x00000f00)>> 6) ]; }
422 if(tile & 0x00f00000) { *(where+12) = pal[((tile & 0x00f00000)>>18)+1];
423 *(where+13) = pal[((tile & 0x00f00000)>>18)+2];
424 *(where+14) = pal[((tile & 0x00f00000)>>18) ]; }
425 if(tile & 0x000f0000) { *(where+15) = pal[((tile & 0x000f0000)>>14)+1];
426 *(where+16) = pal[((tile & 0x000f0000)>>14)+2];
427 *(where+17) = pal[((tile & 0x000f0000)>>14) ]; }
428 if(tile & 0xf0000000) { *(where+18) = pal[((tile & 0xf0000000)>>26)+1];
429 *(where+19) = pal[((tile & 0xf0000000)>>26)+2];
430 *(where+20) = pal[((tile & 0xf0000000)>>26) ]; }
431 if(tile & 0x0f000000) { *(where+21) = pal[((tile & 0x0f000000)>>22)+1];
432 *(where+22) = pal[((tile & 0x0f000000)>>22)+2];
433 *(where+23) = pal[((tile & 0x0f000000)>>22) ]; }
437 // Blit tile solidly, for 4 byte-per-pixel
438 inline void md_vdp::draw_tile4_solid(int which, int line, unsigned char *where)
440 unsigned tile, temp, *pal;
441 unsigned *wwhere = (unsigned*)where;
443 pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
444 temp = *pal; *pal = highpal[reg[7]&0x3f]; // Get background color
446 if(which & 0x1000) // y flipped
447 line ^= 7; // take from the bottom, instead of the top
449 if(reg[12] & 2) // interlace
450 tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
451 else
452 tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
454 // Blit the tile!
455 if(which & 0x800) // x flipped
457 *(wwhere ) = pal[((tile & PIXEL7)>>SHIFT7)];
458 *(wwhere+1) = pal[((tile & PIXEL6)>>SHIFT6)];
459 *(wwhere+2) = pal[((tile & PIXEL5)>>SHIFT5)];
460 *(wwhere+3) = pal[((tile & PIXEL4)>>SHIFT4)];
461 *(wwhere+4) = pal[((tile & PIXEL3)>>SHIFT3)];
462 *(wwhere+5) = pal[((tile & PIXEL2)>>SHIFT2)];
463 *(wwhere+6) = pal[((tile & PIXEL1)>>SHIFT1)];
464 *(wwhere+7) = pal[((tile & PIXEL0)>>SHIFT0)];
465 } else {
466 *(wwhere ) = pal[((tile & PIXEL0)>>SHIFT0)];
467 *(wwhere+1) = pal[((tile & PIXEL1)>>SHIFT1)];
468 *(wwhere+2) = pal[((tile & PIXEL2)>>SHIFT2)];
469 *(wwhere+3) = pal[((tile & PIXEL3)>>SHIFT3)];
470 *(wwhere+4) = pal[((tile & PIXEL4)>>SHIFT4)];
471 *(wwhere+5) = pal[((tile & PIXEL5)>>SHIFT5)];
472 *(wwhere+6) = pal[((tile & PIXEL6)>>SHIFT6)];
473 *(wwhere+7) = pal[((tile & PIXEL7)>>SHIFT7)];
475 // Restore the original color
476 *pal = temp;
479 // Blit tile, leaving color zero transparent, for 4 byte per pixel
480 inline void md_vdp::draw_tile4(int which, int line, unsigned char *where)
482 unsigned tile, *pal;
483 unsigned *wwhere = (unsigned*)where;
485 pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
487 if(which & 0x1000) // y flipped
488 line ^= 7; // take from the bottom, instead of the top
490 if(reg[12] & 2) // interlace
491 tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
492 else
493 tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
494 // If the tile is all 0's, why waste the time?
495 if(!tile) return;
497 // Blit the tile!
498 if(which & 0x800) // x flipped
500 if(tile & PIXEL7) *(wwhere ) = pal[((tile & PIXEL7)>>SHIFT7)];
501 if(tile & PIXEL6) *(wwhere+1) = pal[((tile & PIXEL6)>>SHIFT6)];
502 if(tile & PIXEL5) *(wwhere+2) = pal[((tile & PIXEL5)>>SHIFT5)];
503 if(tile & PIXEL4) *(wwhere+3) = pal[((tile & PIXEL4)>>SHIFT4)];
504 if(tile & PIXEL3) *(wwhere+4) = pal[((tile & PIXEL3)>>SHIFT3)];
505 if(tile & PIXEL2) *(wwhere+5) = pal[((tile & PIXEL2)>>SHIFT2)];
506 if(tile & PIXEL1) *(wwhere+6) = pal[((tile & PIXEL1)>>SHIFT1)];
507 if(tile & PIXEL0) *(wwhere+7) = pal[((tile & PIXEL0)>>SHIFT0)];
508 } else {
509 if(tile & PIXEL0) *(wwhere ) = pal[((tile & PIXEL0)>>SHIFT0)];
510 if(tile & PIXEL1) *(wwhere+1) = pal[((tile & PIXEL1)>>SHIFT1)];
511 if(tile & PIXEL2) *(wwhere+2) = pal[((tile & PIXEL2)>>SHIFT2)];
512 if(tile & PIXEL3) *(wwhere+3) = pal[((tile & PIXEL3)>>SHIFT3)];
513 if(tile & PIXEL4) *(wwhere+4) = pal[((tile & PIXEL4)>>SHIFT4)];
514 if(tile & PIXEL5) *(wwhere+5) = pal[((tile & PIXEL5)>>SHIFT5)];
515 if(tile & PIXEL6) *(wwhere+6) = pal[((tile & PIXEL6)>>SHIFT6)];
516 if(tile & PIXEL7) *(wwhere+7) = pal[((tile & PIXEL7)>>SHIFT7)];
519 #endif // ASM_TILES
521 // Draw the window (front or back)
522 void md_vdp::draw_window(int line, int front)
524 int size;
525 int x, y, w, start;
526 int pl, add;
527 int total_window;
528 unsigned char *where;
529 int which;
530 // Set everything up
531 y = line >> 3;
532 total_window = (y < (reg[18]&0x1f)) ^ (reg[18] >> 7);
534 // Wide or narrow
535 size = (reg[12] & 1)? 64 : 32;
537 pl = (reg[3] << 10) + ((y&0x3f)*size*2);
539 // Wide(320) or narrow(256)?
540 if(reg[12] & 1)
542 w = 40;
543 start = -8;
544 } else {
545 w = 32;
546 start = 24;
548 add = -2;
549 where = dest + (start * Bpp);
550 for(x=-1; x<w; ++x)
552 if(!total_window)
553 if(reg[17] & 0x80)
555 if(x < ((reg[17]&0x1f) << 1)) goto skip;
556 } else {
557 if(x >= ((reg[17]&0x1f) << 1)) goto skip;
559 which = get_word(((unsigned char*)vram) + (pl+(add&((size-1)<<1))));
560 if((which>>15) == front)
561 draw_tile(which, line&7, where);
562 skip:
563 add += 2; where += Bpp_times8;
567 void md_vdp::draw_sprites(int line, int front)
569 unsigned which;
570 int tx, ty, x, y, xend, ysize, yoff, i;
571 unsigned char *where, *sprite;
572 // Sprites have to be in reverse order :P
573 for(i = sprite_count - 1; i >= 0; --i)
575 sprite = sprite_base + (sprite_order[i] << 3);
576 // Get the first tile
577 which = get_word(sprite + 4);
578 // Only do it if it's on the right priority
579 if((which >> 15) == front)
581 // Get the sprite's location
582 y = get_word(sprite);
583 x = get_word(sprite + 6) & 0x1ff;
585 // Interlace?
586 if(reg[12] & 2)
587 y = (y & 0x3fe) >> 1;
588 else
589 y &= 0x1ff;
591 x -= 0x80;
592 y -= 0x80;
593 yoff = (line - y);
595 // Narrow mode?
596 if(!(reg[12] & 1)) x += 32;
598 xend = ((sprite[2] << 1) & 0x18) + x;
599 ysize = sprite[2] & 0x3;
601 // Render if this sprite's on this line
602 if(xend > -8 && x < 320 && yoff >= 0 && yoff <= (ysize<<3)+7)
604 ty = yoff & 7;
605 // y flipped?
606 if(which & 0x1000)
607 which += ysize - (yoff >> 3);
608 else
609 which += (yoff >> 3);
610 ++ysize;
611 // x flipped?
612 if(which & 0x800)
614 where = dest + (xend * Bpp);
615 for(tx = xend; tx >= x; tx -= 8)
617 if(tx > -8 && tx < 320)
618 draw_tile(which, ty, where);
619 which += ysize;
620 where -= Bpp_times8;
622 } else {
623 where = dest + (x * Bpp);
624 for(tx = x; tx <= xend; tx += 8)
626 if(tx > -8 && tx < 320)
627 draw_tile(which, ty, where);
628 which += ysize;
629 where += Bpp_times8;
637 // The body for the next few functions is in an extraneous header file.
638 // Phil, I hope I left enough in this file for GLOBAL to hack it right. ;)
639 // Thanks to John Stiles for this trick :)
641 void md_vdp::draw_plane_back0(int line)
643 #define FRONT 0
644 #define PLANE 0
645 #include "ras-drawplane.h"
646 #undef PLANE
647 #undef FRONT
650 void md_vdp::draw_plane_back1(int line)
652 #define FRONT 0
653 #define PLANE 1
654 #include "ras-drawplane.h"
655 #undef PLANE
656 #undef FRONT
659 void md_vdp::draw_plane_front0(int line)
661 #define FRONT 1
662 #define PLANE 0
663 #include "ras-drawplane.h"
664 #undef PLANE
665 #undef FRONT
668 void md_vdp::draw_plane_front1(int line)
670 #define FRONT 1
671 #define PLANE 1
672 #include "ras-drawplane.h"
673 #undef PLANE
674 #undef FRONT
677 // The main interface function, to generate a scanline
678 void md_vdp::draw_scanline(struct bmap *bits, int line)
680 unsigned *ptr, i;
681 // Set the destination in the bmap
682 dest = bits->data + (bits->pitch * (line + 8) + 16);
683 // If bytes per pixel hasn't yet been set, do it
684 if(!Bpp)
686 if(bits->bpp <= 8) Bpp = 1;
687 else if(bits->bpp <= 16) Bpp = 2;
688 else if(bits->bpp <= 24) Bpp = 3;
689 else Bpp = 4;
690 Bpp_times8 = Bpp << 3; // used for tile blitting
691 #ifdef ASM_TILES
692 _asm_tiles_init(vram, reg, highpal); // pass these values to the asm tiles
693 #endif
696 // If the palette's been changed, update it
697 if(dirt[0x34] & 2)
699 ptr = highpal;
700 // What color depth are we?
701 switch(bits->bpp)
703 case 32:
704 case 24:
705 for(i = 0; i < 128; i += 2)
706 *ptr++ = ((cram[i+1]&0x0e) << 20) |
707 ((cram[i+1]&0xe0) << 8 ) |
708 ((cram[i] &0x0e) << 4 );
709 break;
710 case 16:
711 for(i = 0; i < 128; i += 2)
712 *ptr++ = ((cram[i+1]&0x0e) << 12) |
713 ((cram[i+1]&0xe0) << 3 ) |
714 ((cram[i] &0x0e) << 1 );
715 break;
716 case 15:
717 for(i = 0; i < 128; i += 2)
718 *ptr++ = ((cram[i+1]&0x0e) << 11) |
719 ((cram[i+1]&0xe0) << 2 ) |
720 ((cram[i] &0x0e) << 1 );
721 break;
722 case 8:
723 default:
724 // Let the hardware palette sort it out :P
725 for(i = 0; i < 64; ++i) *ptr++ = i;
727 // Clean up the dirt
728 dirt[0x34] &= ~2;
729 pal_dirty = 1;
731 // Render the screen if it's turned on
732 if(reg[1] & 0x40)
734 // Recalculate the sprite order, if it's dirty
735 if((dirt[0x30] & 0x20) || (dirt[0x34] & 1))
737 unsigned next = 0;
738 // Find the sprite base in VRAM
739 sprite_base = vram + (reg[5]<<9);
740 // Order the sprites
741 sprite_count = sprite_order[0] = 0;
742 do {
743 next = sprite_base[(next << 3) + 3];
744 sprite_order[++sprite_count] = next;
745 // No more than 256 sprites/line, a reasonable limit ;)
746 } while (next && sprite_count < 0x100);
747 // Clean up the dirt
748 dirt[0x30] &= ~0x20; dirt[0x34] &= ~1;
750 // Draw, from the bottom up
751 // Low priority
752 draw_plane_back1(line);
753 draw_plane_back0(line);
754 draw_window(line, 0);
755 draw_sprites(line, 0);
756 // High priority
757 draw_plane_front1(line);
758 draw_plane_front0(line);
759 draw_window(line, 1);
760 draw_sprites(line, 1);
761 } else {
762 // The display is off, paint it black
763 // Do it a dword at a time
764 unsigned *destl = (unsigned*)dest;
765 for(i = 0; i < (80 * Bpp); ++i) destl[i] = 0;
768 // If we're in narrow (256) mode, cut off the messy edges
769 if(!(reg[12] & 1))
771 unsigned *destl = (unsigned*)dest;
772 for(i = 0; i < Bpp_times8; ++i)
773 destl[i] = destl[i + (72 * Bpp)] = 0;