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.
7 
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"
17 
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;
21 
22 // Macros, to route draw_tile and draw_tile_solid to the right handler
23 #define draw_tile(which, line, where) \
24 	switch(Bpp)\
25 	  {\
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;\
34 	  }
35 
36 #define draw_tile_solid(which, line, where) \
37 	switch(Bpp)\
38 	  {\
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;\
47 	  }
48 
49 // Silly utility function, get a big-endian word
50 #ifdef WORDS_BIGENDIAN
get_word(unsigned char * where)51 static inline int get_word(unsigned char *where)
52   { return (int)(*(unsigned short*)where); }
53 #else
get_word(unsigned char * where)54 static inline int get_word(unsigned char *where)
55   { return (where[0] << 8) | where[1]; }
56 #endif
57 
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
94 
95 #ifdef WITH_X86_TILES
96 extern "C" {
97 
98 void asm_tiles_init(unsigned char *vram,
99 		    unsigned char *reg,
100 		    unsigned *highpal);
101 
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);
110 }
111 
112 // Pass off these calls to assembler counterparts
draw_tile1_solid(int which,int line,unsigned char * where)113 inline void md_vdp::draw_tile1_solid(int which, int line, unsigned char *where)
114   { drawtile1_solid(which, line, where); }
115 
draw_tile1(int which,int line,unsigned char * where)116 inline void md_vdp::draw_tile1(int which, int line, unsigned char *where)
117   { drawtile1(which, line, where); }
118 
draw_tile2_solid(int which,int line,unsigned char * where)119 inline void md_vdp::draw_tile2_solid(int which, int line, unsigned char *where)
120   { drawtile2_solid(which, line, where); }
121 
draw_tile2(int which,int line,unsigned char * where)122 inline void md_vdp::draw_tile2(int which, int line, unsigned char *where)
123   { drawtile2(which, line, where); }
124 
draw_tile3_solid(int which,int line,unsigned char * where)125 inline void md_vdp::draw_tile3_solid(int which, int line, unsigned char *where)
126   { drawtile3_solid(which, line, where); }
127 
draw_tile3(int which,int line,unsigned char * where)128 inline void md_vdp::draw_tile3(int which, int line, unsigned char *where)
129   { drawtile3(which, line, where); }
130 
draw_tile4_solid(int which,int line,unsigned char * where)131 inline void md_vdp::draw_tile4_solid(int which, int line, unsigned char *where)
132   { drawtile4_solid(which, line, where); }
133 
draw_tile4(int which,int line,unsigned char * where)134 inline void md_vdp::draw_tile4(int which, int line, unsigned char *where)
135   { drawtile4(which, line, where); }
136 
137 #else // WITH_X86_TILES
138 
has_zero_nibbles(uint32_t u32)139 static bool has_zero_nibbles(uint32_t u32)
140 {
141 	return ((u32 - 0x11111111) & ~u32 & 0x88888888);
142 }
143 
144 // Blit tile solidly, for 1 byte-per-pixel
draw_tile1_solid(int which,int line,unsigned char * where)145 inline void md_vdp::draw_tile1_solid(int which, int line, unsigned char *where)
146 {
147   unsigned tile, pal;
148 
149   pal = (which >> 9 & 0x30); // Determine which 16-color palette
150 
151   if(which & 0x1000) // y flipped
152     line ^= 7; // take from the bottom, instead of the top
153 
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));
158 
159   // Blit the tile!
160   if(which & 0x800) // x flipped
161     {
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;
179     }
180 }
181 
182 // Blit tile, leaving color zero transparent, for 1 byte per pixel
draw_tile1(int which,int line,unsigned char * where)183 inline void md_vdp::draw_tile1(int which, int line, unsigned char *where)
184 {
185   unsigned tile, pal;
186 
187   pal = (which >> 9 & 0x30); // Determine which 16-color palette
188 
189   if(which & 0x1000) // y flipped
190     line ^= 7; // take from the bottom, instead of the top
191 
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;
198 
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;
211     }
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;
221     }
222     return;
223   }
224 
225   // Blit the tile!
226   if(which & 0x800) // x flipped
227     {
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;
245     }
246 }
247 
248 // Blit tile solidly, for 2 byte-per-pixel
draw_tile2_solid(int which,int line,unsigned char * where)249 inline void md_vdp::draw_tile2_solid(int which, int line, unsigned char *where)
250 {
251   unsigned tile, temp, *pal;
252   unsigned short *wwhere = (unsigned short*)where;
253 
254   pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
255   temp = *pal; *pal = highpal[reg[7]&0x3f]; // Get background color
256 
257   if(which & 0x1000) // y flipped
258     line ^= 7; // take from the bottom, instead of the top
259 
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));
264 
265   // Blit the tile!
266   if(which & 0x800) // x flipped
267     {
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)];
285     }
286   // Restore the original color
287   *pal = temp;
288 }
289 
290 // Blit tile, leaving color zero transparent, for 2 byte per pixel
draw_tile2(int which,int line,unsigned char * where)291 inline void md_vdp::draw_tile2(int which, int line, unsigned char *where)
292 {
293   unsigned tile, *pal;
294   unsigned short *wwhere = (unsigned short*)where;
295 
296   pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
297 
298   if(which & 0x1000) // y flipped
299     line ^= 7; // take from the bottom, instead of the top
300 
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;
307 
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)];
320     }
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)];
330     }
331     return;
332   }
333 
334   // Blit the tile!
335   if(which & 0x800) // x flipped
336     {
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)];
354     }
355 }
356 
draw_tile3_solid(int which,int line,unsigned char * where)357 inline void md_vdp::draw_tile3_solid(int which, int line, unsigned char *where)
358 {
359   unsigned tile, temp, *pal;
360   uint24_t *wwhere = (uint24_t *)where;
361 
362   pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
363   temp = *pal; *pal = highpal[reg[7]&0x3f]; // Get background color
364 
365   if(which & 0x1000) // y flipped
366     line ^= 7; // take from the bottom, instead of the top
367 
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));
372 
373   // Blit the tile!
374   if(which & 0x800) // x flipped
375     {
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)]);
393     }
394   // Restore the original color
395   *pal = temp;
396 }
397 
draw_tile3(int which,int line,unsigned char * where)398 inline void md_vdp::draw_tile3(int which, int line, unsigned char *where)
399 {
400   unsigned tile, *pal;
401   uint24_t *wwhere = (uint24_t *)where;
402 
403   pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
404 
405   if(which & 0x1000) // y flipped
406     line ^= 7; // take from the bottom, instead of the top
407 
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;
414 
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)]);
427     }
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)]);
437     }
438     return;
439   }
440 
441   // Blit the tile!
442   if(which & 0x800) // x flipped
443     {
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)]);
493     }
494 }
495 
496 // Blit tile solidly, for 4 byte-per-pixel
draw_tile4_solid(int which,int line,unsigned char * where)497 inline void md_vdp::draw_tile4_solid(int which, int line, unsigned char *where)
498 {
499   unsigned tile, temp, *pal;
500   unsigned *wwhere = (unsigned*)where;
501 
502   pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
503   temp = *pal; *pal = highpal[reg[7]&0x3f]; // Get background color
504 
505   if(which & 0x1000) // y flipped
506     line ^= 7; // take from the bottom, instead of the top
507 
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));
512 
513   // Blit the tile!
514   if(which & 0x800) // x flipped
515     {
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)];
533     }
534   // Restore the original color
535   *pal = temp;
536 }
537 
538 // Blit tile, leaving color zero transparent, for 4 byte per pixel
draw_tile4(int which,int line,unsigned char * where)539 inline void md_vdp::draw_tile4(int which, int line, unsigned char *where)
540 {
541   unsigned tile, *pal;
542   unsigned *wwhere = (unsigned*)where;
543 
544   pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
545 
546   if(which & 0x1000) // y flipped
547     line ^= 7; // take from the bottom, instead of the top
548 
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;
555 
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)];
568     }
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)];
578     }
579     return;
580   }
581 
582   // Blit the tile!
583   if(which & 0x800) // x flipped
584     {
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)];
602     }
603 }
604 #endif // WITH_X86_TILES
605 
606 // Draw the window (front or back)
draw_window(int line,int front)607 void md_vdp::draw_window(int line, int front)
608 {
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);
618 
619   // Wide or narrow
620   size = (reg[12] & 1)? 64 : 32;
621 
622   pl = (reg[3] << 10) + ((y&0x3f)*size*2);
623 
624   // Wide(320) or narrow(256)?
625   if(reg[12] & 1)
626     {
627       w = 40;
628       start = -8;
629     } else {
630       w = 32;
631       start = 24;
632     }
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;
640 			}
641 			else {
642 				if (x >= ((reg[17] & 0x1f) << 1))
643 					goto skip;
644 			}
645 		}
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;
653 	}
654 }
655 
get_sprite_info(struct sprite_info & info,int index)656 inline void md_vdp::get_sprite_info(struct sprite_info& info, int index)
657 {
658 	uint_fast16_t prop;
659 
660 	info.sprite = (sprite_base + (index << 3));
661 
662 	// Get the sprite's location
663 	info.y = get_word(info.sprite);
664 	info.x = (get_word(info.sprite + 6) & 0x1ff);
665 
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);
674 
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)));
681 
682 	if (info.inter)
683 		info.y = ((info.y & 0x3fe) >> 1);
684 	else
685 		info.y &= 0x1ff;
686 
687 	info.x -= 0x80;
688 	info.y -= 0x80;
689 
690 	// Narrow mode?
691 	if (!(reg[12] & 1))
692 		info.x += 32;
693 
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);
698 }
699 
sprite_masking_overflow(int line)700 void md_vdp::sprite_masking_overflow(int line)
701 {
702 	int masking_sprite_index;
703 	bool masking_effective;
704 	int frame_limit;
705 	int line_limit;
706 	int dots;
707 	int i;
708 
709 	/*
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.
715 	 *
716 	 * Thanks for Charles MacDonald for explaining this to me (vext01).
717 	 *
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.
722 	 */
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;
732 	}
733 	else {
734 		frame_limit = 64;
735 		line_limit = 16;
736 		dots = 256;
737 	}
738 	for (i = 0; i < sprite_count; i++) {
739 		int x, y, w, h;
740 		int idx;
741 		uint8_t *sprite;
742 
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;
749 		}
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;
786 		}
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;
797 		}
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;
807 	}
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;
813 }
814 
sprite_mask_add(uint8_t * dest,int pitch,struct sprite_info & info,int value)815 inline void md_vdp::sprite_mask_add(uint8_t* dest, int pitch,
816 				    struct sprite_info& info, int value)
817 {
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;
824 
825 	dest += info.x;
826 	dest += (pitch * info.y);
827 	if (info.yflip) {
828 		dest += (pitch * (info.h - 1));
829 		pitch = -pitch;
830 	}
831 	if (info.xflip) {
832 		dest += (info.w - 1);
833 		unit = -unit;
834 	}
835 	while (len) {
836 		uint_fast32_t dots = be2h32(*tile);
837 		unsigned int tmp;
838 
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)));
843 			/*
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.
848 			 */
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;
861 		}
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;
872 			}
873 			else {
874 				/* Next tiles row. */
875 				dest += (pitch - (8 * unit));
876 			}
877 		}
878 		else {
879 			/* Next line of dots. */
880 			dest -= (8 * unit);
881 			dest += pitch;
882 		}
883 		--len;
884 	}
885 }
886 
sprite_mask_generate()887 void md_vdp::sprite_mask_generate()
888 {
889 	int i;
890 
891 	memset(sprite_mask, 0xff, sizeof(sprite_mask));
892 	for (i = (sprite_count - 1); (i >= 0); --i) {
893 		sprite_info info;
894 
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);
909 	}
910 }
911 
draw_sprites(int line,bool front)912 void md_vdp::draw_sprites(int line, bool front)
913 {
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;
922 
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;
928     }
929   }
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)
938     {
939       sprite_info info;
940 
941       get_sprite_info(info, sprite_order[i]);
942       // Only do it if it's on the right priority.
943       if (info.prio == front)
944 	{
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)
956 	    {
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)
971 		    {
972 		      if(tx > -8 && tx < 320)
973 			draw_tile(which, ty, where);
974 		      which += ysize;
975 		      where -= Bpp_times8;
976 		    }
977 	        }
978 		else {
979 		  where = dest + (x * (int)Bpp);
980 		  for(tx = x; tx <= xend; tx += 8)
981 		    {
982 		      if(tx > -8 && tx < 320)
983 			draw_tile(which, ty, where);
984 		      which += ysize;
985 		      where += Bpp_times8;
986 		    }
987 		}
988 	      }
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;
1000 
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;
1008 
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);
1016 		    }
1017 		    which += ysize;
1018 		    where -= Bpp_times8;
1019 		  }
1020 	        }
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;
1027 
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);
1035 		    }
1036 		    which += ysize;
1037 		    where += Bpp_times8;
1038 		  }
1039 		}
1040 	      }
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
1046 		};
1047 		int ph;
1048 		int fx;
1049 
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]);
1060 	      }
1061 #endif
1062 	    }
1063 	}
1064       dots = 0;
1065     }
1066 }
1067 
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 :)
1071 
draw_plane_back0(int line)1072 void md_vdp::draw_plane_back0(int line)
1073 {
1074 #define FRONT 0
1075 #define PLANE 0
1076 #include "ras-drawplane.h"
1077 #undef PLANE
1078 #undef FRONT
1079 }
1080 
draw_plane_back1(int line)1081 void md_vdp::draw_plane_back1(int line)
1082 {
1083 #define FRONT 0
1084 #define PLANE 1
1085 #include "ras-drawplane.h"
1086 #undef PLANE
1087 #undef FRONT
1088 }
1089 
draw_plane_front0(int line)1090 void md_vdp::draw_plane_front0(int line)
1091 {
1092 #define FRONT 1
1093 #define PLANE 0
1094 #include "ras-drawplane.h"
1095 #undef PLANE
1096 #undef FRONT
1097 }
1098 
draw_plane_front1(int line)1099 void md_vdp::draw_plane_front1(int line)
1100 {
1101 #define FRONT 1
1102 #define PLANE 1
1103 #include "ras-drawplane.h"
1104 #undef PLANE
1105 #undef FRONT
1106 }
1107 
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
1114 
1115 // The main interface function, to generate a scanline
draw_scanline(struct bmap * bits,int line)1116 void md_vdp::draw_scanline(struct bmap *bits, int line)
1117 {
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)))
1124     {
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
1133     }
1134 
1135   // If the palette's been changed, update it
1136   if(dirt[0x34] & 2)
1137     {
1138       ptr = highpal;
1139       // What color depth are we?
1140       switch(bits->bpp)
1141         {
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;
1178 	}
1179       // Clean up the dirt
1180       dirt[0x34] &= ~2;
1181       pal_dirty = 1;
1182     }
1183   // Render the screen if it's turned on
1184   if(reg[1] & 0x40)
1185     {
1186       // Recalculate the sprite order, if it's dirty
1187       if((dirt[0x30] & 0x20) || (dirt[0x34] & 1))
1188 	{
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();
1204 	}
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;
1223     }
1224 
1225   // If we're in narrow (256) mode, cut off the messy edges
1226   if(!(reg[12] & 1))
1227     {
1228       unsigned *destl = (unsigned*)dest;
1229       for(i = 0; i < Bpp_times8; ++i)
1230         destl[i] = destl[i + (72 * Bpp)] = 0;
1231     }
1232 }
1233 
draw_pixel(struct bmap * bits,int x,int y,uint32_t rgb)1234 void md_vdp::draw_pixel(struct bmap *bits, int x, int y, uint32_t rgb)
1235 {
1236 	uint8_t *out;
1237 
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;
1244 
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;
1264 	}
1265 }
1266