1 /* Copyright 2003-2004 Guillaume Duhamel
2 Copyright 2004-2008 Theo Berkau
3 Copyright 2006 Fabien Coulon
4 Copyright 2015 R. Danbrook
5
6 This file is part of Yabause.
7
8 Yabause 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.
12
13 Yabause is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Yabause; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 /*! \file vidsoft.c
24 \brief Software video renderer interface.
25 */
26
27 #include "vidsoft.h"
28 #include "ygl.h"
29 #include "vidshared.h"
30 #include "debug.h"
31 #include "vdp2.h"
32 #include "titan/titan.h"
33
34 #ifdef HAVE_LIBGL
35 #define USE_OPENGL
36 #endif
37
38 #ifdef USE_OPENGL
39 #include "ygl.h"
40 #endif
41
42 #include "yui.h"
43 #include "threads.h"
44
45 #include <stdlib.h>
46 #include <limits.h>
47
48 #if defined WORDS_BIGENDIAN
COLSAT2YAB16(int priority,u32 temp)49 static INLINE u32 COLSAT2YAB16(int priority,u32 temp) { return (priority | (temp & 0x7C00) << 1 | (temp & 0x3E0) << 14 | (temp & 0x1F) << 27); }
COLSAT2YAB32(int priority,u32 temp)50 static INLINE u32 COLSAT2YAB32(int priority,u32 temp) { return (((temp & 0xFF) << 24) | ((temp & 0xFF00) << 8) | ((temp & 0xFF0000) >> 8) | priority); }
COLSAT2YAB32_2(int priority,u32 temp1,u32 temp2)51 static INLINE u32 COLSAT2YAB32_2(int priority,u32 temp1,u32 temp2) { return (((temp2 & 0xFF) << 24) | ((temp2 & 0xFF00) << 8) | ((temp1 & 0xFF) << 8) | priority); }
COLSATSTRIPPRIORITY(u32 pixel)52 static INLINE u32 COLSATSTRIPPRIORITY(u32 pixel) { return (pixel | 0xFF); }
53 #else
COLSAT2YAB16(int priority,u32 temp)54 static INLINE u32 COLSAT2YAB16(int priority,u32 temp) { return (priority << 24 | (temp & 0x1F) << 3 | (temp & 0x3E0) << 6 | (temp & 0x7C00) << 9); }
COLSAT2YAB32(int priority,u32 temp)55 static INLINE u32 COLSAT2YAB32(int priority, u32 temp) { return (priority << 24 | (temp & 0xFF0000) | (temp & 0xFF00) | (temp & 0xFF)); }
COLSAT2YAB32_2(int priority,u32 temp1,u32 temp2)56 static INLINE u32 COLSAT2YAB32_2(int priority,u32 temp1,u32 temp2) { return (priority << 24 | ((temp1 & 0xFF) << 16) | (temp2 & 0xFF00) | (temp2 & 0xFF)); }
COLSATSTRIPPRIORITY(u32 pixel)57 static INLINE u32 COLSATSTRIPPRIORITY(u32 pixel) { return (0xFF000000 | pixel); }
58 #endif
59
60 #define COLOR_ADDt(b) (b>0xFF?0xFF:(b<0?0:b))
61 #define COLOR_ADDb(b1,b2) COLOR_ADDt((signed) (b1) + (b2))
62 #ifdef WORDS_BIGENDIAN
63 #define COLOR_ADD(l,r,g,b) (l & 0xFF) | \
64 (COLOR_ADDb((l >> 8) & 0xFF, b) << 8) | \
65 (COLOR_ADDb((l >> 16) & 0xFF, g) << 16) | \
66 (COLOR_ADDb((l >> 24), r) << 24)
67 #else
68 #define COLOR_ADD(l,r,g,b) COLOR_ADDb((l & 0xFF), r) | \
69 (COLOR_ADDb((l >> 8) & 0xFF, g) << 8) | \
70 (COLOR_ADDb((l >> 16) & 0xFF, b) << 16) | \
71 (l & 0xFF000000)
72 #endif
73
74
75 int VIDSoftInit(void);
76 int VIDSoftSetupGL(void);
77 void VIDSoftDeInit(void);
78 void VIDSoftResize(unsigned int, unsigned int, int);
79 int VIDSoftIsFullscreen(void);
80 int VIDSoftVdp1Reset(void);
81 void VIDSoftVdp1DrawStart(void);
82 void VIDSoftVdp1DrawEnd(void);
83 void VIDSoftVdp1NormalSpriteDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer);
84 void VIDSoftVdp1ScaledSpriteDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer);
85 void VIDSoftVdp1DistortedSpriteDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer);
86 void VIDSoftVdp1PolygonDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer);
87 void VIDSoftVdp1PolylineDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer);
88 void VIDSoftVdp1LineDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer);
89 void VIDSoftVdp1UserClipping(u8 * ram, Vdp1 * regs);
90 void VIDSoftVdp1SystemClipping(u8 * ram, Vdp1 * regs);
91 void VIDSoftVdp1LocalCoordinate(u8 * ram, Vdp1 * regs);
92 void VIDSoftVdp1ReadFrameBuffer(u32 type, u32 addr, void * out);
93 void VIDSoftVdp1WriteFrameBuffer(u32 type, u32 addr, u32 val);
94 int VIDSoftVdp2Reset(void);
95 void VIDSoftVdp2DrawStart(void);
96 void VIDSoftVdp2DrawEnd(void);
97 void VIDSoftVdp2DrawScreens(void);
98 void VIDSoftVdp2SetResolution(u16 TVMD);
99 void VIDSoftGetGlSize(int *width, int *height);
100 void VIDSoftVdp1SwapFrameBuffer(void);
101 void VIDSoftVdp1EraseFrameBuffer(Vdp1* regs, u8 * back_framebuffer);
102 void VidsoftDrawSprite(Vdp2 * vdp2_regs, u8 * sprite_window_mask, u8* vdp1_front_framebuffer, u8 * vdp2_ram, Vdp1* vdp1_regs, Vdp2* vdp2_lines, u8*color_ram);
103 void VIDSoftGetNativeResolution(int *width, int *height, int*interlace);
104 void VIDSoftVdp2DispOff(void);
105
106 VideoInterface_struct VIDSoft = {
107 VIDCORE_SOFT,
108 "Software Video Interface",
109 VIDSoftInit,
110 VIDSoftDeInit,
111 VIDSoftResize,
112 VIDSoftIsFullscreen,
113 VIDSoftVdp1Reset,
114 VIDSoftVdp1DrawStart,
115 VIDSoftVdp1DrawEnd,
116 VIDSoftVdp1NormalSpriteDraw,
117 VIDSoftVdp1ScaledSpriteDraw,
118 VIDSoftVdp1DistortedSpriteDraw,
119 //for the actual hardware, polygons are essentially identical to distorted sprites
120 //the actual hardware draws using diagonal lines, which is why using half-transparent processing
121 //on distorted sprites and polygons is not recommended since the hardware overdraws to prevent gaps
122 //thus, with half-transparent processing some pixels will be processed more than once, producing moire patterns in the drawn shapes
123 VIDSoftVdp1DistortedSpriteDraw,
124 VIDSoftVdp1PolylineDraw,
125 VIDSoftVdp1LineDraw,
126 VIDSoftVdp1UserClipping,
127 VIDSoftVdp1SystemClipping,
128 VIDSoftVdp1LocalCoordinate,
129 VIDSoftVdp1ReadFrameBuffer,
130 VIDSoftVdp1WriteFrameBuffer,
131 VIDSoftVdp2Reset,
132 VIDSoftVdp2DrawStart,
133 VIDSoftVdp2DrawEnd,
134 VIDSoftVdp2DrawScreens,
135 VIDSoftGetGlSize,
136 VIDSoftGetNativeResolution,
137 VIDSoftVdp2DispOff
138 };
139
140 pixel_t *dispbuffer=NULL;
141 u8 *vdp1framebuffer[2]= { NULL, NULL };
142 u8 *vdp1frontframebuffer;
143 u8 *vdp1backframebuffer;
144 u8 sprite_window_mask[704 * 512];
145
146 static int vdp1width;
147 static int vdp1height;
148 static int vdp1interlace;
149 static int vdp1pixelsize;
150 int vdp2width;
151 int rbg0width = 0;
152 int vdp2height;
153
154 #ifdef USE_OPENGL
155 static int outputwidth;
156 static int outputheight;
157 GLuint vao = 0;
158 GLuint vbo = 0;
159 GLuint vshader = 0;
160 GLuint fshader = 0;
161 GLuint gl_shader_prog = 0;
162 GLuint gl_texture_id = 0;
163 #endif
164 extern int VideoUseGL;
165 int vdp2_x_hires = 0;
166 int vdp2_interlace = 0;
167 static int rbg0height = 0;
168 int bilinear = 0;
169 int vidsoft_num_layer_threads = 0;
170 int bad_cycle_setting[6] = { 0 };
171
172 struct VidsoftVdp1ThreadContext
173 {
174 volatile int draw_finished;
175 volatile int need_draw;
176 Vdp1 regs;
177 u8 ram[0x80000];
178 u8 back_framebuffer[0x40000];
179 }vidsoft_vdp1_thread_context;
180
181 int vidsoft_vdp1_thread_enabled = 0;
182
183 typedef struct { s16 x; s16 y; } vdp1vertex;
184
185 typedef struct
186 {
187 int pagepixelwh, pagepixelwh_bits, pagepixelwh_mask;
188 int planepixelwidth, planepixelwidth_bits, planepixelwidth_mask;
189 int planepixelheight, planepixelheight_bits, planepixelheight_mask;
190 int screenwidth;
191 int screenheight;
192 int oldcellx, oldcelly, oldcellcheck;
193 int xmask, ymask;
194 u32 planetbl[16];
195 } screeninfo_struct;
196
197 //////////////////////////////////////////////////////////////////////////////
198
Vdp2ColorRamGetColor(u32 addr,u8 * vdp2_color_ram)199 static INLINE u32 FASTCALL Vdp2ColorRamGetColor(u32 addr, u8* vdp2_color_ram)
200 {
201 switch(Vdp2Internal.ColorMode)
202 {
203 case 0:
204 {
205 u32 tmp;
206 addr <<= 1;
207 tmp = T2ReadWord(vdp2_color_ram, addr & 0xFFF);
208 /* we preserve MSB for special color calculation mode 3 (see Vdp2 user's manual 3.4 and 12.3) */
209 return (((tmp & 0x1F) << 3) | ((tmp & 0x03E0) << 6) | ((tmp & 0x7C00) << 9)) | ((tmp & 0x8000) << 16);
210 }
211 case 1:
212 {
213 u32 tmp;
214 addr <<= 1;
215 tmp = T2ReadWord(vdp2_color_ram, addr & 0xFFF);
216 /* we preserve MSB for special color calculation mode 3 (see Vdp2 user's manual 3.4 and 12.3) */
217 return (((tmp & 0x1F) << 3) | ((tmp & 0x03E0) << 6) | ((tmp & 0x7C00) << 9)) | ((tmp & 0x8000) << 16);
218 }
219 case 2:
220 {
221 addr <<= 2;
222 return T2ReadLong(vdp2_color_ram, addr & 0xFFF);
223 }
224 default: break;
225 }
226
227 return 0;
228 }
229
230 //////////////////////////////////////////////////////////////////////////////
231
Vdp2PatternAddr(vdp2draw_struct * info,Vdp2 * regs,u8 * ram)232 static INLINE void Vdp2PatternAddr(vdp2draw_struct *info, Vdp2* regs, u8* ram)
233 {
234 switch(info->patterndatasize)
235 {
236 case 1:
237 {
238 u16 tmp = T1ReadWord(ram, info->addr);
239
240 info->addr += 2;
241 info->specialfunction = (info->supplementdata >> 9) & 0x1;
242 info->specialcolorfunction = (info->supplementdata >> 8) & 0x1;
243
244 switch(info->colornumber)
245 {
246 case 0: // in 16 colors
247 info->paladdr = ((tmp & 0xF000) >> 8) | ((info->supplementdata & 0xE0) << 3);
248 break;
249 default: // not in 16 colors
250 info->paladdr = (tmp & 0x7000) >> 4;
251 break;
252 }
253
254 switch(info->auxmode)
255 {
256 case 0:
257 info->flipfunction = (tmp & 0xC00) >> 10;
258
259 switch(info->patternwh)
260 {
261 case 1:
262 info->charaddr = (tmp & 0x3FF) | ((info->supplementdata & 0x1F) << 10);
263 break;
264 case 2:
265 info->charaddr = ((tmp & 0x3FF) << 2) | (info->supplementdata & 0x3) | ((info->supplementdata & 0x1C) << 10);
266 break;
267 }
268 break;
269 case 1:
270 info->flipfunction = 0;
271
272 switch(info->patternwh)
273 {
274 case 1:
275 info->charaddr = (tmp & 0xFFF) | ((info->supplementdata & 0x1C) << 10);
276 break;
277 case 2:
278 info->charaddr = ((tmp & 0xFFF) << 2) | (info->supplementdata & 0x3) | ((info->supplementdata & 0x10) << 10);
279 break;
280 }
281 break;
282 }
283
284 break;
285 }
286 case 2: {
287 u16 tmp1 = T1ReadWord(ram, info->addr);
288 u16 tmp2 = T1ReadWord(ram, info->addr+2);
289 info->addr += 4;
290 info->charaddr = tmp2 & 0x7FFF;
291 info->flipfunction = (tmp1 & 0xC000) >> 14;
292 switch(info->colornumber) {
293 case 0:
294 info->paladdr = (tmp1 & 0x7F) << 4;
295 break;
296 default:
297 info->paladdr = ((tmp1 & 0x70) << 4);
298 break;
299 }
300 info->specialfunction = (tmp1 & 0x2000) >> 13;
301 info->specialcolorfunction = (tmp1 & 0x1000) >> 12;
302 break;
303 }
304 }
305
306 if (!(regs->VRSIZE & 0x8000))
307 info->charaddr &= 0x3FFF;
308
309 info->charaddr *= 0x20; // selon Runik
310 if (info->specialprimode == 1) {
311 info->priority = (info->priority & 0xE) | (info->specialfunction & 1);
312 }
313 }
314
315 //////////////////////////////////////////////////////////////////////////////
316
DoNothing(UNUSED void * info,u32 pixel)317 static INLINE u32 FASTCALL DoNothing(UNUSED void *info, u32 pixel)
318 {
319 return pixel;
320 }
321
322 //////////////////////////////////////////////////////////////////////////////
323
DoColorOffset(void * info,u32 pixel)324 static INLINE u32 FASTCALL DoColorOffset(void *info, u32 pixel)
325 {
326 return COLOR_ADD(pixel, ((vdp2draw_struct *)info)->cor,
327 ((vdp2draw_struct *)info)->cog,
328 ((vdp2draw_struct *)info)->cob);
329 }
330
331 //////////////////////////////////////////////////////////////////////////////
332
ReadVdp2ColorOffset(Vdp2 * regs,vdp2draw_struct * info,int clofmask,int ccmask)333 static INLINE void ReadVdp2ColorOffset(Vdp2 * regs, vdp2draw_struct *info, int clofmask, int ccmask)
334 {
335 if (regs->CLOFEN & clofmask)
336 {
337 // color offset enable
338 if (regs->CLOFSL & clofmask)
339 {
340 // color offset B
341 info->cor = regs->COBR & 0xFF;
342 if (regs->COBR & 0x100)
343 info->cor |= 0xFFFFFF00;
344
345 info->cog = regs->COBG & 0xFF;
346 if (regs->COBG & 0x100)
347 info->cog |= 0xFFFFFF00;
348
349 info->cob = regs->COBB & 0xFF;
350 if (regs->COBB & 0x100)
351 info->cob |= 0xFFFFFF00;
352 }
353 else
354 {
355 // color offset A
356 info->cor = regs->COAR & 0xFF;
357 if (regs->COAR & 0x100)
358 info->cor |= 0xFFFFFF00;
359
360 info->cog = regs->COAG & 0xFF;
361 if (regs->COAG & 0x100)
362 info->cog |= 0xFFFFFF00;
363
364 info->cob = regs->COAB & 0xFF;
365 if (regs->COAB & 0x100)
366 info->cob |= 0xFFFFFF00;
367 }
368
369 info->PostPixelFetchCalc = &DoColorOffset;
370 }
371 else // color offset disable
372 info->PostPixelFetchCalc = &DoNothing;
373
374 }
375
376 //////////////////////////////////////////////////////////////////////////////
377
Vdp2FetchPixel(vdp2draw_struct * info,int x,int y,u32 * color,u32 * dot,u8 * ram,int charaddr,int paladdr,u8 * vdp2_color_ram)378 static INLINE int Vdp2FetchPixel(vdp2draw_struct *info, int x, int y, u32 *color, u32 *dot, u8 * ram, int charaddr, int paladdr, u8* vdp2_color_ram)
379 {
380 switch(info->colornumber)
381 {
382 case 0: // 4 BPP
383 *dot = T1ReadByte(ram, ((charaddr + ((y * info->cellw) + x) / 2) & 0x7FFFF));
384 if (!(x & 0x1)) *dot >>= 4;
385 if (!(*dot & 0xF) && info->transparencyenable) return 0;
386 else
387 {
388 *color = Vdp2ColorRamGetColor(info->coloroffset + (paladdr | (*dot & 0xF)),vdp2_color_ram);
389 return 1;
390 }
391 case 1: // 8 BPP
392 *dot = T1ReadByte(ram, ((charaddr + (y * info->cellw) + x) & 0x7FFFF));
393 if (!(*dot & 0xFF) && info->transparencyenable) return 0;
394 else
395 {
396 *color = Vdp2ColorRamGetColor(info->coloroffset + (paladdr | (*dot & 0xFF)), vdp2_color_ram);
397 return 1;
398 }
399 case 2: // 16 BPP(palette)
400 *dot = T1ReadWord(ram, ((charaddr + ((y * info->cellw) + x) * 2) & 0x7FFFF));
401 if ((*dot == 0) && info->transparencyenable) return 0;
402 else
403 {
404 *color = Vdp2ColorRamGetColor(info->coloroffset + *dot, vdp2_color_ram);
405 return 1;
406 }
407 case 3: // 16 BPP(RGB)
408 *dot = T1ReadWord(ram, ((charaddr + ((y * info->cellw) + x) * 2) & 0x7FFFF));
409 if (!(*dot & 0x8000) && info->transparencyenable) return 0;
410 else
411 {
412 *color = COLSAT2YAB16(0, *dot);
413 return 1;
414 }
415 case 4: // 32 BPP
416 *dot = T1ReadLong(ram, ((charaddr + ((y * info->cellw) + x) * 4) & 0x7FFFF));
417 if (!(*dot & 0x80000000) && info->transparencyenable) return 0;
418 else
419 {
420 *color = COLSAT2YAB32(0, *dot);
421 return 1;
422 }
423 default:
424 return 0;
425 }
426 }
427
428 //////////////////////////////////////////////////////////////////////////////
429
TestWindow(int wctl,int enablemask,int inoutmask,clipping_struct * clip,int x,int y)430 static INLINE int TestWindow(int wctl, int enablemask, int inoutmask, clipping_struct *clip, int x, int y)
431 {
432 if (wctl & enablemask)
433 {
434 if (wctl & inoutmask)
435 {
436 // Draw inside of window
437 if (x < clip->xstart || x > clip->xend ||
438 y < clip->ystart || y > clip->yend)
439 return 0;
440 }
441 else
442 {
443 // Draw outside of window
444 if (x >= clip->xstart && x <= clip->xend &&
445 y >= clip->ystart && y <= clip->yend)
446 return 0;
447
448 //it seems to overflow vertically on hardware
449 if(clip->yend > vdp2height && (x >= clip->xstart && x <= clip->xend ))
450 return 0;
451 }
452 return 1; // return inactive;
453 }
454 return 3; // return disabled | inactive;
455 }
456
457 //////////////////////////////////////////////////////////////////////////////
458
TestSpriteWindow(int wctl,int x,int y)459 int TestSpriteWindow(int wctl, int x, int y)
460 {
461 int mask;
462 int addr = (y*vdp2width) + x;
463
464 if (addr >= (704 * 512))
465 return 0;
466
467 mask = sprite_window_mask[addr];
468
469 if (wctl & 0x20)//sprite window enabled on layer
470 {
471 if (wctl & 0x10)//inside or outside
472 {
473 if (mask == 0)
474 return 0;
475 }
476 else
477 {
478 if (mask)
479 return 0;
480 }
481
482 return 1;
483 }
484 return 3;
485 }
486
487 //////////////////////////////////////////////////////////////////////////////
488
WindowLogic(int wctl,int w0,int w1)489 int WindowLogic(int wctl, int w0, int w1)
490 {
491 if (((wctl & 0x80) == 0x80))
492 /* AND logic, returns 0 only if both the windows are active */
493 return w0 || w1;
494 else
495 /* OR logic, returns 0 if one of the windows is active */
496 return w0 && w1;
497 }
498
499 //////////////////////////////////////////////////////////////////////////////
500
TestBothWindow(int wctl,clipping_struct * clip,int x,int y)501 static INLINE int TestBothWindow(int wctl, clipping_struct *clip, int x, int y)
502 {
503 int w0 = TestWindow(wctl, 0x2, 0x1, &clip[0], x, y);
504 int w1 = TestWindow(wctl, 0x8, 0x4, &clip[1], x, y);
505 int spr = TestSpriteWindow(wctl, x,y);
506
507 //all windows disabled
508 if ((wctl & 0x2a) == 0)
509 {
510 if ((wctl & 0x80) == 0x80)
511 return 0;
512 else
513 return 1;
514 }
515
516 //if only window 0 is enabled
517 if ((w1 & 2) && (spr & 2)) return w0 & 1;
518 //if only window 1 is enabled
519 if ((w0 & 2) && (spr & 2)) return w1 & 1;
520
521 //window 0 and 1, sprite disabled
522 if ((spr & 2))
523 return WindowLogic(wctl, w0, w1);
524
525 //if only sprite window is enabled
526 if ((w1 & 2) && (w0 & 2)) return spr & 1;
527
528 //window 0 and sprite enabled
529 if ((wctl & 0x2a) == 0x22)
530 return WindowLogic(wctl, w0, spr);
531
532 //window 1 and sprite enabled
533 if ((wctl & 0x2a) == 0x28)
534 return WindowLogic(wctl, w1, spr);
535
536 //all three windows enabled
537 if ((wctl & 0x2a) == 0x2a)
538 {
539 if ((wctl & 0x80) == 0x80)
540 return w0 || w1 || spr;//and logic
541 else
542 return w0 && w1 && spr;//or logic
543 }
544
545 return 1;
546
547 }
548
549 //////////////////////////////////////////////////////////////////////////////
550
GeneratePlaneAddrTable(vdp2draw_struct * info,u32 * planetbl,void FASTCALL (* PlaneAddr)(void *,int,Vdp2 *),Vdp2 * regs)551 static INLINE void GeneratePlaneAddrTable(vdp2draw_struct *info, u32 *planetbl, void FASTCALL (* PlaneAddr)(void *, int, Vdp2* ), Vdp2* regs)
552 {
553 int i;
554
555 for (i = 0; i < (info->mapwh*info->mapwh); i++)
556 {
557 PlaneAddr(info, i, regs);
558 planetbl[i] = info->addr;
559 }
560 }
561
562 //////////////////////////////////////////////////////////////////////////////
563
Vdp2MapCalcXY(vdp2draw_struct * info,int * x,int * y,screeninfo_struct * sinfo,Vdp2 * regs,u8 * ram,int bad_cycle)564 static INLINE void FASTCALL Vdp2MapCalcXY(vdp2draw_struct *info, int *x, int *y,
565 screeninfo_struct *sinfo, Vdp2* regs, u8 * ram, int bad_cycle)
566 {
567 int planenum;
568 int flipfunction;
569 const int pagesize_bits=info->pagewh_bits*2;
570 const int cellwh=(2 + info->patternwh);
571
572 const int check = ((y[0] >> cellwh) << 16) | (x[0] >> cellwh);
573 //if ((x[0] >> cellwh) != sinfo->oldcellx || (y[0] >> cellwh) != sinfo->oldcelly)
574 if(check != sinfo->oldcellcheck)
575 {
576 sinfo->oldcellx = x[0] >> cellwh;
577 sinfo->oldcelly = y[0] >> cellwh;
578 sinfo->oldcellcheck = (sinfo->oldcelly << 16) | sinfo->oldcellx;
579
580 // Calculate which plane we're dealing with
581 planenum = ((y[0] >> sinfo->planepixelheight_bits) * info->mapwh) + (x[0] >> sinfo->planepixelwidth_bits);
582 x[0] = (x[0] & sinfo->planepixelwidth_mask);
583 y[0] = (y[0] & sinfo->planepixelheight_mask);
584
585 // Fetch and decode pattern name data
586 info->addr = sinfo->planetbl[planenum];
587
588 // Figure out which page it's on(if plane size is not 1x1)
589 info->addr += (( ((y[0] >> sinfo->pagepixelwh_bits) << pagesize_bits) << info->planew_bits) +
590 ( (x[0] >> sinfo->pagepixelwh_bits) << pagesize_bits) +
591 (((y[0] & sinfo->pagepixelwh_mask) >> cellwh) << info->pagewh_bits) +
592 ((x[0] & sinfo->pagepixelwh_mask) >> cellwh)) << (info->patterndatasize_bits+1);
593
594 Vdp2PatternAddr(info, regs, ram); // Heh, this could be optimized
595
596 //pipeline the tiles so that they shift over by 1
597 info->pipe[0] = info->pipe[1];
598
599 info->pipe[1].paladdr = info->paladdr;
600 info->pipe[1].charaddr = info->charaddr;
601 info->pipe[1].flipfunction = info->flipfunction;
602 }
603
604 if (bad_cycle)
605 {
606 flipfunction = info->pipe[0].flipfunction;
607 }
608 else
609 {
610 flipfunction = info->flipfunction;
611 }
612
613 // Figure out which pixel in the tile we want
614 if (info->patternwh == 1)
615 {
616 x[0] &= 8-1;
617 y[0] &= 8-1;
618
619 switch(flipfunction & 0x3)
620 {
621 case 0: //none
622 break;
623 case 1: //horizontal flip
624 x[0] = 8 - 1 - x[0];
625 break;
626 case 2: // vertical flip
627 y[0] = 8 - 1 - y[0];
628 break;
629 case 3: //flip both
630 x[0] = 8 - 1 - x[0];
631 y[0] = 8 - 1 - y[0];
632 break;
633 }
634 }
635 else
636 {
637 if (flipfunction)
638 {
639 y[0] &= 16 - 1;
640 if (flipfunction & 0x2)
641 {
642 if (!(y[0] & 8))
643 y[0] = 8 - 1 - y[0] + 16;
644 else
645 y[0] = 16 - 1 - y[0];
646 }
647 else if (y[0] & 8)
648 y[0] += 8;
649
650 if (flipfunction & 0x1)
651 {
652 if (!(x[0] & 8))
653 y[0] += 8;
654
655 x[0] &= 8-1;
656 x[0] = 8 - 1 - x[0];
657 }
658 else if (x[0] & 8)
659 {
660 y[0] += 8;
661 x[0] &= 8-1;
662 }
663 else
664 x[0] &= 8-1;
665 }
666 else
667 {
668 y[0] &= 16 - 1;
669
670 if (y[0] & 8)
671 y[0] += 8;
672 if (x[0] & 8)
673 y[0] += 8;
674 x[0] &= 8-1;
675 }
676 }
677 }
678
679 //////////////////////////////////////////////////////////////////////////////
680
SetupScreenVars(vdp2draw_struct * info,screeninfo_struct * sinfo,void FASTCALL (* PlaneAddr)(void *,int,Vdp2 *),Vdp2 * regs)681 static INLINE void SetupScreenVars(vdp2draw_struct *info, screeninfo_struct *sinfo, void FASTCALL (* PlaneAddr)(void *, int, Vdp2*), Vdp2* regs)
682 {
683 if (!info->isbitmap)
684 {
685 sinfo->pagepixelwh=64*8;
686 sinfo->pagepixelwh_bits = 9;
687 sinfo->pagepixelwh_mask = 511;
688
689 sinfo->planepixelwidth=info->planew*sinfo->pagepixelwh;
690 sinfo->planepixelwidth_bits = 8+info->planew;
691 sinfo->planepixelwidth_mask = (1<<(sinfo->planepixelwidth_bits))-1;
692
693 sinfo->planepixelheight=info->planeh*sinfo->pagepixelwh;
694 sinfo->planepixelheight_bits = 8+info->planeh;
695 sinfo->planepixelheight_mask = (1<<(sinfo->planepixelheight_bits))-1;
696
697 sinfo->screenwidth=info->mapwh*sinfo->planepixelwidth;
698 sinfo->screenheight=info->mapwh*sinfo->planepixelheight;
699 sinfo->oldcellx=-1;
700 sinfo->oldcelly=-1;
701 sinfo->oldcellcheck=-1;
702 sinfo->xmask = sinfo->screenwidth-1;
703 sinfo->ymask = sinfo->screenheight-1;
704 GeneratePlaneAddrTable(info, sinfo->planetbl, PlaneAddr, regs);
705 }
706 else
707 {
708 sinfo->pagepixelwh = 0;
709 sinfo->pagepixelwh_bits = 0;
710 sinfo->pagepixelwh_mask = 0;
711 sinfo->planepixelwidth=0;
712 sinfo->planepixelwidth_bits=0;
713 sinfo->planepixelwidth_mask=0;
714 sinfo->planepixelheight=0;
715 sinfo->planepixelheight_bits=0;
716 sinfo->planepixelheight_mask=0;
717 sinfo->screenwidth=0;
718 sinfo->screenheight=0;
719 sinfo->oldcellx=0;
720 sinfo->oldcelly=0;
721 sinfo->oldcellcheck=0;
722 sinfo->xmask = info->cellw-1;
723 sinfo->ymask = info->cellh-1;
724 }
725 }
726
727 //////////////////////////////////////////////////////////////////////////////
728
GetAlpha(vdp2draw_struct * info,u32 color,u32 dot)729 static u8 FASTCALL GetAlpha(vdp2draw_struct * info, u32 color, u32 dot)
730 {
731 if (((info->specialcolormode == 1) || (info->specialcolormode == 2)) && ((info->specialcolorfunction & 1) == 0)) {
732 /* special color calculation mode 1 and 2 enables color calculation only when special color function = 1 */
733 return 0x3F;
734 } else if (info->specialcolormode == 2) {
735 /* special color calculation 2 enables color calculation according to lower bits of the color code */
736 if ((info->specialcode & (1 << ((dot & 0xF) >> 1))) == 0) {
737 return 0x3F;
738 }
739 } else if ((info->specialcolormode == 3) && ((color & 0x80000000) == 0)) {
740 /* special color calculation mode 3 enables color calculation only for dots with MSB = 1 */
741 return 0x3F;
742 }
743 return info->alpha;
744 }
745
746 //////////////////////////////////////////////////////////////////////////////
747
PixelIsSpecialPriority(int specialcode,int dot)748 int PixelIsSpecialPriority(int specialcode, int dot)
749 {
750 dot &= 0xf;
751
752 if (specialcode & 0x01)
753 {
754 if (dot == 0 || dot == 1)
755 return 1;
756 }
757 if (specialcode & 0x02)
758 {
759 if (dot == 2 || dot == 3)
760 return 1;
761 }
762 if (specialcode & 0x04)
763 {
764 if (dot == 4 || dot == 5)
765 return 1;
766 }
767 if (specialcode & 0x08)
768 {
769 if (dot == 6 || dot == 7)
770 return 1;
771 }
772 if (specialcode & 0x10)
773 {
774 if (dot == 8 || dot == 9)
775 return 1;
776 }
777 if (specialcode & 0x20)
778 {
779 if (dot == 0xa || dot == 0xb)
780 return 1;
781 }
782 if (specialcode & 0x40)
783 {
784 if (dot == 0xc || dot == 0xd)
785 return 1;
786 }
787 if (specialcode & 0x80)
788 {
789 if (dot == 0xe || dot == 0xf)
790 return 1;
791 }
792
793 return 0;
794 }
795
796 //////////////////////////////////////////////////////////////////////////////
797
Vdp2GetInterlaceInfo(int * start_line,int * line_increment)798 void Vdp2GetInterlaceInfo(int * start_line, int * line_increment)
799 {
800 if (vdp2_interlace)
801 {
802 if (vdp2_is_odd_frame)
803 {
804 *start_line = 1;
805 }
806 else
807 {
808 *start_line = 0;
809 }
810
811 *line_increment = 2;
812 }
813 else
814 {
815 *start_line = 0;
816 *line_increment = 1;
817 }
818 }
819
820 //////////////////////////////////////////////////////////////////////////////
821
Vdp2DrawScroll(vdp2draw_struct * info,Vdp2 * lines,Vdp2 * regs,u8 * ram,u8 * color_ram,struct CellScrollData * cell_data)822 static void FASTCALL Vdp2DrawScroll(vdp2draw_struct *info, Vdp2* lines, Vdp2* regs, u8* ram, u8* color_ram, struct CellScrollData * cell_data)
823 {
824 int i, j;
825 int x, y;
826 clipping_struct clip[2];
827 u32 linewnd0addr, linewnd1addr;
828 u32 line_window_base[2] = { 0 };
829 screeninfo_struct sinfo;
830 int scrolly;
831 int *mosaic_y, *mosaic_x;
832 clipping_struct colorcalcwindow[2];
833 int start_line = 0, line_increment = 0;
834 int bad_cycle = bad_cycle_setting[info->titan_which_layer];
835 int charaddr, paladdr;
836 int output_y = 0;
837 u32 linescrollx_table[512] = { 0 };
838 u32 linescrolly_table[512] = { 0 };
839 float lineszoom_table[512] = { 0 };
840 int num_vertical_cell_scroll_enabled = 0;
841
842 SetupScreenVars(info, &sinfo, info->PlaneAddr, regs);
843
844 scrolly = info->y;
845
846 clip[0].xstart = clip[0].ystart = clip[0].xend = clip[0].yend = 0;
847 clip[1].xstart = clip[1].ystart = clip[1].xend = clip[1].yend = 0;
848 ReadWindowData(info->wctl, clip, regs);
849 linewnd0addr = linewnd1addr = 0;
850 ReadLineWindowData(&info->islinewindow, info->wctl, &linewnd0addr, &linewnd1addr,regs);
851 line_window_base[0] = linewnd0addr;
852 line_window_base[1] = linewnd1addr;
853 /* color calculation window: in => no color calc, out => color calc */
854 ReadWindowData(regs->WCTLD >> 8, colorcalcwindow, regs);
855 {
856 static int tables_initialized = 0;
857 static int mosaic_table[16][1024];
858 if(!tables_initialized)
859 {
860 tables_initialized = 1;
861 for(i=0;i<16;i++)
862 {
863 int m = i+1;
864 for(j=0;j<1024;j++)
865 mosaic_table[i][j] = j/m*m;
866 }
867 }
868 mosaic_x = mosaic_table[info->mosaicxmask-1];
869 mosaic_y = mosaic_table[info->mosaicymask-1];
870 }
871
872 Vdp2GetInterlaceInfo(&start_line, &line_increment);
873
874 if (regs->SCRCTL & 1)
875 num_vertical_cell_scroll_enabled++;
876 if (regs->SCRCTL & 0x100)
877 num_vertical_cell_scroll_enabled++;
878
879 //pre-generate line scroll tables
880 for (j = start_line; j < vdp2height; j++)
881 {
882 if (info->islinescroll)
883 {
884 //line scroll interval bit
885 int need_increment = ((j != 0) && (((j + 1) % info->lineinc) == 0));
886
887 //horizontal line scroll
888 if (info->islinescroll & 0x1)
889 {
890 linescrollx_table[j] = (T1ReadLong(ram, info->linescrolltbl) >> 16) & 0x7FF;
891 if (need_increment)
892 info->linescrolltbl += 4;
893 }
894
895 //vertical line scroll
896 if (info->islinescroll & 0x2)
897 {
898 linescrolly_table[j] = ((T1ReadWord(ram, info->linescrolltbl) & 0x7FF)) + scrolly;
899 if (need_increment)
900 info->linescrolltbl += 4;
901 y = info->y;
902 }
903
904 //line zoom
905 if (info->islinescroll & 0x4)
906 {
907 lineszoom_table[j] = (T1ReadLong(ram, info->linescrolltbl) & 0x7FF00) / (float)65536.0;
908 if (need_increment)
909 info->linescrolltbl += 4;
910 }
911 }
912 }
913
914 for (j = start_line; j < vdp2height; j += line_increment)
915 {
916 int Y;
917 int linescrollx = 0;
918 // precalculate the coordinate for the line(it's faster) and do line
919 // scroll
920 if (info->islinescroll)
921 {
922 //horizontal line scroll
923 if (info->islinescroll & 0x1)
924 {
925 linescrollx = linescrollx_table[j];
926 }
927
928 //vertical line scroll
929 if (info->islinescroll & 0x2)
930 {
931 info->y = linescrolly_table[j];
932 y = info->y;
933 }
934 else
935 //y = info->y+((int)(info->coordincy *(float)(info->mosaicymask > 1 ? (j / info->mosaicymask * info->mosaicymask) : j)));
936 y = info->y + info->coordincy*mosaic_y[j];
937
938 //line zoom
939 if (info->islinescroll & 0x4)
940 {
941 info->coordincx = lineszoom_table[j];
942 }
943 }
944 else
945 //y = info->y+((int)(info->coordincy *(float)(info->mosaicymask > 1 ? (j / info->mosaicymask * info->mosaicymask) : j)));
946 y = info->y + info->coordincy*mosaic_y[j];
947
948 if (vdp2_interlace)
949 {
950 linewnd0addr = line_window_base[0] + (j * 4);
951 linewnd1addr = line_window_base[1] + (j * 4);
952 }
953
954 // if line window is enabled, adjust clipping values
955 ReadLineWindowClip(info->islinewindow, clip, &linewnd0addr, &linewnd1addr, ram, regs);
956 y &= sinfo.ymask;
957
958 if (info->isverticalscroll && (!vdp2_x_hires))//seems to be ignored in hi res
959 {
960 // this is *wrong*, vertical scroll use a different value per cell
961 // info->verticalscrolltbl should be incremented by info->verticalscrollinc
962 // each time there's a cell change and reseted at the end of the line...
963 // or something like that :)
964 u32 scroll_value = 0;
965 int y_value = 0;
966
967 if (vdp2_interlace)
968 y_value = j / 2;
969 else
970 y_value = j;
971
972 if (num_vertical_cell_scroll_enabled == 1)
973 {
974 scroll_value = cell_data[y_value].data[0] >> 16;
975 }
976 else
977 {
978 if (info->titan_which_layer == TITAN_NBG0)
979 scroll_value = cell_data[y_value].data[0] >> 16;//reload cell data per line for sonic 2, 2 player mode
980 else if (info->titan_which_layer == TITAN_NBG1)
981 scroll_value = cell_data[y_value].data[1] >> 16;
982 }
983
984 y += scroll_value;
985 y &= 0x1FF;
986 }
987
988 Y=y;
989
990 if (vdp2_interlace)
991 info->LoadLineParams(info, &sinfo, j / 2, lines);
992 else
993 info->LoadLineParams(info, &sinfo, j, lines);
994
995 if (!info->enable)
996 continue;
997
998 for (i = 0; i < vdp2width; i++)
999 {
1000 u32 color, dot;
1001 /* I'm really not sure about this... but I think the way we handle
1002 high resolution gets in the way with window process. I may be wrong...
1003 This was added for Cotton Boomerang */
1004 int priority;
1005
1006 // See if screen position is clipped, if it isn't, continue
1007 if (!TestBothWindow(info->wctl, clip, i, j))
1008 {
1009 continue;
1010 }
1011
1012 //x = info->x+((int)(info->coordincx*(float)((info->mosaicxmask > 1) ? (i / info->mosaicxmask * info->mosaicxmask) : i)));
1013 x = info->x + mosaic_x[i]*info->coordincx;
1014 x &= sinfo.xmask;
1015
1016 if (linescrollx) {
1017 x += linescrollx;
1018 x &= 0x3FF;
1019 }
1020
1021 // Fetch Pixel, if it isn't transparent, continue
1022 if (!info->isbitmap)
1023 {
1024 // Tile
1025 y=Y;
1026 Vdp2MapCalcXY(info, &x, &y, &sinfo, regs, ram, bad_cycle);
1027 }
1028
1029 if (!bad_cycle)
1030 {
1031 charaddr = info->charaddr;
1032 paladdr = info->paladdr;
1033 }
1034 else
1035 {
1036 charaddr = info->pipe[0].charaddr;
1037 paladdr = info->pipe[0].paladdr;
1038 }
1039
1040 if (!Vdp2FetchPixel(info, x, y, &color, &dot, ram, charaddr, paladdr,color_ram))
1041 {
1042 continue;
1043 }
1044
1045 priority = info->priority;
1046
1047 //per-pixel priority is on
1048 if (info->specialprimode == 2)
1049 {
1050 priority = info->priority & 0xE;
1051
1052 if (info->specialfunction & 1)
1053 {
1054 if (PixelIsSpecialPriority(info->specialcode,dot))
1055 {
1056 priority |= 1;
1057 }
1058 }
1059 }
1060
1061 // Apply color offset and color calculation/special color calculation
1062 // and then continue.
1063 // We almost need to know well ahead of time what the top
1064 // and second pixel is in order to work this.
1065
1066 {
1067 u8 alpha;
1068 /* if we're in the valid area of the color calculation window, don't do color calculation */
1069 if (!TestBothWindow(regs->WCTLD >> 8, colorcalcwindow, i, j))
1070 alpha = 0x3F;
1071 else
1072 alpha = GetAlpha(info, color, dot);
1073
1074 TitanPutPixel(priority, i, output_y, info->PostPixelFetchCalc(info, COLSAT2YAB32(alpha, color)), info->linescreen, info);
1075 }
1076 }
1077 output_y++;
1078 }
1079 }
1080
1081 //////////////////////////////////////////////////////////////////////////////
1082
Rbg0PutHiresPixel(vdp2draw_struct * info,u32 color,u32 dot,int i,int j)1083 void Rbg0PutHiresPixel(vdp2draw_struct *info, u32 color, u32 dot, int i, int j)
1084 {
1085 u32 pixel = info->PostPixelFetchCalc(info, COLSAT2YAB32(GetAlpha(info, color, dot), color));
1086 int x_pos = i * 2;
1087 TitanPutPixel(info->priority, x_pos, j, pixel, info->linescreen, info);
1088 TitanPutPixel(info->priority, x_pos + 1, j, pixel, info->linescreen, info);
1089 }
1090
1091 //////////////////////////////////////////////////////////////////////////////
1092
Rbg0PutPixel(vdp2draw_struct * info,u32 color,u32 dot,int i,int j)1093 void Rbg0PutPixel(vdp2draw_struct *info, u32 color, u32 dot, int i, int j)
1094 {
1095 if (vdp2_x_hires)
1096 {
1097 Rbg0PutHiresPixel(info, color, dot, i, j);
1098 }
1099 else
1100 TitanPutPixel(info->priority, i, j, info->PostPixelFetchCalc(info, COLSAT2YAB32(GetAlpha(info, color, dot), color)), info->linescreen, info);
1101 }
1102
1103 //////////////////////////////////////////////////////////////////////////////
1104
CheckBanks(Vdp2 * regs,int compare_value)1105 int CheckBanks(Vdp2* regs, int compare_value)
1106 {
1107 if (((regs->RAMCTL >> 0) & 3) == compare_value)//a0
1108 return 0;
1109 if (((regs->RAMCTL >> 2) & 3) == compare_value)//a1
1110 return 0;
1111 if (((regs->RAMCTL >> 4) & 3) == compare_value)//b0
1112 return 0;
1113 if (((regs->RAMCTL >> 6) & 3) == compare_value)//b1
1114 return 0;
1115
1116 return 1;//no setting present
1117 }
1118
Rbg0CheckRam(Vdp2 * regs)1119 int Rbg0CheckRam(Vdp2* regs)
1120 {
1121 if (((regs->RAMCTL >> 8) & 3) == 3)//both banks are divided
1122 {
1123 //ignore delta kax if the coefficient table
1124 //bank is unspecified
1125 if (CheckBanks(regs, 1))
1126 return 1;
1127 }
1128
1129 return 0;
1130 }
1131
Vdp2DrawRotationFP(vdp2draw_struct * info,vdp2rotationparameterfp_struct * parameter,Vdp2 * lines,Vdp2 * regs,u8 * ram,u8 * color_ram,struct CellScrollData * cell_data)1132 static void FASTCALL Vdp2DrawRotationFP(vdp2draw_struct *info, vdp2rotationparameterfp_struct *parameter, Vdp2* lines, Vdp2* regs, u8* ram, u8* color_ram, struct CellScrollData * cell_data)
1133 {
1134 int i, j;
1135 int x, y;
1136 screeninfo_struct sinfo;
1137 vdp2rotationparameterfp_struct *p=¶meter[info->rotatenum];
1138 clipping_struct clip[2];
1139 u32 linewnd0addr, linewnd1addr;
1140
1141 clip[0].xstart = clip[0].ystart = clip[0].xend = clip[0].yend = 0;
1142 clip[1].xstart = clip[1].ystart = clip[1].xend = clip[1].yend = 0;
1143 ReadWindowData(info->wctl, clip, regs);
1144 linewnd0addr = linewnd1addr = 0;
1145 ReadLineWindowData(&info->islinewindow, info->wctl, &linewnd0addr, &linewnd1addr, regs);
1146
1147 Vdp2ReadRotationTableFP(info->rotatenum, p, regs, ram);
1148
1149 if (!p->coefenab)
1150 {
1151 fixed32 xmul, ymul, C, F;
1152
1153 // Since coefficients aren't being used, we can simplify the drawing process
1154 if (IsScreenRotatedFP(p))
1155 {
1156 // No rotation
1157 info->x = touint(mulfixed(p->kx, (p->Xst - p->Px)) + p->Px + p->Mx);
1158 info->y = touint(mulfixed(p->ky, (p->Yst - p->Py)) + p->Py + p->My);
1159 info->coordincx = tofloat(p->kx);
1160 info->coordincy = tofloat(p->ky);
1161 }
1162 else
1163 {
1164 GenerateRotatedVarFP(p, &xmul, &ymul, &C, &F);
1165
1166 // Do simple rotation
1167 CalculateRotationValuesFP(p);
1168
1169 SetupScreenVars(info, &sinfo, info->PlaneAddr, regs);
1170
1171 for (j = 0; j < vdp2height; j++)
1172 {
1173 info->LoadLineParams(info, &sinfo, j, lines);
1174 ReadLineWindowClip(info->islinewindow, clip, &linewnd0addr, &linewnd1addr, ram, regs);
1175
1176 for (i = 0; i < rbg0width; i++)
1177 {
1178 u32 color, dot;
1179
1180 if (!TestBothWindow(info->wctl, clip, i, j))
1181 continue;
1182
1183 x = GenerateRotatedXPosFP(p, i, xmul, ymul, C) & sinfo.xmask;
1184 y = GenerateRotatedYPosFP(p, i, xmul, ymul, F) & sinfo.ymask;
1185
1186 // Convert coordinates into graphics
1187 if (!info->isbitmap)
1188 {
1189 // Tile
1190 Vdp2MapCalcXY(info, &x, &y, &sinfo, regs, ram,0);
1191 }
1192
1193 // Fetch pixel
1194 if (!Vdp2FetchPixel(info, x, y, &color, &dot, ram, info->charaddr,info->paladdr, color_ram))
1195 {
1196 continue;
1197 }
1198
1199 Rbg0PutPixel(info, color, dot, i, j);
1200 }
1201 xmul += p->deltaXst;
1202 ymul += p->deltaYst;
1203 }
1204
1205 return;
1206 }
1207 }
1208 else
1209 {
1210 fixed32 xmul, ymul, C, F;
1211 u32 coefx, coefy;
1212 u32 rcoefx, rcoefy;
1213 u32 lineAddr, lineColor, lineInc;
1214 u16 lineColorAddr;
1215
1216 fixed32 xmul2, ymul2, C2, F2;
1217 u32 coefx2, coefy2;
1218 u32 rcoefx2, rcoefy2;
1219 screeninfo_struct sinfo2;
1220 vdp2rotationparameterfp_struct *p2 = NULL;
1221
1222 clipping_struct rpwindow[2];
1223 int userpwindow = 0;
1224 int isrplinewindow = 0;
1225 u32 rplinewnd0addr, rplinewnd1addr;
1226
1227 if ((regs->RPMD & 3) == 2)
1228 p2 = ¶meter[1 - info->rotatenum];
1229 else if ((regs->RPMD & 3) == 3)
1230 {
1231 ReadWindowData(regs->WCTLD, rpwindow, regs);
1232 rplinewnd0addr = rplinewnd1addr = 0;
1233 ReadLineWindowData(&isrplinewindow, regs->WCTLD, &rplinewnd0addr, &rplinewnd1addr, regs);
1234 userpwindow = 1;
1235 p2 = ¶meter[1 - info->rotatenum];
1236 }
1237
1238 GenerateRotatedVarFP(p, &xmul, &ymul, &C, &F);
1239
1240 // Rotation using Coefficient Tables(now this stuff just gets wacky. It
1241 // has to be done in software, no exceptions)
1242 CalculateRotationValuesFP(p);
1243
1244 SetupScreenVars(info, &sinfo, p->PlaneAddr, regs);
1245 coefx = coefy = 0;
1246 rcoefx = rcoefy = 0;
1247
1248 if (p2 != NULL)
1249 {
1250 Vdp2ReadRotationTableFP(1 - info->rotatenum, p2, regs, ram);
1251 GenerateRotatedVarFP(p2, &xmul2, &ymul2, &C2, &F2);
1252 CalculateRotationValuesFP(p2);
1253 SetupScreenVars(info, &sinfo2, p2->PlaneAddr, regs);
1254 coefx2 = coefy2 = 0;
1255 rcoefx2 = rcoefy2 = 0;
1256 }
1257
1258 if (Rbg0CheckRam(regs))//sonic r / all star baseball 97
1259 {
1260 if (p->coefenab && p->coefmode == 0)
1261 {
1262 p->deltaKAx = 0;
1263 }
1264
1265 if (p2 && p2->coefenab && p2->coefmode == 0)
1266 {
1267 p2->deltaKAx = 0;
1268 }
1269 }
1270
1271 if (info->linescreen)
1272 {
1273 if ((info->rotatenum == 0) && (regs->KTCTL & 0x10))
1274 info->linescreen = 2;
1275 else if (regs->KTCTL & 0x1000)
1276 info->linescreen = 3;
1277 if (regs->VRSIZE & 0x8000)
1278 lineAddr = (regs->LCTA.all & 0x7FFFF) << 1;
1279 else
1280 lineAddr = (regs->LCTA.all & 0x3FFFF) << 1;
1281
1282 lineInc = regs->LCTA.part.U & 0x8000 ? 2 : 0;
1283 }
1284
1285 for (j = 0; j < rbg0height; j++)
1286 {
1287 if (p->deltaKAx == 0)
1288 {
1289 Vdp2ReadCoefficientFP(p,
1290 p->coeftbladdr +
1291 (coefy + touint(rcoefy)) *
1292 p->coefdatasize, ram);
1293 }
1294 if ((p2 != NULL) && p2->coefenab && (p2->deltaKAx == 0))
1295 {
1296 Vdp2ReadCoefficientFP(p2,
1297 p2->coeftbladdr +
1298 (coefy2 + touint(rcoefy2)) *
1299 p2->coefdatasize, ram);
1300 }
1301
1302 if (info->linescreen > 1)
1303 {
1304 lineColorAddr = (T1ReadWord(ram, lineAddr) & 0x780) | p->linescreen;
1305 lineColor = Vdp2ColorRamGetColor(lineColorAddr, color_ram);
1306 lineAddr += lineInc;
1307 TitanPutLineHLine(info->linescreen, j, COLSAT2YAB32(0x3F, lineColor));
1308 }
1309
1310 info->LoadLineParams(info, &sinfo, j, lines);
1311 ReadLineWindowClip(info->islinewindow, clip, &linewnd0addr, &linewnd1addr, ram, regs);
1312
1313 if (userpwindow)
1314 ReadLineWindowClip(isrplinewindow, rpwindow, &rplinewnd0addr, &rplinewnd1addr, ram, regs);
1315
1316 for (i = 0; i < rbg0width; i++)
1317 {
1318 u32 color, dot;
1319
1320 if (p->deltaKAx != 0)
1321 {
1322 Vdp2ReadCoefficientFP(p,
1323 p->coeftbladdr +
1324 (coefy + coefx + toint(rcoefx + rcoefy)) *
1325 p->coefdatasize, ram);
1326 coefx += toint(p->deltaKAx);
1327 rcoefx += decipart(p->deltaKAx);
1328 }
1329 if ((p2 != NULL) && p2->coefenab && (p2->deltaKAx != 0))
1330 {
1331 Vdp2ReadCoefficientFP(p2,
1332 p2->coeftbladdr +
1333 (coefy2 + coefx2 + toint(rcoefx2 + rcoefy2)) *
1334 p2->coefdatasize, ram);
1335 coefx2 += toint(p2->deltaKAx);
1336 rcoefx2 += decipart(p2->deltaKAx);
1337 }
1338
1339 if (!TestBothWindow(info->wctl, clip, i, j))
1340 continue;
1341
1342 if (((! userpwindow) && p->msb) || (userpwindow && (! TestBothWindow(regs->WCTLD, rpwindow, i, j))))
1343 {
1344 if ((p2 == NULL) || (p2->coefenab && p2->msb)) continue;
1345
1346 x = GenerateRotatedXPosFP(p2, i, xmul2, ymul2, C2);
1347 y = GenerateRotatedYPosFP(p2, i, xmul2, ymul2, F2);
1348
1349 switch(p2->screenover) {
1350 case 0:
1351 x &= sinfo2.xmask;
1352 y &= sinfo2.ymask;
1353 break;
1354 case 1:
1355 VDP2LOG("Screen-over mode 1 not implemented");
1356 x &= sinfo2.xmask;
1357 y &= sinfo2.ymask;
1358 break;
1359 case 2:
1360 if ((x > sinfo2.xmask) || (y > sinfo2.ymask)) continue;
1361 break;
1362 case 3:
1363 if ((x > 512) || (y > 512)) continue;
1364 }
1365
1366 // Convert coordinates into graphics
1367 if (!info->isbitmap)
1368 {
1369 // Tile
1370 Vdp2MapCalcXY(info, &x, &y, &sinfo2, regs, ram, 0);
1371 }
1372 }
1373 else if (p->msb) continue;
1374 else
1375 {
1376 x = GenerateRotatedXPosFP(p, i, xmul, ymul, C);
1377 y = GenerateRotatedYPosFP(p, i, xmul, ymul, F);
1378
1379 switch(p->screenover) {
1380 case 0:
1381 x &= sinfo.xmask;
1382 y &= sinfo.ymask;
1383 break;
1384 case 1:
1385 VDP2LOG("Screen-over mode 1 not implemented");
1386 x &= sinfo.xmask;
1387 y &= sinfo.ymask;
1388 break;
1389 case 2:
1390 if ((x > sinfo.xmask) || (y > sinfo.ymask)) continue;
1391 break;
1392 case 3:
1393 if ((x > 512) || (y > 512)) continue;
1394 }
1395
1396 // Convert coordinates into graphics
1397 if (!info->isbitmap)
1398 {
1399 // Tile
1400 Vdp2MapCalcXY(info, &x, &y, &sinfo, regs, ram, 0);
1401 }
1402 }
1403
1404 // Fetch pixel
1405 if (!Vdp2FetchPixel(info, x, y, &color, &dot, ram, info->charaddr, info->paladdr, color_ram))
1406 {
1407 continue;
1408 }
1409
1410 Rbg0PutPixel(info, color, dot, i, j);
1411 }
1412 xmul += p->deltaXst;
1413 ymul += p->deltaYst;
1414 coefx = 0;
1415 rcoefx = 0;
1416 coefy += toint(p->deltaKAst);
1417 rcoefy += decipart(p->deltaKAst);
1418
1419 if (p2 != NULL)
1420 {
1421 xmul2 += p2->deltaXst;
1422 ymul2 += p2->deltaYst;
1423 if (p2->coefenab)
1424 {
1425 coefx2 = 0;
1426 rcoefx2 = 0;
1427 coefy2 += toint(p2->deltaKAst);
1428 rcoefy2 += decipart(p2->deltaKAst);
1429 }
1430 }
1431 }
1432 return;
1433 }
1434
1435 Vdp2DrawScroll(info, lines, regs, ram, color_ram, cell_data);
1436 }
1437
1438 //////////////////////////////////////////////////////////////////////////////
1439
Vdp2DrawBackScreen(void)1440 static void Vdp2DrawBackScreen(void)
1441 {
1442 int i, j;
1443
1444 // Only draw black if TVMD's DISP and BDCLMD bits are cleared
1445 if ((Vdp2Regs->TVMD & 0x8000) == 0 && (Vdp2Regs->TVMD & 0x100) == 0)
1446 {
1447 // Draw Black
1448 for (j = 0; j < vdp2height; j++)
1449 TitanPutBackHLine(j, COLSAT2YAB32(0x3F, 0));
1450 }
1451 else
1452 {
1453 // Draw Back Screen
1454 u32 scrAddr;
1455 u16 dot;
1456 vdp2draw_struct info = { 0 };
1457
1458 ReadVdp2ColorOffset(Vdp2Regs, &info, (1 << 5), 0);
1459
1460 if (Vdp2Regs->VRSIZE & 0x8000)
1461 scrAddr = (((Vdp2Regs->BKTAU & 0x7) << 16) | Vdp2Regs->BKTAL) * 2;
1462 else
1463 scrAddr = (((Vdp2Regs->BKTAU & 0x3) << 16) | Vdp2Regs->BKTAL) * 2;
1464
1465 if (Vdp2Regs->BKTAU & 0x8000)
1466 {
1467 // Per Line
1468 for (i = 0; i < vdp2height; i++)
1469 {
1470 dot = T1ReadWord(Vdp2Ram, scrAddr);
1471 scrAddr += 2;
1472
1473 TitanPutBackHLine(i, info.PostPixelFetchCalc(&info, COLSAT2YAB16(0x3f, dot)));
1474 }
1475 }
1476 else
1477 {
1478 // Single Color
1479 dot = T1ReadWord(Vdp2Ram, scrAddr);
1480
1481 for (j = 0; j < vdp2height; j++)
1482 TitanPutBackHLine(j, info.PostPixelFetchCalc(&info, COLSAT2YAB16(0x3f, dot)));
1483 }
1484 }
1485 }
1486
1487 //////////////////////////////////////////////////////////////////////////////
1488
Vdp2DrawLineScreen(void)1489 static void Vdp2DrawLineScreen(void)
1490 {
1491 u32 scrAddr;
1492 u16 color;
1493 u32 dot;
1494 int i;
1495 int alpha;
1496
1497 /* no need to go further if no screen is using the line screen */
1498 if (Vdp2Regs->LNCLEN == 0)
1499 return;
1500
1501 if (Vdp2Regs->VRSIZE & 0x8000)
1502 scrAddr = (Vdp2Regs->LCTA.all & 0x7FFFF) << 1;
1503 else
1504 scrAddr = (Vdp2Regs->LCTA.all & 0x3FFFF) << 1;
1505
1506 alpha = (Vdp2Regs->CCRLB & 0x1f) << 1;
1507
1508 if (Vdp2Regs->LCTA.part.U & 0x8000)
1509 {
1510 /* per line */
1511 for (i = 0; i < vdp2height; i++)
1512 {
1513 color = T1ReadWord(Vdp2Ram, scrAddr) & 0x7FF;
1514 dot = Vdp2ColorRamGetColor(color, Vdp2ColorRam);
1515 scrAddr += 2;
1516
1517 TitanPutLineHLine(1, i, COLSAT2YAB32(alpha, dot));
1518 }
1519 }
1520 else
1521 {
1522 /* single color, implemented but not tested... */
1523 color = T1ReadWord(Vdp2Ram, scrAddr) & 0x7FF;
1524 dot = Vdp2ColorRamGetColor(color, Vdp2ColorRam);
1525 for (i = 0; i < vdp2height; i++)
1526 TitanPutLineHLine(1, i, COLSAT2YAB32(alpha, dot));
1527 }
1528 }
1529
1530 //////////////////////////////////////////////////////////////////////////////
1531
LoadLineParamsNBG0(vdp2draw_struct * info,screeninfo_struct * sinfo,int line,Vdp2 * lines)1532 static void LoadLineParamsNBG0(vdp2draw_struct * info, screeninfo_struct * sinfo, int line, Vdp2* lines)
1533 {
1534 Vdp2 * regs;
1535
1536 regs = Vdp2RestoreRegs(line, lines);
1537 if (regs == NULL) return;
1538 ReadVdp2ColorOffset(regs, info, 0x1, 0x1);
1539 info->specialprimode = regs->SFPRMD & 0x3;
1540 info->enable = regs->BGON & 0x1 || regs->BGON & 0x20;//nbg0 or rbg1
1541 GeneratePlaneAddrTable(info, sinfo->planetbl, info->PlaneAddr, regs);//sonic 2, 2 player mode
1542 }
1543
1544 //////////////////////////////////////////////////////////////////////////////
1545
Vdp2DrawNBG0(Vdp2 * lines,Vdp2 * regs,u8 * ram,u8 * color_ram,struct CellScrollData * cell_data)1546 static void Vdp2DrawNBG0(Vdp2* lines, Vdp2* regs, u8* ram, u8* color_ram, struct CellScrollData * cell_data)
1547 {
1548 vdp2draw_struct info = { 0 };
1549 vdp2rotationparameterfp_struct parameter[2];
1550
1551 info.titan_which_layer = TITAN_NBG0;
1552 info.titan_shadow_enabled = (regs->SDCTL >> 0) & 1;
1553
1554 parameter[0].PlaneAddr = (void FASTCALL (*)(void *, int, Vdp2*))&Vdp2ParameterAPlaneAddr;
1555 parameter[1].PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2ParameterBPlaneAddr;
1556
1557 if (regs->BGON & 0x20)
1558 {
1559 // RBG1 mode
1560 info.enable = regs->BGON & 0x20;
1561
1562 // Read in Parameter B
1563 Vdp2ReadRotationTableFP(1, ¶meter[1], regs, ram);
1564
1565 if((info.isbitmap = regs->CHCTLA & 0x2) != 0)
1566 {
1567 // Bitmap Mode
1568 ReadBitmapSize(&info, regs->CHCTLA >> 2, 0x3);
1569
1570 info.charaddr = (regs->MPOFR & 0x70) * 0x2000;
1571 info.paladdr = (regs->BMPNA & 0x7) << 8;
1572 info.flipfunction = 0;
1573 info.specialfunction = 0;
1574 info.specialcolorfunction = (regs->BMPNA & 0x10) >> 4;
1575 }
1576 else
1577 {
1578 // Tile Mode
1579 info.mapwh = 4;
1580 ReadPlaneSize(&info, regs->PLSZ >> 12);
1581 ReadPatternData(&info, regs->PNCN0, regs->CHCTLA & 0x1);
1582 }
1583
1584 info.rotatenum = 1;
1585 info.rotatemode = 0;
1586 info.PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2ParameterBPlaneAddr;
1587 }
1588 else if (regs->BGON & 0x1)
1589 {
1590 // NBG0 mode
1591 info.enable = regs->BGON & 0x1;
1592
1593 if((info.isbitmap = regs->CHCTLA & 0x2) != 0)
1594 {
1595 // Bitmap Mode
1596 ReadBitmapSize(&info, regs->CHCTLA >> 2, 0x3);
1597
1598 info.x = regs->SCXIN0 & 0x7FF;
1599 info.y = regs->SCYIN0 & 0x7FF;
1600
1601 info.charaddr = (regs->MPOFN & 0x7) * 0x20000;
1602 info.paladdr = (regs->BMPNA & 0x7) << 8;
1603 info.flipfunction = 0;
1604 info.specialfunction = 0;
1605 info.specialcolorfunction = (regs->BMPNA & 0x10) >> 4;
1606 }
1607 else
1608 {
1609 // Tile Mode
1610 info.mapwh = 2;
1611
1612 ReadPlaneSize(&info, regs->PLSZ);
1613
1614 info.x = regs->SCXIN0 & 0x7FF;
1615 info.y = regs->SCYIN0 & 0x7FF;
1616 ReadPatternData(&info, regs->PNCN0, regs->CHCTLA & 0x1);
1617 }
1618
1619 info.coordincx = (regs->ZMXN0.all & 0x7FF00) / (float) 65536;
1620 info.coordincy = (regs->ZMYN0.all & 0x7FF00) / (float) 65536;
1621 info.PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2NBG0PlaneAddr;
1622 }
1623
1624 info.transparencyenable = !(regs->BGON & 0x100);
1625 info.specialprimode = regs->SFPRMD & 0x3;
1626
1627 info.colornumber = (regs->CHCTLA & 0x70) >> 4;
1628
1629 if (regs->CCCTL & 0x201)
1630 info.alpha = ((~regs->CCRNA & 0x1F) << 1) + 1;
1631 else
1632 info.alpha = 0x3F;
1633 if ((regs->CCCTL & 0x201) == 0x201) info.alpha |= 0x80;
1634 else if ((regs->CCCTL & 0x101) == 0x101) info.alpha |= 0x80;
1635 info.specialcolormode = regs->SFCCMD & 0x3;
1636 if (regs->SFSEL & 0x1)
1637 info.specialcode = regs->SFCODE >> 8;
1638 else
1639 info.specialcode = regs->SFCODE & 0xFF;
1640 info.linescreen = 0;
1641 if (regs->LNCLEN & 0x1)
1642 info.linescreen = 1;
1643
1644 info.coloroffset = (regs->CRAOFA & 0x7) << 8;
1645 ReadVdp2ColorOffset(regs, &info, 0x1, 0x1);
1646 info.priority = regs->PRINA & 0x7;
1647
1648 if (!(info.enable & Vdp2External.disptoggle))
1649 return;
1650
1651 ReadMosaicData(&info, 0x1, regs);
1652 ReadLineScrollData(&info, regs->SCRCTL & 0xFF, regs->LSTA0.all);
1653 if (regs->SCRCTL & 1)
1654 {
1655 info.isverticalscroll = 1;
1656 info.verticalscrolltbl = (regs->VCSTA.all & 0x7FFFE) << 1;
1657 if (regs->SCRCTL & 0x100)
1658 info.verticalscrollinc = 8;
1659 else
1660 info.verticalscrollinc = 4;
1661 }
1662 else
1663 info.isverticalscroll = 0;
1664 info.wctl = regs->WCTLA;
1665
1666 info.LoadLineParams = (void (*)(void *, void *,int ,Vdp2*)) LoadLineParamsNBG0;
1667
1668 if (info.enable == 1)
1669 {
1670 // NBG0 draw
1671 Vdp2DrawScroll(&info, lines, regs, ram, color_ram, cell_data);
1672 }
1673 else
1674 {
1675 // RBG1 draw
1676 Vdp2DrawRotationFP(&info, parameter, lines, regs, ram, color_ram, cell_data);
1677 }
1678 }
1679
1680 //////////////////////////////////////////////////////////////////////////////
1681
LoadLineParamsNBG1(vdp2draw_struct * info,screeninfo_struct * sinfo,int line,Vdp2 * lines)1682 static void LoadLineParamsNBG1(vdp2draw_struct * info, screeninfo_struct * sinfo, int line, Vdp2* lines)
1683 {
1684 Vdp2 * regs;
1685
1686 regs = Vdp2RestoreRegs(line, lines);
1687 if (regs == NULL) return;
1688 ReadVdp2ColorOffset(regs, info, 0x2, 0x2);
1689 info->specialprimode = (regs->SFPRMD >> 2) & 0x3;
1690 info->enable = regs->BGON & 0x2;//f1 challenge map when zoomed out
1691 GeneratePlaneAddrTable(info, sinfo->planetbl, info->PlaneAddr, regs);
1692 }
1693
1694 //////////////////////////////////////////////////////////////////////////////
1695
Vdp2DrawNBG1(Vdp2 * lines,Vdp2 * regs,u8 * ram,u8 * color_ram,struct CellScrollData * cell_data)1696 static void Vdp2DrawNBG1(Vdp2* lines, Vdp2* regs, u8* ram, u8* color_ram, struct CellScrollData * cell_data)
1697 {
1698 vdp2draw_struct info = { 0 };
1699
1700 info.titan_which_layer = TITAN_NBG1;
1701 info.titan_shadow_enabled = (regs->SDCTL >> 1) & 1;
1702
1703 info.enable = regs->BGON & 0x2;
1704 info.transparencyenable = !(regs->BGON & 0x200);
1705 info.specialprimode = (regs->SFPRMD >> 2) & 0x3;
1706
1707 info.colornumber = (regs->CHCTLA & 0x3000) >> 12;
1708
1709 if((info.isbitmap = regs->CHCTLA & 0x200) != 0)
1710 {
1711 ReadBitmapSize(&info, regs->CHCTLA >> 10, 0x3);
1712
1713 info.x = regs->SCXIN1 & 0x7FF;
1714 info.y = regs->SCYIN1 & 0x7FF;
1715
1716 info.charaddr = ((regs->MPOFN & 0x70) >> 4) * 0x20000;
1717 info.paladdr = regs->BMPNA & 0x700;
1718 info.flipfunction = 0;
1719 info.specialfunction = 0;
1720 info.specialcolorfunction = (regs->BMPNA & 0x1000) >> 12;
1721 }
1722 else
1723 {
1724 info.mapwh = 2;
1725
1726 ReadPlaneSize(&info, regs->PLSZ >> 2);
1727
1728 info.x = regs->SCXIN1 & 0x7FF;
1729 info.y = regs->SCYIN1 & 0x7FF;
1730
1731 ReadPatternData(&info, regs->PNCN1, regs->CHCTLA & 0x100);
1732 }
1733
1734 if (regs->CCCTL & 0x202)
1735 info.alpha = ((~regs->CCRNA & 0x1F00) >> 7) + 1;
1736 else
1737 info.alpha = 0x3F;
1738 if ((regs->CCCTL & 0x202) == 0x202) info.alpha |= 0x80;
1739 else if ((regs->CCCTL & 0x102) == 0x102) info.alpha |= 0x80;
1740 info.specialcolormode = (regs->SFCCMD >> 2) & 0x3;
1741 if (regs->SFSEL & 0x2)
1742 info.specialcode = regs->SFCODE >> 8;
1743 else
1744 info.specialcode = regs->SFCODE & 0xFF;
1745 info.linescreen = 0;
1746 if (regs->LNCLEN & 0x2)
1747 info.linescreen = 1;
1748
1749 info.coloroffset = (regs->CRAOFA & 0x70) << 4;
1750 ReadVdp2ColorOffset(regs, &info, 0x2, 0x2);
1751 info.coordincx = (regs->ZMXN1.all & 0x7FF00) / (float) 65536;
1752 info.coordincy = (regs->ZMYN1.all & 0x7FF00) / (float) 65536;
1753
1754 info.priority = (regs->PRINA >> 8) & 0x7;
1755 info.PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2NBG1PlaneAddr;
1756
1757 if (!(info.enable & Vdp2External.disptoggle) ||
1758 (regs->BGON & 0x1 && (regs->CHCTLA & 0x70) >> 4 == 4)) // If NBG0 16M mode is enabled, don't draw
1759 return;
1760
1761 ReadMosaicData(&info, 0x2, regs);
1762 ReadLineScrollData(&info, regs->SCRCTL >> 8, regs->LSTA1.all);
1763 if (regs->SCRCTL & 0x100)
1764 {
1765 info.isverticalscroll = 1;
1766 if (regs->SCRCTL & 0x1)
1767 {
1768 info.verticalscrolltbl = 4 + ((regs->VCSTA.all & 0x7FFFE) << 1);
1769 info.verticalscrollinc = 8;
1770 }
1771 else
1772 {
1773 info.verticalscrolltbl = (regs->VCSTA.all & 0x7FFFE) << 1;
1774 info.verticalscrollinc = 4;
1775 }
1776 }
1777 else
1778 info.isverticalscroll = 0;
1779 info.wctl = regs->WCTLA >> 8;
1780
1781 info.LoadLineParams = (void(*)(void *, void*, int, Vdp2*)) LoadLineParamsNBG1;
1782
1783 Vdp2DrawScroll(&info, lines, regs, ram, color_ram, cell_data);
1784 }
1785
1786 //////////////////////////////////////////////////////////////////////////////
1787
LoadLineParamsNBG2(vdp2draw_struct * info,screeninfo_struct * sinfo,int line,Vdp2 * lines)1788 static void LoadLineParamsNBG2(vdp2draw_struct * info, screeninfo_struct * sinfo, int line, Vdp2* lines)
1789 {
1790 Vdp2 * regs;
1791
1792 regs = Vdp2RestoreRegs(line, lines);
1793 if (regs == NULL) return;
1794 ReadVdp2ColorOffset(regs, info, 0x4, 0x4);
1795 info->specialprimode = (regs->SFPRMD >> 4) & 0x3;
1796 info->enable = regs->BGON & 0x4;
1797 GeneratePlaneAddrTable(info, sinfo->planetbl, info->PlaneAddr, regs);
1798 }
1799
1800 //////////////////////////////////////////////////////////////////////////////
1801
Vdp2DrawNBG2(Vdp2 * lines,Vdp2 * regs,u8 * ram,u8 * color_ram,struct CellScrollData * cell_data)1802 static void Vdp2DrawNBG2(Vdp2* lines, Vdp2* regs, u8* ram, u8* color_ram, struct CellScrollData * cell_data)
1803 {
1804 vdp2draw_struct info = { 0 };
1805
1806 info.titan_which_layer = TITAN_NBG2;
1807 info.titan_shadow_enabled = (regs->SDCTL >> 2) & 1;
1808
1809 info.enable = regs->BGON & 0x4;
1810 info.transparencyenable = !(regs->BGON & 0x400);
1811 info.specialprimode = (regs->SFPRMD >> 4) & 0x3;
1812
1813 info.colornumber = (regs->CHCTLB & 0x2) >> 1;
1814 info.mapwh = 2;
1815
1816 ReadPlaneSize(&info, regs->PLSZ >> 4);
1817 info.x = regs->SCXN2 & 0x7FF;
1818 info.y = regs->SCYN2 & 0x7FF;
1819 ReadPatternData(&info, regs->PNCN2, regs->CHCTLB & 0x1);
1820
1821 if (regs->CCCTL & 0x204)
1822 info.alpha = ((~regs->CCRNB & 0x1F) << 1) + 1;
1823 else
1824 info.alpha = 0x3F;
1825 if ((regs->CCCTL & 0x204) == 0x204) info.alpha |= 0x80;
1826 else if ((regs->CCCTL & 0x104) == 0x104) info.alpha |= 0x80;
1827 info.specialcolormode = (regs->SFCCMD >> 4) & 0x3;
1828 if (regs->SFSEL & 0x4)
1829 info.specialcode = regs->SFCODE >> 8;
1830 else
1831 info.specialcode = regs->SFCODE & 0xFF;
1832 info.linescreen = 0;
1833 if (regs->LNCLEN & 0x4)
1834 info.linescreen = 1;
1835
1836 info.coloroffset = regs->CRAOFA & 0x700;
1837 ReadVdp2ColorOffset(regs, &info, 0x4, 0x4);
1838 info.coordincx = info.coordincy = 1;
1839
1840 info.priority = regs->PRINB & 0x7;
1841 info.PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2NBG2PlaneAddr;
1842
1843 if (!(info.enable & Vdp2External.disptoggle) ||
1844 (regs->BGON & 0x1 && (regs->CHCTLA & 0x70) >> 4 >= 2)) // If NBG0 2048/32786/16M mode is enabled, don't draw
1845 return;
1846
1847 ReadMosaicData(&info, 0x4, regs);
1848 info.islinescroll = 0;
1849 info.isverticalscroll = 0;
1850 info.wctl = regs->WCTLB;
1851 info.isbitmap = 0;
1852
1853 info.LoadLineParams = (void(*)(void *,void*, int, Vdp2*)) LoadLineParamsNBG2;
1854
1855 Vdp2DrawScroll(&info, lines, regs, ram, color_ram, cell_data);
1856 }
1857
1858 //////////////////////////////////////////////////////////////////////////////
1859
LoadLineParamsNBG3(vdp2draw_struct * info,screeninfo_struct * sinfo,int line,Vdp2 * lines)1860 static void LoadLineParamsNBG3(vdp2draw_struct * info, screeninfo_struct * sinfo, int line, Vdp2* lines)
1861 {
1862 Vdp2 * regs;
1863
1864 regs = Vdp2RestoreRegs(line, lines);
1865 if (regs == NULL) return;
1866 ReadVdp2ColorOffset(regs, info, 0x8, 0x8);
1867 info->specialprimode = (regs->SFPRMD >> 6) & 0x3;
1868 info->enable = regs->BGON & 0x8;
1869 GeneratePlaneAddrTable(info, sinfo->planetbl, info->PlaneAddr, regs);
1870 }
1871
1872 //////////////////////////////////////////////////////////////////////////////
1873
Vdp2DrawNBG3(Vdp2 * lines,Vdp2 * regs,u8 * ram,u8 * color_ram,struct CellScrollData * cell_data)1874 static void Vdp2DrawNBG3(Vdp2* lines, Vdp2* regs, u8* ram, u8* color_ram, struct CellScrollData * cell_data)
1875 {
1876 vdp2draw_struct info = { 0 };
1877
1878 info.titan_which_layer = TITAN_NBG3;
1879 info.titan_shadow_enabled = (regs->SDCTL >> 3) & 1;
1880
1881 info.enable = regs->BGON & 0x8;
1882 info.transparencyenable = !(regs->BGON & 0x800);
1883 info.specialprimode = (regs->SFPRMD >> 6) & 0x3;
1884
1885 info.colornumber = (regs->CHCTLB & 0x20) >> 5;
1886
1887 info.mapwh = 2;
1888
1889 ReadPlaneSize(&info, regs->PLSZ >> 6);
1890 info.x = regs->SCXN3 & 0x7FF;
1891 info.y = regs->SCYN3 & 0x7FF;
1892 ReadPatternData(&info, regs->PNCN3, regs->CHCTLB & 0x10);
1893
1894 if (regs->CCCTL & 0x208)
1895 info.alpha = ((~regs->CCRNB & 0x1F00) >> 7) + 1;
1896 else
1897 info.alpha = 0x3F;
1898 if ((regs->CCCTL & 0x208) == 0x208) info.alpha |= 0x80;
1899 else if ((regs->CCCTL & 0x108) == 0x108) info.alpha |= 0x80;
1900 info.specialcolormode = (regs->SFCCMD >> 6) & 0x3;
1901 if (regs->SFSEL & 0x8)
1902 info.specialcode = regs->SFCODE >> 8;
1903 else
1904 info.specialcode = regs->SFCODE & 0xFF;
1905 info.linescreen = 0;
1906 if (regs->LNCLEN & 0x8)
1907 info.linescreen = 1;
1908
1909 info.coloroffset = (regs->CRAOFA & 0x7000) >> 4;
1910 ReadVdp2ColorOffset(regs, &info, 0x8, 0x8);
1911 info.coordincx = info.coordincy = 1;
1912
1913 info.priority = (regs->PRINB >> 8) & 0x7;
1914 info.PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2NBG3PlaneAddr;
1915
1916 if (!(info.enable & Vdp2External.disptoggle) ||
1917 (regs->BGON & 0x1 && (regs->CHCTLA & 0x70) >> 4 == 4) || // If NBG0 16M mode is enabled, don't draw
1918 (regs->BGON & 0x2 && (regs->CHCTLA & 0x3000) >> 12 >= 2)) // If NBG1 2048/32786 is enabled, don't draw
1919 return;
1920
1921 ReadMosaicData(&info, 0x8, regs);
1922 info.islinescroll = 0;
1923 info.isverticalscroll = 0;
1924 info.wctl = regs->WCTLB >> 8;
1925 info.isbitmap = 0;
1926
1927 info.LoadLineParams = (void(*)(void *, void*, int, Vdp2*)) LoadLineParamsNBG3;
1928
1929 Vdp2DrawScroll(&info, lines, regs, ram, color_ram, cell_data);
1930 }
1931
1932 //////////////////////////////////////////////////////////////////////////////
1933
LoadLineParamsRBG0(vdp2draw_struct * info,screeninfo_struct * sinfo,int line,Vdp2 * lines)1934 static void LoadLineParamsRBG0(vdp2draw_struct * info, screeninfo_struct * sinfo, int line, Vdp2* lines)
1935 {
1936 Vdp2 * regs;
1937
1938 regs = Vdp2RestoreRegs(line, lines);
1939 if (regs == NULL) return;
1940 ReadVdp2ColorOffset(regs, info, 0x10, 0x10);
1941 info->specialprimode = (regs->SFPRMD >> 8) & 0x3;
1942 }
1943
1944 //////////////////////////////////////////////////////////////////////////////
1945
Vdp2DrawRBG0(Vdp2 * lines,Vdp2 * regs,u8 * ram,u8 * color_ram,struct CellScrollData * cell_data)1946 static void Vdp2DrawRBG0(Vdp2* lines, Vdp2* regs, u8* ram, u8* color_ram, struct CellScrollData * cell_data)
1947 {
1948 vdp2draw_struct info = { 0 };
1949 vdp2rotationparameterfp_struct parameter[2];
1950
1951 info.titan_which_layer = TITAN_RBG0;
1952 info.titan_shadow_enabled = (regs->SDCTL >> 4) & 1;
1953
1954 parameter[0].PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2ParameterAPlaneAddr;
1955 parameter[1].PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2ParameterBPlaneAddr;
1956
1957 info.enable = regs->BGON & 0x10;
1958 info.priority = regs->PRIR & 0x7;
1959 if (!(info.enable & Vdp2External.disptoggle))
1960 return;
1961 info.transparencyenable = !(regs->BGON & 0x1000);
1962 info.specialprimode = (regs->SFPRMD >> 8) & 0x3;
1963
1964 info.colornumber = (regs->CHCTLB & 0x7000) >> 12;
1965
1966 // Figure out which Rotation Parameter we're using
1967 switch (regs->RPMD & 0x3)
1968 {
1969 case 0:
1970 // Parameter A
1971 info.rotatenum = 0;
1972 info.rotatemode = 0;
1973 info.PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2ParameterAPlaneAddr;
1974 break;
1975 case 1:
1976 // Parameter B
1977 info.rotatenum = 1;
1978 info.rotatemode = 0;
1979 info.PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2ParameterBPlaneAddr;
1980 break;
1981 case 2:
1982 // Parameter A+B switched via coefficients
1983 case 3:
1984 // Parameter A+B switched via rotation parameter window
1985 default:
1986 info.rotatenum = 0;
1987 info.rotatemode = 1 + (regs->RPMD & 0x1);
1988 info.PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2ParameterAPlaneAddr;
1989 break;
1990 }
1991
1992 Vdp2ReadRotationTableFP(info.rotatenum, ¶meter[info.rotatenum], regs, ram);
1993
1994 if((info.isbitmap = regs->CHCTLB & 0x200) != 0)
1995 {
1996 // Bitmap Mode
1997 ReadBitmapSize(&info, regs->CHCTLB >> 10, 0x1);
1998
1999 if (info.rotatenum == 0)
2000 // Parameter A
2001 info.charaddr = (regs->MPOFR & 0x7) * 0x20000;
2002 else
2003 // Parameter B
2004 info.charaddr = (regs->MPOFR & 0x70) * 0x2000;
2005
2006 info.paladdr = (regs->BMPNB & 0x7) << 8;
2007 info.flipfunction = 0;
2008 info.specialfunction = 0;
2009 info.specialcolorfunction = (regs->BMPNB & 0x10) >> 4;
2010 }
2011 else
2012 {
2013 // Tile Mode
2014 info.mapwh = 4;
2015
2016 if (info.rotatenum == 0)
2017 // Parameter A
2018 ReadPlaneSize(&info, regs->PLSZ >> 8);
2019 else
2020 // Parameter B
2021 ReadPlaneSize(&info, regs->PLSZ >> 12);
2022
2023 ReadPatternData(&info, regs->PNCR, regs->CHCTLB & 0x100);
2024 }
2025
2026 if (regs->CCCTL & 0x210)
2027 info.alpha = ((~regs->CCRR & 0x1F) << 1) + 1;
2028 else
2029 info.alpha = 0x3F;
2030 if ((regs->CCCTL & 0x210) == 0x210) info.alpha |= 0x80;
2031 else if ((regs->CCCTL & 0x110) == 0x110) info.alpha |= 0x80;
2032 info.specialcolormode = (regs->SFCCMD >> 8) & 0x3;
2033 if (regs->SFSEL & 0x10)
2034 info.specialcode = regs->SFCODE >> 8;
2035 else
2036 info.specialcode = regs->SFCODE & 0xFF;
2037 info.linescreen = 0;
2038 if (regs->LNCLEN & 0x10)
2039 info.linescreen = 1;
2040
2041 info.coloroffset = (regs->CRAOFB & 0x7) << 8;
2042
2043 ReadVdp2ColorOffset(regs, &info, 0x10, 0x10);
2044 info.coordincx = info.coordincy = 1;
2045
2046 ReadMosaicData(&info, 0x10, regs);
2047 info.islinescroll = 0;
2048 info.isverticalscroll = 0;
2049 info.wctl = regs->WCTLC;
2050
2051 info.LoadLineParams = (void(*)(void *, void*, int, Vdp2*)) LoadLineParamsRBG0;
2052
2053 Vdp2DrawRotationFP(&info, parameter, lines, regs, ram, color_ram, cell_data);
2054 }
2055
2056 //////////////////////////////////////////////////////////////////////////////
2057
LoadLineParamsSprite(vdp2draw_struct * info,int line,Vdp2 * lines)2058 static void LoadLineParamsSprite(vdp2draw_struct * info, int line, Vdp2* lines)
2059 {
2060 Vdp2 * regs;
2061
2062 regs = Vdp2RestoreRegs(line, lines);
2063 if (regs == NULL) return;
2064 ReadVdp2ColorOffset(regs, info, 0x40, 0x40);
2065 }
2066
2067 //////////////////////////////////////////////////////////////////////////////
2068
2069 struct {
2070 volatile int need_draw[6];
2071 volatile int draw_finished[6];
2072 Vdp2 lines[270];
2073 Vdp2 regs;
2074 u8 ram[0x80000];
2075 u8 color_ram[0x1000];
2076 struct CellScrollData cell_scroll_data[270];
2077 }vidsoft_thread_context;
2078
2079 #define DECLARE_THREAD(NAME, LAYER, FUNC) \
2080 void NAME(void * data) \
2081 { \
2082 for (;;) \
2083 { \
2084 if (vidsoft_thread_context.need_draw[LAYER]) \
2085 { \
2086 vidsoft_thread_context.need_draw[LAYER] = 0; \
2087 FUNC(vidsoft_thread_context.lines, &vidsoft_thread_context.regs, vidsoft_thread_context.ram, vidsoft_thread_context.color_ram, vidsoft_thread_context.cell_scroll_data); \
2088 vidsoft_thread_context.draw_finished[LAYER] = 1; \
2089 } \
2090 YabThreadSleep(); \
2091 } \
2092 }
2093
DECLARE_THREAD(VidsoftRbg0Thread,TITAN_RBG0,Vdp2DrawRBG0)2094 DECLARE_THREAD(VidsoftRbg0Thread, TITAN_RBG0, Vdp2DrawRBG0)
2095 DECLARE_THREAD(VidsoftNbg0Thread, TITAN_NBG0, Vdp2DrawNBG0)
2096 DECLARE_THREAD(VidsoftNbg1Thread, TITAN_NBG1, Vdp2DrawNBG1)
2097 DECLARE_THREAD(VidsoftNbg2Thread, TITAN_NBG2, Vdp2DrawNBG2)
2098 DECLARE_THREAD(VidsoftNbg3Thread, TITAN_NBG3, Vdp2DrawNBG3)
2099
2100 //////////////////////////////////////////////////////////////////////////////
2101
2102 void VIDSoftSetNumLayerThreads(int num)
2103 {
2104 vidsoft_num_layer_threads = num;
2105 }
2106
2107 //////////////////////////////////////////////////////////////////////////////
2108
VidsoftVdp1Thread(void * data)2109 void VidsoftVdp1Thread(void* data)
2110 {
2111 for (;;)
2112 {
2113 if (vidsoft_vdp1_thread_context.need_draw)
2114 {
2115 vidsoft_vdp1_thread_context.need_draw = 0;
2116 Vdp1DrawCommands(vidsoft_vdp1_thread_context.ram, &vidsoft_vdp1_thread_context.regs, vidsoft_vdp1_thread_context.back_framebuffer);
2117 memcpy(vdp1backframebuffer, vidsoft_vdp1_thread_context.back_framebuffer, 0x40000);
2118 vidsoft_vdp1_thread_context.draw_finished = 1;
2119 }
2120
2121 YabThreadSleep();
2122 }
2123 }
2124
2125 //////////////////////////////////////////////////////////////////////////////
2126
VidsoftWaitForVdp1Thread()2127 void VidsoftWaitForVdp1Thread()
2128 {
2129 if (vidsoft_vdp1_thread_enabled)
2130 {
2131 while (!vidsoft_vdp1_thread_context.draw_finished){}
2132 }
2133 }
2134
2135 //////////////////////////////////////////////////////////////////////////////
2136
VIDSoftSetVdp1ThreadEnable(int b)2137 void VIDSoftSetVdp1ThreadEnable(int b)
2138 {
2139 vidsoft_vdp1_thread_enabled = b;
2140
2141 }
2142
VidsoftSpriteThread(void * data)2143 void VidsoftSpriteThread(void * data)
2144 {
2145 for (;;)
2146 {
2147 if (vidsoft_thread_context.need_draw[TITAN_SPRITE])
2148 {
2149 vidsoft_thread_context.need_draw[TITAN_SPRITE] = 0;
2150 VidsoftDrawSprite(&vidsoft_thread_context.regs, sprite_window_mask, vdp1frontframebuffer, vidsoft_thread_context.ram, Vdp1Regs,vidsoft_thread_context.lines, vidsoft_thread_context.color_ram);
2151 vidsoft_thread_context.draw_finished[TITAN_SPRITE] = 1;
2152 }
2153 YabThreadSleep();
2154 }
2155 }
2156
2157 //////////////////////////////////////////////////////////////////////////////
2158
VIDSoftInit(void)2159 int VIDSoftInit(void)
2160 {
2161 int i;
2162
2163 if (TitanInit() == -1)
2164 return -1;
2165
2166 if ((dispbuffer = (pixel_t *)calloc(sizeof(pixel_t), 704 * 512)) == NULL)
2167 return -1;
2168
2169 // Initialize VDP1 framebuffer 1
2170 if ((vdp1framebuffer[0] = (u8 *)calloc(sizeof(u8), 0x40000)) == NULL)
2171 return -1;
2172
2173 // Initialize VDP1 framebuffer 2
2174 if ((vdp1framebuffer[1] = (u8 *)calloc(sizeof(u8), 0x40000)) == NULL)
2175 return -1;
2176
2177 vdp1backframebuffer = vdp1framebuffer[0];
2178 vdp1frontframebuffer = vdp1framebuffer[1];
2179 rbg0width = vdp2width = 320;
2180 vdp2height = 224;
2181
2182 #ifdef USE_OPENGL
2183 if (VideoUseGL)
2184 if (VIDSoftSetupGL() != 0)
2185 return -1;
2186 #endif
2187
2188 for (i = 0; i < 6; i++)
2189 {
2190 vidsoft_thread_context.draw_finished[i] = 1;
2191 vidsoft_thread_context.need_draw[i] = 0;
2192 }
2193
2194 vidsoft_vdp1_thread_context.need_draw = 0;
2195 vidsoft_vdp1_thread_context.draw_finished = 1;
2196 YabThreadStart(YAB_THREAD_VIDSOFT_VDP1, VidsoftVdp1Thread, 0);
2197
2198 YabThreadStart(YAB_THREAD_VIDSOFT_LAYER_RBG0, VidsoftRbg0Thread, 0);
2199 YabThreadStart(YAB_THREAD_VIDSOFT_LAYER_NBG0, VidsoftNbg0Thread, 0);
2200 YabThreadStart(YAB_THREAD_VIDSOFT_LAYER_NBG1, VidsoftNbg1Thread, 0);
2201 YabThreadStart(YAB_THREAD_VIDSOFT_LAYER_NBG2, VidsoftNbg2Thread, 0);
2202 YabThreadStart(YAB_THREAD_VIDSOFT_LAYER_NBG3, VidsoftNbg3Thread, 0);
2203 YabThreadStart(YAB_THREAD_VIDSOFT_LAYER_SPRITE, VidsoftSpriteThread, 0);
2204
2205 return 0;
2206 }
2207
2208 //////////////////////////////////////////////////////////////////////////////
2209
VIDSoftSetBilinear(int b)2210 void VIDSoftSetBilinear(int b)
2211 {
2212 bilinear = b;
2213 }
2214
2215 //////////////////////////////////////////////////////////////////////////////
2216
VIDSoftSetupGL(void)2217 int VIDSoftSetupGL(void)
2218 {
2219 #ifdef USE_OPENGL
2220 GLint status;
2221 GLint texAttrib;
2222 GLint posAttrib;
2223
2224 // Shader sources
2225 const GLchar* vshader_src =
2226 "#version 330 core\n"
2227 "in vec2 position;"
2228 "in vec2 texcoord;"
2229 "out vec2 outcoord;"
2230 "void main() {"
2231 " outcoord = texcoord;"
2232 " gl_Position = vec4(position, 0.0, 1.0);"
2233 "}";
2234
2235 const GLchar* fshader_src =
2236 "#version 330 core\n"
2237 "in vec2 outcoord;"
2238 "out vec4 fragcolor;"
2239 "uniform sampler2D sattex;"
2240 "void main() {"
2241 " fragcolor = texture(sattex, outcoord);"
2242 "}";
2243
2244 const float vertices[16] = {
2245 -1.0f, -1.0f, // Vertex 1 (X, Y)
2246 -1.0f, 1.0f, // Vertex 2 (X, Y)
2247 1.0f, -1.0f, // Vertex 3 (X, Y)
2248 1.0f, 1.0f, // Vertex 4 (X, Y)
2249 0.0, 1.0, // Texture 1 (X, Y)
2250 0.0, 0.0, // Texture 2 (X, Y)
2251 1.0, 1.0, // Texture 3 (X, Y)
2252 1.0, 0.0 // Texture 4 (X, Y)
2253 };
2254
2255 outputwidth = vdp2width;
2256 outputheight = vdp2height;
2257
2258 glewInit();
2259
2260 glGenVertexArrays(1, &vao);
2261 glBindVertexArray(vao);
2262
2263 glGenBuffers(1, &vbo);
2264 glBindBuffer(GL_ARRAY_BUFFER, vbo);
2265 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
2266
2267 vshader = glCreateShader(GL_VERTEX_SHADER);
2268 glShaderSource(vshader, 1, &vshader_src, NULL);
2269 glCompileShader(vshader);
2270
2271 glGetShaderiv(vshader, GL_COMPILE_STATUS, &status);
2272 if (status == GL_FALSE)
2273 {
2274 YGLLOG("Failed to compile vertex shader\n");
2275 return -1;
2276 }
2277
2278 fshader = glCreateShader(GL_FRAGMENT_SHADER);
2279 glShaderSource(fshader, 1, &fshader_src, NULL);
2280 glCompileShader(fshader);
2281
2282 glGetShaderiv(fshader, GL_COMPILE_STATUS, &status);
2283 if (status == GL_FALSE)
2284 {
2285 YGLLOG("Failed to compile fragment shader\n");
2286 return -1;
2287 }
2288
2289 gl_shader_prog = glCreateProgram();
2290 glAttachShader(gl_shader_prog, vshader);
2291 glAttachShader(gl_shader_prog, fshader);
2292
2293 glLinkProgram(gl_shader_prog);
2294
2295 glValidateProgram(gl_shader_prog);
2296 glGetProgramiv(gl_shader_prog, GL_LINK_STATUS, &status);
2297 if (status == GL_FALSE)
2298 {
2299 YGLLOG("Failed to link shader program\n");
2300 return -1;
2301 }
2302
2303 glUseProgram(gl_shader_prog);
2304
2305 posAttrib = glGetAttribLocation(gl_shader_prog, "position");
2306 glEnableVertexAttribArray(posAttrib);
2307 glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0);
2308
2309 texAttrib = glGetAttribLocation(gl_shader_prog, "texcoord");
2310 glEnableVertexAttribArray(texAttrib);
2311 glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 0, (void*)(8 * sizeof(GLfloat)));
2312
2313 glGenTextures(1, &gl_texture_id);
2314 glActiveTexture(GL_TEXTURE0);
2315 glBindTexture(GL_TEXTURE_2D, gl_texture_id);
2316
2317 if (bilinear) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); }
2318 else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); }
2319 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2320
2321 glViewport(0, 0, outputwidth, outputheight);
2322
2323 glUniform1i(glGetUniformLocation(gl_shader_prog, "sattex"), 0);
2324 #endif
2325 return 0;
2326 }
2327
2328 //////////////////////////////////////////////////////////////////////////////
2329
VIDSoftDeInit(void)2330 void VIDSoftDeInit(void)
2331 {
2332 if (dispbuffer)
2333 {
2334 free(dispbuffer);
2335 dispbuffer = NULL;
2336 }
2337
2338 if (vdp1framebuffer[0])
2339 free(vdp1framebuffer[0]);
2340
2341 if (vdp1framebuffer[1])
2342 free(vdp1framebuffer[1]);
2343 #ifdef USE_OPENGL
2344 if (VideoUseGL)
2345 {
2346 if (gl_texture_id) { glDeleteTextures(1, &gl_texture_id); }
2347 if (gl_shader_prog) { glDeleteProgram(gl_shader_prog); }
2348 if (vshader) { glDeleteShader(vshader); }
2349 if (fshader) { glDeleteShader(fshader); }
2350 if (vao) { glDeleteVertexArrays(1, &vao); }
2351 if (vbo) { glDeleteBuffers(1, &vbo); }
2352 }
2353 #endif
2354 }
2355
2356 //////////////////////////////////////////////////////////////////////////////
2357
2358 static int IsFullscreen = 0;
2359
VIDSoftResize(unsigned int w,unsigned int h,int on)2360 void VIDSoftResize(unsigned int w, unsigned int h, int on)
2361 {
2362 #ifdef USE_OPENGL
2363 if (VideoUseGL)
2364 {
2365 IsFullscreen = on;
2366 glClear(GL_COLOR_BUFFER_BIT);
2367 glViewport(0, 0, w, h);
2368 outputwidth = w;
2369 outputheight = h;
2370 }
2371 #endif
2372 }
2373
2374 //////////////////////////////////////////////////////////////////////////////
2375
VIDSoftIsFullscreen(void)2376 int VIDSoftIsFullscreen(void) {
2377 return IsFullscreen;
2378 }
2379
2380 //////////////////////////////////////////////////////////////////////////////
2381
VIDSoftVdp1Reset(void)2382 int VIDSoftVdp1Reset(void)
2383 {
2384 Vdp1Regs->userclipX1 = Vdp1Regs->systemclipX1 = 0;
2385 Vdp1Regs->userclipY1 = Vdp1Regs->systemclipY1 = 0;
2386 Vdp1Regs->userclipX2 = Vdp1Regs->systemclipX2 = 512;
2387 Vdp1Regs->userclipY2 = Vdp1Regs->systemclipY2 = 256;
2388
2389 return 0;
2390 }
2391
2392 //////////////////////////////////////////////////////////////////////////////
2393
VIDSoftVdp1DrawStartBody(Vdp1 * regs,u8 * back_framebuffer)2394 void VIDSoftVdp1DrawStartBody(Vdp1* regs, u8 * back_framebuffer)
2395 {
2396 if (regs->FBCR & 8)
2397 vdp1interlace = 2;
2398 else
2399 vdp1interlace = 1;
2400 if (regs->TVMR & 0x1)
2401 {
2402 if (regs->TVMR & 0x2)
2403 {
2404 // Rotation 8-bit
2405 vdp1width = 512;
2406 vdp1height = 512;
2407 }
2408 else
2409 {
2410 // Normal 8-bit
2411 vdp1width = 1024;
2412 vdp1height = 256;
2413 }
2414
2415 vdp1pixelsize = 1;
2416 }
2417 else
2418 {
2419 // Rotation/Normal 16-bit
2420 vdp1width = 512;
2421 vdp1height = 256;
2422 vdp1pixelsize = 2;
2423 }
2424
2425 VIDSoftVdp1EraseFrameBuffer(regs, back_framebuffer);
2426
2427 //night warriors doesn't set clipping most frames and uses
2428 //the last part of the vdp1 framebuffer as scratch ram
2429 //the previously set clipping values need to be reused
2430 }
2431 //////////////////////////////////////////////////////////////////////////////
2432
VIDSoftVdp1DrawStart()2433 void VIDSoftVdp1DrawStart()
2434 {
2435 if (vidsoft_vdp1_thread_enabled)
2436 {
2437 VidsoftWaitForVdp1Thread();
2438
2439 //take a snapshot of the vdp1 state, to be used by the thread
2440 memcpy(vidsoft_vdp1_thread_context.ram, Vdp1Ram, 0x80000);
2441 memcpy(&vidsoft_vdp1_thread_context.regs, Vdp1Regs, sizeof(Vdp1));
2442 memcpy(vidsoft_vdp1_thread_context.back_framebuffer, vdp1backframebuffer, 0x40000);
2443
2444 VIDSoftVdp1DrawStartBody(&vidsoft_vdp1_thread_context.regs, vidsoft_vdp1_thread_context.back_framebuffer);
2445
2446 //start thread
2447 vidsoft_vdp1_thread_context.draw_finished = 0;
2448 vidsoft_vdp1_thread_context.need_draw = 1;
2449 YabThreadWake(YAB_THREAD_VIDSOFT_VDP1);
2450
2451 Vdp1FakeDrawCommands(Vdp1Ram, Vdp1Regs);
2452 }
2453 else
2454 {
2455 VIDSoftVdp1DrawStartBody(Vdp1Regs, vdp1backframebuffer);
2456 Vdp1DrawCommands(Vdp1Ram, Vdp1Regs, vdp1backframebuffer);
2457 }
2458 }
2459
2460 //////////////////////////////////////////////////////////////////////////////
2461
VIDSoftVdp1DrawEnd(void)2462 void VIDSoftVdp1DrawEnd(void)
2463 {
2464 }
2465
2466 //////////////////////////////////////////////////////////////////////////////
2467
Vdp1ReadPattern16(u32 base,u32 offset,u8 * ram)2468 static INLINE u16 Vdp1ReadPattern16( u32 base, u32 offset , u8 * ram) {
2469
2470 u16 dot = T1ReadByte(ram, (base + (offset >> 1)) & 0x7FFFF);
2471 if ((offset & 0x1) == 0) dot >>= 4; // Even pixel
2472 else dot &= 0xF; // Odd pixel
2473 return dot;
2474 }
2475
Vdp1ReadPattern64(u32 base,u32 offset,u8 * ram)2476 static INLINE u16 Vdp1ReadPattern64(u32 base, u32 offset, u8 * ram) {
2477
2478 return T1ReadByte(ram, (base + offset) & 0x7FFFF) & 0x3F;
2479 }
2480
Vdp1ReadPattern128(u32 base,u32 offset,u8 * ram)2481 static INLINE u16 Vdp1ReadPattern128(u32 base, u32 offset, u8 * ram) {
2482
2483 return T1ReadByte(ram, (base + offset) & 0x7FFFF) & 0x7F;
2484 }
2485
Vdp1ReadPattern256(u32 base,u32 offset,u8 * ram)2486 static INLINE u16 Vdp1ReadPattern256(u32 base, u32 offset, u8 * ram) {
2487
2488 return T1ReadByte(ram, (base + offset) & 0x7FFFF) & 0xFF;
2489 }
2490
Vdp1ReadPattern64k(u32 base,u32 offset,u8 * ram)2491 static INLINE u16 Vdp1ReadPattern64k(u32 base, u32 offset, u8 * ram) {
2492
2493 return T1ReadWord(ram, ( base + 2*offset) & 0x7FFFF);
2494 }
2495
2496 ////////////////////////////////////////////////////////////////////////////////
2497
alphablend16(u32 d,u32 s,u32 level)2498 static INLINE u32 alphablend16(u32 d, u32 s, u32 level)
2499 {
2500 int r,g,b,sr,sg,sb,dr,dg,db;
2501
2502 int invlevel = 256-level;
2503 sr = s & 0x001f; dr = d & 0x001f;
2504 r = (sr*level + dr*invlevel)>>8; r&= 0x1f;
2505 sg = s & 0x03e0; dg = d & 0x03e0;
2506 g = (sg*level + dg*invlevel)>>8; g&= 0x03e0;
2507 sb = s & 0x7c00; db = d & 0x7c00;
2508 b = (sb*level + db*invlevel)>>8; b&= 0x7c00;
2509 return r|g|b;
2510 }
2511
2512 typedef struct _COLOR_PARAMS
2513 {
2514 double r,g,b;
2515 } COLOR_PARAMS;
2516
2517 COLOR_PARAMS leftColumnColor;
2518
2519
2520
2521 int currentPixel;
2522 int currentPixelIsVisible;
2523 int characterWidth;
2524 int characterHeight;
2525
getpixel(int linenumber,int currentlineindex,vdp1cmd_struct * cmd,u8 * ram)2526 static int getpixel(int linenumber, int currentlineindex, vdp1cmd_struct *cmd, u8 * ram) {
2527
2528 u32 characterAddress;
2529 u32 colorlut;
2530 u16 colorbank;
2531 u8 SPD;
2532 int endcode;
2533 int endcodesEnabled;
2534 int untexturedColor = 0;
2535 int isTextured = 1;
2536 int currentShape = cmd->CMDCTRL & 0x7;
2537 int flip;
2538
2539 characterAddress = cmd->CMDSRCA << 3;
2540 colorbank = cmd->CMDCOLR;
2541 colorlut = (u32)colorbank << 3;
2542 SPD = ((cmd->CMDPMOD & 0x40) != 0);//show the actual color of transparent pixels if 1 (they won't be drawn transparent)
2543 endcodesEnabled = ((cmd->CMDPMOD & 0x80) == 0) ? 1 : 0;
2544 flip = (cmd->CMDCTRL & 0x30) >> 4;
2545
2546 //4 polygon, 5 polyline or 6 line
2547 if(currentShape == 4 || currentShape == 5 || currentShape == 6) {
2548 isTextured = 0;
2549 untexturedColor = cmd->CMDCOLR;
2550 }
2551
2552 switch( flip ) {
2553 case 1:
2554 // Horizontal flipping
2555 currentlineindex = characterWidth - currentlineindex-1;
2556 break;
2557 case 2:
2558 // Vertical flipping
2559 linenumber = characterHeight - linenumber-1;
2560
2561 break;
2562 case 3:
2563 // Horizontal/Vertical flipping
2564 linenumber = characterHeight - linenumber-1;
2565 currentlineindex = characterWidth - currentlineindex-1;
2566 break;
2567 }
2568
2569 switch ((cmd->CMDPMOD >> 3) & 0x7)
2570 {
2571 case 0x0: //4bpp bank
2572 endcode = 0xf;
2573 currentPixel = Vdp1ReadPattern16( characterAddress + (linenumber*(characterWidth>>1)), currentlineindex , ram);
2574 if(isTextured && endcodesEnabled && currentPixel == endcode)
2575 return 1;
2576 if (!((currentPixel == 0) && !SPD))
2577 currentPixel = (colorbank &0xfff0)| currentPixel;
2578 currentPixelIsVisible = 0xf;
2579 break;
2580
2581 case 0x1://4bpp lut
2582 endcode = 0xf;
2583 currentPixel = Vdp1ReadPattern16(characterAddress + (linenumber*(characterWidth >> 1)), currentlineindex, ram);
2584 if(isTextured && endcodesEnabled && currentPixel == endcode)
2585 return 1;
2586 if (!(currentPixel == 0 && !SPD))
2587 currentPixel = T1ReadWord(ram, (currentPixel * 2 + colorlut) & 0x7FFFF);
2588 currentPixelIsVisible = 0xffff;
2589 break;
2590 case 0x2://8pp bank (64 color)
2591 //is there a hardware bug with endcodes in this color mode?
2592 //there are white lines around some characters in scud
2593 //using an endcode of 63 eliminates the white lines
2594 //but also causes some dropout due to endcodes being triggered that aren't triggered on hardware
2595 //the closest thing i can do to match the hardware is make all pixels with color index 63 transparent
2596 //this needs more hardware testing
2597
2598 endcode = 63;
2599 currentPixel = Vdp1ReadPattern64(characterAddress + (linenumber*(characterWidth)), currentlineindex, ram);
2600 if(isTextured && endcodesEnabled && currentPixel == endcode)
2601 currentPixel = 0;
2602 // return 1;
2603 if (!((currentPixel == 0) && !SPD))
2604 currentPixel = (colorbank&0xffc0) | currentPixel;
2605 currentPixelIsVisible = 0x3f;
2606 break;
2607 case 0x3://128 color
2608 endcode = 0xff;
2609 currentPixel = Vdp1ReadPattern128(characterAddress + (linenumber*characterWidth), currentlineindex, ram);
2610 if(isTextured && endcodesEnabled && currentPixel == endcode)
2611 return 1;
2612 if (!((currentPixel == 0) && !SPD))
2613 currentPixel = (colorbank&0xff80) | currentPixel;//dead or alive needs colorbank to be masked
2614 currentPixelIsVisible = 0x7f;
2615 break;
2616 case 0x4://256 color
2617 endcode = 0xff;
2618 currentPixel = Vdp1ReadPattern256(characterAddress + (linenumber*characterWidth), currentlineindex, ram);
2619 if(isTextured && endcodesEnabled && currentPixel == endcode)
2620 return 1;
2621 currentPixelIsVisible = 0xff;
2622 if (!((currentPixel == 0) && !SPD))
2623 currentPixel = (colorbank&0xff00) | currentPixel;
2624 break;
2625 case 0x5://16bpp bank
2626 case 0x6://prohibited, used by (at least) Beach de Reach and seems to behave like 0x5
2627 endcode = 0x7fff;
2628 currentPixel = Vdp1ReadPattern64k(characterAddress + (linenumber*characterWidth * 2), currentlineindex, ram);
2629 if(isTextured && endcodesEnabled && currentPixel == endcode)
2630 return 1;
2631
2632 /* the transparent pixel in 16bpp is supposed to be 0x0000
2633 but some games use pixels with invalid values and expect
2634 them to be transparent (see vdp1 doc p. 92) */
2635 if (!(currentPixel & 0x8000) && !SPD)
2636 currentPixel = 0;
2637
2638 currentPixelIsVisible = 0xffff;
2639 break;
2640 }
2641
2642 if(!isTextured)
2643 currentPixel = untexturedColor;
2644
2645 //force the MSB to be on if MSBON is set
2646 //currentPixel |= cmd.CMDPMOD & (1 << 15);
2647
2648 return 0;
2649 }
2650
gouraudAdjust(int color,int tableValue)2651 static int gouraudAdjust( int color, int tableValue )
2652 {
2653 color += (tableValue - 0x10);
2654
2655 if ( color < 0 ) color = 0;
2656 if ( color > 0x1f ) color = 0x1f;
2657
2658 return color;
2659 }
2660
2661
CheckDil(int y,Vdp1 * regs)2662 static int CheckDil(int y, Vdp1 * regs)
2663 {
2664 int dil = (regs->FBCR >> 2) & 1;
2665
2666 if (vdp1interlace == 2)
2667 {
2668 if (dil)
2669 {
2670 if ((y & 1) == 0)
2671 return 1;
2672 }
2673 else
2674 {
2675 if ((y & 1))
2676 return 1;
2677 }
2678 }
2679
2680 return 0;
2681 }
2682
IsUserClipped(int x,int y,Vdp1 * regs)2683 static INLINE int IsUserClipped(int x, int y, Vdp1* regs)
2684 {
2685 return !(x >= regs->userclipX1 &&
2686 x <= regs->userclipX2 &&
2687 y >= regs->userclipY1 &&
2688 y <= regs->userclipY2);
2689 }
2690
IsSystemClipped(int x,int y,Vdp1 * regs)2691 static INLINE int IsSystemClipped(int x, int y, Vdp1* regs)
2692 {
2693 return !(x >= 0 &&
2694 x <= regs->systemclipX2 &&
2695 y >= 0 &&
2696 y <= regs->systemclipY2);
2697 }
2698
IsClipped(int x,int y,Vdp1 * regs,vdp1cmd_struct * cmd)2699 int IsClipped(int x, int y, Vdp1* regs, vdp1cmd_struct * cmd)
2700 {
2701 if (cmd->CMDPMOD & 0x0400)//user clipping enabled
2702 {
2703 int is_user_clipped = IsUserClipped(x, y, regs);
2704
2705 if (((cmd->CMDPMOD >> 9) & 0x3) == 0x3)//outside clipping mode
2706 is_user_clipped = !is_user_clipped;
2707
2708 return is_user_clipped || IsSystemClipped(x, y, regs);
2709 }
2710 else
2711 {
2712 return IsSystemClipped(x, y, regs);
2713 }
2714 }
2715
putpixel8(int x,int y,Vdp1 * regs,vdp1cmd_struct * cmd,u8 * back_framebuffer)2716 static void putpixel8(int x, int y, Vdp1 * regs, vdp1cmd_struct *cmd, u8 * back_framebuffer) {
2717
2718 int y2 = y / vdp1interlace;
2719 u8 * iPix = &back_framebuffer[(y2 * vdp1width) + x];
2720 int mesh = cmd->CMDPMOD & 0x0100;
2721 int SPD = ((cmd->CMDPMOD & 0x40) != 0);//show the actual color of transparent pixels if 1 (they won't be drawn transparent)
2722
2723 if (iPix >= (back_framebuffer + 0x40000))
2724 return;
2725
2726 if (CheckDil(y, regs))
2727 return;
2728
2729 currentPixel &= 0xFF;
2730
2731 if (mesh && ((x ^ y2) & 1)) {
2732 return;
2733 }
2734
2735 if (IsClipped(x, y, regs, cmd))
2736 return;
2737
2738 if ( SPD || (currentPixel & currentPixelIsVisible))
2739 {
2740 switch( cmd->CMDPMOD & 0x7 )//we want bits 0,1,2
2741 {
2742 default:
2743 case 0: // replace
2744 if (!((currentPixel == 0) && !SPD))
2745 *(iPix) = currentPixel;
2746 break;
2747 }
2748 }
2749 }
2750
putpixel(int x,int y,Vdp1 * regs,vdp1cmd_struct * cmd,u8 * back_framebuffer)2751 static void putpixel(int x, int y, Vdp1* regs, vdp1cmd_struct * cmd, u8 * back_framebuffer) {
2752
2753 u16* iPix;
2754 int mesh = cmd->CMDPMOD & 0x0100;
2755 int SPD = ((cmd->CMDPMOD & 0x40) != 0);//show the actual color of transparent pixels if 1 (they won't be drawn transparent)
2756 int original_y = y;
2757
2758 if (CheckDil(y, regs))
2759 return;
2760
2761 y /= vdp1interlace;
2762 iPix = &((u16 *)back_framebuffer)[(y * vdp1width) + x];
2763
2764 if (iPix >= (u16*)(back_framebuffer + 0x40000))
2765 return;
2766
2767 if(mesh && (x^y)&1)
2768 return;
2769
2770 if (IsClipped(x, original_y, regs, cmd))
2771 return;
2772
2773 if (cmd->CMDPMOD & (1 << 15))
2774 {
2775 if (currentPixel) {
2776 *iPix |= 0x8000;
2777 return;
2778 }
2779 }
2780
2781 if ( SPD || (currentPixel & currentPixelIsVisible))
2782 {
2783 switch( cmd->CMDPMOD & 0x7 )//we want bits 0,1,2
2784 {
2785 case 0: // replace
2786 if (!((currentPixel == 0) && !SPD))
2787 *(iPix) = currentPixel;
2788 break;
2789 case 1: // shadow
2790 if (*(iPix) & (1 << 15)) // only if MSB of framebuffer data is set
2791 *(iPix) = alphablend16(*(iPix), 0, (1 << 7)) | (1 << 15);
2792 break;
2793 case 2: // half luminance
2794 *(iPix) = ((currentPixel & ~0x8421) >> 1) | (1 << 15);
2795 break;
2796 case 3: // half transparent
2797 if ( *(iPix) & (1 << 15) )//only if MSB of framebuffer data is set
2798 *(iPix) = alphablend16( *(iPix), currentPixel, (1 << 7) ) | (1 << 15);
2799 else
2800 *(iPix) = currentPixel;
2801 break;
2802 case 4: //gouraud
2803 #define COLOR(r,g,b) (((r)&0x1F)|(((g)&0x1F)<<5)|(((b)&0x1F)<<10) |0x8000 )
2804
2805 //handle the special case demonstrated in the sgl chrome demo
2806 //if we are in a paletted bank mode and the other two colors are unused, adjust the index value instead of rgb
2807 if(
2808 (((cmd->CMDPMOD >> 3) & 0x7) != 5) &&
2809 (((cmd->CMDPMOD >> 3) & 0x7) != 1) &&
2810 (int)leftColumnColor.g == 16 &&
2811 (int)leftColumnColor.b == 16)
2812 {
2813 int c = (int)(leftColumnColor.r-0x10);
2814 if(c < 0) c = 0;
2815 currentPixel = currentPixel+c;
2816 *(iPix) = currentPixel;
2817 break;
2818 }
2819 *(iPix) = COLOR(
2820 gouraudAdjust(
2821 currentPixel&0x001F,
2822 (int)leftColumnColor.r),
2823
2824 gouraudAdjust(
2825 (currentPixel&0x03e0) >> 5,
2826 (int)leftColumnColor.g),
2827
2828 gouraudAdjust(
2829 (currentPixel&0x7c00) >> 10,
2830 (int)leftColumnColor.b)
2831 );
2832 break;
2833 default:
2834 *(iPix) = alphablend16( COLOR((int)leftColumnColor.r,(int)leftColumnColor.g, (int)leftColumnColor.b), currentPixel, (1 << 7) ) | (1 << 15);
2835 break;
2836 }
2837 }
2838 }
2839
iterateOverLine(int x1,int y1,int x2,int y2,int greedy,void * data,int (* line_callback)(int x,int y,int i,void * data,Vdp1 * regs,vdp1cmd_struct * cmd,u8 * ram,u8 * back_framebuffer),Vdp1 * regs,vdp1cmd_struct * cmd,u8 * ram,u8 * back_framebuffer)2840 static int iterateOverLine(int x1, int y1, int x2, int y2, int greedy, void *data,
2841 int(*line_callback)(int x, int y, int i, void *data, Vdp1* regs, vdp1cmd_struct * cmd, u8* ram, u8* back_framebuffer), Vdp1* regs, vdp1cmd_struct * cmd, u8 * ram, u8* back_framebuffer) {
2842 int i, a, ax, ay, dx, dy;
2843
2844 a = i = 0;
2845 dx = x2 - x1;
2846 dy = y2 - y1;
2847 ax = (dx >= 0) ? 1 : -1;
2848 ay = (dy >= 0) ? 1 : -1;
2849
2850 //burning rangers tries to draw huge shapes
2851 //this will at least let it run
2852 if(abs(dx) > 999 || abs(dy) > 999)
2853 return INT_MAX;
2854
2855 if (abs(dx) > abs(dy)) {
2856 if (ax != ay) dx = -dx;
2857
2858 for (; x1 != x2; x1 += ax, i++) {
2859 if (line_callback && line_callback(x1, y1, i, data, regs, cmd, ram, back_framebuffer) != 0) return i + 1;
2860
2861 a += dy;
2862 if (abs(a) >= abs(dx)) {
2863 a -= dx;
2864 y1 += ay;
2865
2866 // Make sure we 'fill holes' the same as the Saturn
2867 if (greedy) {
2868 i ++;
2869 if (ax == ay) {
2870 if (line_callback &&
2871 line_callback(x1 + ax, y1 - ay, i, data, regs, cmd, ram, back_framebuffer) != 0)
2872 return i + 1;
2873 } else {
2874 if (line_callback &&
2875 line_callback(x1, y1, i, data, regs, cmd, ram, back_framebuffer) != 0)
2876 return i + 1;
2877 }
2878 }
2879 }
2880 }
2881
2882 // If the line isn't greedy here, we end up with gaps that don't occur on the Saturn
2883 if (/*(i == 0) || (y1 != y2)*/1) {
2884 if (line_callback) line_callback(x2, y2, i, data, regs, cmd, ram, back_framebuffer);
2885 i ++;
2886 }
2887 } else {
2888 if (ax != ay) dy = -dy;
2889
2890 for (; y1 != y2; y1 += ay, i++) {
2891 if (line_callback && line_callback(x1, y1, i, data, regs, cmd, ram, back_framebuffer) != 0) return i + 1;
2892
2893 a += dx;
2894 if (abs(a) >= abs(dy)) {
2895 a -= dy;
2896 x1 += ax;
2897
2898 if (greedy) {
2899 i ++;
2900 if (ay == ax) {
2901 if (line_callback &&
2902 line_callback(x1, y1, i, data, regs, cmd, ram, back_framebuffer) != 0)
2903 return i + 1;
2904 } else {
2905 if (line_callback &&
2906 line_callback(x1 - ax, y1 + ay, i, data, regs, cmd, ram, back_framebuffer) != 0)
2907 return i + 1;
2908 }
2909 }
2910 }
2911 }
2912
2913 if (/*(i == 0) || (y1 != y2)*/1) {
2914 if (line_callback) line_callback(x2, y2, i, data, regs, cmd, ram, back_framebuffer);
2915 i ++;
2916 }
2917 }
2918
2919 return i;
2920 }
2921
2922 typedef struct {
2923 double linenumber;
2924 double texturestep;
2925 double xredstep;
2926 double xgreenstep;
2927 double xbluestep;
2928 int endcodesdetected;
2929 int previousStep;
2930 } DrawLineData;
2931
DrawLineCallback(int x,int y,int i,void * data,Vdp1 * regs,vdp1cmd_struct * cmd,u8 * ram,u8 * back_framebuffer)2932 static int DrawLineCallback(int x, int y, int i, void *data, Vdp1* regs, vdp1cmd_struct * cmd, u8* ram, u8* back_framebuffer)
2933 {
2934 int currentStep;
2935 DrawLineData *linedata = data;
2936
2937 leftColumnColor.r += linedata->xredstep;
2938 leftColumnColor.g += linedata->xgreenstep;
2939 leftColumnColor.b += linedata->xbluestep;
2940
2941 currentStep = (int)i * linedata->texturestep;
2942 if (getpixel(linedata->linenumber, currentStep, cmd, ram)) {
2943 if (currentStep != linedata->previousStep) {
2944 linedata->previousStep = currentStep;
2945 linedata->endcodesdetected ++;
2946 }
2947 } else if (vdp1pixelsize == 2) {
2948 putpixel(x, y, regs, cmd, back_framebuffer);
2949 } else {
2950 putpixel8(x, y, regs, cmd, back_framebuffer);
2951 }
2952
2953 if (linedata->endcodesdetected == 2) return -1;
2954
2955 return 0;
2956 }
2957
DrawLine(int x1,int y1,int x2,int y2,int greedy,double linenumber,double texturestep,double xredstep,double xgreenstep,double xbluestep,Vdp1 * regs,vdp1cmd_struct * cmd,u8 * ram,u8 * back_framebuffer)2958 static int DrawLine(int x1, int y1, int x2, int y2, int greedy, double linenumber, double texturestep, double xredstep, double xgreenstep, double xbluestep, Vdp1* regs, vdp1cmd_struct *cmd, u8 * ram, u8* back_framebuffer)
2959 {
2960 DrawLineData data;
2961
2962 data.linenumber = linenumber;
2963 data.texturestep = texturestep;
2964 data.xredstep = xredstep;
2965 data.xgreenstep = xgreenstep;
2966 data.xbluestep = xbluestep;
2967 data.endcodesdetected = 0;
2968 data.previousStep = 123456789;
2969
2970 return iterateOverLine(x1, y1, x2, y2, greedy, &data, DrawLineCallback, regs, cmd, ram, back_framebuffer);
2971 }
2972
interpolate(double start,double end,int numberofsteps)2973 static INLINE double interpolate(double start, double end, int numberofsteps) {
2974
2975 double stepvalue = 0;
2976
2977 if(numberofsteps == 0)
2978 return 1;
2979
2980 stepvalue = (end - start) / numberofsteps;
2981
2982 return stepvalue;
2983 }
2984
2985 typedef union _COLOR { // xbgr x555
2986 struct {
2987 #ifdef WORDS_BIGENDIAN
2988 u16 x:1;
2989 u16 b:5;
2990 u16 g:5;
2991 u16 r:5;
2992 #else
2993 u16 r:5;
2994 u16 g:5;
2995 u16 b:5;
2996 u16 x:1;
2997 #endif
2998 };
2999 u16 value;
3000 } COLOR;
3001
3002 COLOR gouraudA;
3003 COLOR gouraudB;
3004 COLOR gouraudC;
3005 COLOR gouraudD;
3006
gouraudTable(u8 * ram,Vdp1 * regs,vdp1cmd_struct * cmd)3007 static void gouraudTable(u8* ram, Vdp1* regs, vdp1cmd_struct * cmd)
3008 {
3009 int gouraudTableAddress;
3010
3011
3012
3013 gouraudTableAddress = (((unsigned int)cmd->CMDGRDA) << 3);
3014
3015 gouraudA.value = T1ReadWord(ram, gouraudTableAddress);
3016 gouraudB.value = T1ReadWord(ram, gouraudTableAddress + 2);
3017 gouraudC.value = T1ReadWord(ram, gouraudTableAddress + 4);
3018 gouraudD.value = T1ReadWord(ram, gouraudTableAddress + 6);
3019 }
3020
3021 int xleft[1000];
3022 int yleft[1000];
3023 int xright[1000];
3024 int yright[1000];
3025
3026 static int
storeLineCoords(int x,int y,int i,void * arrays,Vdp1 * regs,vdp1cmd_struct * cmd,u8 * ram,u8 * back_framebuffer)3027 storeLineCoords(int x, int y, int i, void *arrays, Vdp1* regs, vdp1cmd_struct * cmd, u8* ram, u8* back_framebuffer) {
3028 int **intArrays = arrays;
3029
3030 intArrays[0][i] = x;
3031 intArrays[1][i] = y;
3032
3033 return 0;
3034 }
3035
3036 //skip objects that are completely outside of system clipping
is_pre_clipped(s16 tl_x,s16 tl_y,s16 bl_x,s16 bl_y,s16 tr_x,s16 tr_y,s16 br_x,s16 br_y,Vdp1 * regs)3037 int is_pre_clipped(s16 tl_x, s16 tl_y, s16 bl_x, s16 bl_y, s16 tr_x, s16 tr_y, s16 br_x, s16 br_y, Vdp1* regs)
3038 {
3039 int y_val = regs->systemclipY2;
3040
3041 if (vdp1interlace)
3042 y_val *= 2;
3043
3044 //if all x values are to the left of the screen
3045 if ((tl_x < 0) &&
3046 (bl_x < 0) &&
3047 (tr_x < 0) &&
3048 (br_x < 0))
3049 return 1;
3050
3051 //to the right
3052 if ((tl_x > regs->systemclipX2) &&
3053 (bl_x > regs->systemclipX2) &&
3054 (tr_x > regs->systemclipX2) &&
3055 (br_x > regs->systemclipX2))
3056 return 1;
3057
3058 //above
3059 if ((tl_y < 0) &&
3060 (bl_y < 0) &&
3061 (tr_y < 0) &&
3062 (br_y < 0))
3063 return 1;
3064
3065 //below
3066 if ((tl_y > y_val) &&
3067 (bl_y > y_val) &&
3068 (tr_y > y_val) &&
3069 (br_y > y_val))
3070 return 1;
3071
3072 return 0;
3073 }
3074
3075 //a real vdp1 draws with arbitrary lines
3076 //this is why endcodes are possible
3077 //this is also the reason why half-transparent shading causes moire patterns
3078 //and the reason why gouraud shading can be applied to a single line draw command
drawQuad(s16 tl_x,s16 tl_y,s16 bl_x,s16 bl_y,s16 tr_x,s16 tr_y,s16 br_x,s16 br_y,u8 * ram,Vdp1 * regs,vdp1cmd_struct * cmd,u8 * back_framebuffer)3079 static void drawQuad(s16 tl_x, s16 tl_y, s16 bl_x, s16 bl_y, s16 tr_x, s16 tr_y, s16 br_x, s16 br_y, u8 * ram, Vdp1* regs, vdp1cmd_struct * cmd, u8* back_framebuffer){
3080
3081 int totalleft;
3082 int totalright;
3083 int total;
3084 int i;
3085 int *intarrays[2];
3086
3087 COLOR_PARAMS topLeftToBottomLeftColorStep = {0,0,0}, topRightToBottomRightColorStep = {0,0,0};
3088
3089 //how quickly we step through the line arrays
3090 double leftLineStep = 1;
3091 double rightLineStep = 1;
3092
3093 //a lookup table for the gouraud colors
3094 COLOR colors[4];
3095
3096 if (is_pre_clipped(tl_x, tl_y, bl_x, bl_y, tr_x, tr_y, br_x, br_y, regs))
3097 return;
3098
3099 characterWidth = ((cmd->CMDSIZE >> 8) & 0x3F) * 8;
3100 characterHeight = cmd->CMDSIZE & 0xFF;
3101
3102 intarrays[0] = xleft; intarrays[1] = yleft;
3103 totalleft = iterateOverLine(tl_x, tl_y, bl_x, bl_y, 0, intarrays, storeLineCoords, regs, cmd, ram, back_framebuffer);
3104 intarrays[0] = xright; intarrays[1] = yright;
3105 totalright = iterateOverLine(tr_x, tr_y, br_x, br_y, 0, intarrays, storeLineCoords, regs, cmd, ram, back_framebuffer);
3106
3107 //just for now since burning rangers will freeze up trying to draw huge shapes
3108 if(totalleft == INT_MAX || totalright == INT_MAX)
3109 return;
3110
3111 total = totalleft > totalright ? totalleft : totalright;
3112
3113
3114 if (cmd->CMDPMOD & (1 << 2)) {
3115
3116 gouraudTable(ram, regs, cmd);
3117
3118 { colors[0] = gouraudA; colors[1] = gouraudD; colors[2] = gouraudB; colors[3] = gouraudC; }
3119
3120 topLeftToBottomLeftColorStep.r = interpolate(colors[0].r,colors[1].r,total);
3121 topLeftToBottomLeftColorStep.g = interpolate(colors[0].g,colors[1].g,total);
3122 topLeftToBottomLeftColorStep.b = interpolate(colors[0].b,colors[1].b,total);
3123
3124 topRightToBottomRightColorStep.r = interpolate(colors[2].r,colors[3].r,total);
3125 topRightToBottomRightColorStep.g = interpolate(colors[2].g,colors[3].g,total);
3126 topRightToBottomRightColorStep.b = interpolate(colors[2].b,colors[3].b,total);
3127 }
3128
3129 //we have to step the equivalent of less than one pixel on the shorter side
3130 //to make sure textures stretch properly and the shape is correct
3131 if(total == totalleft && totalleft != totalright) {
3132 //left side is larger
3133 leftLineStep = 1;
3134 rightLineStep = (double)totalright / totalleft;
3135 }
3136 else if(totalleft != totalright){
3137 //right side is larger
3138 rightLineStep = 1;
3139 leftLineStep = (double)totalleft / totalright;
3140 }
3141
3142 for(i = 0; i < total; i++) {
3143
3144 int xlinelength;
3145
3146 double xtexturestep;
3147 double ytexturestep;
3148
3149 COLOR_PARAMS rightColumnColor;
3150
3151 COLOR_PARAMS leftToRightStep = {0,0,0};
3152
3153 //get the length of the line we are about to draw
3154 xlinelength = iterateOverLine(
3155 xleft[(int)(i*leftLineStep)],
3156 yleft[(int)(i*leftLineStep)],
3157 xright[(int)(i*rightLineStep)],
3158 yright[(int)(i*rightLineStep)],
3159 1, NULL, NULL, regs, cmd, ram, back_framebuffer);
3160
3161 //so from 0 to the width of the texture / the length of the line is how far we need to step
3162 xtexturestep=interpolate(0,characterWidth,xlinelength);
3163
3164 //now we need to interpolate the y texture coordinate across multiple lines
3165 ytexturestep=interpolate(0,characterHeight,total);
3166
3167 //gouraud interpolation
3168 if(cmd->CMDPMOD & (1 << 2)) {
3169
3170 //for each new line we need to step once more through each column
3171 //and add the orignal color + the number of steps taken times the step value to the bottom of the shape
3172 //to get the current colors to use to interpolate across the line
3173
3174 leftColumnColor.r = colors[0].r +(topLeftToBottomLeftColorStep.r*i);
3175 leftColumnColor.g = colors[0].g +(topLeftToBottomLeftColorStep.g*i);
3176 leftColumnColor.b = colors[0].b +(topLeftToBottomLeftColorStep.b*i);
3177
3178 rightColumnColor.r = colors[2].r +(topRightToBottomRightColorStep.r*i);
3179 rightColumnColor.g = colors[2].g +(topRightToBottomRightColorStep.g*i);
3180 rightColumnColor.b = colors[2].b +(topRightToBottomRightColorStep.b*i);
3181
3182 //interpolate colors across to get the right step values
3183 leftToRightStep.r = interpolate(leftColumnColor.r,rightColumnColor.r,xlinelength);
3184 leftToRightStep.g = interpolate(leftColumnColor.g,rightColumnColor.g,xlinelength);
3185 leftToRightStep.b = interpolate(leftColumnColor.b,rightColumnColor.b,xlinelength);
3186 }
3187
3188 DrawLine(
3189 xleft[(int)(i*leftLineStep)],
3190 yleft[(int)(i*leftLineStep)],
3191 xright[(int)(i*rightLineStep)],
3192 yright[(int)(i*rightLineStep)],
3193 1,
3194 ytexturestep*i,
3195 xtexturestep,
3196 leftToRightStep.r,
3197 leftToRightStep.g,
3198 leftToRightStep.b,
3199 regs,
3200 cmd,
3201 ram, back_framebuffer
3202 );
3203 }
3204 }
3205
VIDSoftVdp1NormalSpriteDraw(u8 * ram,Vdp1 * regs,u8 * back_framebuffer)3206 void VIDSoftVdp1NormalSpriteDraw(u8 * ram, Vdp1 * regs, u8 * back_framebuffer) {
3207
3208 s16 topLeftx,topLefty,topRightx,topRighty,bottomRightx,bottomRighty,bottomLeftx,bottomLefty;
3209 int spriteWidth;
3210 int spriteHeight;
3211 vdp1cmd_struct cmd;
3212 Vdp1ReadCommand(&cmd, regs->addr, ram);
3213
3214 topLeftx = cmd.CMDXA + regs->localX;
3215 topLefty = cmd.CMDYA + regs->localY;
3216 spriteWidth = ((cmd.CMDSIZE >> 8) & 0x3F) * 8;
3217 spriteHeight = cmd.CMDSIZE & 0xFF;
3218
3219 topRightx = topLeftx + (spriteWidth - 1);
3220 topRighty = topLefty;
3221 bottomRightx = topLeftx + (spriteWidth - 1);
3222 bottomRighty = topLefty + (spriteHeight - 1);
3223 bottomLeftx = topLeftx;
3224 bottomLefty = topLefty + (spriteHeight - 1);
3225
3226 drawQuad(topLeftx, topLefty, bottomLeftx, bottomLefty, topRightx, topRighty, bottomRightx, bottomRighty, ram, regs, &cmd, back_framebuffer);
3227 }
3228
VIDSoftVdp1ScaledSpriteDraw(u8 * ram,Vdp1 * regs,u8 * back_framebuffer)3229 void VIDSoftVdp1ScaledSpriteDraw(u8* ram, Vdp1*regs, u8 * back_framebuffer){
3230
3231 s32 topLeftx,topLefty,topRightx,topRighty,bottomRightx,bottomRighty,bottomLeftx,bottomLefty;
3232 int x0,y0,x1,y1;
3233 vdp1cmd_struct cmd;
3234 Vdp1ReadCommand(&cmd, regs->addr, ram);
3235
3236 x0 = cmd.CMDXA + regs->localX;
3237 y0 = cmd.CMDYA + regs->localY;
3238
3239 switch ((cmd.CMDCTRL >> 8) & 0xF)
3240 {
3241 case 0x0: // Only two coordinates
3242 default:
3243 x1 = ((int)cmd.CMDXC) - x0 + regs->localX + 1;
3244 y1 = ((int)cmd.CMDYC) - y0 + regs->localY + 1;
3245 break;
3246 case 0x5: // Upper-left
3247 x1 = ((int)cmd.CMDXB) + 1;
3248 y1 = ((int)cmd.CMDYB) + 1;
3249 break;
3250 case 0x6: // Upper-Center
3251 x1 = ((int)cmd.CMDXB);
3252 y1 = ((int)cmd.CMDYB);
3253 x0 = x0 - x1/2;
3254 x1++;
3255 y1++;
3256 break;
3257 case 0x7: // Upper-Right
3258 x1 = ((int)cmd.CMDXB);
3259 y1 = ((int)cmd.CMDYB);
3260 x0 = x0 - x1;
3261 x1++;
3262 y1++;
3263 break;
3264 case 0x9: // Center-left
3265 x1 = ((int)cmd.CMDXB);
3266 y1 = ((int)cmd.CMDYB);
3267 y0 = y0 - y1/2;
3268 x1++;
3269 y1++;
3270 break;
3271 case 0xA: // Center-center
3272 x1 = ((int)cmd.CMDXB);
3273 y1 = ((int)cmd.CMDYB);
3274 x0 = x0 - x1/2;
3275 y0 = y0 - y1/2;
3276 x1++;
3277 y1++;
3278 break;
3279 case 0xB: // Center-right
3280 x1 = ((int)cmd.CMDXB);
3281 y1 = ((int)cmd.CMDYB);
3282 x0 = x0 - x1;
3283 y0 = y0 - y1/2;
3284 x1++;
3285 y1++;
3286 break;
3287 case 0xD: // Lower-left
3288 x1 = ((int)cmd.CMDXB);
3289 y1 = ((int)cmd.CMDYB);
3290 y0 = y0 - y1;
3291 x1++;
3292 y1++;
3293 break;
3294 case 0xE: // Lower-center
3295 x1 = ((int)cmd.CMDXB);
3296 y1 = ((int)cmd.CMDYB);
3297 x0 = x0 - x1/2;
3298 y0 = y0 - y1;
3299 x1++;
3300 y1++;
3301 break;
3302 case 0xF: // Lower-right
3303 x1 = ((int)cmd.CMDXB);
3304 y1 = ((int)cmd.CMDYB);
3305 x0 = x0 - x1;
3306 y0 = y0 - y1;
3307 x1++;
3308 y1++;
3309 break;
3310 }
3311
3312 topLeftx = x0;
3313 topLefty = y0;
3314
3315 topRightx = x1+x0 - 1;
3316 topRighty = topLefty;
3317
3318 bottomRightx = x1+x0 - 1;
3319 bottomRighty = y1+y0 - 1;
3320
3321 bottomLeftx = topLeftx;
3322 bottomLefty = y1+y0 - 1;
3323
3324 drawQuad(topLeftx, topLefty, bottomLeftx, bottomLefty, topRightx, topRighty, bottomRightx, bottomRighty, ram, regs, &cmd, back_framebuffer);
3325 }
3326
VIDSoftVdp1DistortedSpriteDraw(u8 * ram,Vdp1 * regs,u8 * back_framebuffer)3327 void VIDSoftVdp1DistortedSpriteDraw(u8* ram, Vdp1*regs, u8 * back_framebuffer) {
3328
3329 s32 xa,ya,xb,yb,xc,yc,xd,yd;
3330 vdp1cmd_struct cmd;
3331
3332 Vdp1ReadCommand(&cmd, regs->addr, ram);
3333
3334 xa = (s32)(cmd.CMDXA + regs->localX);
3335 ya = (s32)(cmd.CMDYA + regs->localY);
3336
3337 xb = (s32)(cmd.CMDXB + regs->localX);
3338 yb = (s32)(cmd.CMDYB + regs->localY);
3339
3340 xc = (s32)(cmd.CMDXC + regs->localX);
3341 yc = (s32)(cmd.CMDYC + regs->localY);
3342
3343 xd = (s32)(cmd.CMDXD + regs->localX);
3344 yd = (s32)(cmd.CMDYD + regs->localY);
3345
3346 drawQuad(xa, ya, xd, yd, xb, yb, xc, yc, ram, regs, &cmd, back_framebuffer);
3347 }
3348
gouraudLineSetup(double * redstep,double * greenstep,double * bluestep,int length,COLOR table1,COLOR table2,u8 * ram,Vdp1 * regs,vdp1cmd_struct * cmd,u8 * back_framebuffer)3349 static void gouraudLineSetup(double * redstep, double * greenstep, double * bluestep, int length, COLOR table1, COLOR table2, u8* ram, Vdp1* regs, vdp1cmd_struct * cmd, u8 * back_framebuffer) {
3350
3351 gouraudTable(ram ,regs, cmd);
3352
3353 *redstep =interpolate(table1.r,table2.r,length);
3354 *greenstep =interpolate(table1.g,table2.g,length);
3355 *bluestep =interpolate(table1.b,table2.b,length);
3356
3357 leftColumnColor.r = table1.r;
3358 leftColumnColor.g = table1.g;
3359 leftColumnColor.b = table1.b;
3360 }
3361
VIDSoftVdp1PolylineDraw(u8 * ram,Vdp1 * regs,u8 * back_framebuffer)3362 void VIDSoftVdp1PolylineDraw(u8* ram, Vdp1*regs, u8 * back_framebuffer)
3363 {
3364 int X[4];
3365 int Y[4];
3366 double redstep = 0, greenstep = 0, bluestep = 0;
3367 int length;
3368 vdp1cmd_struct cmd;
3369
3370 Vdp1ReadCommand(&cmd, regs->addr, ram);
3371
3372 X[0] = (int)regs->localX + (int)((s16)T1ReadWord(ram, regs->addr + 0x0C));
3373 Y[0] = (int)regs->localY + (int)((s16)T1ReadWord(ram, regs->addr + 0x0E));
3374 X[1] = (int)regs->localX + (int)((s16)T1ReadWord(ram, regs->addr + 0x10));
3375 Y[1] = (int)regs->localY + (int)((s16)T1ReadWord(ram, regs->addr + 0x12));
3376 X[2] = (int)regs->localX + (int)((s16)T1ReadWord(ram, regs->addr + 0x14));
3377 Y[2] = (int)regs->localY + (int)((s16)T1ReadWord(ram, regs->addr + 0x16));
3378 X[3] = (int)regs->localX + (int)((s16)T1ReadWord(ram, regs->addr + 0x18));
3379 Y[3] = (int)regs->localY + (int)((s16)T1ReadWord(ram, regs->addr + 0x1A));
3380
3381 length = iterateOverLine(X[0], Y[0], X[1], Y[1], 1, NULL, NULL, regs, &cmd, ram, back_framebuffer);
3382 gouraudLineSetup(&redstep, &greenstep, &bluestep, length, gouraudA, gouraudB, ram, regs, &cmd, back_framebuffer);
3383 DrawLine(X[0], Y[0], X[1], Y[1], 0, 0, 0, redstep, greenstep, bluestep, regs, &cmd, ram, back_framebuffer);
3384
3385 length = iterateOverLine(X[1], Y[1], X[2], Y[2], 1, NULL, NULL, regs, &cmd, ram, back_framebuffer);
3386 gouraudLineSetup(&redstep, &greenstep, &bluestep, length, gouraudB, gouraudC, ram, regs, &cmd, back_framebuffer);
3387 DrawLine(X[1], Y[1], X[2], Y[2], 0, 0, 0, redstep, greenstep, bluestep, regs, &cmd, ram, back_framebuffer);
3388
3389 length = iterateOverLine(X[2], Y[2], X[3], Y[3], 1, NULL, NULL, regs, &cmd, ram, back_framebuffer);
3390 gouraudLineSetup(&redstep, &greenstep, &bluestep, length, gouraudD, gouraudC, ram, regs, &cmd, back_framebuffer);
3391 DrawLine(X[3], Y[3], X[2], Y[2], 0, 0, 0, redstep, greenstep, bluestep, regs, &cmd, ram, back_framebuffer);
3392
3393 length = iterateOverLine(X[3], Y[3], X[0], Y[0], 1, NULL, NULL, regs, &cmd, ram, back_framebuffer);
3394 gouraudLineSetup(&redstep, &greenstep, &bluestep, length, gouraudA, gouraudD, ram, regs, &cmd, back_framebuffer);
3395 DrawLine(X[0], Y[0], X[3], Y[3], 0, 0, 0, redstep, greenstep, bluestep, regs, &cmd, ram, back_framebuffer);
3396 }
3397
VIDSoftVdp1LineDraw(u8 * ram,Vdp1 * regs,u8 * back_framebuffer)3398 void VIDSoftVdp1LineDraw(u8* ram, Vdp1*regs, u8* back_framebuffer)
3399 {
3400 int x1, y1, x2, y2;
3401 double redstep = 0, greenstep = 0, bluestep = 0;
3402 int length;
3403 vdp1cmd_struct cmd;
3404
3405 Vdp1ReadCommand(&cmd, regs->addr, ram);
3406
3407 x1 = (int)regs->localX + (int)((s16)T1ReadWord(ram, regs->addr + 0x0C));
3408 y1 = (int)regs->localY + (int)((s16)T1ReadWord(ram, regs->addr + 0x0E));
3409 x2 = (int)regs->localX + (int)((s16)T1ReadWord(ram, regs->addr + 0x10));
3410 y2 = (int)regs->localY + (int)((s16)T1ReadWord(ram, regs->addr + 0x12));
3411
3412 length = iterateOverLine(x1, y1, x2, y2, 1, NULL, NULL, regs, &cmd, ram, back_framebuffer);
3413 gouraudLineSetup(&redstep, &bluestep, &greenstep, length, gouraudA, gouraudB, ram, regs, &cmd, back_framebuffer);
3414 DrawLine(x1, y1, x2, y2, 0, 0, 0, redstep, greenstep, bluestep, regs, &cmd, ram, back_framebuffer);
3415 }
3416
3417 //////////////////////////////////////////////////////////////////////////////
3418
VIDSoftVdp1UserClipping(u8 * ram,Vdp1 * regs)3419 void VIDSoftVdp1UserClipping(u8* ram, Vdp1*regs)
3420 {
3421 regs->userclipX1 = T1ReadWord(ram, regs->addr + 0xC);
3422 regs->userclipY1 = T1ReadWord(ram, regs->addr + 0xE);
3423 regs->userclipX2 = T1ReadWord(ram, regs->addr + 0x14);
3424 regs->userclipY2 = T1ReadWord(ram, regs->addr + 0x16);
3425 }
3426
3427 //////////////////////////////////////////////////////////////////////////////
3428
VIDSoftVdp1SystemClipping(u8 * ram,Vdp1 * regs)3429 void VIDSoftVdp1SystemClipping(u8* ram, Vdp1*regs)
3430 {
3431 regs->systemclipX1 = 0;
3432 regs->systemclipY1 = 0;
3433 regs->systemclipX2 = T1ReadWord(ram, regs->addr + 0x14);
3434 regs->systemclipY2 = T1ReadWord(ram, regs->addr + 0x16);
3435 }
3436
3437 //////////////////////////////////////////////////////////////////////////////
3438
VIDSoftVdp1LocalCoordinate(u8 * ram,Vdp1 * regs)3439 void VIDSoftVdp1LocalCoordinate(u8* ram, Vdp1*regs)
3440 {
3441 regs->localX = T1ReadWord(ram, regs->addr + 0xC);
3442 regs->localY = T1ReadWord(ram, regs->addr + 0xE);
3443 }
3444
3445 //////////////////////////////////////////////////////////////////////////////
3446
VIDSoftVdp1ReadFrameBuffer(u32 type,u32 addr,void * out)3447 void VIDSoftVdp1ReadFrameBuffer(u32 type, u32 addr, void * out)
3448 {
3449 u32 val;
3450
3451 VidsoftWaitForVdp1Thread();
3452
3453 switch (type)
3454 {
3455 case 0:
3456 val = T1ReadByte(vdp1backframebuffer, addr);
3457 *(u8*)out = val;
3458 break;
3459 case 1:
3460 val = T1ReadWord(vdp1backframebuffer, addr);
3461 #ifndef WORDS_BIGENDIAN
3462 val = BSWAP16L(val);
3463 #endif
3464 *(u16*)out = val;
3465 break;
3466 case 2:
3467 #if 0 //enable when burning rangers is fixed
3468 val = T1ReadLong(vdp1backframebuffer, addr);
3469 #ifndef WORDS_BIGENDIAN
3470 val = BSWAP32(val);
3471 #endif
3472 val = (val & 0xffff) << 16 | (val & 0xffff0000) >> 16;
3473 *(u32*)out = val;
3474 #else
3475 *(u32*)out = 0;
3476 #endif
3477 break;
3478 default:
3479 break;
3480 }
3481 }
3482
3483 //////////////////////////////////////////////////////////////////////////////
3484
VIDSoftVdp1WriteFrameBuffer(u32 type,u32 addr,u32 val)3485 void VIDSoftVdp1WriteFrameBuffer(u32 type, u32 addr, u32 val)
3486 {
3487 VidsoftWaitForVdp1Thread();
3488
3489 switch (type)
3490 {
3491 case 0:
3492 T1WriteByte(vdp1backframebuffer, addr, val);
3493 break;
3494 case 1:
3495 #ifndef WORDS_BIGENDIAN
3496 val = BSWAP16L(val);
3497 #endif
3498 T1WriteWord(vdp1backframebuffer, addr, val);
3499 break;
3500 case 2:
3501 #ifndef WORDS_BIGENDIAN
3502 val = BSWAP32(val);
3503 #endif
3504 val = (val & 0xffff) << 16 | (val & 0xffff0000) >> 16;
3505 T1WriteLong(vdp1backframebuffer, addr, val);
3506 break;
3507 default:
3508 break;
3509 }
3510 }
3511
3512 //////////////////////////////////////////////////////////////////////////////
3513
VIDSoftVdp2Reset(void)3514 int VIDSoftVdp2Reset(void)
3515 {
3516 return 0;
3517 }
3518
3519 //////////////////////////////////////////////////////////////////////////////
3520
VIDSoftVdp2DrawStart(void)3521 void VIDSoftVdp2DrawStart(void)
3522 {
3523 int titanblendmode = TITAN_BLEND_TOP;
3524 if (Vdp2Regs->CCCTL & 0x100) titanblendmode = TITAN_BLEND_ADD;
3525 else if (Vdp2Regs->CCCTL & 0x200) titanblendmode = TITAN_BLEND_BOTTOM;
3526 TitanSetBlendingMode(titanblendmode);
3527
3528 Vdp2DrawBackScreen();
3529 Vdp2DrawLineScreen();
3530
3531 //dracula x bad cycle setting
3532 if (Vdp2Regs->CYCA0L == 0x5566 &&
3533 Vdp2Regs->CYCA0U == 0x47ff &&
3534 Vdp2Regs->CYCA1L == 0xffff &&
3535 Vdp2Regs->CYCA1U == 0xffff &&
3536 Vdp2Regs->CYCB0L == 0x12ff &&
3537 Vdp2Regs->CYCB0U == 0x03ff &&
3538 Vdp2Regs->CYCB1L == 0xffff &&
3539 Vdp2Regs->CYCB1U == 0xffff)
3540 {
3541 bad_cycle_setting[TITAN_NBG3] = 1;
3542 }
3543 else
3544 bad_cycle_setting[TITAN_NBG3] = 0;
3545 }
3546
3547 //////////////////////////////////////////////////////////////////////////////
3548
3549
VidsoftDrawSprite(Vdp2 * vdp2_regs,u8 * spr_window_mask,u8 * vdp1_front_framebuffer,u8 * vdp2_ram,Vdp1 * vdp1_regs,Vdp2 * vdp2_lines,u8 * color_ram)3550 void VidsoftDrawSprite(Vdp2 * vdp2_regs, u8 * spr_window_mask, u8* vdp1_front_framebuffer, u8 * vdp2_ram, Vdp1* vdp1_regs, Vdp2* vdp2_lines, u8*color_ram)
3551 {
3552 int i, i2;
3553 u16 pixel;
3554 u8 prioritytable[8];
3555 u32 vdp1coloroffset;
3556 int colormode = vdp2_regs->SPCTL & 0x20;
3557 vdp2draw_struct info = { 0 };
3558 int islinewindow;
3559 clipping_struct clip[2];
3560 u32 linewnd0addr, linewnd1addr;
3561 int wctl;
3562 clipping_struct colorcalcwindow[2];
3563 int framebuffer_readout_y = 0;
3564 int start_line = 0, line_increment = 0;
3565 int sprite_window_enabled = vdp2_regs->SPCTL & 0x10;
3566 int vdp1spritetype = 0;
3567
3568 if (sprite_window_enabled)
3569 {
3570 memset(spr_window_mask, 0, 704 * 512);
3571 }
3572
3573 // Figure out whether to draw vdp1 framebuffer or vdp2 framebuffer pixels
3574 // based on priority
3575 if (Vdp1External.disptoggle && (vdp2_regs->TVMD & 0x8000))
3576 {
3577 int SPCCCS = (vdp2_regs->SPCTL >> 12) & 0x3;
3578 int SPCCN = (vdp2_regs->SPCTL >> 8) & 0x7;
3579 u8 colorcalctable[8];
3580 vdp2rotationparameterfp_struct p;
3581 int x, y;
3582 int output_y = 0;
3583
3584 prioritytable[0] = vdp2_regs->PRISA & 0x7;
3585 prioritytable[1] = (vdp2_regs->PRISA >> 8) & 0x7;
3586 prioritytable[2] = vdp2_regs->PRISB & 0x7;
3587 prioritytable[3] = (vdp2_regs->PRISB >> 8) & 0x7;
3588 prioritytable[4] = vdp2_regs->PRISC & 0x7;
3589 prioritytable[5] = (vdp2_regs->PRISC >> 8) & 0x7;
3590 prioritytable[6] = vdp2_regs->PRISD & 0x7;
3591 prioritytable[7] = (vdp2_regs->PRISD >> 8) & 0x7;
3592 colorcalctable[0] = ((~vdp2_regs->CCRSA & 0x1F) << 1) + 1;
3593 colorcalctable[1] = ((~vdp2_regs->CCRSA >> 7) & 0x3E) + 1;
3594 colorcalctable[2] = ((~vdp2_regs->CCRSB & 0x1F) << 1) + 1;
3595 colorcalctable[3] = ((~vdp2_regs->CCRSB >> 7) & 0x3E) + 1;
3596 colorcalctable[4] = ((~vdp2_regs->CCRSC & 0x1F) << 1) + 1;
3597 colorcalctable[5] = ((~vdp2_regs->CCRSC >> 7) & 0x3E) + 1;
3598 colorcalctable[6] = ((~vdp2_regs->CCRSD & 0x1F) << 1) + 1;
3599 colorcalctable[7] = ((~vdp2_regs->CCRSD >> 7) & 0x3E) + 1;
3600
3601 vdp1coloroffset = (vdp2_regs->CRAOFB & 0x70) << 4;
3602 vdp1spritetype = vdp2_regs->SPCTL & 0xF;
3603
3604 ReadVdp2ColorOffset(vdp2_regs, &info, 0x40, 0x40);
3605
3606 wctl = vdp2_regs->WCTLC >> 8;
3607 clip[0].xstart = clip[0].ystart = clip[0].xend = clip[0].yend = 0;
3608 clip[1].xstart = clip[1].ystart = clip[1].xend = clip[1].yend = 0;
3609 ReadWindowData(wctl, clip, vdp2_regs);
3610 linewnd0addr = linewnd1addr = 0;
3611 ReadLineWindowData(&islinewindow, wctl, &linewnd0addr, &linewnd1addr, vdp2_regs);
3612
3613 /* color calculation window: in => no color calc, out => color calc */
3614 ReadWindowData(vdp2_regs->WCTLD >> 8, colorcalcwindow, vdp2_regs);
3615
3616 if (vdp1_regs->TVMR & 2)
3617 Vdp2ReadRotationTableFP(0, &p, vdp2_regs, vdp2_ram);
3618
3619 info.titan_which_layer = TITAN_SPRITE;
3620
3621 info.linescreen = (vdp2_regs->LNCLEN >> 5) & 1;
3622
3623 Vdp2GetInterlaceInfo(&start_line, &line_increment);
3624
3625 for (i2 = start_line; i2 < vdp2height; i2 += line_increment)
3626 {
3627 float framebuffer_readout_pos = 0;
3628
3629 ReadLineWindowClip(islinewindow, clip, &linewnd0addr, &linewnd1addr, vdp2_ram, vdp2_regs);
3630
3631 if (vdp2_interlace)
3632 LoadLineParamsSprite(&info, i2 / 2, vdp2_lines);
3633 else
3634 LoadLineParamsSprite(&info, i2, vdp2_lines);
3635
3636 if (vdp2_interlace)
3637 {
3638 y = framebuffer_readout_y;
3639 framebuffer_readout_y += 1;
3640 }
3641 else
3642 {
3643 y = i2;
3644 }
3645
3646 for (i = 0; i < vdp2width; i++)
3647 {
3648
3649 info.titan_shadow_type = 0;
3650
3651 // See if screen position is clipped, if it isn't, continue
3652 if (!(vdp2_regs->SPCTL & 0x10))
3653 {
3654 if (!TestBothWindow(wctl, clip, i, i2))
3655 {
3656 continue;
3657 }
3658 }
3659
3660 if (vdp1_regs->TVMR & 2) {
3661 x = (touint(p.Xst + i * p.deltaX + i2 * p.deltaXst)) & (vdp1width - 1);
3662 y = (touint(p.Yst + i * p.deltaY + i2 * p.deltaYst)) & (vdp1height - 1);
3663 }
3664 else
3665 {
3666 if (vdp1width == 1024 && vdp2_x_hires)
3667 {
3668 //hi res vdp1 and hi res vdp2
3669 //pixels 1:1
3670 x = (int)framebuffer_readout_pos;
3671 framebuffer_readout_pos += 1;
3672 }
3673 else if (vdp1width == 512 && vdp2_x_hires)
3674 {
3675 //low res vdp1,hi res vdp2
3676 //vdp1 pixel doubling
3677 x = (int)framebuffer_readout_pos;
3678 framebuffer_readout_pos += .5;
3679 }
3680 else if (vdp1width == 1024 && (!vdp2_x_hires))
3681 {
3682 //hi res vdp1, low res vdp2
3683 //the vdp1 framebuffer is read out at half-res
3684 x = (int)framebuffer_readout_pos;
3685 framebuffer_readout_pos += 2;
3686 }
3687 else
3688 x = i;
3689 }
3690
3691 if (vdp1pixelsize == 2)
3692 {
3693 // 16-bit pixel size
3694 pixel = ((u16 *)vdp1_front_framebuffer)[(y * vdp1width) + x];
3695
3696 if (pixel == 0)
3697 ;
3698 else if (pixel & 0x8000 && colormode)
3699 {
3700 // 16 BPP
3701 u8 alpha = 0x3F;
3702 if (TestBothWindow(vdp2_regs->WCTLD >> 8, colorcalcwindow, i, i2) && (vdp2_regs->CCCTL & 0x40))
3703 {
3704 switch (SPCCCS) {
3705 case 0:
3706 if (prioritytable[0] <= SPCCN)
3707 {
3708 alpha = colorcalctable[0];
3709 if (vdp2_regs->CCCTL & 0x300) alpha |= 0x80;
3710 }
3711 break;
3712 case 1:
3713 if (prioritytable[0] == SPCCN)
3714 {
3715 alpha = colorcalctable[0];
3716 if (vdp2_regs->CCCTL & 0x300) alpha |= 0x80;
3717 }
3718 break;
3719 case 2:
3720 if (prioritytable[0] >= SPCCN)
3721 {
3722 alpha = colorcalctable[0];
3723 if (vdp2_regs->CCCTL & 0x300) alpha |= 0x80;
3724 }
3725 break;
3726 case 3:
3727 alpha = colorcalctable[0];
3728 if (vdp2_regs->CCCTL & 0x300) alpha |= 0x80;
3729 break;
3730 }
3731 }
3732
3733 // if pixel is 0x8000, only draw pixel if sprite window
3734 // is disabled/sprite type 2-7. sprite types 0 and 1 are
3735 // -always- drawn and sprite types 8-F are always
3736 // transparent.
3737 if (pixel != 0x8000 || vdp1spritetype < 2 || (vdp1spritetype < 8 && !(vdp2_regs->SPCTL & 0x10)))
3738 TitanPutPixel(prioritytable[0], i, output_y, info.PostPixelFetchCalc(&info, COLSAT2YAB16(alpha, pixel)), info.linescreen, &info);
3739 }
3740 else
3741 {
3742 // Color bank
3743 spritepixelinfo_struct spi;
3744 u8 alpha = 0x3F;
3745 u32 dot;
3746
3747 Vdp1GetSpritePixelInfo(vdp1spritetype, &pixel, &spi);
3748 if (spi.normalshadow)
3749 {
3750 info.titan_shadow_type = TITAN_NORMAL_SHADOW;
3751 TitanPutPixel(prioritytable[spi.priority], i, output_y, COLSAT2YAB16(0x3f, 0), info.linescreen, &info);
3752 continue;
3753 }
3754
3755 dot = Vdp2ColorRamGetColor(vdp1coloroffset + pixel,color_ram);
3756
3757 if (TestBothWindow(vdp2_regs->WCTLD >> 8, colorcalcwindow, i, i2) && (vdp2_regs->CCCTL & 0x40))
3758 {
3759 int transparent = 0;
3760
3761 /* Sprite color calculation */
3762 switch (SPCCCS) {
3763 case 0:
3764 if (prioritytable[spi.priority] <= SPCCN)
3765 transparent = 1;
3766 break;
3767 case 1:
3768 if (prioritytable[spi.priority] == SPCCN)
3769 transparent = 1;
3770 break;
3771 case 2:
3772 if (prioritytable[spi.priority] >= SPCCN)
3773 transparent = 1;
3774 break;
3775 case 3:
3776 if (dot & 0x80000000)
3777 transparent = 1;
3778 break;
3779 }
3780
3781 if (vdp2_regs->CCCTL & 0x200) {
3782 /* "bottom" mode, the alpha channel will be used by another layer,
3783 so we set it regardless of whether sprites are transparent or not.
3784 The highest priority bit is only set if the sprite is transparent
3785 (in this case, it's the alpha channel of the lower priority layer
3786 that will be used. */
3787 alpha = colorcalctable[spi.colorcalc];
3788 if (transparent) alpha |= 0x80;
3789 }
3790 else if (transparent) {
3791 alpha = colorcalctable[spi.colorcalc];
3792 if (vdp2_regs->CCCTL & 0x100) alpha |= 0x80;
3793 }
3794 }
3795 if (spi.msbshadow)
3796 {
3797 if (sprite_window_enabled) {
3798 spr_window_mask[(y*vdp2width) + x] = 1;
3799 info.titan_shadow_type = TITAN_MSB_SHADOW;
3800 }
3801 else
3802 {
3803 info.titan_shadow_type = TITAN_MSB_SHADOW;
3804 }
3805
3806 if (pixel == 0)
3807 {
3808 TitanPutPixel(prioritytable[spi.priority], i, output_y, info.PostPixelFetchCalc(&info, COLSAT2YAB32(alpha, 0)), info.linescreen, &info);
3809 continue;
3810 }
3811 }
3812
3813 if ((sprite_window_enabled))
3814 {
3815 if (!TestBothWindow(wctl, clip, i, i2))
3816 {
3817 continue;
3818 }
3819 }
3820
3821 TitanPutPixel(prioritytable[spi.priority], i, output_y, info.PostPixelFetchCalc(&info, COLSAT2YAB32(alpha, dot)), info.linescreen, &info);
3822 }
3823 }
3824 else
3825 {
3826 // 8-bit pixel size
3827 pixel = vdp1_front_framebuffer[(y * vdp1width) + x];
3828
3829 if (pixel != 0)
3830 {
3831 // Color bank(fix me)
3832 spritepixelinfo_struct spi;
3833 u8 alpha = 0x3F;
3834 u32 dot;
3835
3836 Vdp1GetSpritePixelInfo(vdp1spritetype, &pixel, &spi);
3837 if (spi.normalshadow)
3838 {
3839 info.titan_shadow_type = TITAN_NORMAL_SHADOW;
3840 TitanPutPixel(prioritytable[spi.priority], i, output_y, COLSAT2YAB16(0x3f, 0), info.linescreen, &info);
3841 continue;
3842 }
3843
3844 dot = Vdp2ColorRamGetColor(vdp1coloroffset + pixel, color_ram);
3845
3846 if (TestBothWindow(vdp2_regs->WCTLD >> 8, colorcalcwindow, i, i2) && (vdp2_regs->CCCTL & 0x40))
3847 {
3848 int transparent = 0;
3849
3850 /* Sprite color calculation */
3851 switch (SPCCCS) {
3852 case 0:
3853 if (prioritytable[spi.priority] <= SPCCN)
3854 transparent = 1;
3855 break;
3856 case 1:
3857 if (prioritytable[spi.priority] == SPCCN)
3858 transparent = 1;
3859 break;
3860 case 2:
3861 if (prioritytable[spi.priority] >= SPCCN)
3862 transparent = 1;
3863 break;
3864 case 3:
3865 if (dot & 0x80000000)
3866 transparent = 1;
3867 break;
3868 }
3869
3870 if (vdp2_regs->CCCTL & 0x200) {
3871 /* "bottom" mode, the alpha channel will be used by another layer,
3872 so we set it regardless of whether sprites are transparent or not.
3873 The highest priority bit is only set if the sprite is transparent
3874 (in this case, it's the alpha channel of the lower priority layer
3875 that will be used. */
3876 alpha = colorcalctable[spi.colorcalc];
3877 if (transparent) alpha |= 0x80;
3878 }
3879 else if (transparent) {
3880 alpha = colorcalctable[spi.colorcalc];
3881 if (vdp2_regs->CCCTL & 0x100) alpha |= 0x80;
3882 }
3883 }
3884
3885 TitanPutPixel(prioritytable[spi.priority], i, output_y, info.PostPixelFetchCalc(&info, COLSAT2YAB32(alpha, dot)), info.linescreen, &info);
3886 }
3887 }
3888 }
3889
3890 output_y++;
3891 }
3892 }
3893 }
3894
VIDSoftVdp2DrawEnd(void)3895 void VIDSoftVdp2DrawEnd(void)
3896 {
3897 if (vidsoft_num_layer_threads > 0)
3898 {
3899 while (!vidsoft_thread_context.draw_finished[TITAN_NBG0]){}
3900 while (!vidsoft_thread_context.draw_finished[TITAN_NBG1]){}
3901 while (!vidsoft_thread_context.draw_finished[TITAN_NBG2]){}
3902 while (!vidsoft_thread_context.draw_finished[TITAN_NBG3]){}
3903 while (!vidsoft_thread_context.draw_finished[TITAN_RBG0]){}
3904 while (!vidsoft_thread_context.draw_finished[TITAN_SPRITE]){}
3905 }
3906
3907 TitanRender(dispbuffer);
3908
3909 VIDSoftVdp1SwapFrameBuffer();
3910
3911 if (OSDUseBuffer())
3912 OSDDisplayMessages(dispbuffer, vdp2width, vdp2height);
3913
3914 #ifdef USE_OPENGL
3915 if (VideoUseGL)
3916 {
3917 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, vdp2width, vdp2height, 0, GL_RGBA, GL_UNSIGNED_BYTE, dispbuffer);
3918 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
3919 glClear(GL_COLOR_BUFFER_BIT);
3920 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3921
3922 if (! OSDUseBuffer())
3923 OSDDisplayMessages(NULL, -1, -1);
3924 }
3925 #endif
3926
3927 YuiSwapBuffers();
3928 }
3929
3930 //////////////////////////////////////////////////////////////////////////////
3931
VidsoftStartLayerThread(int * layer_priority,int * draw_priority_0,int * num_threads_dispatched,int which_layer,void (* layer_func)(Vdp2 * lines,Vdp2 * regs,u8 * ram,u8 * color_ram,struct CellScrollData * cell_data))3932 void VidsoftStartLayerThread(int * layer_priority, int * draw_priority_0, int * num_threads_dispatched, int which_layer, void(*layer_func) (Vdp2* lines, Vdp2* regs, u8* ram, u8* color_ram, struct CellScrollData * cell_data))
3933 {
3934 if (layer_priority[which_layer] > 0 || draw_priority_0[which_layer])
3935 {
3936 if (*num_threads_dispatched < vidsoft_num_layer_threads)
3937 {
3938 vidsoft_thread_context.need_draw[which_layer] = 1;
3939 vidsoft_thread_context.draw_finished[which_layer] = 0;
3940 YabThreadWake(YAB_THREAD_VIDSOFT_LAYER_NBG3 + which_layer);
3941 *num_threads_dispatched = *num_threads_dispatched + 1;
3942 }
3943 else
3944 {
3945 (*layer_func) (Vdp2Lines, Vdp2Regs, Vdp2Ram, Vdp2ColorRam, cell_scroll_data);
3946 }
3947 }
3948 }
3949
3950 //////////////////////////////////////////////////////////////////////////////
3951
IsSpriteWindowEnabled(u16 wtcl)3952 int IsSpriteWindowEnabled(u16 wtcl)
3953 {
3954 if (((wtcl& (1 << 13)) == 0) &&
3955 ((wtcl & (1 << 5)) == 0))
3956 return 0;
3957
3958 return 1;
3959 }
3960
CanUseSpriteThread()3961 int CanUseSpriteThread()
3962 {
3963 //check if sprite window is enabled
3964 if ((Vdp2Regs->SPCTL & (1 << 4)) == 0)
3965 return 1;
3966
3967 //check if any layers are using it
3968 if (IsSpriteWindowEnabled(Vdp2Regs->WCTLA) ||
3969 IsSpriteWindowEnabled(Vdp2Regs->WCTLB) ||
3970 IsSpriteWindowEnabled(Vdp2Regs->WCTLC) ||
3971 IsSpriteWindowEnabled(Vdp2Regs->WCTLD))
3972 {
3973 //thread cannot be used
3974 return 0;
3975 }
3976
3977 return 1;
3978 }
3979
VIDSoftVdp2DrawScreens(void)3980 void VIDSoftVdp2DrawScreens(void)
3981 {
3982 int draw_priority_0[6] = { 0 };
3983 int layer_priority[6] = { 0 };
3984 int num_threads_dispatched = 0;
3985
3986 VIDSoftVdp2SetResolution(Vdp2Regs->TVMD);
3987 layer_priority[TITAN_NBG0] = Vdp2Regs->PRINA & 0x7;
3988 layer_priority[TITAN_NBG1] = ((Vdp2Regs->PRINA >> 8) & 0x7);
3989 layer_priority[TITAN_NBG2] = (Vdp2Regs->PRINB & 0x7);
3990 layer_priority[TITAN_NBG3] = ((Vdp2Regs->PRINB >> 8) & 0x7);
3991 layer_priority[TITAN_RBG0] = (Vdp2Regs->PRIR & 0x7);
3992
3993 TitanErase();
3994
3995 if (Vdp2Regs->SFPRMD & 0x3FF)
3996 {
3997 draw_priority_0[TITAN_NBG0] = (Vdp2Regs->SFPRMD >> 0) & 0x3;
3998 draw_priority_0[TITAN_NBG1] = (Vdp2Regs->SFPRMD >> 2) & 0x3;
3999 draw_priority_0[TITAN_NBG2] = (Vdp2Regs->SFPRMD >> 4) & 0x3;
4000 draw_priority_0[TITAN_NBG3] = (Vdp2Regs->SFPRMD >> 6) & 0x3;
4001 draw_priority_0[TITAN_RBG0] = (Vdp2Regs->SFPRMD >> 8) & 0x3;
4002 }
4003
4004 if (vidsoft_num_layer_threads > 0)
4005 {
4006 memcpy(vidsoft_thread_context.lines, Vdp2Lines, sizeof(Vdp2) * 270);
4007 memcpy(&vidsoft_thread_context.regs, Vdp2Regs, sizeof(Vdp2));
4008 memcpy(vidsoft_thread_context.ram, Vdp2Ram, 0x80000);
4009 memcpy(vidsoft_thread_context.color_ram, Vdp2ColorRam, 0x1000);
4010 memcpy(vidsoft_thread_context.cell_scroll_data, cell_scroll_data, sizeof(struct CellScrollData) * 270);
4011 }
4012
4013 //draw vdp2 sprite layer on a thread if sprite window is not enabled
4014 if (CanUseSpriteThread() && vidsoft_num_layer_threads > 0)
4015 {
4016 vidsoft_thread_context.need_draw[TITAN_SPRITE] = 1;
4017 vidsoft_thread_context.draw_finished[TITAN_SPRITE] = 0;
4018 YabThreadWake(YAB_THREAD_VIDSOFT_LAYER_SPRITE);
4019 num_threads_dispatched++;
4020 }
4021 else
4022 {
4023 VidsoftDrawSprite(Vdp2Regs, sprite_window_mask, vdp1frontframebuffer, Vdp2Ram, Vdp1Regs, Vdp2Lines, Vdp2ColorRam);
4024 }
4025
4026 if (vidsoft_num_layer_threads > 0)
4027 {
4028 VidsoftStartLayerThread(layer_priority, draw_priority_0, &num_threads_dispatched, TITAN_NBG0, Vdp2DrawNBG0);
4029 VidsoftStartLayerThread(layer_priority, draw_priority_0, &num_threads_dispatched, TITAN_RBG0, Vdp2DrawRBG0);
4030 VidsoftStartLayerThread(layer_priority, draw_priority_0, &num_threads_dispatched, TITAN_NBG1, Vdp2DrawNBG1);
4031 VidsoftStartLayerThread(layer_priority, draw_priority_0, &num_threads_dispatched, TITAN_NBG2, Vdp2DrawNBG2);
4032 VidsoftStartLayerThread(layer_priority, draw_priority_0, &num_threads_dispatched, TITAN_NBG3, Vdp2DrawNBG3);
4033 }
4034 else
4035 {
4036 Vdp2DrawNBG0(Vdp2Lines, Vdp2Regs, Vdp2Ram, Vdp2ColorRam, cell_scroll_data);
4037 Vdp2DrawNBG1(Vdp2Lines, Vdp2Regs, Vdp2Ram, Vdp2ColorRam, cell_scroll_data);
4038 Vdp2DrawNBG2(Vdp2Lines, Vdp2Regs, Vdp2Ram, Vdp2ColorRam, cell_scroll_data);
4039 Vdp2DrawNBG3(Vdp2Lines, Vdp2Regs, Vdp2Ram, Vdp2ColorRam, cell_scroll_data);
4040 Vdp2DrawRBG0(Vdp2Lines, Vdp2Regs, Vdp2Ram, Vdp2ColorRam, cell_scroll_data);
4041 }
4042 }
4043
4044 //////////////////////////////////////////////////////////////////////////////
4045
VIDSoftVdp2DrawScreen(int screen)4046 void VIDSoftVdp2DrawScreen(int screen)
4047 {
4048 VIDSoftVdp2SetResolution(Vdp2Regs->TVMD);
4049
4050 switch(screen)
4051 {
4052 case 0:
4053 Vdp2DrawNBG0(Vdp2Lines, Vdp2Regs, Vdp2Ram, Vdp2ColorRam, cell_scroll_data);
4054 break;
4055 case 1:
4056 Vdp2DrawNBG1(Vdp2Lines, Vdp2Regs, Vdp2Ram, Vdp2ColorRam, cell_scroll_data);
4057 break;
4058 case 2:
4059 Vdp2DrawNBG2(Vdp2Lines, Vdp2Regs, Vdp2Ram, Vdp2ColorRam, cell_scroll_data);
4060 break;
4061 case 3:
4062 Vdp2DrawNBG3(Vdp2Lines, Vdp2Regs, Vdp2Ram, Vdp2ColorRam, cell_scroll_data);
4063 break;
4064 case 4:
4065 Vdp2DrawRBG0(Vdp2Lines, Vdp2Regs, Vdp2Ram, Vdp2ColorRam, cell_scroll_data);
4066 break;
4067 }
4068 }
4069
4070 //////////////////////////////////////////////////////////////////////////////
4071
VIDSoftVdp2SetResolution(u16 TVMD)4072 void VIDSoftVdp2SetResolution(u16 TVMD)
4073 {
4074 // This needs some work
4075
4076 // Horizontal Resolution
4077 switch (TVMD & 0x7)
4078 {
4079 case 0:
4080 rbg0width = vdp2width = 320;
4081 break;
4082 case 1:
4083 rbg0width = vdp2width = 352;
4084 break;
4085 case 2:
4086 vdp2width = 640;
4087 rbg0width = 320;
4088 break;
4089 case 3:
4090 vdp2width = 704;
4091 rbg0width = 352;
4092 break;
4093 case 4:
4094 rbg0width = vdp2width = 320;
4095 break;
4096 case 5:
4097 rbg0width = vdp2width = 352;
4098 break;
4099 case 6:
4100 vdp2width = 640;
4101 rbg0width = 320;
4102 break;
4103 case 7:
4104 vdp2width = 704;
4105 rbg0width = 352;
4106 break;
4107 }
4108
4109 if ((vdp2width == 704) || (vdp2width == 640))
4110 vdp2_x_hires = 1;
4111 else
4112 vdp2_x_hires = 0;
4113
4114 // Vertical Resolution
4115 switch ((TVMD >> 4) & 0x3)
4116 {
4117 case 0:
4118 rbg0height = vdp2height = 224;
4119 break;
4120 case 1:
4121 rbg0height = vdp2height = 240;
4122 break;
4123 case 2:
4124 rbg0height = vdp2height = 256;
4125 break;
4126 default: break;
4127 }
4128
4129 // Check for interlace
4130 switch ((TVMD >> 6) & 0x3)
4131 {
4132 case 3: // Double-density Interlace
4133 vdp2height *= 2;
4134 vdp2_interlace=1;
4135 break;
4136 case 2: // Single-density Interlace
4137 case 0: // Non-interlace
4138 default:
4139 vdp2_interlace = 0;
4140 break;
4141 }
4142
4143 TitanSetResolution(vdp2width, vdp2height);
4144 }
4145
4146 //////////////////////////////////////////////////////////////////////////////
4147
VIDSoftVdp1SwapFrameBuffer(void)4148 void VIDSoftVdp1SwapFrameBuffer(void)
4149 {
4150 if (((Vdp1Regs->FBCR & 2) == 0) || Vdp1External.manualchange)
4151 {
4152 u8 *temp;
4153 if (vidsoft_vdp1_thread_enabled)
4154 {
4155 VidsoftWaitForVdp1Thread();
4156 }
4157
4158 temp = vdp1frontframebuffer;
4159 vdp1frontframebuffer = vdp1backframebuffer;
4160 vdp1backframebuffer = temp;
4161 Vdp1External.manualchange = 0;
4162 }
4163 }
4164
4165 //////////////////////////////////////////////////////////////////////////////
4166
VIDSoftVdp1EraseFrameBuffer(Vdp1 * regs,u8 * back_framebuffer)4167 void VIDSoftVdp1EraseFrameBuffer(Vdp1* regs, u8 * back_framebuffer)
4168 {
4169 int i,i2;
4170 int w,h;
4171
4172 if (((regs->FBCR & 2) == 0) || Vdp1External.manualerase)
4173 {
4174 h = (regs->EWRR & 0x1FF) + 1;
4175 if (h > vdp1height) h = vdp1height;
4176 w = ((regs->EWRR >> 6) & 0x3F8) + 8;
4177 if (w > vdp1width) w = vdp1width;
4178
4179 if (vdp1pixelsize == 2)
4180 {
4181 for (i2 = (regs->EWLR & 0x1FF); i2 < h; i2++)
4182 {
4183 for (i = ((regs->EWLR >> 6) & 0x1F8); i < w; i++)
4184 ((u16 *)back_framebuffer)[(i2 * vdp1width) + i] = regs->EWDR;
4185 }
4186 }
4187 else
4188 {
4189 w = regs->EWRR >> 9;
4190 w *= 16;
4191
4192 for (i2 = (regs->EWLR & 0x1FF); i2 < h; i2++)
4193 {
4194 for (i = ((regs->EWLR >> 6) & 0x1F8); i < w; i++)
4195 {
4196 int pos = (i2 * vdp1width) + i;
4197
4198 if (pos < 0x3FFFF)
4199 back_framebuffer[pos] = regs->EWDR & 0xFF;
4200 }
4201 }
4202 }
4203 Vdp1External.manualerase = 0;
4204 }
4205 }
4206
4207 //////////////////////////////////////////////////////////////////////////////
4208
VIDSoftGetGlSize(int * width,int * height)4209 void VIDSoftGetGlSize(int *width, int *height)
4210 {
4211 #ifdef USE_OPENGL
4212 int usegl = 0;
4213
4214 if (VideoUseGL)
4215 usegl = 1;
4216
4217 if (usegl)
4218 {
4219 *width = outputwidth;
4220 *height = outputheight;
4221 }
4222 else
4223 #endif
4224 {
4225 *width = vdp2width;
4226 *height = vdp2height;
4227 }
4228 }
4229
VIDSoftGetNativeResolution(int * width,int * height,int * interlace)4230 void VIDSoftGetNativeResolution(int *width, int *height, int* interlace)
4231 {
4232 *width = vdp2width;
4233 *height = vdp2height;
4234 *interlace = vdp2_interlace;
4235 }
4236
VIDSoftVdp2DispOff()4237 void VIDSoftVdp2DispOff()
4238 {
4239 TitanErase();
4240 }
4241