1 //---------------------------------------------------------------------------
2 // NEOPOP : Emulator as in Dreamland
3 //
4 // Copyright (c) 2001-2002 by neopop_uk
5 //---------------------------------------------------------------------------
6
7 //---------------------------------------------------------------------------
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version. See also the license.txt file for
12 // additional informations.
13 //---------------------------------------------------------------------------
14
15 #include <stdlib.h>
16 #include <string.h>
17 #include <math.h>
18
19 #include "neopop.h"
20 #include "mem.h"
21 #include "gfx.h"
22 #include "interrupt.h"
23 #include "dma.h"
24 #include "TLCS-900h/TLCS900h_registers.h"
25 #include "../state.h"
26 #include "../video.h"
27 #ifdef MSB_FIRST
28 #include "../masmem.h"
29 #endif
30
31 static const unsigned char mirrored[] = {
32 0x00, 0x40, 0x80, 0xc0, 0x10, 0x50, 0x90, 0xd0,
33 0x20, 0x60, 0xa0, 0xe0, 0x30, 0x70, 0xb0, 0xf0,
34 0x04, 0x44, 0x84, 0xc4, 0x14, 0x54, 0x94, 0xd4,
35 0x24, 0x64, 0xa4, 0xe4, 0x34, 0x74, 0xb4, 0xf4,
36 0x08, 0x48, 0x88, 0xc8, 0x18, 0x58, 0x98, 0xd8,
37 0x28, 0x68, 0xa8, 0xe8, 0x38, 0x78, 0xb8, 0xf8,
38 0x0c, 0x4c, 0x8c, 0xcc, 0x1c, 0x5c, 0x9c, 0xdc,
39 0x2c, 0x6c, 0xac, 0xec, 0x3c, 0x7c, 0xbc, 0xfc,
40 0x01, 0x41, 0x81, 0xc1, 0x11, 0x51, 0x91, 0xd1,
41 0x21, 0x61, 0xa1, 0xe1, 0x31, 0x71, 0xb1, 0xf1,
42 0x05, 0x45, 0x85, 0xc5, 0x15, 0x55, 0x95, 0xd5,
43 0x25, 0x65, 0xa5, 0xe5, 0x35, 0x75, 0xb5, 0xf5,
44 0x09, 0x49, 0x89, 0xc9, 0x19, 0x59, 0x99, 0xd9,
45 0x29, 0x69, 0xa9, 0xe9, 0x39, 0x79, 0xb9, 0xf9,
46 0x0d, 0x4d, 0x8d, 0xcd, 0x1d, 0x5d, 0x9d, 0xdd,
47 0x2d, 0x6d, 0xad, 0xed, 0x3d, 0x7d, 0xbd, 0xfd,
48 0x02, 0x42, 0x82, 0xc2, 0x12, 0x52, 0x92, 0xd2,
49 0x22, 0x62, 0xa2, 0xe2, 0x32, 0x72, 0xb2, 0xf2,
50 0x06, 0x46, 0x86, 0xc6, 0x16, 0x56, 0x96, 0xd6,
51 0x26, 0x66, 0xa6, 0xe6, 0x36, 0x76, 0xb6, 0xf6,
52 0x0a, 0x4a, 0x8a, 0xca, 0x1a, 0x5a, 0x9a, 0xda,
53 0x2a, 0x6a, 0xaa, 0xea, 0x3a, 0x7a, 0xba, 0xfa,
54 0x0e, 0x4e, 0x8e, 0xce, 0x1e, 0x5e, 0x9e, 0xde,
55 0x2e, 0x6e, 0xae, 0xee, 0x3e, 0x7e, 0xbe, 0xfe,
56 0x03, 0x43, 0x83, 0xc3, 0x13, 0x53, 0x93, 0xd3,
57 0x23, 0x63, 0xa3, 0xe3, 0x33, 0x73, 0xb3, 0xf3,
58 0x07, 0x47, 0x87, 0xc7, 0x17, 0x57, 0x97, 0xd7,
59 0x27, 0x67, 0xa7, 0xe7, 0x37, 0x77, 0xb7, 0xf7,
60 0x0b, 0x4b, 0x8b, 0xcb, 0x1b, 0x5b, 0x9b, 0xdb,
61 0x2b, 0x6b, 0xab, 0xeb, 0x3b, 0x7b, 0xbb, 0xfb,
62 0x0f, 0x4f, 0x8f, 0xcf, 0x1f, 0x5f, 0x9f, 0xdf,
63 0x2f, 0x6f, 0xaf, 0xef, 0x3f, 0x7f, 0xbf, 0xff
64 };
65
drawColourPattern(ngpgfx_t * gfx,uint16_t * cfb_scanline,uint8_t * zbuffer,uint8 screenx,uint16 tile,uint8 tiley,uint16 mirror,uint16 * palette_ptr,uint8 pal,uint8 depth)66 static void drawColourPattern(ngpgfx_t *gfx, uint16_t *cfb_scanline, uint8_t *zbuffer,
67 uint8 screenx, uint16 tile, uint8 tiley, uint16 mirror,
68 uint16* palette_ptr, uint8 pal, uint8 depth)
69 {
70 uint16_t *ptr16;
71 int index, left, right, highmark, xx;
72 int x = screenx;
73 if (x > 0xf8)
74 x -= 256;
75 if (x >= SCREEN_WIDTH)
76 return;
77
78 /* Get the data for the "tiley'th" line of "tile". */
79 ptr16 = (uint16_t*)(gfx->CharacterRAM + (tile * 16) + (tiley * 2));
80 #ifdef MSB_FIRST
81 index = LoadU16_RBO(ptr16);
82 #else
83 index = *ptr16;
84 #endif
85
86 /* Horizontal Flip */
87 if (mirror)
88 index = mirrored[(index & 0xff00)>>8] | (mirrored[(index & 0xff)] << 8);
89
90 palette_ptr += pal << 2;
91 left = MAX(MAX(x, gfx->winx), 0);
92 right = x+7;
93
94 highmark = MIN(gfx->winw + gfx->winx, SCREEN_WIDTH)-1;
95
96 if (right > highmark)
97 {
98 index >>= (right - highmark)*2;
99 right = highmark;
100 }
101
102 for (xx = right; xx>=left; --xx,index>>=2)
103 {
104 uint16_t data16;
105 uint16_t *scan = &cfb_scanline[xx];
106 uint8_t *zbuf = &zbuffer[xx];
107 if (depth <= *zbuf || (index&3)==0)
108 continue;
109 *zbuf = depth;
110
111 /* Get the colour of the pixel */
112 ptr16 = (uint16_t*)&palette_ptr[index&3];
113
114 #ifdef MSB_FIRST
115 data16 = LoadU16_RBO(ptr16);
116 #else
117 data16 = *ptr16;
118 #endif
119 if (gfx->negative)
120 data16 = ~data16;
121
122 *scan = data16;
123 }
124 }
125
draw_colour_scroll1(ngpgfx_t * gfx,uint16_t * cfb_scanline,uint8_t * zbuffer,uint8 depth,int ngpc_scanline)126 static void draw_colour_scroll1(ngpgfx_t *gfx,
127 uint16_t *cfb_scanline,
128 uint8_t *zbuffer, uint8 depth, int ngpc_scanline)
129 {
130 unsigned i;
131 uint8_t line = ngpc_scanline + gfx->scroll1y;
132 uint8_t row = line & 7; /* Which row? */
133
134 /* Draw Foreground scroll plane (Scroll 1) */
135 for (i = 0; i < 32; i++)
136 {
137 uint16_t *ptr16 = (uint16_t*)(gfx->ScrollVRAM + ((i + ((line >> 3) << 5)) << 1));
138 #ifdef MSB_FIRST
139 uint16_t data16 = LoadU16_RBO(ptr16);
140 #else
141 uint16_t data16 = *ptr16;
142 #endif
143
144 /* Draw the line of the tile */
145 drawColourPattern(gfx, cfb_scanline, zbuffer, (i << 3) - gfx->scroll1x, data16 & 0x01FF,
146 (data16 & 0x4000) ? (7 - row) : row, data16 & 0x8000, (uint16_t*)(gfx->ColorPaletteRAM + 0x0080),
147 (data16 & 0x1E00) >> 9, depth);
148 }
149 }
150
draw_colour_scroll2(ngpgfx_t * gfx,uint16_t * cfb_scanline,uint8_t * zbuffer,uint8 depth,int ngpc_scanline)151 static void draw_colour_scroll2(ngpgfx_t *gfx, uint16_t *cfb_scanline,
152 uint8_t *zbuffer, uint8 depth, int ngpc_scanline)
153 {
154 unsigned i;
155 uint8_t line = ngpc_scanline + gfx->scroll2y;
156 uint8_t row = line & 7; /* Which row? */
157
158 /* Draw Background scroll plane (Scroll 2) */
159 for (i = 0; i < 32; i++)
160 {
161 uint16_t *ptr16 = (uint16_t*)(gfx->ScrollVRAM + 0x0800 + ((i + ((line >> 3) << 5)) << 1));
162 #ifdef MSB_FIRST
163 uint16_t data16 = LoadU16_RBO(ptr16);
164 #else
165 uint16_t data16 = *ptr16;
166 #endif
167
168 /* Draw the line of the tile */
169 drawColourPattern(gfx, cfb_scanline, zbuffer, (i << 3) - gfx->scroll2x, data16 & 0x01FF,
170 (data16 & 0x4000) ? (7 - row) : row, data16 & 0x8000, (uint16_t*)(gfx->ColorPaletteRAM + 0x0100),
171 (data16 & 0x1E00) >> 9, depth);
172 }
173 }
174
draw_scanline_colour(ngpgfx_t * gfx,uint16_t * cfb_scanline,int layer_enable,int ngpc_scanline)175 static void draw_scanline_colour(ngpgfx_t *gfx, uint16_t *cfb_scanline,
176 int layer_enable, int ngpc_scanline)
177 {
178 int16_t lastSpriteX;
179 int16_t lastSpriteY;
180 int spr;
181 uint16_t *scan;
182 int x = 0;
183 uint8_t zbuffer[256] = {0};
184 /* Window colour */
185 uint16_t *ptr16 = (uint16_t*)(gfx->ColorPaletteRAM + 0x01F0 + (gfx->oowc << 1));
186 #ifdef MSB_FIRST
187 uint16_t data16 = LoadU16_RBO(ptr16);
188 #else
189 uint16_t data16 = *ptr16;
190 #endif
191 if (gfx->negative)
192 data16 = ~data16;
193
194 scan = &cfb_scanline[0];
195
196 /* Middle */
197 if (!(ngpc_scanline < gfx->winy) && ngpc_scanline < gfx->winy + gfx->winh)
198 {
199 for (x = 0; x < MIN(gfx->winx, SCREEN_WIDTH); x++)
200 *scan++ = data16;
201
202 x = MIN(gfx->winx + gfx->winw, SCREEN_WIDTH);
203 scan = &cfb_scanline[x];
204 }
205
206 /*Bottom and Top */
207 for (; x < SCREEN_WIDTH; x++)
208 *scan++ = data16;
209
210 /* Ignore above and below the window's top and bottom */
211
212 if (ngpc_scanline >= gfx->winy && ngpc_scanline < gfx->winy + gfx->winh)
213 {
214 int x;
215 uint16_t *scan;
216 uint16_t *ptr16 = (uint16_t*)(uint8*)(gfx->ColorPaletteRAM + 0x01E0 + ((gfx->bgc & 7) << 1));
217 #ifdef MSB_FIRST
218 data16 = LoadU16_RBO(ptr16);
219 #else
220 data16 = *ptr16;
221 #endif
222
223 if (gfx->negative)
224 data16 = ~data16;
225
226 data16 = data16;
227
228 x = gfx->winx;
229 scan = &cfb_scanline[x];
230
231 /*Draw background */
232 for (; x < MIN(gfx->winx + gfx->winw, SCREEN_WIDTH); x++)
233 *scan++ = data16;
234
235 /*Swap Front/Back scroll planes? */
236 if (gfx->planeSwap)
237 {
238 if(layer_enable & 1)
239 draw_colour_scroll1(gfx, cfb_scanline, zbuffer, ZDEPTH_BACKGROUND_SCROLL, ngpc_scanline); /* Swap */
240 if(layer_enable & 2)
241 draw_colour_scroll2(gfx, cfb_scanline, zbuffer, ZDEPTH_FOREGROUND_SCROLL, ngpc_scanline);
242 }
243 else
244 {
245 if(layer_enable & 1)
246 draw_colour_scroll2(gfx, cfb_scanline, zbuffer, ZDEPTH_BACKGROUND_SCROLL, ngpc_scanline); /* Normal */
247 if(layer_enable & 2)
248 draw_colour_scroll1(gfx, cfb_scanline, zbuffer, ZDEPTH_FOREGROUND_SCROLL, ngpc_scanline);
249 }
250
251 /* Draw Sprites */
252 /*Last sprite position, (defaults to top-left, sure?) */
253 lastSpriteX = 0;
254 lastSpriteY = 0;
255
256 if(layer_enable & 4)
257 for (spr = 0; spr < 64; spr++)
258 {
259 uint8_t sx = gfx->SpriteVRAM[(spr * 4) + 2]; /* X position */
260 uint8_t sy = gfx->SpriteVRAM[(spr * 4) + 3]; /* Y position */
261 int16_t x = sx;
262 int16_t y = sy;
263 uint16_t *ptr16 = (uint16_t*)(gfx->SpriteVRAM + (spr * 4));
264 #ifdef MSB_FIRST
265 uint16_t data16 = LoadU16_RBO(ptr16);
266 #else
267 uint16_t data16 = *ptr16;
268 #endif
269 uint8_t priority = (data16 & 0x1800) >> 11;
270
271 if (data16 & 0x0400)
272 x = lastSpriteX + sx; /* Horizontal chain? */
273 if (data16 & 0x0200)
274 y = lastSpriteY + sy; /* Vertical chain? */
275
276 /* Store the position for chaining */
277 lastSpriteX = x;
278 lastSpriteY = y;
279
280 /* Visible? */
281 if (priority == 0)
282 continue;
283
284 /* Scroll the sprite */
285 x += gfx->scrollsprx;
286 y += gfx->scrollspry;
287
288 /* Off-screen? */
289 if (x > 248 && x < 256)
290 x = x - 256;
291 else
292 x &= 0xFF;
293 if (y > 248 && y < 256)
294 y = y - 256;
295 else
296 y &= 0xFF;
297
298 /* In range? */
299 if (ngpc_scanline >= y && ngpc_scanline <= y + 7)
300 {
301 uint8_t row = (ngpc_scanline - y) & 7; /* Which row? */
302 drawColourPattern(gfx, cfb_scanline, zbuffer, (uint8)x, data16 & 0x01FF,
303 (data16 & 0x4000) ? 7 - row : row, data16 & 0x8000,
304 (uint16_t*)gfx->ColorPaletteRAM, gfx->SpriteVRAMColor[spr] & 0xF, priority << 1);
305 }
306 }
307 }
308 }
309
MonoPlot(ngpgfx_t * gfx,uint16_t * cfb_scanline,uint8_t * zbuffer,uint8 x,uint8 * palette_ptr,uint16 pal_hi,uint8 index,uint8 depth)310 static void MonoPlot(ngpgfx_t *gfx, uint16_t *cfb_scanline, uint8_t *zbuffer,
311 uint8 x, uint8* palette_ptr, uint16 pal_hi, uint8 index, uint8 depth)
312 {
313 uint16 r, g, b;
314 uint8_t data8, *zbuf;
315 uint16_t *scan, data16;
316
317 /* Clip */
318 if (index == 0 || x < gfx->winx || x >= (gfx->winw + gfx->winx) || x >= SCREEN_WIDTH)
319 return;
320
321 zbuf = &zbuffer[x];
322
323 /*Depth check, <= to stop later sprites overwriting pixels! */
324 if (depth <= *zbuf)
325 return;
326 *zbuf = depth;
327
328 /*Get the colour of the pixel */
329 data8 = palette_ptr[(pal_hi ? 3 : 0) + index - 1];
330
331 r = (data8 & 7) << 1;
332 g = (data8 & 7) << 5;
333 b = (data8 & 7) << 9;
334
335 scan = &cfb_scanline[x];
336 data16 = ~(r | g | b);
337 if (gfx->negative)
338 data16 = ~(data16);
339
340 *scan++ = data16;
341 }
342
drawMonoPattern(ngpgfx_t * gfx,uint16_t * cfb_scanline,uint8_t * zbuffer,uint8 screenx,uint16 tile,uint8 tiley,uint16 mirror,uint8 * palette_ptr,uint16 pal,uint8 depth)343 static void drawMonoPattern(ngpgfx_t *gfx,
344 uint16_t *cfb_scanline, uint8_t *zbuffer, uint8 screenx, uint16 tile, uint8 tiley, uint16 mirror,
345 uint8* palette_ptr, uint16 pal, uint8 depth)
346 {
347 /* Get the data for th e "tiley'th" line of "tile". */
348 uint16_t *ptr16 = (uint16_t*)(gfx->CharacterRAM + (tile * 16) + (tiley * 2));
349 #ifdef MSB_FIRST
350 uint16_t data = LoadU16_RBO(ptr16);
351 #else
352 uint16_t data = *ptr16;
353 #endif
354
355 if (mirror)
356 {
357 /* Horizontal Flip */
358 MonoPlot(gfx, cfb_scanline, zbuffer, screenx + 7, palette_ptr, pal, (data & 0xC000) >> 0xE, depth);
359 MonoPlot(gfx, cfb_scanline, zbuffer, screenx + 6, palette_ptr, pal, (data & 0x3000) >> 0xC, depth);
360 MonoPlot(gfx, cfb_scanline, zbuffer, screenx + 5, palette_ptr, pal, (data & 0x0C00) >> 0xA, depth);
361 MonoPlot(gfx, cfb_scanline, zbuffer, screenx + 4, palette_ptr, pal, (data & 0x0300) >> 0x8, depth);
362 MonoPlot(gfx, cfb_scanline, zbuffer, screenx + 3, palette_ptr, pal, (data & 0x00C0) >> 0x6, depth);
363 MonoPlot(gfx, cfb_scanline, zbuffer, screenx + 2, palette_ptr, pal, (data & 0x0030) >> 0x4, depth);
364 MonoPlot(gfx, cfb_scanline, zbuffer, screenx + 1, palette_ptr, pal, (data & 0x000C) >> 0x2, depth);
365 MonoPlot(gfx, cfb_scanline, zbuffer, screenx + 0, palette_ptr, pal, (data & 0x0003) >> 0x0, depth);
366 }
367 else
368 {
369 /*Normal */
370 MonoPlot(gfx, cfb_scanline, zbuffer, screenx + 0, palette_ptr, pal, (data & 0xC000) >> 0xE, depth);
371 MonoPlot(gfx, cfb_scanline, zbuffer, screenx + 1, palette_ptr, pal, (data & 0x3000) >> 0xC, depth);
372 MonoPlot(gfx, cfb_scanline, zbuffer, screenx + 2, palette_ptr, pal, (data & 0x0C00) >> 0xA, depth);
373 MonoPlot(gfx, cfb_scanline, zbuffer, screenx + 3, palette_ptr, pal, (data & 0x0300) >> 0x8, depth);
374 MonoPlot(gfx, cfb_scanline, zbuffer, screenx + 4, palette_ptr, pal, (data & 0x00C0) >> 0x6, depth);
375 MonoPlot(gfx, cfb_scanline, zbuffer, screenx + 5, palette_ptr, pal, (data & 0x0030) >> 0x4, depth);
376 MonoPlot(gfx, cfb_scanline, zbuffer, screenx + 6, palette_ptr, pal, (data & 0x000C) >> 0x2, depth);
377 MonoPlot(gfx, cfb_scanline, zbuffer, screenx + 7, palette_ptr, pal, (data & 0x0003) >> 0x0, depth);
378 }
379 }
380
draw_mono_scroll1(ngpgfx_t * gfx,uint16_t * cfb_scanline,uint8_t * zbuffer,uint8 depth,int ngpc_scanline)381 static void draw_mono_scroll1(ngpgfx_t *gfx, uint16_t *cfb_scanline,
382 uint8_t *zbuffer, uint8 depth, int ngpc_scanline)
383 {
384 unsigned i;
385 uint8_t line = ngpc_scanline + gfx->scroll1y;
386 uint8_t row = line & 7; /* Which row? */
387
388 /* Draw Foreground scroll plane (Scroll 1) */
389 for (i = 0; i < 32; i++)
390 {
391 uint16_t *ptr16 = (uint16_t*)(gfx->ScrollVRAM + ((i + ((line >> 3) << 5)) << 1));
392 #ifdef MSB_FIRST
393 uint16_t data16 = LoadU16_RBO(ptr16);
394 #else
395 uint16_t data16 = *ptr16;
396 #endif
397
398 //Draw the line of the tile
399 drawMonoPattern(gfx, cfb_scanline, zbuffer, (i << 3) - gfx->scroll1x, data16 & 0x01FF,
400 (data16 & 0x4000) ? 7 - row : row, data16 & 0x8000, gfx->SCRP1PLT,
401 data16 & 0x2000, depth);
402 }
403 }
404
draw_mono_scroll2(ngpgfx_t * gfx,uint16_t * cfb_scanline,uint8_t * zbuffer,uint8 depth,int ngpc_scanline)405 static void draw_mono_scroll2(ngpgfx_t *gfx, uint16_t *cfb_scanline, uint8_t *zbuffer, uint8 depth, int ngpc_scanline)
406 {
407 unsigned i;
408 uint8_t line = ngpc_scanline + gfx->scroll2y;
409 uint8_t row = line & 7; //Which row?
410
411 /* Draw Background scroll plane (Scroll 2) */
412 for (i = 0; i < 32; i++)
413 {
414 uint16_t *ptr16 = (uint16_t*)(gfx->ScrollVRAM + 0x0800 + ((i + ((line >> 3) << 5)) << 1));
415 #ifdef MSB_FIRST
416 uint16_t data16 = LoadU16_RBO(ptr16);
417 #else
418 uint16_t data16 = *ptr16;
419 #endif
420
421 /* Draw the line of the tile */
422 drawMonoPattern(gfx, cfb_scanline, zbuffer, (i << 3) - gfx->scroll2x, data16 & 0x01FF,
423 (data16 & 0x4000) ? 7 - row : row, data16 & 0x8000, gfx->SCRP2PLT,
424 data16 & 0x2000, depth);
425 }
426 }
427
draw_scanline_mono(ngpgfx_t * gfx,uint16_t * cfb_scanline,int layer_enable,int ngpc_scanline)428 static void draw_scanline_mono(ngpgfx_t *gfx,
429 uint16_t *cfb_scanline, int layer_enable, int ngpc_scanline)
430 {
431 int x;
432 uint16_t *scan;
433 int16_t lastSpriteX;
434 int16_t lastSpriteY;
435 int spr;
436 uint8_t zbuffer[256] = {0};
437
438 /* Window colour */
439 uint16_t r = (uint16)gfx->oowc << 1;
440 uint16_t g = (uint16)gfx->oowc << 5;
441 uint16_t b = (uint16)gfx->oowc << 9;
442 uint16_t data16 = ~(r | g | b);
443
444 if (gfx->negative)
445 data16 = ~data16;
446
447 x = 0;
448 scan = &cfb_scanline[x];
449
450 /* Middle */
451 if (!(ngpc_scanline < gfx->winy) && ngpc_scanline < gfx->winy + gfx->winh)
452 {
453 for (; x < MIN(gfx->winx, SCREEN_WIDTH); x++)
454 *scan++ = data16;
455
456 x = MIN(gfx->winx + gfx->winw, SCREEN_WIDTH);
457 }
458
459 /* Bottom and Top */
460 for (; x < SCREEN_WIDTH; x++)
461 *scan++ = data16;
462
463 /* Ignore above and below the window's top and bottom */
464 if (ngpc_scanline >= gfx->winy && ngpc_scanline < gfx->winy + gfx->winh)
465 {
466 int x;
467 uint16_t *scan;
468
469 data16 = 0x0FFF;
470
471 /* Background colour Enabled? */
472 if ((gfx->bgc & 0xC0) == 0x80)
473 {
474 r = (uint16)(gfx->bgc & 7) << 1;
475 g = (uint16)(gfx->bgc & 7) << 5;
476 b = (uint16)(gfx->bgc & 7) << 9;
477 data16 = ~(r | g | b);
478 }
479
480 if (gfx->negative)
481 data16 = ~data16;
482
483 x = gfx->winx;
484 scan = &cfb_scanline[x];
485
486 /* Draw background */
487 for (; x < MIN(gfx->winx + gfx->winw, SCREEN_WIDTH); x++)
488 *scan++ = data16;
489
490 /* Swap Front/Back scroll planes? */
491 if (gfx->planeSwap)
492 {
493 if(layer_enable & 1)
494 draw_mono_scroll1(gfx, cfb_scanline, zbuffer, ZDEPTH_BACKGROUND_SCROLL, ngpc_scanline); //Swap
495 if(layer_enable & 2)
496 draw_mono_scroll2(gfx, cfb_scanline, zbuffer, ZDEPTH_FOREGROUND_SCROLL, ngpc_scanline);
497 }
498 else
499 {
500 if(layer_enable & 1)
501 draw_mono_scroll2(gfx, cfb_scanline, zbuffer, ZDEPTH_BACKGROUND_SCROLL, ngpc_scanline); //Normal
502 if(layer_enable & 2)
503 draw_mono_scroll1(gfx, cfb_scanline, zbuffer, ZDEPTH_FOREGROUND_SCROLL, ngpc_scanline);
504 }
505
506 /* Draw Sprites */
507 /* Last sprite position, (defaults to top-left, sure?) */
508 lastSpriteX = 0;
509 lastSpriteY = 0;
510 if(layer_enable & 4)
511 for (spr = 0; spr < 64; spr++)
512 {
513 uint8_t priority, row;
514 uint8_t sx = gfx->SpriteVRAM[(spr * 4) + 2]; //X position
515 uint8_t sy = gfx->SpriteVRAM[(spr * 4) + 3]; //Y position
516 int16_t x = sx;
517 int16_t y = sy;
518 uint16_t *ptr16 = (uint16_t*)(gfx->SpriteVRAM + (spr * 4));
519
520 #ifdef MSB_FIRST
521 data16 = LoadU16_RBO(ptr16);
522 #else
523 data16 = *ptr16;
524 #endif
525 priority = (data16 & 0x1800) >> 11;
526
527 if (data16 & 0x0400)
528 x = lastSpriteX + sx; //Horizontal chain?
529 if (data16 & 0x0200)
530 y = lastSpriteY + sy; //Vertical chain?
531
532 //Store the position for chaining
533 lastSpriteX = x;
534 lastSpriteY = y;
535
536 //Visible?
537 if (priority == 0)
538 continue;
539
540 //Scroll the sprite
541 x += gfx->scrollsprx;
542 y += gfx->scrollspry;
543
544 //Off-screen?
545 if (x > 248 && x < 256) x = x - 256; else x &= 0xFF;
546 if (y > 248 && y < 256) y = y - 256; else y &= 0xFF;
547
548 //In range?
549 if (ngpc_scanline >= y && ngpc_scanline <= y + 7)
550 {
551 row = (ngpc_scanline - y) & 7; //Which row?
552 drawMonoPattern(gfx, cfb_scanline, zbuffer, (uint8)x, data16 & 0x01FF,
553 (data16 & 0x4000) ? 7 - row : row, data16 & 0x8000,
554 gfx->SPPLT, data16 & 0x2000, priority << 1);
555 }
556 }
557
558 }
559 }
560
ngpgfx_delayed_settings(ngpgfx_t * gfx)561 static void ngpgfx_delayed_settings(ngpgfx_t *gfx)
562 {
563 //Window dimensions
564 gfx->winx = gfx->WBA_H;
565 gfx->winy = gfx->WBA_V;
566 gfx->winw = gfx->WSI_H;
567 gfx->winh = gfx->WSI_V;
568
569 /* Scroll Planes (Confirmed delayed) */
570 gfx->scroll1x = gfx->S1SO_H;
571 gfx->scroll1y = gfx->S1SO_V;
572
573 gfx->scroll2x = gfx->S2SO_H;
574 gfx->scroll2y = gfx->S2SO_V;
575
576 /* Sprite offset (Confirmed delayed) */
577 gfx->scrollsprx = gfx->PO_H;
578 gfx->scrollspry = gfx->PO_V;
579
580 /* Plane Priority (Confirmed delayed) */
581 gfx->planeSwap = gfx->P_F & 0x80;
582
583 /* Background colour register (Confirmed delayed) */
584 gfx->bgc = gfx->BG_COL;
585
586 /* 2D Control register (Confirmed delayed) */
587 gfx->oowc = gfx->CONTROL_2D & 7;
588 gfx->negative = gfx->CONTROL_2D & 0x80;
589 }
590
ngpgfx_reset(ngpgfx_t * gfx)591 void ngpgfx_reset(ngpgfx_t *gfx)
592 {
593 memset(gfx->SPPLT, 0x7, sizeof(gfx->SPPLT));
594 memset(gfx->SCRP1PLT, 0x7, sizeof(gfx->SCRP1PLT));
595 memset(gfx->SCRP2PLT, 0x7, sizeof(gfx->SCRP2PLT));
596
597 gfx->raster_line = 0;
598 gfx->S1SO_H = 0;
599 gfx->S1SO_V = 0;
600 gfx->S2SO_H = 0;
601 gfx->S2SO_V = 0;
602 gfx->WBA_H = 0;
603 gfx->WBA_V = 0;
604
605 gfx->WSI_H = 0xFF;
606 gfx->WSI_V = 0xFF;
607
608 gfx->C_OVR = 0;
609 gfx->BLNK = 0;
610
611 gfx->PO_H = 0;
612 gfx->PO_V = 0;
613 gfx->P_F = 0;
614
615 gfx->BG_COL = 0x7;
616 gfx->CONTROL_2D = 0;
617 gfx->CONTROL_INT = 0;
618 gfx->SCREEN_PERIOD = 0xC6;
619 gfx->K2GE_MODE = 0;
620
621 ngpgfx_delayed_settings(gfx);
622 }
623
ngpgfx_power(ngpgfx_t * gfx)624 void ngpgfx_power(ngpgfx_t *gfx)
625 {
626 ngpgfx_reset(gfx);
627
628 memset(gfx->ScrollVRAM, 0, sizeof(gfx->ScrollVRAM));
629 memset(gfx->CharacterRAM, 0, sizeof(gfx->CharacterRAM));
630 memset(gfx->SpriteVRAM, 0, sizeof(gfx->SpriteVRAM));
631 memset(gfx->SpriteVRAMColor, 0, sizeof(gfx->SpriteVRAMColor));
632 memset(gfx->ColorPaletteRAM, 0, sizeof(gfx->ColorPaletteRAM));
633 }
634
635
ngpgfx_hint(ngpgfx_t * gfx)636 bool ngpgfx_hint(ngpgfx_t *gfx)
637 {
638 /* H_Int / Delayed settings */
639 if ((gfx->raster_line < SCREEN_HEIGHT-1 || gfx->raster_line == gfx->SCREEN_PERIOD))
640 {
641 /* Get delayed settings */
642 ngpgfx_delayed_settings(gfx);
643
644 /* Allowed? */
645 if (gfx->CONTROL_INT & 0x40)
646 return 1;
647 }
648
649 return 0;
650 }
651
ngpgfx_set_pixel_format(ngpgfx_t * gfx,int depth)652 void ngpgfx_set_pixel_format(ngpgfx_t *gfx, int depth)
653 {
654 unsigned i;
655
656 for(i = 0; i < 4096; i++)
657 {
658 int r = (i & 0xF) * 17;
659 int g = ((i >> 4) & 0xF) * 17;
660 int b = ((i >> 8) & 0xF) * 17;
661
662 switch(depth)
663 {
664 case 15: gfx->ColorMap[i] = MAKECOLOR_15(r, g, b, 0); break;
665 case 16: gfx->ColorMap[i] = MAKECOLOR_16(r, g, b, 0); break;
666 default: gfx->ColorMap[i] = MAKECOLOR_24(r, g, b, 0); break;
667 }
668 }
669 }
670
ngpgfx_draw(ngpgfx_t * gfx,void * data,bool skip)671 bool ngpgfx_draw(ngpgfx_t *gfx, void *data, bool skip)
672 {
673 unsigned x;
674 bool ret = 0;
675 MDFN_Surface *surface = (MDFN_Surface*)data;
676
677 /* Draw the scanline */
678 if (gfx->raster_line < SCREEN_HEIGHT && !skip)
679 {
680 uint16_t cfb_scanline[256];
681
682 if (!gfx->K2GE_MODE)
683 draw_scanline_colour(gfx, cfb_scanline, gfx->layer_enable, gfx->raster_line);
684 else
685 draw_scanline_mono(gfx, cfb_scanline, gfx->layer_enable, gfx->raster_line);
686
687 switch (surface->depth)
688 {
689 case 15:
690 case 16: {
691 uint16_t *dest = surface->pixels + surface->pitch * gfx->raster_line;
692
693 for (x = 0; x < SCREEN_WIDTH; x++)
694 dest[x] = gfx->ColorMap[cfb_scanline[x] & 4095];
695 } break;
696
697 case 24: {
698 uint32_t *dest = ((uint32_t *) surface->pixels) + surface->pitch * gfx->raster_line;
699
700 for (x = 0; x < SCREEN_WIDTH; x++)
701 dest[x] = gfx->ColorMap[cfb_scanline[x] & 4095];
702 } break;
703 }
704 }
705 gfx->raster_line++;
706
707 /* V_Int? */
708 if (gfx->raster_line == SCREEN_HEIGHT)
709 {
710 gfx->BLNK = 1;
711 ret = 1;
712
713 if(gfx->CONTROL_INT & 0x80) /* (statusIFF() <= 4 */
714 TestIntHDMA(5, 0x0B);
715 }
716
717 /* End of V_Int */
718 if(gfx->raster_line == gfx->SCREEN_PERIOD + 1)
719 {
720 /* Last scanline + 1 */
721 gfx->raster_line = 0;
722 gfx->C_OVR = 0;
723 gfx->BLNK = 0;
724 }
725
726 return ret;
727 }
728
ngpgfx_StateAction(ngpgfx_t * gfx,void * data,int load,int data_only)729 int ngpgfx_StateAction(ngpgfx_t *gfx, void *data, int load, int data_only)
730 {
731 StateMem *sm = (StateMem*)data;
732 SFORMAT StateRegs[] =
733 {
734 { &(gfx->raster_line), sizeof(gfx->raster_line), 0x80000000, "raster_line" },
735 { &(gfx->S1SO_H), (uint32_t)(sizeof(gfx->S1SO_H)), 0x80000000, "S1SO_H" },
736 { &(gfx->S1SO_V), (uint32_t)(sizeof(gfx->S1SO_V)), 0x80000000, "S1SO_V" },
737 { &(gfx->S2SO_H), (uint32_t)(sizeof(gfx->S2SO_H)), 0x80000000, "S2SO_H" },
738 { &(gfx->S2SO_V), (uint32_t)(sizeof(gfx->S2SO_V)), 0x80000000, "S2SO_V" },
739 { &(gfx->WBA_H), (uint32_t)(sizeof(gfx->WBA_H)), 0x80000000, "WBA_H" },
740 { &(gfx->WBA_V), (uint32_t)(sizeof(gfx->WBA_V)), 0x80000000, "WBA_V" },
741 { &(gfx->WSI_H), (uint32_t)(sizeof(gfx->WSI_H)), 0x80000000, "WSI_H" },
742 { &(gfx->WSI_V), (uint32_t)(sizeof(gfx->WSI_V)), 0x80000000, "WSI_V" },
743 { &(gfx->C_OVR), (uint32_t)1, 0x80000000 | 0x08000000, "C_OVR" },
744 { &(gfx->BLNK), (uint32_t)1, 0x80000000 | 0x08000000, "BLNK" },
745 { &(gfx->PO_H), (uint32_t)(sizeof(gfx->PO_H)), 0x80000000, "PO_H" },
746 { &(gfx->PO_V), (uint32_t)(sizeof(gfx->PO_V)), 0x80000000, "PO_V" },
747 { &(gfx->P_F), (uint32_t)(sizeof(gfx->P_F)), 0x80000000, "P_F" },
748 { &(gfx->BG_COL), (uint32_t)(sizeof(gfx->BG_COL)), 0x80000000, "BG_COL" },
749 { &(gfx->CONTROL_2D), (uint32_t)(sizeof(gfx->CONTROL_2D)), 0x80000000, "CONTROL_2D" },
750 { &(gfx->CONTROL_INT), (uint32_t)(sizeof(gfx->CONTROL_INT)), 0x80000000, "CONTROL_INT" },
751 { &(gfx->SCREEN_PERIOD), (uint32_t)(sizeof(gfx->SCREEN_PERIOD)), 0x80000000, "SCREEN_PERIOD" },
752 { &(gfx->K2GE_MODE), (uint32_t)(sizeof(gfx->K2GE_MODE)), 0x80000000, "K2GE_MODE" },
753
754 { (gfx->SPPLT), (uint32_t)(6), 0, "SPPLT" },
755 { (gfx->SCRP1PLT), (uint32_t)(6), 0, "SCRP1PLT" },
756 { (gfx->SCRP2PLT), (uint32_t)(6), 0, "SCRP2PLT" },
757
758 { &(gfx->winx), (uint32_t)(sizeof(gfx->winx)), 0x80000000, "winx" },
759 { &(gfx->winw), (uint32_t)(sizeof(gfx->winw)), 0x80000000, "winw" },
760 { &(gfx->winy), (uint32_t)(sizeof(gfx->winy)), 0x80000000, "winy" },
761 { &(gfx->winh), (uint32_t)(sizeof(gfx->winh)), 0x80000000, "winh" },
762 { &(gfx->scroll1x), (uint32_t)(sizeof(gfx->scroll1x)), 0x80000000, "scroll1x" },
763 { &(gfx->scroll1y), (uint32_t)(sizeof(gfx->scroll1y)), 0x80000000, "scroll1y" },
764 { &(gfx->scroll2x), (uint32_t)(sizeof(gfx->scroll2x)), 0x80000000, "scroll2x" },
765 { &(gfx->scroll2y), (uint32_t)(sizeof(gfx->scroll2y)), 0x80000000, "scroll2y" },
766 { &(gfx->scrollsprx), (uint32_t)(sizeof(gfx->scrollsprx)), 0x80000000, "scrollsprx" },
767 { &(gfx->scrollspry), (uint32_t)(sizeof(gfx->scrollspry)), 0x80000000, "scrollspry" },
768 { &(gfx->planeSwap), (uint32_t)(sizeof(gfx->planeSwap)), 0x80000000, "planeSwap" },
769 { &(gfx->bgc), (uint32_t)(sizeof(gfx->bgc)), 0x80000000, "bgc" },
770 { &(gfx->oowc), (uint32_t)(sizeof(gfx->oowc)), 0x80000000, "oowc" },
771
772 { &(gfx->negative), (uint32_t)(sizeof(gfx->negative)), 0x80000000, "negative" },
773
774 { (gfx->ScrollVRAM), (uint32_t)(4096), 0, "ScrollVRAM" },
775 { (gfx->CharacterRAM), (uint32_t)(8192), 0, "CharacterRAM" },
776 { (gfx->SpriteVRAM), (uint32_t)(256), 0, "SpriteVRAM" },
777 { (gfx->SpriteVRAMColor), (uint32_t)(0x40), 0, "SpriteVRAMColor" },
778 { (gfx->ColorPaletteRAM), (uint32_t)(0x200), 0, "ColorPaletteRAM" },
779
780 { 0, 0, 0, 0 }
781 };
782
783 if(!MDFNSS_StateAction(sm, load, data_only, StateRegs, "GFX", false))
784 return(0);
785
786 return(1);
787 }
788
ngpgfx_SetLayerEnableMask(ngpgfx_t * gfx,uint64_t mask)789 void ngpgfx_SetLayerEnableMask(ngpgfx_t *gfx, uint64_t mask)
790 {
791 gfx->layer_enable = mask;
792 }
793
ngpgfx_write8(ngpgfx_t * gfx,uint32 address,uint8 data)794 void ngpgfx_write8(ngpgfx_t *gfx, uint32 address, uint8 data)
795 {
796 if(address >= 0x9000 && address <= 0x9fff)
797 gfx->ScrollVRAM[address - 0x9000] = data;
798 else if(address >= 0xa000 && address <= 0xbfff)
799 gfx->CharacterRAM[address - 0xa000] = data;
800 else if(address >= 0x8800 && address <= 0x88ff)
801 gfx->SpriteVRAM[address - 0x8800] = data;
802 else if(address >= 0x8c00 && address <= 0x8c3f)
803 gfx->SpriteVRAMColor[address - 0x8c00] = data & 0x0f;
804 else if(address >= 0x8200 && address <= 0x83ff)
805 gfx->ColorPaletteRAM[address - 0x8200] = data;
806 else switch(address)
807 {
808 case 0x8000:
809 gfx->CONTROL_INT = data & 0xC0;
810 break;
811 case 0x8002:
812 gfx->WBA_H = data;
813 break;
814 case 0x8003:
815 gfx->WBA_V = data;
816 break;
817 case 0x8004:
818 gfx->WSI_H = data;
819 break;
820 case 0x8005:
821 gfx->WSI_V = data;
822 break;
823 case 0x8006:
824 gfx->SCREEN_PERIOD = data;
825 break;
826 case 0x8012:
827 gfx->CONTROL_2D = data & 0x87;
828 break;
829 case 0x8020:
830 gfx->PO_H = data;
831 break;
832 case 0x8021:
833 gfx->PO_V = data;
834 break;
835 case 0x8030:
836 gfx->P_F = data & 0x80;
837 break;
838 case 0x8032:
839 gfx->S1SO_H = data;
840 break;
841 case 0x8033:
842 gfx->S1SO_V = data;
843 break;
844 case 0x8034:
845 gfx->S2SO_H = data;
846 break;
847 case 0x8035:
848 gfx->S2SO_V = data;
849 break;
850 case 0x8101:
851 gfx->SPPLT[0] = data & 0x7;
852 break;
853 case 0x8102:
854 gfx->SPPLT[1] = data & 0x7;
855 break;
856 case 0x8103:
857 gfx->SPPLT[2] = data & 0x7;
858 break;
859 case 0x8105:
860 gfx->SPPLT[3] = data & 0x7;
861 break;
862 case 0x8106:
863 gfx->SPPLT[4] = data & 0x7;
864 break;
865 case 0x8107:
866 gfx->SPPLT[5] = data & 0x7;
867 break;
868 case 0x8109:
869 gfx->SCRP1PLT[0] = data & 0x7;
870 break;
871 case 0x810a:
872 gfx->SCRP1PLT[1] = data & 0x7;
873 break;
874 case 0x810b:
875 gfx->SCRP1PLT[2] = data & 0x7;
876 break;
877 case 0x810d:
878 gfx->SCRP1PLT[3] = data & 0x7;
879 break;
880 case 0x810e:
881 gfx->SCRP1PLT[4] = data & 0x7;
882 break;
883 case 0x810f:
884 gfx->SCRP1PLT[5] = data & 0x7;
885 break;
886 case 0x8111:
887 gfx->SCRP2PLT[0] = data & 0x7;
888 break;
889 case 0x8112:
890 gfx->SCRP2PLT[1] = data & 0x7;
891 break;
892 case 0x8113:
893 gfx->SCRP2PLT[2] = data & 0x7;
894 break;
895
896 case 0x8115:
897 gfx->SCRP2PLT[3] = data & 0x7;
898 break;
899 case 0x8116:
900 gfx->SCRP2PLT[4] = data & 0x7;
901 break;
902 case 0x8117:
903 gfx->SCRP2PLT[5] = data & 0x7;
904 break;
905
906 case 0x8118:
907 gfx->BG_COL = data & 0xC7;
908 break;
909
910 case 0x87e0:
911 if(data == 0x52)
912 {
913 /* GEreset */
914 neopop_reset();
915 }
916 break;
917 case 0x87e2:
918 gfx->K2GE_MODE = data & 0x80;
919 break;
920 }
921 }
922
ngpgfx_write16(ngpgfx_t * gfx,uint32 address,uint16 data)923 void ngpgfx_write16(ngpgfx_t *gfx, uint32 address, uint16 data)
924 {
925 ngpgfx_write8(gfx, address, data & 0xFF);
926 ngpgfx_write8(gfx, address + 1, data >> 8);
927 }
928
ngpgfx_read8(ngpgfx_t * gfx,uint32_t address)929 uint8_t ngpgfx_read8(ngpgfx_t *gfx, uint32_t address)
930 {
931 if(address >= 0x9000 && address <= 0x9fff)
932 return(gfx->ScrollVRAM[address - 0x9000]);
933 else if(address >= 0xa000 && address <= 0xbfff)
934 return(gfx->CharacterRAM[address - 0xa000]);
935 else if(address >= 0x8800 && address <= 0x88ff)
936 return(gfx->SpriteVRAM[address - 0x8800]);
937 else if(address >= 0x8c00 && address <= 0x8c3f)
938 return(gfx->SpriteVRAMColor[address - 0x8c00]);
939 else if(address >= 0x8200 && address <= 0x83ff)
940 return(gfx->ColorPaletteRAM[address - 0x8200]);
941 else switch(address)
942 {
943 case 0x8000:
944 return gfx->CONTROL_INT;
945 case 0x8002:
946 return gfx->WBA_H;
947 case 0x8003:
948 return gfx->WBA_V;
949 case 0x8004:
950 return gfx->WSI_H;
951 case 0x8005:
952 return gfx->WSI_V;
953 case 0x8006:
954 return gfx->SCREEN_PERIOD;
955 case 0x8008:
956 return( (uint8)((abs(TIMER_HINT_RATE - (int)timer_hint)) >> 2) ); //RAS.H read (Simulated horizontal raster position)
957 case 0x8009:
958 return gfx->raster_line;
959 case 0x8010:
960 return((gfx->C_OVR ? 0x80 : 0x00) | (gfx->BLNK ? 0x40 : 0x00));
961 case 0x8012:
962 return gfx->CONTROL_2D;
963 case 0x8020:
964 return gfx->PO_H;
965 case 0x8021:
966 return gfx->PO_V;
967 case 0x8030:
968 return gfx->P_F;
969 case 0x8032:
970 return gfx->S1SO_H;
971 case 0x8033:
972 return gfx->S1SO_V;
973 case 0x8034:
974 return gfx->S2SO_H;
975 case 0x8035:
976 return gfx->S2SO_V;
977 case 0x8101:
978 return gfx->SPPLT[0];
979 case 0x8102:
980 return gfx->SPPLT[1];
981 case 0x8103:
982 return gfx->SPPLT[2];
983 case 0x8105:
984 return gfx->SPPLT[3];
985 case 0x8106:
986 return gfx->SPPLT[4];
987 case 0x8107:
988 return gfx->SPPLT[5];
989 case 0x8108:
990 return gfx->SCRP1PLT[0];
991 case 0x8109:
992 return gfx->SCRP1PLT[1];
993 case 0x810a:
994 return gfx->SCRP1PLT[2];
995 case 0x810d:
996 return gfx->SCRP1PLT[3];
997 case 0x810e:
998 return gfx->SCRP1PLT[4];
999 case 0x810f:
1000 return gfx->SCRP1PLT[5];
1001 case 0x8111:
1002 return gfx->SCRP2PLT[0];
1003 case 0x8112:
1004 return gfx->SCRP2PLT[1];
1005 case 0x8113:
1006 return gfx->SCRP2PLT[2];
1007 case 0x8115:
1008 return gfx->SCRP2PLT[3];
1009 case 0x8116:
1010 return gfx->SCRP2PLT[4];
1011 case 0x8117:
1012 return gfx->SCRP2PLT[5];
1013 case 0x8118:
1014 return(gfx->BG_COL);
1015 case 0x87e2:
1016 return(gfx->K2GE_MODE);
1017 }
1018
1019 return 0;
1020 }
1021
ngpgfx_read16(ngpgfx_t * gfx,uint32_t address)1022 uint16_t ngpgfx_read16(ngpgfx_t *gfx, uint32_t address)
1023 {
1024 uint16_t ret;
1025
1026 ret = ngpgfx_read8(gfx, address);
1027 ret |= ngpgfx_read8(gfx, address + 1) << 8;
1028
1029 return(ret);
1030 }
1031
1032