Add VCS links
[debian-dgen.git] / ras.cpp
blob1e60165ade63cbe050eea63903e4e8c41a4294c8
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 <string.h>
11 #include <stdint.h>
12 #include <assert.h>
13 #include "system.h"
14 #include "md.h"
15 #include "pd.h"
16 #include "rc-vars.h"
18 // This is marked each time the palette is updated. Handy for the 8bpp
19 // implementation, so we don't waste time changing the palette unnecessarily.
20 int pal_dirty;
22 // Macros, to route draw_tile and draw_tile_solid to the right handler
23 #define draw_tile(which, line, where) \
24 switch(Bpp)\
26 case 1:\
27 draw_tile1((which),(line),(where)); break;\
28 case 2:\
29 draw_tile2((which),(line),(where)); break;\
30 case 3:\
31 draw_tile3((which),(line),(where)); break;\
32 case 4:\
33 draw_tile4((which),(line),(where)); break;\
36 #define draw_tile_solid(which, line, where) \
37 switch(Bpp)\
39 case 1:\
40 draw_tile1_solid((which),(line),(where)); break;\
41 case 2:\
42 draw_tile2_solid((which),(line),(where)); break;\
43 case 3:\
44 draw_tile3_solid((which),(line),(where)); break;\
45 case 4:\
46 draw_tile4_solid((which),(line),(where)); break;\
49 // Silly utility function, get a big-endian word
50 #ifdef WORDS_BIGENDIAN
51 static inline int get_word(unsigned char *where)
52 { return (int)(*(unsigned short*)where); }
53 #else
54 static inline int get_word(unsigned char *where)
55 { return (where[0] << 8) | where[1]; }
56 #endif
58 // Tile pixel masks
59 #ifdef WORDS_BIGENDIAN
60 # define PIXEL0 (0xf0000000)
61 # define PIXEL1 (0x0f000000)
62 # define PIXEL2 (0x00f00000)
63 # define PIXEL3 (0x000f0000)
64 # define PIXEL4 (0x0000f000)
65 # define PIXEL5 (0x00000f00)
66 # define PIXEL6 (0x000000f0)
67 # define PIXEL7 (0x0000000f)
68 # define SHIFT0 (28)
69 # define SHIFT1 (24)
70 # define SHIFT2 (20)
71 # define SHIFT3 (16)
72 # define SHIFT4 (12)
73 # define SHIFT5 ( 8)
74 # define SHIFT6 ( 4)
75 # define SHIFT7 ( 0)
76 #else // WORDS_BIGENDIAN
77 # define PIXEL0 (0x000000f0)
78 # define PIXEL1 (0x0000000f)
79 # define PIXEL2 (0x0000f000)
80 # define PIXEL3 (0x00000f00)
81 # define PIXEL4 (0x00f00000)
82 # define PIXEL5 (0x000f0000)
83 # define PIXEL6 (0xf0000000)
84 # define PIXEL7 (0x0f000000)
85 # define SHIFT0 ( 4)
86 # define SHIFT1 ( 0)
87 # define SHIFT2 (12)
88 # define SHIFT3 ( 8)
89 # define SHIFT4 (20)
90 # define SHIFT5 (16)
91 # define SHIFT6 (28)
92 # define SHIFT7 (24)
93 #endif // WORDS_BIGENDIAN
95 #ifdef WITH_X86_TILES
96 extern "C" {
98 void asm_tiles_init(unsigned char *vram,
99 unsigned char *reg,
100 unsigned *highpal);
102 void drawtile1(int which, int line, unsigned char *where);
103 void drawtile1_solid(int which, int line, unsigned char *where);
104 void drawtile2(int which, int line, unsigned char *where);
105 void drawtile2_solid(int which, int line, unsigned char *where);
106 void drawtile3(int which, int line, unsigned char *where);
107 void drawtile3_solid(int which, int line, unsigned char *where);
108 void drawtile4(int which, int line, unsigned char *where);
109 void drawtile4_solid(int which, int line, unsigned char *where);
112 // Pass off these calls to assembler counterparts
113 inline void md_vdp::draw_tile1_solid(int which, int line, unsigned char *where)
114 { drawtile1_solid(which, line, where); }
116 inline void md_vdp::draw_tile1(int which, int line, unsigned char *where)
117 { drawtile1(which, line, where); }
119 inline void md_vdp::draw_tile2_solid(int which, int line, unsigned char *where)
120 { drawtile2_solid(which, line, where); }
122 inline void md_vdp::draw_tile2(int which, int line, unsigned char *where)
123 { drawtile2(which, line, where); }
125 inline void md_vdp::draw_tile3_solid(int which, int line, unsigned char *where)
126 { drawtile3_solid(which, line, where); }
128 inline void md_vdp::draw_tile3(int which, int line, unsigned char *where)
129 { drawtile3(which, line, where); }
131 inline void md_vdp::draw_tile4_solid(int which, int line, unsigned char *where)
132 { drawtile4_solid(which, line, where); }
134 inline void md_vdp::draw_tile4(int which, int line, unsigned char *where)
135 { drawtile4(which, line, where); }
137 #else // WITH_X86_TILES
139 static bool has_zero_nibbles(uint32_t u32)
141 return ((u32 - 0x11111111) & ~u32 & 0x88888888);
144 // Blit tile solidly, for 1 byte-per-pixel
145 inline void md_vdp::draw_tile1_solid(int which, int line, unsigned char *where)
147 unsigned tile, pal;
149 pal = (which >> 9 & 0x30); // Determine which 16-color palette
151 if(which & 0x1000) // y flipped
152 line ^= 7; // take from the bottom, instead of the top
154 if(reg[12] & 2) // interlace
155 tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
156 else
157 tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
159 // Blit the tile!
160 if(which & 0x800) // x flipped
162 *(where ) = ((tile & PIXEL7)>>SHIFT7) | pal;
163 *(where+1) = ((tile & PIXEL6)>>SHIFT6) | pal;
164 *(where+2) = ((tile & PIXEL5)>>SHIFT5) | pal;
165 *(where+3) = ((tile & PIXEL4)>>SHIFT4) | pal;
166 *(where+4) = ((tile & PIXEL3)>>SHIFT3) | pal;
167 *(where+5) = ((tile & PIXEL2)>>SHIFT2) | pal;
168 *(where+6) = ((tile & PIXEL1)>>SHIFT1) | pal;
169 *(where+7) = ((tile & PIXEL0)>>SHIFT0) | pal;
170 } else {
171 *(where ) = ((tile & PIXEL0)>>SHIFT0) | pal;
172 *(where+1) = ((tile & PIXEL1)>>SHIFT1) | pal;
173 *(where+2) = ((tile & PIXEL2)>>SHIFT2) | pal;
174 *(where+3) = ((tile & PIXEL3)>>SHIFT3) | pal;
175 *(where+4) = ((tile & PIXEL4)>>SHIFT4) | pal;
176 *(where+5) = ((tile & PIXEL5)>>SHIFT5) | pal;
177 *(where+6) = ((tile & PIXEL6)>>SHIFT6) | pal;
178 *(where+7) = ((tile & PIXEL7)>>SHIFT7) | pal;
182 // Blit tile, leaving color zero transparent, for 1 byte per pixel
183 inline void md_vdp::draw_tile1(int which, int line, unsigned char *where)
185 unsigned tile, pal;
187 pal = (which >> 9 & 0x30); // Determine which 16-color palette
189 if(which & 0x1000) // y flipped
190 line ^= 7; // take from the bottom, instead of the top
192 if(reg[12] & 2) // interlace
193 tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
194 else
195 tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
196 // If the tile is all 0's, why waste the time?
197 if(!tile) return;
199 // If the tile doesn't have any transparent pixels, draw it solidly.
200 if (!has_zero_nibbles(tile)) {
201 if (which & 0x800) {
202 // x flipped
203 *(where ) = ((tile & PIXEL7)>>SHIFT7) | pal;
204 *(where+1) = ((tile & PIXEL6)>>SHIFT6) | pal;
205 *(where+2) = ((tile & PIXEL5)>>SHIFT5) | pal;
206 *(where+3) = ((tile & PIXEL4)>>SHIFT4) | pal;
207 *(where+4) = ((tile & PIXEL3)>>SHIFT3) | pal;
208 *(where+5) = ((tile & PIXEL2)>>SHIFT2) | pal;
209 *(where+6) = ((tile & PIXEL1)>>SHIFT1) | pal;
210 *(where+7) = ((tile & PIXEL0)>>SHIFT0) | pal;
212 else {
213 *(where ) = ((tile & PIXEL0)>>SHIFT0) | pal;
214 *(where+1) = ((tile & PIXEL1)>>SHIFT1) | pal;
215 *(where+2) = ((tile & PIXEL2)>>SHIFT2) | pal;
216 *(where+3) = ((tile & PIXEL3)>>SHIFT3) | pal;
217 *(where+4) = ((tile & PIXEL4)>>SHIFT4) | pal;
218 *(where+5) = ((tile & PIXEL5)>>SHIFT5) | pal;
219 *(where+6) = ((tile & PIXEL6)>>SHIFT6) | pal;
220 *(where+7) = ((tile & PIXEL7)>>SHIFT7) | pal;
222 return;
225 // Blit the tile!
226 if(which & 0x800) // x flipped
228 if(tile & PIXEL7) *(where ) = ((tile & PIXEL7)>>SHIFT7) | pal;
229 if(tile & PIXEL6) *(where+1) = ((tile & PIXEL6)>>SHIFT6) | pal;
230 if(tile & PIXEL5) *(where+2) = ((tile & PIXEL5)>>SHIFT5) | pal;
231 if(tile & PIXEL4) *(where+3) = ((tile & PIXEL4)>>SHIFT4) | pal;
232 if(tile & PIXEL3) *(where+4) = ((tile & PIXEL3)>>SHIFT3) | pal;
233 if(tile & PIXEL2) *(where+5) = ((tile & PIXEL2)>>SHIFT2) | pal;
234 if(tile & PIXEL1) *(where+6) = ((tile & PIXEL1)>>SHIFT1) | pal;
235 if(tile & PIXEL0) *(where+7) = ((tile & PIXEL0)>>SHIFT0) | pal;
236 } else {
237 if(tile & PIXEL0) *(where ) = ((tile & PIXEL0)>>SHIFT0) | pal;
238 if(tile & PIXEL1) *(where+1) = ((tile & PIXEL1)>>SHIFT1) | pal;
239 if(tile & PIXEL2) *(where+2) = ((tile & PIXEL2)>>SHIFT2) | pal;
240 if(tile & PIXEL3) *(where+3) = ((tile & PIXEL3)>>SHIFT3) | pal;
241 if(tile & PIXEL4) *(where+4) = ((tile & PIXEL4)>>SHIFT4) | pal;
242 if(tile & PIXEL5) *(where+5) = ((tile & PIXEL5)>>SHIFT5) | pal;
243 if(tile & PIXEL6) *(where+6) = ((tile & PIXEL6)>>SHIFT6) | pal;
244 if(tile & PIXEL7) *(where+7) = ((tile & PIXEL7)>>SHIFT7) | pal;
248 // Blit tile solidly, for 2 byte-per-pixel
249 inline void md_vdp::draw_tile2_solid(int which, int line, unsigned char *where)
251 unsigned tile, temp, *pal;
252 unsigned short *wwhere = (unsigned short*)where;
254 pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
255 temp = *pal; *pal = highpal[reg[7]&0x3f]; // Get background color
257 if(which & 0x1000) // y flipped
258 line ^= 7; // take from the bottom, instead of the top
260 if(reg[12] & 2) // interlace
261 tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
262 else
263 tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
265 // Blit the tile!
266 if(which & 0x800) // x flipped
268 *(wwhere ) = pal[((tile & PIXEL7)>>SHIFT7)];
269 *(wwhere+1) = pal[((tile & PIXEL6)>>SHIFT6)];
270 *(wwhere+2) = pal[((tile & PIXEL5)>>SHIFT5)];
271 *(wwhere+3) = pal[((tile & PIXEL4)>>SHIFT4)];
272 *(wwhere+4) = pal[((tile & PIXEL3)>>SHIFT3)];
273 *(wwhere+5) = pal[((tile & PIXEL2)>>SHIFT2)];
274 *(wwhere+6) = pal[((tile & PIXEL1)>>SHIFT1)];
275 *(wwhere+7) = pal[((tile & PIXEL0)>>SHIFT0)];
276 } else {
277 *(wwhere ) = pal[((tile & PIXEL0)>>SHIFT0)];
278 *(wwhere+1) = pal[((tile & PIXEL1)>>SHIFT1)];
279 *(wwhere+2) = pal[((tile & PIXEL2)>>SHIFT2)];
280 *(wwhere+3) = pal[((tile & PIXEL3)>>SHIFT3)];
281 *(wwhere+4) = pal[((tile & PIXEL4)>>SHIFT4)];
282 *(wwhere+5) = pal[((tile & PIXEL5)>>SHIFT5)];
283 *(wwhere+6) = pal[((tile & PIXEL6)>>SHIFT6)];
284 *(wwhere+7) = pal[((tile & PIXEL7)>>SHIFT7)];
286 // Restore the original color
287 *pal = temp;
290 // Blit tile, leaving color zero transparent, for 2 byte per pixel
291 inline void md_vdp::draw_tile2(int which, int line, unsigned char *where)
293 unsigned tile, *pal;
294 unsigned short *wwhere = (unsigned short*)where;
296 pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
298 if(which & 0x1000) // y flipped
299 line ^= 7; // take from the bottom, instead of the top
301 if(reg[12] & 2) // interlace
302 tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
303 else
304 tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
305 // If the tile is all 0's, why waste the time?
306 if(!tile) return;
308 // If the tile doesn't have any transparent pixels, draw it solidly.
309 if (!has_zero_nibbles(tile)) {
310 if (which & 0x800) {
311 // x flipped
312 *(wwhere ) = pal[((tile & PIXEL7)>>SHIFT7)];
313 *(wwhere+1) = pal[((tile & PIXEL6)>>SHIFT6)];
314 *(wwhere+2) = pal[((tile & PIXEL5)>>SHIFT5)];
315 *(wwhere+3) = pal[((tile & PIXEL4)>>SHIFT4)];
316 *(wwhere+4) = pal[((tile & PIXEL3)>>SHIFT3)];
317 *(wwhere+5) = pal[((tile & PIXEL2)>>SHIFT2)];
318 *(wwhere+6) = pal[((tile & PIXEL1)>>SHIFT1)];
319 *(wwhere+7) = pal[((tile & PIXEL0)>>SHIFT0)];
321 else {
322 *(wwhere ) = pal[((tile & PIXEL0)>>SHIFT0)];
323 *(wwhere+1) = pal[((tile & PIXEL1)>>SHIFT1)];
324 *(wwhere+2) = pal[((tile & PIXEL2)>>SHIFT2)];
325 *(wwhere+3) = pal[((tile & PIXEL3)>>SHIFT3)];
326 *(wwhere+4) = pal[((tile & PIXEL4)>>SHIFT4)];
327 *(wwhere+5) = pal[((tile & PIXEL5)>>SHIFT5)];
328 *(wwhere+6) = pal[((tile & PIXEL6)>>SHIFT6)];
329 *(wwhere+7) = pal[((tile & PIXEL7)>>SHIFT7)];
331 return;
334 // Blit the tile!
335 if(which & 0x800) // x flipped
337 if(tile & PIXEL7) *(wwhere ) = pal[((tile & PIXEL7)>>SHIFT7)];
338 if(tile & PIXEL6) *(wwhere+1) = pal[((tile & PIXEL6)>>SHIFT6)];
339 if(tile & PIXEL5) *(wwhere+2) = pal[((tile & PIXEL5)>>SHIFT5)];
340 if(tile & PIXEL4) *(wwhere+3) = pal[((tile & PIXEL4)>>SHIFT4)];
341 if(tile & PIXEL3) *(wwhere+4) = pal[((tile & PIXEL3)>>SHIFT3)];
342 if(tile & PIXEL2) *(wwhere+5) = pal[((tile & PIXEL2)>>SHIFT2)];
343 if(tile & PIXEL1) *(wwhere+6) = pal[((tile & PIXEL1)>>SHIFT1)];
344 if(tile & PIXEL0) *(wwhere+7) = pal[((tile & PIXEL0)>>SHIFT0)];
345 } else {
346 if(tile & PIXEL0) *(wwhere ) = pal[((tile & PIXEL0)>>SHIFT0)];
347 if(tile & PIXEL1) *(wwhere+1) = pal[((tile & PIXEL1)>>SHIFT1)];
348 if(tile & PIXEL2) *(wwhere+2) = pal[((tile & PIXEL2)>>SHIFT2)];
349 if(tile & PIXEL3) *(wwhere+3) = pal[((tile & PIXEL3)>>SHIFT3)];
350 if(tile & PIXEL4) *(wwhere+4) = pal[((tile & PIXEL4)>>SHIFT4)];
351 if(tile & PIXEL5) *(wwhere+5) = pal[((tile & PIXEL5)>>SHIFT5)];
352 if(tile & PIXEL6) *(wwhere+6) = pal[((tile & PIXEL6)>>SHIFT6)];
353 if(tile & PIXEL7) *(wwhere+7) = pal[((tile & PIXEL7)>>SHIFT7)];
357 inline void md_vdp::draw_tile3_solid(int which, int line, unsigned char *where)
359 unsigned tile, temp, *pal;
360 uint24_t *wwhere = (uint24_t *)where;
362 pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
363 temp = *pal; *pal = highpal[reg[7]&0x3f]; // Get background color
365 if(which & 0x1000) // y flipped
366 line ^= 7; // take from the bottom, instead of the top
368 if(reg[12] & 2) // interlace
369 tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
370 else
371 tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
373 // Blit the tile!
374 if(which & 0x800) // x flipped
376 u24cpy(&wwhere[0], (uint24_t *)&pal[((tile & PIXEL7) >> SHIFT7)]);
377 u24cpy(&wwhere[1], (uint24_t *)&pal[((tile & PIXEL6) >> SHIFT6)]);
378 u24cpy(&wwhere[2], (uint24_t *)&pal[((tile & PIXEL5) >> SHIFT5)]);
379 u24cpy(&wwhere[3], (uint24_t *)&pal[((tile & PIXEL4) >> SHIFT4)]);
380 u24cpy(&wwhere[4], (uint24_t *)&pal[((tile & PIXEL3) >> SHIFT3)]);
381 u24cpy(&wwhere[5], (uint24_t *)&pal[((tile & PIXEL2) >> SHIFT2)]);
382 u24cpy(&wwhere[6], (uint24_t *)&pal[((tile & PIXEL1) >> SHIFT1)]);
383 u24cpy(&wwhere[7], (uint24_t *)&pal[((tile & PIXEL0) >> SHIFT0)]);
384 } else {
385 u24cpy(&wwhere[0], (uint24_t *)&pal[((tile & PIXEL0) >> SHIFT0)]);
386 u24cpy(&wwhere[1], (uint24_t *)&pal[((tile & PIXEL1) >> SHIFT1)]);
387 u24cpy(&wwhere[2], (uint24_t *)&pal[((tile & PIXEL2) >> SHIFT2)]);
388 u24cpy(&wwhere[3], (uint24_t *)&pal[((tile & PIXEL3) >> SHIFT3)]);
389 u24cpy(&wwhere[4], (uint24_t *)&pal[((tile & PIXEL4) >> SHIFT4)]);
390 u24cpy(&wwhere[5], (uint24_t *)&pal[((tile & PIXEL5) >> SHIFT5)]);
391 u24cpy(&wwhere[6], (uint24_t *)&pal[((tile & PIXEL6) >> SHIFT6)]);
392 u24cpy(&wwhere[7], (uint24_t *)&pal[((tile & PIXEL7) >> SHIFT7)]);
394 // Restore the original color
395 *pal = temp;
398 inline void md_vdp::draw_tile3(int which, int line, unsigned char *where)
400 unsigned tile, *pal;
401 uint24_t *wwhere = (uint24_t *)where;
403 pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
405 if(which & 0x1000) // y flipped
406 line ^= 7; // take from the bottom, instead of the top
408 if(reg[12] & 2) // interlace
409 tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
410 else
411 tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
412 // If it's empty, why waste the time?
413 if(!tile) return;
415 // If the tile doesn't have any transparent pixels, draw it solidly.
416 if (!has_zero_nibbles(tile)) {
417 if (which & 0x800) {
418 // x flipped
419 u24cpy(&wwhere[0], (uint24_t *)&pal[((tile & PIXEL7) >> SHIFT7)]);
420 u24cpy(&wwhere[1], (uint24_t *)&pal[((tile & PIXEL6) >> SHIFT6)]);
421 u24cpy(&wwhere[2], (uint24_t *)&pal[((tile & PIXEL5) >> SHIFT5)]);
422 u24cpy(&wwhere[3], (uint24_t *)&pal[((tile & PIXEL4) >> SHIFT4)]);
423 u24cpy(&wwhere[4], (uint24_t *)&pal[((tile & PIXEL3) >> SHIFT3)]);
424 u24cpy(&wwhere[5], (uint24_t *)&pal[((tile & PIXEL2) >> SHIFT2)]);
425 u24cpy(&wwhere[6], (uint24_t *)&pal[((tile & PIXEL1) >> SHIFT1)]);
426 u24cpy(&wwhere[7], (uint24_t *)&pal[((tile & PIXEL0) >> SHIFT0)]);
428 else {
429 u24cpy(&wwhere[0], (uint24_t *)&pal[((tile & PIXEL0) >> SHIFT0)]);
430 u24cpy(&wwhere[1], (uint24_t *)&pal[((tile & PIXEL1) >> SHIFT1)]);
431 u24cpy(&wwhere[2], (uint24_t *)&pal[((tile & PIXEL2) >> SHIFT2)]);
432 u24cpy(&wwhere[3], (uint24_t *)&pal[((tile & PIXEL3) >> SHIFT3)]);
433 u24cpy(&wwhere[4], (uint24_t *)&pal[((tile & PIXEL4) >> SHIFT4)]);
434 u24cpy(&wwhere[5], (uint24_t *)&pal[((tile & PIXEL5) >> SHIFT5)]);
435 u24cpy(&wwhere[6], (uint24_t *)&pal[((tile & PIXEL6) >> SHIFT6)]);
436 u24cpy(&wwhere[7], (uint24_t *)&pal[((tile & PIXEL7) >> SHIFT7)]);
438 return;
441 // Blit the tile!
442 if(which & 0x800) // x flipped
444 if (tile & PIXEL7)
445 u24cpy(&wwhere[0],
446 (uint24_t *)&pal[((tile & PIXEL7) >> SHIFT7)]);
447 if(tile & PIXEL6)
448 u24cpy(&wwhere[1],
449 (uint24_t *)&pal[((tile & PIXEL6) >> SHIFT6)]);
450 if(tile & PIXEL5)
451 u24cpy(&wwhere[2],
452 (uint24_t *)&pal[((tile & PIXEL5) >> SHIFT5)]);
453 if(tile & PIXEL4)
454 u24cpy(&wwhere[3],
455 (uint24_t *)&pal[((tile & PIXEL4) >> SHIFT4)]);
456 if(tile & PIXEL3)
457 u24cpy(&wwhere[4],
458 (uint24_t *)&pal[((tile & PIXEL3) >> SHIFT3)]);
459 if(tile & PIXEL2)
460 u24cpy(&wwhere[5],
461 (uint24_t *)&pal[((tile & PIXEL2) >> SHIFT2)]);
462 if(tile & PIXEL1)
463 u24cpy(&wwhere[6],
464 (uint24_t *)&pal[((tile & PIXEL1) >> SHIFT1)]);
465 if(tile & PIXEL0)
466 u24cpy(&wwhere[7],
467 (uint24_t *)&pal[((tile & PIXEL0) >> SHIFT0)]);
468 } else {
469 if(tile & PIXEL0)
470 u24cpy(&wwhere[0],
471 (uint24_t *)&pal[((tile & PIXEL0) >> SHIFT0)]);
472 if(tile & PIXEL1)
473 u24cpy(&wwhere[1],
474 (uint24_t *)&pal[((tile & PIXEL1) >> SHIFT1)]);
475 if(tile & PIXEL2)
476 u24cpy(&wwhere[2],
477 (uint24_t *)&pal[((tile & PIXEL2) >> SHIFT2)]);
478 if(tile & PIXEL3)
479 u24cpy(&wwhere[3],
480 (uint24_t *)&pal[((tile & PIXEL3) >> SHIFT3)]);
481 if(tile & PIXEL4)
482 u24cpy(&wwhere[4],
483 (uint24_t *)&pal[((tile & PIXEL4) >> SHIFT4)]);
484 if(tile & PIXEL5)
485 u24cpy(&wwhere[5],
486 (uint24_t *)&pal[((tile & PIXEL5) >> SHIFT5)]);
487 if(tile & PIXEL6)
488 u24cpy(&wwhere[6],
489 (uint24_t *)&pal[((tile & PIXEL6) >> SHIFT6)]);
490 if(tile & PIXEL7)
491 u24cpy(&wwhere[7],
492 (uint24_t *)&pal[((tile & PIXEL7) >> SHIFT7)]);
496 // Blit tile solidly, for 4 byte-per-pixel
497 inline void md_vdp::draw_tile4_solid(int which, int line, unsigned char *where)
499 unsigned tile, temp, *pal;
500 unsigned *wwhere = (unsigned*)where;
502 pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
503 temp = *pal; *pal = highpal[reg[7]&0x3f]; // Get background color
505 if(which & 0x1000) // y flipped
506 line ^= 7; // take from the bottom, instead of the top
508 if(reg[12] & 2) // interlace
509 tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
510 else
511 tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
513 // Blit the tile!
514 if(which & 0x800) // x flipped
516 *(wwhere ) = pal[((tile & PIXEL7)>>SHIFT7)];
517 *(wwhere+1) = pal[((tile & PIXEL6)>>SHIFT6)];
518 *(wwhere+2) = pal[((tile & PIXEL5)>>SHIFT5)];
519 *(wwhere+3) = pal[((tile & PIXEL4)>>SHIFT4)];
520 *(wwhere+4) = pal[((tile & PIXEL3)>>SHIFT3)];
521 *(wwhere+5) = pal[((tile & PIXEL2)>>SHIFT2)];
522 *(wwhere+6) = pal[((tile & PIXEL1)>>SHIFT1)];
523 *(wwhere+7) = pal[((tile & PIXEL0)>>SHIFT0)];
524 } else {
525 *(wwhere ) = pal[((tile & PIXEL0)>>SHIFT0)];
526 *(wwhere+1) = pal[((tile & PIXEL1)>>SHIFT1)];
527 *(wwhere+2) = pal[((tile & PIXEL2)>>SHIFT2)];
528 *(wwhere+3) = pal[((tile & PIXEL3)>>SHIFT3)];
529 *(wwhere+4) = pal[((tile & PIXEL4)>>SHIFT4)];
530 *(wwhere+5) = pal[((tile & PIXEL5)>>SHIFT5)];
531 *(wwhere+6) = pal[((tile & PIXEL6)>>SHIFT6)];
532 *(wwhere+7) = pal[((tile & PIXEL7)>>SHIFT7)];
534 // Restore the original color
535 *pal = temp;
538 // Blit tile, leaving color zero transparent, for 4 byte per pixel
539 inline void md_vdp::draw_tile4(int which, int line, unsigned char *where)
541 unsigned tile, *pal;
542 unsigned *wwhere = (unsigned*)where;
544 pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
546 if(which & 0x1000) // y flipped
547 line ^= 7; // take from the bottom, instead of the top
549 if(reg[12] & 2) // interlace
550 tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
551 else
552 tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
553 // If the tile is all 0's, why waste the time?
554 if(!tile) return;
556 // If the tile doesn't have any transparent pixels, draw it solidly.
557 if (!has_zero_nibbles(tile)) {
558 if (which & 0x800) {
559 // x flipped
560 *(wwhere ) = pal[((tile & PIXEL7)>>SHIFT7)];
561 *(wwhere+1) = pal[((tile & PIXEL6)>>SHIFT6)];
562 *(wwhere+2) = pal[((tile & PIXEL5)>>SHIFT5)];
563 *(wwhere+3) = pal[((tile & PIXEL4)>>SHIFT4)];
564 *(wwhere+4) = pal[((tile & PIXEL3)>>SHIFT3)];
565 *(wwhere+5) = pal[((tile & PIXEL2)>>SHIFT2)];
566 *(wwhere+6) = pal[((tile & PIXEL1)>>SHIFT1)];
567 *(wwhere+7) = pal[((tile & PIXEL0)>>SHIFT0)];
569 else {
570 *(wwhere ) = pal[((tile & PIXEL0)>>SHIFT0)];
571 *(wwhere+1) = pal[((tile & PIXEL1)>>SHIFT1)];
572 *(wwhere+2) = pal[((tile & PIXEL2)>>SHIFT2)];
573 *(wwhere+3) = pal[((tile & PIXEL3)>>SHIFT3)];
574 *(wwhere+4) = pal[((tile & PIXEL4)>>SHIFT4)];
575 *(wwhere+5) = pal[((tile & PIXEL5)>>SHIFT5)];
576 *(wwhere+6) = pal[((tile & PIXEL6)>>SHIFT6)];
577 *(wwhere+7) = pal[((tile & PIXEL7)>>SHIFT7)];
579 return;
582 // Blit the tile!
583 if(which & 0x800) // x flipped
585 if(tile & PIXEL7) *(wwhere ) = pal[((tile & PIXEL7)>>SHIFT7)];
586 if(tile & PIXEL6) *(wwhere+1) = pal[((tile & PIXEL6)>>SHIFT6)];
587 if(tile & PIXEL5) *(wwhere+2) = pal[((tile & PIXEL5)>>SHIFT5)];
588 if(tile & PIXEL4) *(wwhere+3) = pal[((tile & PIXEL4)>>SHIFT4)];
589 if(tile & PIXEL3) *(wwhere+4) = pal[((tile & PIXEL3)>>SHIFT3)];
590 if(tile & PIXEL2) *(wwhere+5) = pal[((tile & PIXEL2)>>SHIFT2)];
591 if(tile & PIXEL1) *(wwhere+6) = pal[((tile & PIXEL1)>>SHIFT1)];
592 if(tile & PIXEL0) *(wwhere+7) = pal[((tile & PIXEL0)>>SHIFT0)];
593 } else {
594 if(tile & PIXEL0) *(wwhere ) = pal[((tile & PIXEL0)>>SHIFT0)];
595 if(tile & PIXEL1) *(wwhere+1) = pal[((tile & PIXEL1)>>SHIFT1)];
596 if(tile & PIXEL2) *(wwhere+2) = pal[((tile & PIXEL2)>>SHIFT2)];
597 if(tile & PIXEL3) *(wwhere+3) = pal[((tile & PIXEL3)>>SHIFT3)];
598 if(tile & PIXEL4) *(wwhere+4) = pal[((tile & PIXEL4)>>SHIFT4)];
599 if(tile & PIXEL5) *(wwhere+5) = pal[((tile & PIXEL5)>>SHIFT5)];
600 if(tile & PIXEL6) *(wwhere+6) = pal[((tile & PIXEL6)>>SHIFT6)];
601 if(tile & PIXEL7) *(wwhere+7) = pal[((tile & PIXEL7)>>SHIFT7)];
604 #endif // WITH_X86_TILES
606 // Draw the window (front or back)
607 void md_vdp::draw_window(int line, int front)
609 int size;
610 int x, y, w, start;
611 int pl, add;
612 int total_window;
613 unsigned char *where;
614 int which;
615 // Set everything up
616 y = line >> 3;
617 total_window = (y < (reg[18]&0x1f)) ^ (reg[18] >> 7);
619 // Wide or narrow
620 size = (reg[12] & 1)? 64 : 32;
622 pl = (reg[3] << 10) + ((y&0x3f)*size*2);
624 // Wide(320) or narrow(256)?
625 if(reg[12] & 1)
627 w = 40;
628 start = -8;
629 } else {
630 w = 32;
631 start = 24;
633 add = -2;
634 where = dest + (start * (int)Bpp);
635 for (x = -1; (x < w); ++x) {
636 if (!total_window) {
637 if (reg[17] & 0x80) {
638 if (x < ((reg[17] & 0x1f) << 1))
639 goto skip;
641 else {
642 if (x >= ((reg[17] & 0x1f) << 1))
643 goto skip;
646 which = get_word(((unsigned char *)vram) +
647 (pl + (add & ((size - 1) << 1))));
648 if ((which >> 15) == front)
649 draw_tile(which, (line & 7), where);
650 skip:
651 add += 2;
652 where += Bpp_times8;
656 inline void md_vdp::get_sprite_info(struct sprite_info& info, int index)
658 uint_fast16_t prop;
660 info.sprite = (sprite_base + (index << 3));
662 // Get the sprite's location
663 info.y = get_word(info.sprite);
664 info.x = (get_word(info.sprite + 6) & 0x1ff);
666 // Interlace?
667 // XXX
668 // "& 1" below is a workaround for a GCC (g++) <= 4.2.1 bug seen
669 // in OpenBSD.
670 // info.inter is a bit-field member of size 1 that normally cannot
671 // store anything other than 0 or 1, but which does in practice,
672 // causing info.tile to point to a bad address and crashing.
673 info.inter = ((reg[12] >> 1) & 1);
675 // Properties
676 prop = get_word(info.sprite + 4);
677 info.prio = (prop >> 15);
678 info.xflip = (prop >> 11);
679 info.yflip = (prop >> 12);
680 info.tile = (uint32_t *)(vram + ((prop & 0x07ff) << (5 + info.inter)));
682 if (info.inter)
683 info.y = ((info.y & 0x3fe) >> 1);
684 else
685 info.y &= 0x1ff;
687 info.x -= 0x80;
688 info.y -= 0x80;
690 // Narrow mode?
691 if (!(reg[12] & 1))
692 info.x += 32;
694 info.tw = (((info.sprite[2] >> 2) & 0x03) + 1);
695 info.th = ((info.sprite[2] & 0x03) + 1);
696 info.w = (info.tw << 3);
697 info.h = (info.th << 3);
700 void md_vdp::sprite_masking_overflow(int line)
702 int masking_sprite_index;
703 bool masking_effective;
704 int frame_limit;
705 int line_limit;
706 int dots;
707 int i;
710 * Search for the highest priority sprite with x = 0. Call this sprite
711 * s0. Any sprite with a lower priority than s0 (therefore higher
712 * index in the array) is not drawn on the scanlines that s0 occupies
713 * on the y-axis. This is called sprite masking and is used by games
714 * like Streets of Rage and Lotus Turbo Challenge.
716 * Thanks for Charles MacDonald for explaining this to me (vext01).
718 * This loop also limits the number of sprites per line, which is 20
719 * in H40 and 16 in H32 _or_ 320 pixels wide in H40 and 256 pixels
720 * wide in H32, with a possibility for the last sprite to be only
721 * partially drawn.
723 masking_sprite_index = -1;
724 // If sprites on the previous line overflowed, sprite masking becomes
725 // effective by default for the current line (it normally isn't).
726 masking_effective = (sprite_overflow_line == (line - 1));
727 // Set sprites and dots limits for the current line.
728 if (reg[12] & 1) {
729 frame_limit = 80;
730 line_limit = 20;
731 dots = 320;
733 else {
734 frame_limit = 64;
735 line_limit = 16;
736 dots = 256;
738 for (i = 0; i < sprite_count; i++) {
739 int x, y, w, h;
740 int idx;
741 uint8_t *sprite;
743 // First, make sure the frame limit hasn't been reached.
744 idx = sprite_order[i];
745 if (idx >= frame_limit) {
746 if (masking_sprite_index == -1)
747 masking_sprite_index = (i - 1);
748 break;
750 // Get current sprite coordinates and dimensions.
751 sprite = (sprite_base + (idx << 3));
752 x = get_word(sprite + 6) & 0x1ff;
753 y = get_word(sprite);
754 if (reg[12] & 2)
755 y = ((y & 0x3fe) >> 1);
756 else
757 y &= 0x1ff;
758 h = (((sprite[2] & 0x03) << 3) + 8);
759 w = (((sprite[2] << 1) & 0x18) + 8);
760 // If this sprite isn't found on the current line, skip it.
761 if (!(((line + 0x80) >= y) && ((line + 0x80) < (y + h))))
762 continue;
763 // Substract sprite from the dots limit and decrease the
764 // sprites limit.
765 dots -= w;
766 --line_limit;
767 // If this sprite is not a masking sprite (x != 0), sprite
768 // masking becomes effective. The next sprite with (x == 0)
769 // will be a masking sprite.
770 if (x != 0)
771 masking_effective = true;
772 // If a dot overflow occured, update sprite_overflow_line with
773 // the current line. This update must be done only once for a
774 // given line.
775 if (dots <= 0) {
776 sprite_overflow_line = line;
777 // If no masking sprite index has been set so far, do
778 // it now. Otherwise reset dots, because this sprite
779 // must not be truncated.
780 if (masking_sprite_index == -1)
781 masking_sprite_index = i;
782 else
783 dots = 0;
784 // Don't process any more sprites, exit from the loop.
785 break;
787 // Check whether sprites limit has been reached.
788 if (line_limit == 0) {
789 // If no masking sprite index has been set so far, do
790 // it now.
791 if (masking_sprite_index == -1)
792 masking_sprite_index = i;
793 // Trigger sprite overflow bit (d6).
794 belongs.coo5 |= 0x40;
795 // Don't process any more sprites, exit from the loop.
796 break;
798 // If sprite masking is effective and the current sprite is a
799 // masking sprite (x == 0), if we haven't already found one
800 // before, use this one, then continue to process the sprites
801 // list as we still need to know whether a dot overflow
802 // occured.
803 if ((masking_effective) &&
804 (x == 0) &&
805 (masking_sprite_index == -1))
806 masking_sprite_index = i;
808 // If no masking sprite index was found, display them all.
809 if (masking_sprite_index == -1)
810 masking_sprite_index = (sprite_count - 1);
811 masking_sprite_index_cache = masking_sprite_index;
812 dots_cache = dots;
815 inline void md_vdp::sprite_mask_add(uint8_t* dest, int pitch,
816 struct sprite_info& info, int value)
818 uint32_t *tile = info.tile;
819 int len = (info.tw * info.h);
820 int lines = (8 << info.inter);
821 int line = 0;
822 int wrap = 0;
823 int unit = 1;
825 dest += info.x;
826 dest += (pitch * info.y);
827 if (info.yflip) {
828 dest += (pitch * (info.h - 1));
829 pitch = -pitch;
831 if (info.xflip) {
832 dest += (info.w - 1);
833 unit = -unit;
835 while (len) {
836 uint_fast32_t dots = be2h32(*tile);
837 unsigned int tmp;
839 for (tmp = 0; (tmp != 8); ++tmp) {
840 assert(dest >= (uint8_t *)sprite_mask);
841 assert(dest < ((uint8_t *)sprite_mask +
842 sizeof(sprite_mask)));
844 * If a non-transparent sprite dot has already been
845 * drawn here, trigger the collision bit (d5).
846 * FIXME: doing this here is hackish and doesn't take
847 * sprites with the high priority bit into account.
849 if (*dest != 0xff)
850 belongs.coo5 |= 0x20;
851 #ifdef WORDS_BIGENDIAN
852 if (dots & 0x0000000f)
853 *dest = value;
854 dots >>= 4;
855 #else
856 if (dots & 0xf0000000)
857 *dest = value;
858 dots <<= 4;
859 #endif
860 dest += unit;
862 ++tile;
863 ++line;
864 if (line == lines) {
865 /* Next tile. */
866 line = 0;
867 ++wrap;
868 if (wrap == info.th) {
869 /* Next tiles column. */
870 dest -= (pitch * (info.h - 1));
871 wrap = 0;
873 else {
874 /* Next tiles row. */
875 dest += (pitch - (8 * unit));
878 else {
879 /* Next line of dots. */
880 dest -= (8 * unit);
881 dest += pitch;
883 --len;
887 void md_vdp::sprite_mask_generate()
889 int i;
891 memset(sprite_mask, 0xff, sizeof(sprite_mask));
892 for (i = (sprite_count - 1); (i >= 0); --i) {
893 sprite_info info;
895 get_sprite_info(info, sprite_order[i]);
896 // We only care about sprites with the low priority bit unset.
897 if (info.prio)
898 continue;
899 // Don't bother with hidden sprites.
900 if ((info.x >= 320) || ((info.x + info.w) < 0))
901 continue;
902 if ((info.y >= 256) || ((info.y + info.h) < 0))
903 continue;
904 info.x += 0x80;
905 info.y += 0x80;
906 // Draw overlap mask for this sprite in a 512x512 virtual area.
907 sprite_mask_add((uint8_t *)sprite_mask, sizeof(sprite_mask[0]),
908 info, i);
912 void md_vdp::draw_sprites(int line, bool front)
914 unsigned int which;
915 int tx, ty, x, y, xend, ysize, yoff, i, masking_sprite_index;
916 int dots;
917 unsigned char *where;
918 #ifdef WITH_DEBUG_VDP
919 static int ant[2];
920 static unsigned long ant_last[2];
921 unsigned long ant_cur;
923 if ((dgen_vdp_sprites_boxing) && (line == 0)) {
924 ant_cur = pd_usecs();
925 if ((ant_cur - ant_last[front]) > 100000) {
926 ant_last[front] = ant_cur;
927 ant[front] ^= 1;
930 #endif
931 masking_sprite_index = masking_sprite_index_cache;
932 dots = dots_cache;
933 // If dots_cache is less than zero, draw the first sprite partially.
934 if (dots > 0)
935 dots = 0;
936 // Sprites have to be in reverse order :P
937 for (i = masking_sprite_index; i >= 0; --i)
939 sprite_info info;
941 get_sprite_info(info, sprite_order[i]);
942 // Only do it if it's on the right priority.
943 if (info.prio == front)
945 which = get_word(info.sprite + 4);
946 // Get the sprite's location
947 y = info.y;
948 x = info.x;
949 yoff = (line - y);
950 xend = ((info.w - 8) + x);
951 // Partial draw if negative.
952 xend += dots;
953 ysize = ((info.h - 8) >> 3);
954 // Render if this sprite's on this line
955 if(xend > -8 && x < 320 && yoff >= 0 && yoff <= (ysize<<3)+7)
957 ty = yoff & 7;
958 // y flipped?
959 if(which & 0x1000)
960 which += ysize - (yoff >> 3);
961 else
962 which += (yoff >> 3);
963 ++ysize;
964 // Unconditionally draw this sprite. It's supposed to always
965 // appear on top of other sprites.
966 if (!front) {
967 // x flipped?
968 if (which & 0x800) {
969 where = dest + (xend * (int)Bpp);
970 for(tx = xend; tx >= x; tx -= 8)
972 if(tx > -8 && tx < 320)
973 draw_tile(which, ty, where);
974 which += ysize;
975 where -= Bpp_times8;
978 else {
979 where = dest + (x * (int)Bpp);
980 for(tx = x; tx <= xend; tx += 8)
982 if(tx > -8 && tx < 320)
983 draw_tile(which, ty, where);
984 which += ysize;
985 where += Bpp_times8;
989 // Draw sprite with the high priority bit set only where it's
990 // not covered by a higher priority sprite (lower index in the
991 // list) but with this bit unset. Those have already been drawn
992 // during the previous pass.
993 else {
994 union {
995 uint32_t t4[8];
996 uint24_t t3[8];
997 uint16_t t2[8];
998 uint8_t t1[8];
999 } tile;
1001 // x flipped?
1002 if (which & 0x800) {
1003 where = dest + (xend * (int)Bpp);
1004 for (tx = xend; (tx >= x); tx -= 8) {
1005 if ((tx > -8) && (tx < 320)) {
1006 int xx;
1007 int xo;
1009 memcpy(tile.t1, where, Bpp_times8);
1010 draw_tile(which, ty, tile.t1);
1011 for (xx = tx, xo = 0; (xo != 8); ++xo, ++xx)
1012 if (sprite_mask[(line + 0x80)][(xx + 0x80)] >= i)
1013 memcpy(&dest[(xx * (int)Bpp)],
1014 &tile.t1[(xo * (int)Bpp)],
1015 (int)Bpp);
1017 which += ysize;
1018 where -= Bpp_times8;
1021 else {
1022 where = dest + (x * (int)Bpp);
1023 for (tx = x; (tx <= xend); tx += 8) {
1024 if ((tx > -8) && (tx < 320)) {
1025 int xx;
1026 int xo;
1028 memcpy(tile.t1, where, Bpp_times8);
1029 draw_tile(which, ty, tile.t1);
1030 for (xx = tx, xo = 0; (xo != 8); ++xo, ++xx)
1031 if (sprite_mask[(line + 0x80)][(xx + 0x80)] >= i)
1032 memcpy(&dest[(xx * (int)Bpp)],
1033 &tile.t1[(xo * (int)Bpp)],
1034 (int)Bpp);
1036 which += ysize;
1037 where += Bpp_times8;
1041 #ifdef WITH_DEBUG_VDP
1042 if (dgen_vdp_sprites_boxing) {
1043 uint32_t color[2] = {
1044 (uint32_t)dgen_vdp_sprites_boxing_bg,
1045 (uint32_t)dgen_vdp_sprites_boxing_fg
1047 int ph;
1048 int fx;
1050 if ((ph = 0, (y == line)) ||
1051 (ph = 1, ((y + info.h - 1) == line)))
1052 for (fx = (ant[front] ^ ph); (fx < info.w); fx += 2)
1053 draw_pixel(this->bmap, (info.x + fx),
1054 line, color[info.prio]);
1055 else
1056 draw_pixel(this->bmap,
1057 (((line & 1) == ant[front]) ?
1058 (info.x + info.w - 1) : info.x),
1059 line, color[info.prio]);
1061 #endif
1064 dots = 0;
1068 // The body for the next few functions is in an extraneous header file.
1069 // Phil, I hope I left enough in this file for GLOBAL to hack it right. ;)
1070 // Thanks to John Stiles for this trick :)
1072 void md_vdp::draw_plane_back0(int line)
1074 #define FRONT 0
1075 #define PLANE 0
1076 #include "ras-drawplane.h"
1077 #undef PLANE
1078 #undef FRONT
1081 void md_vdp::draw_plane_back1(int line)
1083 #define FRONT 0
1084 #define PLANE 1
1085 #include "ras-drawplane.h"
1086 #undef PLANE
1087 #undef FRONT
1090 void md_vdp::draw_plane_front0(int line)
1092 #define FRONT 1
1093 #define PLANE 0
1094 #include "ras-drawplane.h"
1095 #undef PLANE
1096 #undef FRONT
1099 void md_vdp::draw_plane_front1(int line)
1101 #define FRONT 1
1102 #define PLANE 1
1103 #include "ras-drawplane.h"
1104 #undef PLANE
1105 #undef FRONT
1108 // Allow frame components to be hidden when WITH_DEBUG_VDP is defined.
1109 #ifdef WITH_DEBUG_VDP
1110 #define vdp_hide_if(a, b) ((a) ? (void)0 : (void)(b))
1111 #else
1112 #define vdp_hide_if(a, b) (void)(b)
1113 #endif
1115 // The main interface function, to generate a scanline
1116 void md_vdp::draw_scanline(struct bmap *bits, int line)
1118 unsigned *ptr, i;
1119 // Set the destination in the bmap
1120 bmap = bits;
1121 dest = bits->data + (bits->pitch * (line + 8) + 16);
1122 // If bytes per pixel hasn't yet been set, do it
1123 if ((Bpp == 0) || (Bpp != BITS_TO_BYTES(bits->bpp)))
1125 if(bits->bpp <= 8) Bpp = 1;
1126 else if(bits->bpp <= 16) Bpp = 2;
1127 else if(bits->bpp <= 24) Bpp = 3;
1128 else Bpp = 4;
1129 Bpp_times8 = Bpp << 3; // used for tile blitting
1130 #ifdef WITH_X86_TILES
1131 asm_tiles_init(vram, reg, highpal); // pass these values to the asm tiles
1132 #endif
1135 // If the palette's been changed, update it
1136 if(dirt[0x34] & 2)
1138 ptr = highpal;
1139 // What color depth are we?
1140 switch(bits->bpp)
1142 case 24:
1143 #ifdef WORDS_BIGENDIAN
1144 for (i = 0; (i < 128); i += 2)
1145 *ptr++ = (((cram[(i + 1)] & 0x0e) << 28) |
1146 ((cram[(i + 1)] & 0xe0) << 16) |
1147 ((cram[i] & 0x0e) << 12));
1148 break;
1149 #else
1150 for (i = 0; (i < 128); i += 2)
1151 *ptr++ = (((cram[(i + 1)] & 0x0e) << 4) |
1152 ((cram[(i + 1)] & 0xe0) << 16) |
1153 ((cram[i] & 0x0e) << 12));
1154 break;
1155 #endif
1156 case 32:
1157 for(i = 0; i < 128; i += 2)
1158 *ptr++ = ((cram[i+1]&0x0e) << 20) |
1159 ((cram[i+1]&0xe0) << 8 ) |
1160 ((cram[i] &0x0e) << 4 );
1161 break;
1162 case 16:
1163 for(i = 0; i < 128; i += 2)
1164 *ptr++ = ((cram[i+1]&0x0e) << 12) |
1165 ((cram[i+1]&0xe0) << 3 ) |
1166 ((cram[i] &0x0e) << 1 );
1167 break;
1168 case 15:
1169 for(i = 0; i < 128; i += 2)
1170 *ptr++ = ((cram[i+1]&0x0e) << 11) |
1171 ((cram[i+1]&0xe0) << 2 ) |
1172 ((cram[i] &0x0e) << 1 );
1173 break;
1174 case 8:
1175 default:
1176 // Let the hardware palette sort it out :P
1177 for(i = 0; i < 64; ++i) *ptr++ = i;
1179 // Clean up the dirt
1180 dirt[0x34] &= ~2;
1181 pal_dirty = 1;
1183 // Render the screen if it's turned on
1184 if(reg[1] & 0x40)
1186 // Recalculate the sprite order, if it's dirty
1187 if((dirt[0x30] & 0x20) || (dirt[0x34] & 1))
1189 unsigned next = 0;
1190 // Max number of sprites per frame: 80 in H40, 64 in H32.
1191 int max = ((reg[12] & 1) ? 80 : 64);
1192 // Find the sprite base in VRAM
1193 sprite_base = vram + (reg[5]<<9);
1194 // Order the sprites
1195 sprite_count = sprite_order[0] = 0;
1196 do {
1197 next = sprite_base[(next << 3) + 3];
1198 sprite_order[++sprite_count] = next;
1199 } while (next && sprite_count < max);
1200 // Clean up the dirt
1201 dirt[0x30] &= ~0x20; dirt[0x34] &= ~1;
1202 // Generate overlap mask for sprites with high priority bit
1203 sprite_mask_generate();
1205 // Calculate sprite masking and overflow.
1206 sprite_masking_overflow(line);
1207 // Draw, from the bottom up
1208 // Low priority
1209 vdp_hide_if(dgen_vdp_hide_plane_b, draw_plane_back1(line));
1210 vdp_hide_if(dgen_vdp_hide_plane_a, draw_plane_back0(line));
1211 vdp_hide_if(dgen_vdp_hide_plane_w, draw_window(line, 0));
1212 vdp_hide_if(dgen_vdp_hide_sprites, draw_sprites(line, 0));
1213 // High priority
1214 vdp_hide_if(dgen_vdp_hide_plane_b, draw_plane_front1(line));
1215 vdp_hide_if(dgen_vdp_hide_plane_a, draw_plane_front0(line));
1216 vdp_hide_if(dgen_vdp_hide_plane_w, draw_window(line, 1));
1217 vdp_hide_if(dgen_vdp_hide_sprites, draw_sprites(line, 1));
1218 } else {
1219 // The display is off, paint it black
1220 // Do it a dword at a time
1221 unsigned *destl = (unsigned*)dest;
1222 for(i = 0; i < (80 * Bpp); ++i) destl[i] = 0;
1225 // If we're in narrow (256) mode, cut off the messy edges
1226 if(!(reg[12] & 1))
1228 unsigned *destl = (unsigned*)dest;
1229 for(i = 0; i < Bpp_times8; ++i)
1230 destl[i] = destl[i + (72 * Bpp)] = 0;
1234 void md_vdp::draw_pixel(struct bmap *bits, int x, int y, uint32_t rgb)
1236 uint8_t *out;
1238 if ((x < 0) || (x >= bits->w) || (y < 0) || (y >= bits->h))
1239 return;
1240 out = ((bits->data + (bits->pitch * (y + 8) + 16)) +
1241 (x * BITS_TO_BYTES(bits->bpp)));
1242 switch (bits->bpp) {
1243 uint16_t tmp;
1245 case 32:
1246 memcpy(out, &rgb, sizeof(rgb));
1247 break;
1248 case 24:
1249 u24cpy((uint24_t *)out,
1250 (const uint24_t *)((uint8_t *)&rgb + 1));
1251 break;
1252 case 16:
1253 tmp = (((rgb >> 5) & 0xf800) |
1254 ((rgb >> 3) & 0x07e0) |
1255 (rgb & 0x1f));
1256 memcpy(out, &tmp, sizeof(tmp));
1257 break;
1258 case 15:
1259 tmp = (((rgb >> 6) & 0x7c00) |
1260 ((rgb >> 3) & 0x03e0) |
1261 (rgb & 0x1f));
1262 memcpy(out, &tmp, sizeof(tmp));
1263 break;