1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #define FORBIDDEN_SYMBOL_EXCEPTION_printf
24 #define FORBIDDEN_SYMBOL_EXCEPTION_abort
25 #define FORBIDDEN_SYMBOL_EXCEPTION_exit
26
27 #include "Gs2dScreen.h"
28 #include <kernel.h>
29 #include <malloc.h>
30 #include <string.h>
31 #include <assert.h>
32 #include <fileio.h>
33 #include <math.h>
34 #include "DmaPipe.h"
35 #include "GsDefs.h"
36 #include "graphics/surface.h"
37 #include "graphics/colormasks.h"
38 #include "backends/platform/ps2/ps2debug.h"
39
40 extern void *_gp;
41
42 enum Buffers {
43 SCREEN = 0,
44 MOUSE,
45 TEXT,
46 PRINTF
47 };
48
49 /*
50 Supported modes:
51
52 Mode #1 = SDTV progressive (NTSC: 224p / PAL: 256p)
53 Mode #2 = SDTV interlaced (NTSC: 448i / PAL: 512i) <- default
54 Mode #3 = EDTV progressive (NTSC: 480p / PAL: 576p)
55 Mode #4 = HDTV progressive (720p)
56 Mode #5 = HDTV interlaced (1080i)
57 Mode #6 = VESA (640x480@60)
58 Mode #7 = VESA (800x600@60)
59 Mode #8 = VESA (1024x768@60)
60 */
61
62 static ps2_mode_t ps2_mode[] = {
63
64 // -> w, h, interlaced, pitch, mode, vck, magh, magv, dx, dy
65
66 /* #1 : SDTV - progressive */
67 { 640, 224, 0, 640, 0x02, 2560, 4, 0, 160 /*158*/, 25 /*22*/ }, /* NTSC */
68 { 640, 256, 0, 640, 0x03, 2560, 4, 0, 170 /*163*/, 35 /*36*/ }, /* PAL */
69
70 /* #2 : SDTV - interlaced */
71 { 640, 448, 1, 640, 0x02, 2560, 4, 0, 156 /*158*/, 50 /*45*/ }, /* NTSC */
72 { 640, 512, 1, 640, 0x03, 2560, 4, 0, 170 /*163*/, 70 /*72*/ }, /* PAL */
73
74 /* #3 : EDTV */
75 { 720, 480, 0, 768, 0x50, 1440, 2, 0, 58, 35 }, /* NTSC */
76 /* { 720, 576, 0, 768, 0x53, 1440, 2, 0, 62, 45 }, */ /* PAL : full */
77 /* { 656, 576, 0, 704, 0x53, 1312, 2, 0, 62, 45 }, */ /* PAL : redux @ (0,0) */
78 { 656, 576, 0, 704, 0x53, 1312, 2, 0, 78 /*314*/, 45 }, /* PAL : redux @ center'd */
79
80 /* #4/#5 : HDTV */
81 { 1280, 720, 0, 1280, 0x52, 1280, 1, 0, 76 /*302*/, 24 },
82 { 1920, 1080, 1, 1920, 0x51, 1920, 1, 0, 60 /*236*/ /*238*/, 40 },
83
84 /* #6/#7/#8 : VESA 4:3 @ 60Hz */
85 { 640, 480, 0, 640, 0x1A, 1280, 2, 0, 70 /*276*/, 34 },
86 { 800, 600, 0, 832, 0x2B, 1600, 2, 0, 105 /*420*/, 26 },
87 { 1024, 768, 0, 1024, 0x3B, 2048, 2, 0, 144 /*580*/, 34 }
88 };
89
90 #define ANIM_STACK_SIZE (1024 * 32)
91
92 #define ORG_X 256
93 #define ORG_Y 256
94 #define ORIGIN_X (ORG_X << 4)
95 #define ORIGIN_Y (ORG_Y << 4)
96 #define TEX_POW 10
97
98 #define SCALE(x) ((x) << 4)
99
100 #define M_SIZE 128
101 #define M_POW 7
102
103 static volatile uint32 g_VblankCmd = 0, g_DmacCmd = 0;
104 static int g_VblankSema, g_DmacSema, g_AnimSema;
105 static bool g_RunAnim = false;
106 static GsVertex kFullScreen[2];
107 static TexVertex kMouseTex[2] = {
108 { SCALE(1), SCALE(1) },
109 { SCALE(M_SIZE - 1), SCALE(M_SIZE - 1) }
110 };
111 static TexVertex kPrintTex[2] = {
112 { SCALE(1), SCALE(1) },
113 { SCALE(320), SCALE(200) }
114 };
115
116 void runAnimThread(Gs2dScreen *param);
117
vblankStartHandler(int cause)118 int vblankStartHandler(int cause) {
119 // start of VBlank period
120 if (g_VblankCmd) { // is there a new image waiting?
121 GS_DISPFB1 = g_VblankCmd; // show it.
122 g_VblankCmd = 0;
123 iSignalSema(g_VblankSema);
124 }
125 return 0;
126 }
127
dmacHandler(int channel)128 int dmacHandler(int channel) {
129 if (g_DmacCmd && (channel == 2)) { // GS DMA transfer finished,
130 g_VblankCmd = g_DmacCmd; // we want to show the image
131 g_DmacCmd = 0; // when the next vblank occurs
132 iSignalSema(g_DmacSema);
133 }
134 return 0;
135 }
136
vblankEndHandler(int cause)137 int vblankEndHandler(int cause) {
138 if (g_RunAnim)
139 iSignalSema(g_AnimSema);
140 return 0;
141 }
142
143 void createAnimThread(Gs2dScreen *screen);
144
Gs2dScreen(uint16 width,uint16 height)145 Gs2dScreen::Gs2dScreen(uint16 width, uint16 height) {
146
147 _systemQuit = false;
148 ee_sema_t newSema;
149 newSema.init_count = 1;
150 newSema.max_count = 1;
151 g_VblankSema = CreateSema(&newSema);
152 g_DmacSema = CreateSema(&newSema);
153 _screenSema = CreateSema(&newSema);
154 newSema.init_count = 0;
155 newSema.max_count = 255;
156 g_AnimSema = CreateSema(&newSema);
157 assert((g_VblankSema >= 0) && (g_DmacSema >= 0) && (_screenSema >= 0) && (g_AnimSema >= 0));
158
159 _vblankStartId = AddIntcHandler(INT_VBLANK_START, vblankStartHandler, 0);
160 _vblankEndId = AddIntcHandler(INT_VBLANK_END, vblankEndHandler, 0);
161 _dmacId = AddDmacHandler(2, dmacHandler, 0);
162
163 _dmaPipe = new DmaPipe(0x2000);
164
165 EnableIntc(INT_VBLANK_START);
166 EnableIntc(INT_VBLANK_END);
167 EnableDmac(2);
168
169 _tvMode = 0; // force detection
170 _gfxMode = 0;
171
172 _width = width;
173 _height = height;
174 _pitch = (width + 127) & ~127;
175
176 _screenBuf = (uint8 *)memalign(64, _width * _height);
177 _overlayBuf = (uint16 *)memalign(64, _pitch * _height * 2);
178 _clut = (uint32 *)memalign(64, 256 * 4);
179
180 memset(_screenBuf, 0, _width * _height);
181 memset(_clut, 0, 256 * sizeof(uint32));
182 _clut[1] = GS_RGBA(0xC0, 0xC0, 0xC0, 0);
183 clearOverlay();
184
185 char romver[8];
186 uint16 biosver;
187 int fd = fioOpen("rom0:ROMVER", O_RDONLY);
188 fioRead(fd, &romver, 8);
189 fioClose(fd);
190 biosver=atoi(romver);
191 printf("ROMVER = %s\n", romver);
192 printf("ver = %d\n", atoi(romver));
193
194 if (!_tvMode) { // determine TV standard first
195 if (ConfMan.hasKey("tv_mode", "PlayStation2")) {
196 const char *tvname = ConfMan.get("tv_mode", "PlayStation2").c_str();
197
198 if (strcmp("ntsc", tvname) == 0) {
199 _tvMode = 2;
200 }
201 else if (strcmp("pal", tvname) == 0) {
202 _tvMode = 1;
203 }
204 else
205 _tvMode = 0;
206 }
207
208 if (!_tvMode) {
209 if (romver[4] == 'E')
210 _tvMode = TV_PAL;
211 else
212 _tvMode = TV_NTSC;
213
214 printf("Auto-detect TV mode: PSX:%c PS2:%c\n", *(char *)(0x1FC7FF52), romver[4]);
215 }
216 }
217
218 uint8 mode;
219 if (!_gfxMode) { // determine GFX mode next
220 if (ConfMan.hasKey("gfx_mode", "PlayStation2")) {
221 _gfxMode = ConfMan.getInt("gfx_mode", "PlayStation2");
222 // TODO: free more video mem to support these modes
223 if (_gfxMode == 4 || _gfxMode == 5) {
224 printf("Not enough video mem: using EDTV (3)\n");
225 _gfxMode = 3;
226 }
227 else
228 if (_gfxMode == 7 || _gfxMode == 8) {
229 printf("Not enough video mem: using VGA (6)\n");
230 _gfxMode = 6;
231 }
232
233 if (_gfxMode < 1 || _gfxMode > 8) _gfxMode = 2;
234 else
235 if (_gfxMode == 4 || _gfxMode == 5) _tvMode = TV_HDTV;
236 else
237 if (_gfxMode > 5) _tvMode = TV_VESA;
238 }
239 else
240 _gfxMode = 2;
241 }
242
243 // Remap Mode Index
244 mode = _gfxMode;
245 if (_tvMode == TV_NTSC) {
246 mode = (mode * 2) - 1;
247 }
248 else if (_tvMode == TV_PAL) {
249 mode = (mode * 2);
250 }
251 else if (_tvMode == TV_HDTV) {
252 mode += 3;
253 }
254 else /* VESA */ {
255 _tvMode = TV_VESA;
256 mode += 3;
257 }
258 mode--;
259
260 switch (_tvMode) {
261 case TV_NTSC:
262 printf("Setting up TV mode: NTSC\n");
263 break;
264 case TV_PAL:
265 printf("Setting up TV mode: PAL\n");
266 break;
267 case TV_HDTV:
268 printf("Setting up TV mode: HDTV\n");
269 break;
270 case TV_VESA:
271 printf("Setting up TV mode: VESA\n");
272 break;
273 }
274
275 _tvWidth = ps2_mode[mode].w;
276 _tvHeight = ps2_mode[mode].h;
277 _tvPitch = ps2_mode[mode].pitch;
278
279 printf("Setting up GFX mode: %d x %d\n", _tvWidth, _tvHeight);
280
281 kFullScreen[0].z = kFullScreen[1].z = 0;
282 kFullScreen[0].x = ORIGIN_X;
283 kFullScreen[0].y = ORIGIN_Y;
284 kFullScreen[1].x = SCALE(_tvWidth) + ORIGIN_X;
285 kFullScreen[1].y = SCALE(_tvHeight) + ORIGIN_Y;
286 _blitCoords[0] = kFullScreen[0];
287 _blitCoords[1] = kFullScreen[1];
288 _texCoords[0].u = SCALE(1);
289 _texCoords[0].v = SCALE(1);
290 _texCoords[1].u = SCALE(_width);
291 _texCoords[1].v = SCALE(_height);
292
293 uint32 tvFrameSize = _tvPitch * _tvHeight * 4; // 32 bits per pixel
294
295 // setup frame buffer pointers
296 _frameBufPtr[0] = 0;
297 _frameBufPtr[1] = tvFrameSize;
298 _clutPtrs[SCREEN] = tvFrameSize * 2;
299 _clutPtrs[MOUSE] = _clutPtrs[SCREEN] + 0x1000; // the cluts in PSMCT32 take up half a memory page each
300 _clutPtrs[TEXT] = _clutPtrs[SCREEN] + 0x2000;
301 _texPtrs[SCREEN] = _clutPtrs[SCREEN] + 0x3000;
302 _texPtrs[TEXT] = 0; // these buffers are stored in the alpha gaps of the frame buffers
303 _texPtrs[MOUSE] = 128 * 256 * 4;
304 _texPtrs[PRINTF] = _texPtrs[MOUSE] + M_SIZE * M_SIZE * 4;
305
306 _showOverlay = false;
307 _showMouse = false;
308 _mouseScaleX = (_tvWidth << 8) / _width;
309 _mouseScaleY = (_tvHeight << 8) / _height;
310 setMouseXy(_width / 2, _height / 2);
311 _mTraCol = 255;
312 _shakeXOffset = 0;
313 _shakeYOffset = 0;
314
315 _overlayFormat.bytesPerPixel = 2;
316
317 _overlayFormat.rLoss = 3;
318 _overlayFormat.gLoss = 3;
319 _overlayFormat.bLoss = 3;
320 _overlayFormat.aLoss = 8; // 7
321
322 _overlayFormat.rShift = 0;
323 _overlayFormat.gShift = 5;
324 _overlayFormat.bShift = 10;
325 _overlayFormat.aShift = 0; // 15
326
327 // setup hardware now.
328 GS_CSR = CSR_RESET; // Reset GS
329 asm ("sync.p");
330 GS_CSR = 0;
331 GsPutIMR(0x7F00);
332
333
334 if (biosver < 220 && ps2_mode[mode].mode == 0x53) { // EDTV PAL : mode not in BIOS < 2.20
335 // no worries... we work in magic ;-)
336 /* 720x576p */
337 asm ("di");
338 asm ("sync.l; sync.p");
339 GS_PMODE = 0;
340 asm ("sync.l; sync.p");
341 GS_SMODE1 = 0x1742890504;
342 asm ("sync.l; sync.p");
343 GS_SMODE2 = 0;
344 GS_SYNCH1 = 0x402E02003C827;
345 asm ("sync.l; sync.p");
346 GS_SYNCH2 = 0x19CA67;
347 asm ("sync.l; sync.p");
348 GS_SYNCV = 0xA9000002700005;
349 asm ("sync.l; sync.p");
350 GS_SRFSH = 4;
351 asm ("sync.l; sync.p");
352 GS_SMODE1 = 0x1742880504;
353 asm ("sync.l; sync.p");
354 asm ("sync.l; sync.p");
355 GS_SMODE2 = 0;
356 asm("ei");
357 }
358 else { // BIOS
359 SetGsCrt(ps2_mode[mode].interlaced, ps2_mode[mode].mode, 0); // ps2_mode[mode].interlaced);
360 }
361
362 asm("di");
363 GS_PMODE = GS_SET_PMODE(1, 0, 1, 1, 0, 255);
364 GS_BGCOLOUR = GS_RGBA(0, 0, 0, 0);
365 GS_DISPLAY1 = GS_SET_DISPLAY_MODE(ps2_mode[mode]);
366 asm("ei");
367
368 _curDrawBuf = 0;
369
370 _dmaPipe->setOrigin(ORIGIN_X, ORIGIN_Y);
371 _dmaPipe->setConfig(1, 0, 1);
372 _dmaPipe->setScissorRect(0, 0, _tvWidth - 1, _tvHeight - 1);
373 _dmaPipe->setDrawBuffer(_frameBufPtr[_curDrawBuf], _tvPitch, GS_PSMCT24, 0);
374 _dmaPipe->flush();
375
376 _clutChanged = _screenChanged = _overlayChanged = true;
377
378 clearPrintfOverlay();
379 updateScreen();
380
381 createAnimTextures();
382
383 // create animation thread
384 #ifdef __NEW_PS2SDK__
385 ee_thread_t animThread;
386 ee_thread_status_t thisThread;
387 #else
388 ee_thread_t animThread, thisThread;
389 #endif
390 ReferThreadStatus(GetThreadId(), &thisThread);
391
392 _animStack = memalign(64, ANIM_STACK_SIZE);
393 animThread.initial_priority = thisThread.current_priority - 3;
394 animThread.stack = _animStack;
395 animThread.stack_size = ANIM_STACK_SIZE;
396 animThread.func = (void *)runAnimThread;
397 animThread.gp_reg = &_gp;
398
399 _animTid = CreateThread(&animThread);
400 assert(_animTid >= 0);
401 StartThread(_animTid, this);
402 }
403
quit(void)404 void Gs2dScreen::quit(void) {
405 _systemQuit = true;
406 #ifdef __NEW_PS2SDK__
407 ee_thread_status_t statAnim;
408 #else
409 ee_thread_t statAnim;
410 #endif
411 do { // wait until thread called ExitThread()
412 SignalSema(g_AnimSema);
413 ReferThreadStatus(_animTid, &statAnim);
414 } while (statAnim.status != 0x10);
415 DeleteThread(_animTid);
416 free(_animStack);
417 _dmaPipe->waitForDma(); // wait for dmac and vblank for the last time
418 while (g_DmacCmd || g_VblankCmd);
419
420 sioprintf("kill handlers\n");
421 DisableIntc(INT_VBLANK_START);
422 DisableIntc(INT_VBLANK_END);
423 DisableDmac(2);
424 RemoveIntcHandler(INT_VBLANK_START, _vblankStartId);
425 RemoveIntcHandler(INT_VBLANK_END, _vblankEndId);
426 RemoveDmacHandler(2, _dmacId);
427
428 DeleteSema(g_VblankSema);
429 DeleteSema(g_DmacSema);
430 DeleteSema(g_AnimSema);
431 }
432
createAnimTextures(void)433 void Gs2dScreen::createAnimTextures(void) {
434 uint8 *buf = (uint8 *)memalign(64, 16 * 64);
435 memset(buf, 0, 16 * 64);
436 uint32 vramDest = _texPtrs[TEXT];
437 for (int i = 0; i < 16; i++) {
438 uint32 *destPos = (uint32 *)buf;
439 for (int ch = 15; ch >= 0; ch--) {
440 const uint32 *src = (const uint32 *)(_binaryData + ((_binaryPattern[i] >> ch) & 1) * 4 * 14);
441 for (int line = 0; line < 14; line++)
442 destPos[line << 4] = src[line];
443 destPos++;
444 }
445 if (!(i & 1))
446 _dmaPipe->uploadTex( vramDest, 128, 0, 0, GS_PSMT4HH, buf, 128, 16);
447 else {
448 _dmaPipe->uploadTex( vramDest, 128, 0, 0, GS_PSMT4HL, buf, 128, 16);
449 vramDest += 128 * 16 * 4;
450 }
451 _dmaPipe->flush();
452 _dmaPipe->waitForDma();
453 }
454 _dmaPipe->uploadTex(_clutPtrs[TEXT], 64, 0, 0, GS_PSMCT32, _binaryClut, 8, 2);
455 _dmaPipe->flush();
456 free(buf);
457 }
458
newScreenSize(uint16 width,uint16 height)459 void Gs2dScreen::newScreenSize(uint16 width, uint16 height) {
460 if ((width == _width) && (height == _height))
461 return;
462
463 WaitSema(g_DmacSema);
464 WaitSema(g_VblankSema);
465
466 _dmaPipe->flush();
467 _width = width;
468 _height = height;
469 _pitch = (width + 127) & ~127;
470
471 // malloc new buffers
472 free(_screenBuf);
473 free(_overlayBuf);
474 _screenBuf = (uint8 *)memalign(64, _width * _height);
475 _overlayBuf = (uint16 *)memalign(64, _width * _height * 2);
476 memset(_screenBuf, 0, _width * height);
477 memset(_overlayBuf, 0, _width * height * 2);
478 memset(_clut, 0, 256 * sizeof(uint32));
479 _clut[1] = GS_RGBA(0xC0, 0xC0, 0xC0, 0);
480
481 // clear video ram
482 _dmaPipe->uploadTex(_clutPtrs[MOUSE], 64, 0, 0, GS_PSMCT32, _clut, 16, 16);
483 _dmaPipe->uploadTex(_clutPtrs[SCREEN], 64, 0, 0, GS_PSMCT32, _clut, 16, 16);
484 _dmaPipe->uploadTex(_texPtrs[SCREEN], _width, 0, 0, GS_PSMCT16, _overlayBuf, _width, _height);
485 _dmaPipe->flush();
486 _dmaPipe->waitForDma();
487
488 /*_clutChanged = */ _screenChanged = _overlayChanged = false;
489 _clutChanged = true; // reload palette on scr change
490
491 _texCoords[1].u = SCALE(_width);
492 _texCoords[1].v = SCALE(_height);
493 _mouseScaleX = (_tvWidth << 8) / _width;
494 _mouseScaleY = (_tvHeight << 8) / _height;
495 setMouseXy(_width / 2, _height / 2);
496
497 SignalSema(g_VblankSema);
498 SignalSema(g_DmacSema);
499 }
500
copyScreenRect(const uint8 * buf,int pitch,int x,int y,int w,int h)501 void Gs2dScreen::copyScreenRect(const uint8 *buf, int pitch, int x, int y, int w, int h) {
502 if (x < 0) {
503 w += x;
504 buf -= x;
505 x = 0;
506 }
507 if (y < 0) {
508 h += y;
509 buf -= y * pitch;
510 y = 0;
511 }
512 if (x + w > _width)
513 w = (int)_width - x;
514 if (y + h > _height)
515 h = (int)_height - y;
516
517 if ((w > 0) && (h > 0)) {
518 WaitSema(g_DmacSema);
519 uint8 *dest = _screenBuf + y * _width + x;
520 if ((w == pitch) && (pitch == _width))
521 memcpy(dest, buf, w * h);
522 else
523 for (int cnt = 0; cnt < h; cnt++) {
524 memcpy(dest, buf, w);
525 buf += pitch;
526 dest += _width;
527 }
528 _screenChanged = true;
529 SignalSema(g_DmacSema);
530 }
531 }
532
lockScreen()533 Graphics::Surface *Gs2dScreen::lockScreen() {
534 WaitSema(g_DmacSema);
535
536 // -not- _pitch; ! It's EE mem, not Tex
537 _framebuffer.init(_width, _height, _width, _screenBuf, Graphics::PixelFormat::createFormatCLUT8());
538 return &_framebuffer;
539 }
540
unlockScreen()541 void Gs2dScreen::unlockScreen() {
542 _screenChanged = true;
543 SignalSema(g_DmacSema);
544 }
545
setPalette(const uint8 * pal,uint8 start,uint16 num)546 void Gs2dScreen::setPalette(const uint8 *pal, uint8 start, uint16 num) {
547 assert(start + num <= 256);
548
549 WaitSema(g_DmacSema);
550 for (uint16 cnt = 0; cnt < num; cnt++) {
551 uint16 dest = start + cnt;
552 dest = (dest & 0xE7) | ((dest & 0x8) << 1) | ((dest & 0x10) >> 1); // rearrange like the GS expects it
553
554 uint32 color = pal[0] | (pal[1] << 8) | (pal[2] << 16);
555 _clut[dest] = color;
556 pal += 3;
557 }
558 _clutChanged = true;
559 SignalSema(g_DmacSema);
560 }
561
grabPalette(uint8 * pal,uint8 start,uint16 num) const562 void Gs2dScreen::grabPalette(uint8 *pal, uint8 start, uint16 num) const {
563 assert(start + num <= 256);
564 for (uint16 cnt = 0; cnt < num; cnt++) {
565 uint16 src = start + cnt;
566 src = (src & 0xE7) | ((src & 0x8) << 1) | ((src & 0x10) >> 1);
567
568 uint32 color = _clut[src];
569 pal[0] = (color >> 0) & 0xFF;
570 pal[1] = (color >> 8) & 0xFF;
571 pal[2] = (color >> 16) & 0xFF;
572 pal += 3;
573 }
574 }
575
uploadToVram(void)576 void Gs2dScreen::uploadToVram(void) {
577 if (_clutChanged) {
578 _clutChanged = false;
579 uint32 tmp = _clut[_mTraCol];
580 _clut[_mTraCol] = GS_RGBA(0, 0, 0, 0x80); // this mouse color is transparent
581 _dmaPipe->uploadTex(_clutPtrs[MOUSE], 64, 0, 0, GS_PSMCT32, _clut, 16, 16);
582 _dmaPipe->flush();
583 _dmaPipe->waitForDma();
584 _clut[_mTraCol] = tmp;
585
586 _dmaPipe->uploadTex(_clutPtrs[SCREEN], 64, 0, 0, GS_PSMCT32, _clut, 16, 16);
587 }
588
589 if (_showOverlay) {
590 if (_overlayChanged) {
591 _dmaPipe->uploadTex(_texPtrs[SCREEN], _width, 0, 0, GS_PSMCT16, _overlayBuf, _width, _height);
592 _overlayChanged = false;
593 }
594 } else {
595 if (_screenChanged) {
596 _dmaPipe->uploadTex(_texPtrs[SCREEN], _pitch, 0, 0, GS_PSMT8, _screenBuf, _width, _height);
597 _screenChanged = false;
598 }
599 }
600 }
601
602 extern "C" void _ps2sdk_alloc_lock(void);
603 extern "C" void _ps2sdk_alloc_unlock(void);
604
updateScreen(void)605 void Gs2dScreen::updateScreen(void) {
606 WaitSema(_screenSema);
607 uploadToVram();
608 if (!g_RunAnim) {
609 _dmaPipe->flatRect(kFullScreen + 0, kFullScreen + 1, GS_RGBA(0, 0, 0, 0)); // clear screen
610
611 if (_showOverlay) {
612 _dmaPipe->setTex(_texPtrs[SCREEN], _width, TEX_POW, TEX_POW, GS_PSMCT16, 0, 0, 0, 0);
613 _dmaPipe->textureRect(kFullScreen + 0, kFullScreen + 1, _texCoords + 0, _texCoords + 1);
614 } else {
615 _dmaPipe->setTex(_texPtrs[SCREEN], _pitch, TEX_POW, TEX_POW, GS_PSMT8, _clutPtrs[SCREEN], 0, 64, GS_PSMCT32);
616 _dmaPipe->textureRect(_blitCoords + 0, _blitCoords + 1, _texCoords + 0, _texCoords + 1);
617 }
618
619 if (_showMouse) {
620 GsVertex mouseCoords[2];
621 mouseCoords[0].x = (((_mouseX - _hotSpotX) * _mouseScaleX + 8) >> 4) + ORIGIN_X;
622 mouseCoords[0].y = (((_mouseY - _hotSpotY) * _mouseScaleY + 8) >> 4) + ORIGIN_Y;
623 mouseCoords[1].x = mouseCoords[0].x + (((M_SIZE * _mouseScaleX) + 8) >> 4);
624 mouseCoords[1].y = mouseCoords[0].y + (((M_SIZE * _mouseScaleY) + 8) >> 4);
625 mouseCoords[0].z = mouseCoords[1].z = 0;
626
627 _dmaPipe->setTex(_texPtrs[MOUSE], M_SIZE, M_POW, M_POW, GS_PSMT8H, _clutPtrs[MOUSE], 0, 64, GS_PSMCT32);
628 _dmaPipe->textureRect(mouseCoords + 0, mouseCoords + 1, kMouseTex + 0, kMouseTex + 1);
629 }
630
631 _dmaPipe->setTex(_texPtrs[PRINTF], 3 * 128, TEX_POW, TEX_POW, GS_PSMT8H, _clutPtrs[TEXT], 0, 64, GS_PSMCT32);
632 _dmaPipe->textureRect(kFullScreen + 0, kFullScreen + 1, kPrintTex + 0, kPrintTex + 1);
633
634 #if 0
635 _ps2sdk_alloc_lock();
636 uint32 heapTop = (uint32)ps2_sbrk(0);
637 _ps2sdk_alloc_unlock();
638 if (heapTop != (uint32)-1) {
639 float yPos = (((float)heapTop) / (32 * 1024 * 1024)) * _tvHeight;
640 GsVertex bottom = { SCALE(_tvWidth - 40) + ORIGIN_X, SCALE(_tvHeight) + ORIGIN_Y, 0 };
641 GsVertex top = { SCALE(_tvWidth) + ORIGIN_X, 0, 0 };
642 top.y = SCALE((uint16)(_tvHeight - yPos)) + ORIGIN_Y;
643 _dmaPipe->flatRect(&bottom, &top, GS_RGBA(0x80, 0, 0, 0x40));
644 }
645 #endif
646
647 WaitSema(g_DmacSema); // wait for dma transfer, if there's one running
648 WaitSema(g_VblankSema); // wait if there's already an image waiting for vblank
649
650 g_DmacCmd = GS_SET_DISPFB(_frameBufPtr[_curDrawBuf], _tvPitch, GS_PSMCT24); // put it here for dmac/vblank handler
651 _dmaPipe->flush();
652 _curDrawBuf ^= 1;
653 _dmaPipe->setDrawBuffer(_frameBufPtr[_curDrawBuf], _tvPitch, GS_PSMCT24, 0);
654 } else
655 _dmaPipe->flush();
656 SignalSema(_screenSema);
657 }
658
showOverlay(void)659 void Gs2dScreen::showOverlay(void) {
660 _showOverlay = true;
661 clearOverlay();
662 }
663
hideOverlay(void)664 void Gs2dScreen::hideOverlay(void) {
665 _screenChanged = true;
666 _showOverlay = false;
667 }
668
getOverlayFormat(void)669 Graphics::PixelFormat Gs2dScreen::getOverlayFormat(void) {
670 return _overlayFormat;
671 // return Graphics::createPixelFormat<1555>();
672 }
673
getOverlayWidth(void)674 int16 Gs2dScreen::getOverlayWidth(void) {
675 return _width; // _videoMode.overlayWidth;
676 }
677
getOverlayHeight(void)678 int16 Gs2dScreen::getOverlayHeight(void) {
679 return _height; // _videoMode.overlayHeight;
680 }
681
setShakePos(int shakeXOffset,int shakeYOffset)682 void Gs2dScreen::setShakePos(int shakeXOffset, int shakeYOffset) {
683 _shakeXOffset = (shakeXOffset * _mouseScaleX) >> 8;
684 _shakeYOffset = (shakeYOffset * _mouseScaleY) >> 8;
685 _blitCoords[0].x = SCALE(_shakeXOffset) + ORIGIN_X;
686 _blitCoords[0].y = SCALE(_shakeYOffset) + ORIGIN_Y;
687 _blitCoords[1].x = SCALE(_tvWidth + _shakeXOffset) + ORIGIN_X;
688 _blitCoords[1].y = SCALE(_tvHeight + _shakeYOffset) + ORIGIN_Y;
689 }
690
copyPrintfOverlay(const uint8 * buf)691 void Gs2dScreen::copyPrintfOverlay(const uint8 *buf) {
692 assert(!((uint32)buf & 63));
693 _dmaPipe->uploadTex(_texPtrs[PRINTF], 3 * 128, 0, 0, GS_PSMT8H, buf, 320, 200);
694 _dmaPipe->flush();
695 _dmaPipe->waitForDma();
696 }
697
clearPrintfOverlay(void)698 void Gs2dScreen::clearPrintfOverlay(void) {
699 uint8 *tmpBuf = (uint8 *)memalign(64, 320 * 200);
700 memset(tmpBuf, 4, 320 * 200);
701 _dmaPipe->uploadTex(_texPtrs[PRINTF], 3 * 128, 0, 0, GS_PSMT8H, tmpBuf, 320, 200);
702 _dmaPipe->flush();
703 _dmaPipe->waitForDma();
704 free(tmpBuf);
705 }
706
copyOverlayRect(const byte * buf,uint16 pitch,uint16 x,uint16 y,uint16 w,uint16 h)707 void Gs2dScreen::copyOverlayRect(const byte *buf, uint16 pitch, uint16 x, uint16 y, uint16 w, uint16 h) {
708 WaitSema(g_DmacSema);
709
710 // warning("_overlayBuf [dst] = %x", _overlayBuf);
711 // warning("buf [src] = %x", buf);
712
713 // warning("pitch=%d _width=%d - x=%d y=%d w=%d h=%d",
714 // pitch, _width, x, y, w, h);
715
716 if (x >= 65535) x=0;
717 if (y >= 65535) y=0;
718
719 _overlayChanged = true;
720 uint16 *dest = _overlayBuf + y * _width + x;
721 for (uint32 cnt = 0; cnt < h; cnt++) {
722 memcpy(dest, buf, w * 2);
723 dest += _width;
724 buf += pitch;
725 }
726 SignalSema(g_DmacSema);
727 }
728
clearOverlay(void)729 void Gs2dScreen::clearOverlay(void) {
730 WaitSema(g_DmacSema);
731 _overlayChanged = true;
732 // first convert our clut to 16 bit RGBA for the overlay...
733 uint16 palette[256];
734 for (uint32 cnt = 0; cnt < 256; cnt++) {
735 uint32 rgba = _clut[(cnt & 0xE7) | ((cnt & 0x8) << 1) | ((cnt & 0x10) >> 1)];
736 palette[cnt] = ((rgba >> 3) & 0x1F) | (((rgba >> 11) & 0x1F) << 5) | (((rgba >> 19) & 0x1F) << 10);
737 }
738 // now copy the current screen over
739 for (int cnt = 0; cnt < _width * _height; cnt++)
740 _overlayBuf[cnt] = palette[_screenBuf[cnt]];
741 SignalSema(g_DmacSema);
742 }
743
grabOverlay(byte * buf,uint16 pitch)744 void Gs2dScreen::grabOverlay(byte *buf, uint16 pitch) {
745 uint16 *src = _overlayBuf;
746 for (uint32 cnt = 0; cnt < _height; cnt++) {
747 memcpy(buf, src, _width * 2);
748 buf += pitch;
749 src += _width;
750 }
751 }
752
setMouseOverlay(const uint8 * buf,uint16 width,uint16 height,uint16 hotSpotX,uint16 hotSpotY,uint8 transpCol)753 void Gs2dScreen::setMouseOverlay(const uint8 *buf, uint16 width, uint16 height, uint16 hotSpotX, uint16 hotSpotY, uint8 transpCol) {
754 assert((width <= M_SIZE) && (height <= M_SIZE));
755
756 _hotSpotX = hotSpotX;
757 _hotSpotY = hotSpotY;
758 if (_mTraCol != transpCol) {
759 _mTraCol = transpCol;
760 _clutChanged = true;
761 }
762 uint8 *bufCopy = (uint8 *)memalign(64, M_SIZE * M_SIZE); // make a copy to align to 64 bytes
763 memset(bufCopy, _mTraCol, M_SIZE * M_SIZE);
764 for (int cnt = 0; cnt < height; cnt++)
765 memcpy(bufCopy + cnt * M_SIZE, buf + cnt * width, width);
766
767 _dmaPipe->uploadTex( _texPtrs[MOUSE], M_SIZE, 0, 0, GS_PSMT8H, bufCopy, M_SIZE, M_SIZE);
768 _dmaPipe->flush();
769 _dmaPipe->waitForDma(); // make sure all data has been transferred when we free bufCopy
770 free(bufCopy);
771 }
772
showMouse(bool show)773 void Gs2dScreen::showMouse(bool show) {
774 _showMouse = show;
775 }
776
setMouseXy(int16 x,int16 y)777 void Gs2dScreen::setMouseXy(int16 x, int16 y) {
778 _mouseX = x;
779 _mouseY = y;
780 }
781 /*
782 uint8 Gs2dScreen::tvMode(void) {
783 return _tvMode;
784 }
785 */
getWidth(void)786 uint16 Gs2dScreen::getWidth(void) {
787 return _width;
788 }
789
getHeight(void)790 uint16 Gs2dScreen::getHeight(void) {
791 return _height;
792 }
793
wantAnim(bool runIt)794 void Gs2dScreen::wantAnim(bool runIt) {
795 g_RunAnim = runIt;
796 }
797
798 #define LINE_SPACE 20
799 #define SCRL_TIME 8
800 #define V 1000
801 #define Z_TRANSL 65
802
playAnim(void)803 void Gs2dScreen::playAnim(void) {
804 // animate zeros and ones while game accesses memory card, etc.
805 g_RunAnim = false;
806 float yPos = 0.0;
807 uint8 texSta = 0;
808 float scrlSpeed = (_tvMode == TV_PAL) ? (_tvHeight / (SCRL_TIME * 50.0)) : (_tvHeight / (SCRL_TIME * 60.0));
809 uint8 texMax = (_tvHeight / LINE_SPACE) + (ORG_Y / LINE_SPACE);
810 TexVertex texNodes[4] = {
811 { SCALE(1), SCALE(1) }, { SCALE(1), SCALE(14) },
812 { SCALE(128), SCALE(1) }, { SCALE(128), SCALE(14) }
813 };
814 float angleStep = ((2 * M_PI) / _tvHeight);
815
816 while (!_systemQuit) {
817 do {
818 WaitSema(g_AnimSema);
819 } while ((!_systemQuit) && (!g_RunAnim));
820
821 if (_systemQuit)
822 break;
823
824 if (PollSema(_screenSema) > 0) { // make sure no thread is currently drawing
825 WaitSema(g_DmacSema); // dma transfers have to be finished
826 WaitSema(g_VblankSema); // wait for image, if there is one...
827
828 // redraw the engine's last frame
829 _dmaPipe->flatRect(kFullScreen + 0, kFullScreen + 1, GS_RGBA(0, 0, 0, 0)); // clear screen
830
831 if (_showOverlay) {
832 _dmaPipe->setTex(_texPtrs[SCREEN], _width, TEX_POW, TEX_POW, GS_PSMCT16, 0, 0, 0, 0);
833 _dmaPipe->textureRect(kFullScreen + 0, kFullScreen + 1, _texCoords + 0, _texCoords + 1);
834 } else {
835 _dmaPipe->setTex(_texPtrs[SCREEN], _pitch, TEX_POW, TEX_POW, GS_PSMT8, _clutPtrs[SCREEN], 0, 64, GS_PSMCT32);
836 _dmaPipe->textureRect(_blitCoords + 0, _blitCoords + 1, _texCoords + 0, _texCoords + 1);
837 }
838
839 _dmaPipe->setTex(_texPtrs[PRINTF], 3 * 128, TEX_POW, TEX_POW, GS_PSMT8H, _clutPtrs[TEXT], 0, 64, GS_PSMCT32);
840 _dmaPipe->textureRect(kFullScreen + 0, kFullScreen + 1, kPrintTex + 0, kPrintTex + 1);
841
842 if (_showMouse) {
843 GsVertex mouseCoords[2];
844 mouseCoords[0].x = (((_mouseX - _hotSpotX) * _mouseScaleX + 8) >> 4) + ORIGIN_X;
845 mouseCoords[0].y = (((_mouseY - _hotSpotY) * _mouseScaleY + 8) >> 4) + ORIGIN_Y;
846 mouseCoords[1].x = mouseCoords[0].x + (((M_SIZE * _mouseScaleX) + 8) >> 4);
847 mouseCoords[1].y = mouseCoords[0].y + (((M_SIZE * _mouseScaleY) + 8) >> 4);
848 mouseCoords[0].z = mouseCoords[1].z = 0;
849
850 _dmaPipe->setTex(_texPtrs[MOUSE], M_SIZE, M_POW, M_POW, GS_PSMT8H, _clutPtrs[MOUSE], 0, 64, GS_PSMCT32);
851 _dmaPipe->textureRect(mouseCoords + 0, mouseCoords + 1, kMouseTex + 0, kMouseTex + 1);
852 }
853
854 _dmaPipe->setAlphaBlend(SOURCE_COLOR, ZERO_COLOR, SOURCE_ALPHA, DEST_COLOR, 0);
855 yPos -= scrlSpeed;
856 if (yPos <= -LINE_SPACE) {
857 yPos += LINE_SPACE;
858 texSta++;
859 }
860
861 float drawY = yPos;
862
863 for (int i = 0; i < texMax; i++) {
864 uint8 texIdx = (texSta + i) & 0xF;
865
866 float x[4] = { -64.0, -64.0, 64.0, 64.0 };
867 float y[4];
868 y[0] = y[2] = drawY - _tvHeight / 2 - LINE_SPACE / 2;
869 y[1] = y[3] = y[0] + LINE_SPACE;
870 float z[4];
871 GsVertex nodes[4];
872
873 float angle = M_PI / 2 + angleStep * drawY;
874 float rotSin = sinf(angle);
875 float rotCos = cosf(angle);
876 for (int coord = 0; coord < 4; coord++) {
877 z[coord] = rotCos * x[coord];
878 x[coord] = rotSin * x[coord];
879
880 nodes[coord].z = 0;
881 nodes[coord].x = (uint16)(((V * x[coord]) / (z[coord] + V + Z_TRANSL)) * 16);
882 nodes[coord].y = (uint16)(((V * y[coord]) / (z[coord] + V + Z_TRANSL)) * 16);
883 nodes[coord].x += SCALE(_tvWidth - 80 + ORG_X);
884 nodes[coord].y += SCALE(_tvHeight / 2 + ORG_Y);
885 }
886
887 uint32 texPtr = _texPtrs[TEXT] + 128 * 16 * 4 * (texIdx >> 1);
888 if (texIdx & 1)
889 _dmaPipe->setTex(texPtr, 128, 7, 4, GS_PSMT4HL, _clutPtrs[TEXT], 0, 64, GS_PSMCT32);
890 else
891 _dmaPipe->setTex(texPtr, 128, 7, 4, GS_PSMT4HH, _clutPtrs[TEXT], 0, 64, GS_PSMCT32);
892
893 _dmaPipe->textureRect(nodes + 0, nodes + 1, nodes + 2, nodes + 3,
894 texNodes + 0, texNodes + 1, texNodes + 2, texNodes + 3, GS_RGBA(0x80, 0x80, 0x80, 0x80));
895
896 drawY += LINE_SPACE;
897 }
898 g_DmacCmd = GS_SET_DISPFB(_frameBufPtr[_curDrawBuf], _tvPitch, GS_PSMCT24); // put it here for dmac/vblank handler
899 _dmaPipe->flush();
900 _curDrawBuf ^= 1;
901 _dmaPipe->setDrawBuffer(_frameBufPtr[_curDrawBuf], _tvPitch, GS_PSMCT24, 0);
902 _dmaPipe->setAlphaBlend(DEST_COLOR, ZERO_COLOR, SOURCE_ALPHA, SOURCE_COLOR, 0);
903
904 SignalSema(_screenSema);
905 }
906 }
907 ExitThread();
908 }
909
runAnimThread(Gs2dScreen * param)910 void runAnimThread(Gs2dScreen *param) {
911 param->playAnim();
912 }
913
914 // data for the animated zeros and ones...
915 const uint8 Gs2dScreen::_binaryData[4 * 14 * 2] = {
916 // figure zero
917 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x22, 0x22, 0x00, 0x31, 0x13,
918 0x31, 0x13, 0x20, 0x02, 0x22, 0x02, 0x31, 0x13, 0x33, 0x13, 0x20, 0x02, 0x20, 0x02,
919 0x31, 0x33, 0x31, 0x13, 0x20, 0x22, 0x20, 0x02, 0x31, 0x13, 0x31, 0x13, 0x00, 0x22,
920 0x22, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,
921 // figure one
922 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x20, 0x02, 0x00, 0x11, 0x33,
923 0x13, 0x11, 0x22, 0x22, 0x02, 0x00, 0x11, 0x31, 0x13, 0x11, 0x00, 0x20, 0x02, 0x00,
924 0x11, 0x31, 0x13, 0x11, 0x00, 0x20, 0x02, 0x00, 0x11, 0x31, 0x13, 0x11, 0x00, 0x20,
925 0x02, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11
926 };
927
928 const uint16 Gs2dScreen::_binaryPattern[16] = {
929 0xD992, 0x344B, 0xA592, 0x110D,
930 0x9234, 0x2326, 0x5199, 0xC8A6,
931 0x4D29, 0x18B0, 0xA5AA, 0x2949,
932 0x6DB3, 0xB2AA, 0x64A4, 0x3329
933 };
934
935 const uint32 Gs2dScreen::_binaryClut[16] __attribute__((aligned(64))) = {
936 GS_RGBA( 0, 0, 0, 0x40),
937 GS_RGBA( 50, 50, 50, 0x40),
938 GS_RGBA( 204, 204, 0xFF, 0x40),
939 GS_RGBA( 140, 140, 0xFF, 0x40),
940
941 GS_RGBA( 0, 0, 0, 0x80), // scrPrintf: transparent
942 GS_RGBA( 0, 0, 0, 0x20), // scrPrintf: semitransparent
943 GS_RGBA(0xC0, 0xC0, 0xC0, 0), // scrPrintf: red
944 GS_RGBA(0x16, 0x16, 0xF0, 0), // scrPrintf: blue
945
946 GS_RGBA(0xFF, 0xFF, 0xFF, 0x80), GS_RGBA(0xFF, 0xFF, 0xFF, 0x80), // unused
947 GS_RGBA(0xFF, 0xFF, 0xFF, 0x80), GS_RGBA(0xFF, 0xFF, 0xFF, 0x80),
948 GS_RGBA(0xFF, 0xFF, 0xFF, 0x80), GS_RGBA(0xFF, 0xFF, 0xFF, 0x80),
949 GS_RGBA(0xFF, 0xFF, 0xFF, 0x80), GS_RGBA(0xFF, 0xFF, 0xFF, 0x80)
950 };
951