1 /***************************************************************************
3 * ZXEmuT -- ZX Spectrum Emulator with Tcl scripting
5 * Copyright (C) 2012-2020 Ketmar Dark <ketmar@ketmar.no-ip.org>
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, version 3 of the License ONLY.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **************************************************************************/
28 #include "vdfont6x8.c"
29 #include "msxfont8x8.c"
30 #include "fonts_8_16.c"
35 ////////////////////////////////////////////////////////////////////////////////
36 FrameCB frameCB
= NULL
;
38 MouseCB mouseCB
= NULL
;
39 MouseButtonCB mouseButtonCB
= NULL
;
40 WindowActivationCB windowActivationCB
= NULL
;
41 int vidScale
= 3; // 1, 2, 3, 4; default is 3
43 void (*vidBeforeFlipCB
) (SDL_Surface
*sfc
) = NULL
;
45 VidTChar vid_textscr
[VID_TEXT_WIDTH
*VID_TEXT_HEIGHT
];
46 int vid_textscr_active
= 0;
47 int vid_textsrc_height
= 0;
50 // ////////////////////////////////////////////////////////////////////////// //
51 static int actualScale
;
54 // ////////////////////////////////////////////////////////////////////////// //
55 static void screenFlip (void);
58 ////////////////////////////////////////////////////////////////////////////////
59 int optFullscreen
= 0;
61 SDL_Surface
*screen
= NULL
;
62 SDL_Surface
*screenReal
= NULL
;
63 Uint32 palette
[256]; // converted
64 unsigned paletteUsed
= 0;
65 static unsigned paletteUsedCurr
= 0;
66 SDL_Surface
*frameSfc
= NULL
;
67 int vidWindowActivated
= 1;
68 int vidColorMode
= 0; // 0: ok; 1: b/w; 2: green
69 static SurfaceLock frameSfcLock
;
70 static int frameSfcRaped
= 0;
72 static uint8_t pal8bit
[256][4]; // [3] is unused
73 uint8_t palRGB
[256][4]; // [3] is unused
74 int vidRIdx
, vidGIdx
, vidBIdx
;
77 ////////////////////////////////////////////////////////////////////////////////
78 static void initEventSystem (void);
81 ////////////////////////////////////////////////////////////////////////////////
82 static void quitCleanupCB (void) {
87 // ////////////////////////////////////////////////////////////////////////// //
88 void vt_cls (uint8_t ch
, uint8_t attr
) {
89 VidTChar
*d
= vid_textscr
;
90 uint32_t left
= VID_TEXT_WIDTH
*VID_TEXT_HEIGHT
;
99 void vt_writechar (int x
, int y
, uint8_t ch
, uint8_t attr
) {
100 if (x
< 0 || y
< 0 || x
>= VID_TEXT_WIDTH
|| y
>= VID_TEXT_HEIGHT
) return;
101 VidTChar
*d
= vid_textscr
+y
*VID_TEXT_WIDTH
+x
;
107 void vt_writechars (int x
, int y
, int count
, uint8_t ch
, uint8_t attr
) {
108 if (count
<= 0 || y
< 0 || x
>= VID_TEXT_WIDTH
|| y
>= VID_TEXT_HEIGHT
) return;
111 if (count
<= 0) return;
114 if (VID_TEXT_WIDTH
-x
< count
) count
= VID_TEXT_WIDTH
-x
;
115 VidTChar
*d
= vid_textscr
+y
*VID_TEXT_WIDTH
+x
;
124 void vt_writestrcnt (int x
, int y
, const char *s
, size_t slen
, uint8_t attr
) {
125 if (!slen
|| !s
) return;
126 if (y
< 0 || x
>= VID_TEXT_WIDTH
|| y
>= VID_TEXT_HEIGHT
) return;
127 if (slen
> 0x3fffffffU
) slen
= 0x3fffffffU
;
128 int count
= (int)slen
;
131 if (count
<= 0) return;
134 if (VID_TEXT_WIDTH
-x
< count
) count
= VID_TEXT_WIDTH
-x
;
135 VidTChar
*d
= vid_textscr
+y
*VID_TEXT_WIDTH
+x
;
137 d
->ch
= *(const uint8_t *)s
;
145 void vt_writestrz (int x
, int y
, const char *s
, uint8_t attr
) {
146 if (!s
|| !s
[0]) return;
147 if (y
< 0 || x
>= VID_TEXT_WIDTH
|| y
>= VID_TEXT_HEIGHT
) return;
148 vt_writestrcnt(x
, y
, s
, strlen(s
), attr
);
152 ////////////////////////////////////////////////////////////////////////////////
153 static struct timespec timerStart
;
154 static int timerInitialized
= 0;
155 static int timerSource
= -1;
156 #define TIMER_CLOCK_TYPE CLOCK_MONOTONIC_RAW
157 //#define TIMER_CLOCK_TYPE CLOCK_MONOTONIC
160 static int timerCheckClockSource (void) {
161 FILE *fl
= fopen("/sys/devices/system/clocksource/clocksource0/current_clocksource", "r");
165 fprintf(stderr
, "WARNING: can't determine clock source!\n");
168 memset(buf
, 0, sizeof(buf
));
169 if (fgets(buf
, sizeof(buf
)-1, fl
) == NULL
) {
170 fprintf(stderr
, "WARNING: can't determine clock source!\n");
175 while (buf
[0] && isspace(buf
[strlen(buf
)-1])) buf
[strlen(buf
)-1] = 0;
176 //fprintf(stderr, "clock source: %s\n", buf);
177 return (strcasecmp(buf
, "hpet") == 0 ? TIMER_HPET
: TIMER_OTHER
);
181 int timerInit (void) {
182 if (!timerInitialized
) {
183 struct timespec cres
;
185 timerInitialized
= 1;
187 if ((timerSource
= timerCheckClockSource()) < 0) return timerSource
;
189 if (clock_getres(TIMER_CLOCK_TYPE
, &cres
) != 0) {
190 fprintf(stderr
, "ERROR: can't get clock resolution!\n");
193 //fprintf(stderr, "CLOCK_MONOTONIC: %ld:%ld\n", cres.tv_sec, cres.tv_nsec);
195 if (cres
.tv_sec
> 0 || cres
.tv_nsec
> (long)1000000*10 /*10 ms*/) {
196 fprintf(stderr
, "ERROR: real-time clock resolution is too low!\n");
200 if (clock_gettime(TIMER_CLOCK_TYPE
, &timerStart
) != 0) {
201 fprintf(stderr
, "ERROR: can't get real-time clock value!\n");
210 int timerReinit (void) {
211 if (clock_gettime(TIMER_CLOCK_TYPE
, &timerStart
) != 0) {
212 fprintf(stderr
, "ERROR: can't get real-time clock value!\n");
220 int64_t timerGetMS (void) {
223 if (!timerInitialized
) {
224 if (timerInit() < 0) return -1;
225 timerInitialized
= 1;
228 if (clock_gettime(TIMER_CLOCK_TYPE
, &ts
) != 0) {
229 fprintf(stderr
, "ERROR: can't get real-time clock value!\n");
232 // ah, ignore nanoseconds in timerStart here: we need only 'differential' time, and it can start with something weird
233 return ((int64_t)(ts
.tv_sec
-timerStart
.tv_sec
))*1000+(ts
.tv_nsec
-timerStart
.tv_nsec
)/1000000;
237 int64_t timerGetMicroSeconds (void) {
240 if (!timerInitialized
) {
241 if (timerInit() < 0) return -1;
242 timerInitialized
= 1;
245 if (clock_gettime(TIMER_CLOCK_TYPE
, &ts
) != 0) {
246 fprintf(stderr
, "ERROR: can't get real-time clock value!\n");
249 // ah, ignore nanoseconds in timerStart here: we need only 'differential' time, and it can start with something weird
250 return ((int64_t)(ts
.tv_sec
-timerStart
.tv_sec
))*1000000+(ts
.tv_nsec
-timerStart
.tv_nsec
)/1000;
254 ////////////////////////////////////////////////////////////////////////////////
255 void sdlInit (void) {
256 if (SDL_Init(SDL_INIT_VIDEO
|SDL_INIT_TIMER
/*| SDL_INIT_AUDIO*/) < 0) {
257 fprintf(stderr
, "FATAL: can't set videomode!\n");
260 SDL_WM_SetCaption("ZXEmuT", "ZXEmuT");
261 SDL_EnableKeyRepeat(200, 25);
262 SDL_EnableUNICODE(1);
263 //SDL_EnableUNICODE(0);
264 atexit(quitCleanupCB
);
268 #define COLORCUBE_BITS (6)
269 #define COLORCUBE_LINE_SIZE (1u<<COLORCUBE_BITS)
270 static uint8_t colorcube
[COLORCUBE_LINE_SIZE
*COLORCUBE_LINE_SIZE
*COLORCUBE_LINE_SIZE
];
271 static uint8_t colorcube2
[COLORCUBE_LINE_SIZE
*COLORCUBE_LINE_SIZE
*COLORCUBE_LINE_SIZE
];
272 static int cc2built
= 0;
274 static inline void ccubeSet (uint8_t palidx
, uint8_t r
, uint8_t g
, uint8_t b
) {
275 #if COLORCUBE_BITS < 8
276 r
>>= 8-COLORCUBE_BITS
;
277 g
>>= 8-COLORCUBE_BITS
;
278 b
>>= 8-COLORCUBE_BITS
;
280 colorcube
[r
*(COLORCUBE_LINE_SIZE
*COLORCUBE_LINE_SIZE
)+g
*COLORCUBE_LINE_SIZE
+b
] = palidx
;
284 static inline uint8_t ccubeGet (uint8_t r
, uint8_t g
, uint8_t b
) {
285 #if COLORCUBE_BITS < 8
286 r
>>= 8-COLORCUBE_BITS
;
287 g
>>= 8-COLORCUBE_BITS
;
288 b
>>= 8-COLORCUBE_BITS
;
290 return colorcube
[r
*(COLORCUBE_LINE_SIZE
*COLORCUBE_LINE_SIZE
)+g
*COLORCUBE_LINE_SIZE
+b
];
294 static inline uint8_t ccube2Get (uint8_t r
, uint8_t g
, uint8_t b
) {
295 #if COLORCUBE_BITS < 8
296 r
>>= 8-COLORCUBE_BITS
;
297 g
>>= 8-COLORCUBE_BITS
;
298 b
>>= 8-COLORCUBE_BITS
;
300 return colorcube2
[r
*(COLORCUBE_LINE_SIZE
*COLORCUBE_LINE_SIZE
)+g
*COLORCUBE_LINE_SIZE
+b
];
304 static inline int32_t rgbDistanceSquared (uint8_t r0
, uint8_t g0
, uint8_t b0
, uint8_t r1
, uint8_t g1
, uint8_t b1
) {
305 const int32_t rmean
= ((int32_t)r0
+(int32_t)r1
)/2;
306 const int32_t r
= (int32_t)r0
-(int32_t)r1
;
307 const int32_t g
= (int32_t)g0
-(int32_t)g1
;
308 const int32_t b
= (int32_t)b0
-(int32_t)b1
;
309 return (((512+rmean
)*r
*r
)/256)+4*g
*g
+(((767-rmean
)*b
*b
)/256);
313 static void buildCC2 (void) {
314 if (cc2built
) return;
315 for (int ir
= 0; ir
< COLORCUBE_LINE_SIZE
; ++ir
) {
316 for (int ig
= 0; ig
< COLORCUBE_LINE_SIZE
; ++ig
) {
317 for (int ib
= 0; ib
< COLORCUBE_LINE_SIZE
; ++ib
) {
318 const int r
= (int)(ir
*255.0f
/((float)(COLORCUBE_LINE_SIZE
-1))/*+0.5f*/);
319 const int g
= (int)(ig
*255.0f
/((float)(COLORCUBE_LINE_SIZE
-1))/*+0.5f*/);
320 const int b
= (int)(ib
*255.0f
/((float)(COLORCUBE_LINE_SIZE
-1))/*+0.5f*/);
322 int best_dist
= 0x7fffffff;
323 for (int i
= 0; i
< 255; ++i
) {
324 int32_t dist
= rgbDistanceSquared(pal8bit
[i
][0], pal8bit
[i
][1], pal8bit
[i
][2], r
, g
, b
);
325 if (best_color
< 0 || dist
< best_dist
) {
331 colorcube2
[ir
*(COLORCUBE_LINE_SIZE
*COLORCUBE_LINE_SIZE
)+ig
*COLORCUBE_LINE_SIZE
+ib
] = best_color
;
339 void vidResetPalette (void) {
340 paletteUsedCurr
= paletteUsed
;
344 uint8_t vidAllocColor (int r
, int g
, int b
) {
345 const uint8_t r8
= (r
< 0 ? 0 : r
> 255 ? 255 : (uint8_t)r
);
346 const uint8_t g8
= (g
< 0 ? 0 : g
> 255 ? 255 : (uint8_t)g
);
347 const uint8_t b8
= (b
< 0 ? 0 : b
> 255 ? 255 : (uint8_t)b
);
348 uint8_t v
= ccubeGet(r8
, g8
, b8
);
349 if (v
!= 255) return v
;
350 if (paletteUsedCurr
< 255) {
352 palette
[paletteUsedCurr
] = SDL_MapRGB(screen
->format
, r8
, g8
, b8
);
353 SDL_GetRGB(palette
[paletteUsedCurr
], screen
->format
, &palRGB
[paletteUsedCurr
][0], &palRGB
[paletteUsedCurr
][1], &palRGB
[paletteUsedCurr
][2]);
354 pal8bit
[paletteUsedCurr
][0] = r8
;
355 pal8bit
[paletteUsedCurr
][1] = g8
;
356 pal8bit
[paletteUsedCurr
][2] = b8
;
357 ccubeSet(paletteUsedCurr
, r8
, g8
, b8
);
358 return paletteUsedCurr
++;
360 // can't alloc, find nearest
362 return ccube2Get(r8
, g8
, b8
);
366 static void buildColorCache (void) {
368 memset(colorcube
, 255, sizeof(colorcube
));
369 memset(pal8bit
, 0, sizeof(pal8bit
));
371 for (f
= 0; f
< sizeof(zxPalette
)/3; ++f
) {
372 palette
[f
] = SDL_MapRGB(screen
->format
, zxPalette
[f
*3+0], zxPalette
[f
*3+1], zxPalette
[f
*3+2]);
373 ccubeSet(f
, zxPalette
[f
*3+0], zxPalette
[f
*3+1], zxPalette
[f
*3+2]);
374 pal8bit
[f
][0] = zxPalette
[f
*3+0];
375 pal8bit
[f
][1] = zxPalette
[f
*3+1];
376 pal8bit
[f
][2] = zxPalette
[f
*3+2];
378 paletteUsed
= paletteUsedCurr
= f
;
379 for (; f
< 256; ++f
) palette
[f
] = SDL_MapRGB(screen
->format
, 0, 0, 0);
380 for (f
= 0; f
< 256; ++f
) {
381 SDL_GetRGB(palette
[f
], screen
->format
, &palRGB
[f
][0], &palRGB
[f
][1], &palRGB
[f
][2]);
387 void rebuildPalette (void) {
388 if (screen
) buildColorCache();
392 static void lvCreateSurfaces (void) {
394 screenReal
= SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE
| SDL_FULLSCREEN
);
396 screen
= SDL_CreateRGBSurface(SDL_SWSURFACE
, 320, 240, screenReal
->format
->BitsPerPixel
, screenReal
->format
->Rmask
, screenReal
->format
->Gmask
, screenReal
->format
->Bmask
, 0);
398 actualScale
= vidScale
;
399 if (actualScale
< 1) actualScale
= 1; else if (actualScale
> 4) actualScale
= 4;
400 screenReal
= SDL_SetVideoMode(320*actualScale
, 240*actualScale
, 32, SDL_SWSURFACE
/*|SDL_DOUBLEBUF*/);
401 screen
= SDL_CreateRGBSurface(SDL_SWSURFACE
, 320, 240, screenReal
->format
->BitsPerPixel
, screenReal
->format
->Rmask
, screenReal
->format
->Gmask
, screenReal
->format
->Bmask
, 0);
403 if (screen
== NULL
) {
404 fprintf(stderr
, "FATAL: can't set videomode!\n");
408 if (screen
->format
->BitsPerPixel
!= 32 || (screenReal
!= NULL
&& screenReal
->format
->BitsPerPixel
!= 32) ||
409 (screen
->format
->Rshift
%8 || screen
->format
->Gshift
%8 || screen
->format
->Bshift
%8)) {
410 fprintf(stderr
, "FATAL: videomode initialization error!\n");
411 //fprintf(stderr, "Rmask=0x%08x; Gmask=0x%08x; Bmask=0x%08x\n", screen->format->Rmask, screen->format->Gmask, screen->format->Bmask);
416 vidRIdx
= screen
->format
->Rshift
/8;
417 vidGIdx
= screen
->format
->Gshift
/8;
418 vidBIdx
= screen
->format
->Bshift
/8;
419 //fprintf(stderr, "BPP: %u\n", screen->format->BytesPerPixel);
425 void initVideo (void) {
431 void switchFullScreen (void) {
432 const int needInit
= !!screen
;
435 screenReal
= SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE
/*|SDL_DOUBLEBUF*/);
437 screenReal
= SDL_SetVideoMode(320*3, 240*3, 32, SDL_SWSURFACE
|SDL_FULLSCREEN
);
439 optFullscreen
= !optFullscreen
;
440 if (screenReal
== NULL
|| screenReal
->format
->BitsPerPixel
!= 32) {
441 fprintf(stderr
, "FATAL: can't switch videomode!\n");
445 if (screen
) { SDL_FreeSurface(screen
); screen
= NULL
; }
446 optFullscreen
= !optFullscreen
;
447 if (needInit
) lvCreateSurfaces();
449 if (needInit
) screenFlip();
453 void updateScale (void) {
454 const int needInit
= !!screen
;
455 if (screen
) { SDL_FreeSurface(screen
); screen
= NULL
; }
463 ////////////////////////////////////////////////////////////////////////////////
464 void lockSurface (SurfaceLock
*lock
, SDL_Surface
*s
) {
467 lock
->needUnlock
= 0;
468 if (s
!= NULL
&& SDL_MUSTLOCK(s
)) {
469 lock
->needUnlock
= (SDL_LockSurface(s
) == 0);
475 void unlockSurface (SurfaceLock
*lock
) {
476 if (lock
&& lock
->s
&& lock
->needUnlock
) {
477 SDL_UnlockSurface(lock
->s
);
478 lock
->needUnlock
= 0;
483 void clearScreen (Uint8 col
) {
485 Uint32 clr
= palette
[col
];
486 Uint32
*d
= (Uint32
*)((Uint8
*)frameSfc
->pixels
);
488 for (int y
= 0; y
< frameSfc
->h
; ++y
) {
489 for (int x
= 0; x
< frameSfc
->w
; ++x
) d
[x
] = clr
;
490 d
= (Uint32
*)(((Uint8
*)d
)+frameSfc
->pitch
);
496 ////////////////////////////////////////////////////////////////////////////////
497 // surface must be locked!
498 void drawChar6 (char ch
, int x
, int y
, Uint8 fg
, Uint8 bg
) {
499 int pos
= (ch
&0xff)*8;
501 for (int dy
= 0; dy
< 8; ++dy
) {
502 uint8_t b
= font6x8
[pos
++];
504 for (int dx
= 0; dx
< 6; ++dx
) {
505 Uint8 c
= (b
&0x80 ? fg
: bg
);
507 if (c
!= 255) putPixel(x
+dx
, y
+dy
, c
);
514 void drawStr6 (const char *str
, int x
, int y
, Uint8 fg
, Uint8 bg
) {
517 drawChar6(*str
++, x
, y
, fg
, bg
);
524 void drawChar8 (char ch
, int x
, int y
, Uint8 fg
, Uint8 bg
) {
525 int pos
= (ch
&0xff)*8;
527 for (int dy
= 0; dy
< 8; ++dy
) {
528 uint8_t b
= msxfont8x8
[pos
++];
530 for (int dx
= 0; dx
< 8; ++dx
) {
531 Uint8 c
= (b
&0x80 ? fg
: bg
);
533 if (c
!= 255) putPixel(x
+dx
, y
+dy
, c
);
540 void drawStr8 (const char *str
, int x
, int y
, Uint8 fg
, Uint8 bg
) {
543 drawChar8(*str
++, x
, y
, fg
, bg
);
550 void drawStr6Outline (const char *str
, int x
, int y
, Uint8 fg
, Uint8 oc
) {
551 for (int dy
= -1; dy
< 2; ++dy
) {
552 for (int dx
= -1; dx
< 2; ++dx
) {
553 if (dx
|| dy
) drawStr6(str
, x
+dx
, y
+dy
, oc
, 255);
556 drawStr6(str
, x
, y
, fg
, 255);
560 void drawStr8Outline (const char *str
, int x
, int y
, Uint8 fg
, Uint8 oc
) {
561 for (int dy
= -1; dy
< 2; ++dy
) {
562 for (int dx
= -1; dx
< 2; ++dx
) {
563 if (dx
|| dy
) drawStr8(str
, x
+dx
, y
+dy
, oc
, 255);
566 drawStr8(str
, x
, y
, fg
, 255);
570 ////////////////////////////////////////////////////////////////////////////////
572 static void drawCharZI (const uint8_t *dta, int hgt, int x, int y, Uint8 c1, Uint8 c2) {
573 int wdt = *dta++, yofs = ((wdt>>4)&0x0f);
577 for (int dy = 0; dy < hgt; ++dy) {
578 for (int dx = 0; dx < wdt; dx += 4) {
581 for (int c = 0; c < 4; ++c) {
582 switch ((b>>6)&0x03) {
584 case 1: putPixel(x+dx+c, y+dy, c1); break;
585 case 2: putPixel(x+dx+c, y+dy, c2); break;
595 void drawZFont (void) {
596 const uint8_t *st = zfont;
597 int x = 1, y = 1, hgt = zfont[0];
599 for (int f = 33; f <= 95; ++f) {
600 const uint8_t *st = zfont+(f-32)*2;
601 int ofs = st[0]+256*st[1], w;
605 if (x+w > 319) { x = 1; y += hgt+2; }
606 drawCharZI(st, hgt, x, y, 66, 67);
613 int drawCharZ (char ch
, int x
, int y
, Uint8 c1
, Uint8 c2
) {
614 if (ch
>= 'a' && ch
<= 'z') ch
-= 32;
615 if (ch
< 33 || ch
> 95) ch
= '?';
617 const uint8_t *st
= zfont
+(ch
-32)*2;
618 int ofs
= st
[0]+256*st
[1], wdt
, yofs
, hgt
= zfont
[0];
622 yofs
= ((wdt
>>4)&0x0f);
624 if (c1
== 255 && c2
== 255) return wdt
;
629 for (int dx
= 0; dx
< wdt
; dx
+= 4) {
632 for (int c
= 0; c
< 4; ++c
, ++px
) {
633 switch ((b
>>6)&0x03) {
635 case 1: putPixel(px
, y
, c1
); break;
636 case 2: putPixel(px
, y
, c2
); break;
637 case 3: /*putPixel(x+dx+c, y+dy, 2);*/ break;
651 int drawStrZ (const char *str
, int x
, int y
, Uint8 c1
, Uint8 c2
) {
655 int w
= drawCharZ(*str
++, x
, y
, c1
, c2
);
664 static inline Uint32
fixColor (Uint32 clr
) {
666 Uint8
*ca
= (Uint8
*)&clr
;
667 Uint8 r
= ca
[vidRIdx
], g
= ca
[vidGIdx
], b
= ca
[vidBIdx
];
668 //Uint32 lumi = (0.3*((double)r/255.0)+0.59*((double)g/255.0)+0.11*((double)b/255.0))*255.0;
669 Uint32 lumi
= (4915*r
+9666*g
+1802*b
);
671 if (vidColorMode
> 2) {
672 if (lumi
>= 128*16384) lumi
/= 16384; else lumi
/= 11000;
676 if (lumi
> 255) lumi
= 255;
678 switch (vidColorMode
) {
679 case 1: case 3: // b/w
680 ca
[vidRIdx
] = ca
[vidGIdx
] = ca
[vidBIdx
] = lumi
;
682 case 2: case 4: // green
683 ca
[vidRIdx
] = ca
[vidBIdx
] = 0;
692 ////////////////////////////////////////////////////////////////////////////////
693 static void Blit4xInternal (void) {
694 const Uint32
*scrB
= screen
->pixels
; // 320x240
695 Uint32
*scrR
= screenReal
->pixels
; // 1280x960
696 for (int y
= 0; y
< screen
->h
; ++y
) {
697 const Uint32
*s
= scrB
;
699 Uint32
*d1
= (Uint32
*)((Uint8
*)d0
+screenReal
->pitch
);
700 Uint32
*d2
= (Uint32
*)((Uint8
*)d1
+screenReal
->pitch
);
701 Uint32
*d3
= (Uint32
*)((Uint8
*)d2
+screenReal
->pitch
);
702 for (int x
= 0; x
< screen
->w
; ++x
) {
703 const Uint32 clr
= fixColor(*s
++);
704 d0
[0] = d0
[1] = d0
[2] = d0
[3] = clr
;
705 d1
[0] = d1
[1] = d1
[2] = d1
[3] = clr
;
706 d2
[0] = d2
[1] = d2
[2] = d2
[3] = clr
;
707 d3
[0] = d3
[1] = d3
[2] = d3
[3] = clr
;
713 scrB
= (Uint32
*)((Uint8
*)scrB
+screen
->pitch
);
714 scrR
= (Uint32
*)((Uint8
*)scrR
+screenReal
->pitch
*4);
719 static void TV4xInternal (void) {
720 Uint32
*scrR
= screenReal
->pixels
; // 1280x960
721 scrR
= (Uint32
*)((Uint8
*)scrR
+screenReal
->pitch
);
722 for (int y
= screenReal
->h
/4; y
--; scrR
= (Uint32
*)((Uint8
*)scrR
+screenReal
->pitch
*4)) {
724 for (int x
= 0; x
< screen
->w
; ++x
) {
725 const Uint32 c0
= *d0
;
726 Uint32 c1
= (((c0
&0x00ff00ff)*7)>>3)&0x00ff00ff;
727 c1
|= (((c0
&0x0000ff00)*7)>>3)&0x0000ff00;
728 d0
[0] = d0
[1] = d0
[2] = d0
[3] = c1
;
729 //d0[0] = d0[1] = d0[2] = d0[3] = 0x00ff0000;
732 d0
= (Uint32
*)((Uint8
*)scrR
+screenReal
->pitch
);
733 for (int x
= 0; x
< screen
->w
; ++x
) {
735 Uint32 c1
= (((c0
&0x00ff00ff)*7)>>3)&0x00ff00ff;
736 c1
|= (((c0
&0x0000ff00)*7)>>3)&0x0000ff00;
737 d0
[0] = d0
[1] = d0
[2] = d0
[3] = c1
;
740 c1
= (((c0
&0x00ff00ff)*7)>>3)&0x00ff00ff;
741 c1
|= (((c0
&0x0000ff00)*7)>>3)&0x0000ff00;
742 d0
[0] = d0
[1] = d0
[2] = d0
[3] = c1
;
744 //d0[0] = d0[1] = d0[2] = d0[3] = 0x00ff0000;
751 static void Blit4x (void) {
752 const int needUnlock
= (SDL_MUSTLOCK(screenReal
) ? SDL_LockSurface(screenReal
) == 0 : 0);
754 if (needUnlock
) SDL_UnlockSurface(screenReal
);
758 static void Blit4xTV (void) {
759 const int needUnlock
= (SDL_MUSTLOCK(screenReal
) ? SDL_LockSurface(screenReal
) == 0 : 0);
760 /*FIXME: make this faster!*/
763 if (needUnlock
) SDL_UnlockSurface(screenReal
);
767 static void Blit3xInternal (void) {
768 const Uint32
*scrB
= screen
->pixels
; // 320x240
769 Uint32
*scrR
= screenReal
->pixels
; // 960x720
770 for (int y
= 0; y
< screen
->h
; ++y
) {
771 const Uint32
*s
= scrB
;
773 Uint32
*d1
= (Uint32
*)((Uint8
*)d0
+screenReal
->pitch
);
774 Uint32
*d2
= (Uint32
*)((Uint8
*)d1
+screenReal
->pitch
);
775 for (int x
= 0; x
< screen
->w
; ++x
) {
776 const Uint32 clr
= fixColor(*s
++);
777 d0
[0] = d0
[1] = d0
[2] = clr
;
778 d1
[0] = d1
[1] = d1
[2] = clr
;
779 d2
[0] = d2
[1] = d2
[2] = clr
;
784 scrB
= (Uint32
*)((Uint8
*)scrB
+screen
->pitch
);
785 scrR
= (Uint32
*)((Uint8
*)scrR
+screenReal
->pitch
*3);
790 static void TV3xInternal (void) {
791 Uint32
*scrR
= screenReal
->pixels
; // 960x720
792 scrR
= (Uint32
*)((Uint8
*)scrR
+screenReal
->pitch
);
793 for (int y
= screenReal
->h
/2; y
--; scrR
= (Uint32
*)((Uint8
*)scrR
+screenReal
->pitch
*2)) {
795 for (int x
= 0; x
< screen
->w
; ++x
) {
796 const Uint32 c0
= *d0
;
797 Uint32 c1
= (((c0
&0x00ff00ff)*7)>>3)&0x00ff00ff;
798 c1
|= (((c0
&0x0000ff00)*7)>>3)&0x0000ff00;
799 d0
[0] = d0
[1] = d0
[2] = c1
;
806 static void Blit3x (void) {
807 const int needUnlock
= (SDL_MUSTLOCK(screenReal
) ? SDL_LockSurface(screenReal
) == 0 : 0);
809 if (needUnlock
) SDL_UnlockSurface(screenReal
);
813 static void Blit3xTV (void) {
814 const int needUnlock
= (SDL_MUSTLOCK(screenReal
) ? SDL_LockSurface(screenReal
) == 0 : 0);
815 /*FIXME: make this faster!*/
818 if (needUnlock
) SDL_UnlockSurface(screenReal
);
822 static void Blit2x (void) {
823 const int needUnlock
= (SDL_MUSTLOCK(screenReal
) ? SDL_LockSurface(screenReal
) == 0 : 0);
824 const Uint32
*scrB
= screen
->pixels
; // 320x240
825 Uint32
*scrR
= screenReal
->pixels
; // 640x480
826 for (int y
= 0; y
< screen
->h
; ++y
) {
827 const Uint32
*s
= scrB
;
828 Uint32
*d
= scrR
, *d2
= (Uint32
*)((Uint8
*)d
+screenReal
->pitch
);
829 for (int x
= 0; x
< screen
->w
; ++x
) {
830 const Uint32 clr
= fixColor(*s
++);
836 scrB
= (Uint32
*)((Uint8
*)scrB
+screen
->pitch
);
837 scrR
= (Uint32
*)((Uint8
*)scrR
+screenReal
->pitch
*2);
839 if (needUnlock
) SDL_UnlockSurface(screenReal
);
843 static void Blit2xTV (void) {
844 const int needUnlock
= (SDL_MUSTLOCK(screenReal
) ? SDL_LockSurface(screenReal
) == 0 : 0);
845 const Uint32
*scrB
= screen
->pixels
; // 320x240
846 Uint32
*scrR
= screenReal
->pixels
; // 640x480
847 for (int y
= 0; y
< screen
->h
; ++y
) {
848 const Uint32
*s
= scrB
;
849 Uint32
*d
= scrR
, *d2
= (Uint32
*)((Uint8
*)d
+screenReal
->pitch
);
850 for (int x
= 0; x
< screen
->w
; ++x
) {
851 const Uint32 c0
= fixColor(*s
);
852 Uint32 c1
= (((c0
&0x00ff00ff)*7)>>3)&0x00ff00ff;
853 c1
|= (((c0
&0x0000ff00)*7)>>3)&0x0000ff00;
859 scrB
= (Uint32
*)((Uint8
*)scrB
+screen
->pitch
);
860 scrR
= (Uint32
*)((Uint8
*)scrR
+screenReal
->pitch
*2);
862 if (needUnlock
) SDL_UnlockSurface(screenReal
);
866 static void Blit1x (void) {
867 const int needUnlock
= (SDL_MUSTLOCK(screenReal
) ? SDL_LockSurface(screenReal
) == 0 : 0);
868 const Uint32
*scrB
= screen
->pixels
; // 320x240
869 Uint32
*scrR
= screenReal
->pixels
; // 320x240
870 for (int y
= 0; y
< screen
->h
; ++y
) {
871 const Uint32
*s
= scrB
;
873 for (int x
= 0; x
< screen
->w
; ++x
) {
874 const Uint32 clr
= fixColor(*s
++);
878 scrB
= (Uint32
*)((Uint8
*)scrB
+screen
->pitch
);
879 scrR
= (Uint32
*)((Uint8
*)scrR
+screenReal
->pitch
);
881 if (needUnlock
) SDL_UnlockSurface(screenReal
);
885 static void vidRenderTextScr16x2 (SDL_Surface
*sfc
) {
887 Uint32
*sp
= (Uint32
*)((Uint8
*)sfc
->pixels
);
888 // move down a little
890 if (sfc->h > 480*2+16*2) sp = (Uint32 *)((Uint8 *)sp+sfc->pitch*16);
891 else if (sfc->h > 480*2) sp = (Uint32 *)((Uint8 *)sp+sfc->pitch*((sfc->h-480)/2));
893 // center horizontally
894 sp
+= (sfc
->w
-640*2)/2;
896 const uint32_t vhgt
=
897 vid_textsrc_height
<= 0 ? (uint32_t)VID_TEXT_HEIGHT
:
898 vid_textsrc_height
> VID_TEXT_HEIGHT
? VID_TEXT_HEIGHT
:
899 (uint32_t)vid_textsrc_height
;
900 const VidTChar
*tp
= vid_textscr
;
901 for (uint32_t y
= 0; y
< vhgt
; ++y
) {
903 for (uint32_t x
= 0; x
< (uint32_t)VID_TEXT_WIDTH
; ++x
, ++tp
, d
+= 16) {
905 Uint32 bc
= palette
[(tp
->attr
>>4)&0x0f];
906 Uint32 fc
= palette
[tp
->attr
&0x0f];
907 const uint8_t *cptr
= vid_font8x16
+16*tp
->ch
;
910 cdest1
= (Uint32
*)((Uint8
*)cdest1
+sfc
->pitch
);
911 for (uint32_t dy
= 0; dy
< 16; ++dy
) {
913 for (uint32_t dx
= 0; dx
< 8; ++dx
) {
914 *cdest0
++ = (b
&0x80 ? fc
: bc
);
915 *cdest0
++ = (b
&0x80 ? fc
: bc
);
916 *cdest1
++ = (b
&0x80 ? fc
: bc
);
917 *cdest1
++ = (b
&0x80 ? fc
: bc
);
921 cdest0
= (Uint32
*)((Uint8
*)cdest0
+sfc
->pitch
*2);
923 cdest1
= (Uint32
*)((Uint8
*)cdest1
+sfc
->pitch
*2);
927 sp
= (Uint32
*)((Uint8
*)sp
+sfc
->pitch
*(16*2));
932 static void vidRenderTextScr16 (SDL_Surface
*sfc
) {
934 Uint32
*sp
= (Uint32
*)((Uint8
*)sfc
->pixels
);
935 // move down a little
937 if (sfc->h > 480+16*2) sp = (Uint32 *)((Uint8 *)sp+sfc->pitch*16);
938 else if (sfc->h > 480) sp = (Uint32 *)((Uint8 *)sp+sfc->pitch*((sfc->h-480)/2));
940 // center horizontally
941 sp
+= (sfc
->w
-640)/2;
943 const uint32_t vhgt
=
944 vid_textsrc_height
<= 0 ? (uint32_t)VID_TEXT_HEIGHT
:
945 vid_textsrc_height
> VID_TEXT_HEIGHT
? VID_TEXT_HEIGHT
:
946 (uint32_t)vid_textsrc_height
;
947 const VidTChar
*tp
= vid_textscr
;
948 for (uint32_t y
= 0; y
< vhgt
; ++y
) {
950 for (uint32_t x
= 0; x
< (uint32_t)VID_TEXT_WIDTH
; ++x
, ++tp
, d
+= 8) {
952 Uint32 bc
= palette
[(tp
->attr
>>4)&0x0f];
953 Uint32 fc
= palette
[tp
->attr
&0x0f];
954 const uint8_t *cptr
= vid_font8x16
+16*tp
->ch
;
956 for (uint32_t dy
= 0; dy
< 16; ++dy
) {
958 for (uint32_t dx
= 0; dx
< 8; ++dx
) {
959 *cdest
++ = (b
&0x80 ? fc
: bc
);
963 cdest
= (Uint32
*)((Uint8
*)cdest
+sfc
->pitch
);
967 sp
= (Uint32
*)((Uint8
*)sp
+sfc
->pitch
*16);
972 static void vidRenderTextScr8 (SDL_Surface
*sfc
) {
974 Uint32
*sp
= (Uint32
*)((Uint8
*)sfc
->pixels
);
975 // move down a little
977 if (sfc->h > 240+8*2) sp = (Uint32 *)((Uint8 *)sp+sfc->pitch*8);
978 else if (sfc->h > 240) sp = (Uint32 *)((Uint8 *)sp+sfc->pitch*((sfc->h-240)/2));
980 // center horizontally
981 sp
+= (sfc
->w
-320)/2;
983 const uint32_t vhgt
=
984 vid_textsrc_height
<= 0 ? (uint32_t)VID_TEXT_HEIGHT
:
985 vid_textsrc_height
> VID_TEXT_HEIGHT
? VID_TEXT_HEIGHT
:
986 (uint32_t)vid_textsrc_height
;
987 const VidTChar
*tp
= vid_textscr
;
988 for (uint32_t y
= 0; y
< vhgt
; ++y
) {
990 for (uint32_t x
= 0; x
< (uint32_t)VID_TEXT_WIDTH
; ++x
, ++tp
, d
+= 8) {
992 Uint32 bc
= palette
[(tp
->attr
>>4)&0x0f];
993 Uint32 fc
= palette
[tp
->attr
&0x0f];
994 const uint8_t *cptr
= vid_font8x8
+8*tp
->ch
;
996 for (uint32_t dy
= 0; dy
< 8; ++dy
) {
998 for (uint32_t dx
= 0; dx
< 8; ++dx
) {
999 *cdest
++ = (b
&0x80 ? fc
: bc
);
1003 cdest
= (Uint32
*)((Uint8
*)cdest
+sfc
->pitch
);
1007 sp
= (Uint32
*)((Uint8
*)sp
+sfc
->pitch
*8);
1012 static void vidRenderTextScr (SDL_Surface
*sfc
) {
1013 if (sfc
->w
>= 320*4 && sfc
->h
>= 240*4) vidRenderTextScr16x2(sfc
);
1014 else if (sfc
->w
>= 320*2 && sfc
->h
>= 240*2) vidRenderTextScr16(sfc
);
1015 else vidRenderTextScr8(sfc
);
1019 static void screenFlip (void) {
1021 lockSurface(&frameSfcLock, screen);
1023 unlockSurface(&frameSfcLock);
1026 if (screenReal
!= NULL
) {
1028 if (!optFullscreen) {
1029 if (optTVScaler) Blit3xTV(); else Blit3x();
1031 if (optTVScaler > 1 || (optTVScaler && !optFullscreen)) Blit2xTV(); else Blit2x();
1034 switch (actualScale
) {
1035 case 1: Blit1x(); break;
1036 case 2: if (optTVScaler
) Blit2xTV(); else Blit2x(); break;
1037 case 3: if (optTVScaler
) Blit3xTV(); else Blit3x(); break;
1038 case 4: if (optTVScaler
) Blit4xTV(); else Blit4x(); break;
1039 default: __builtin_trap();
1042 if (vidBeforeFlipCB
) {
1043 const int needUnlock
= (SDL_MUSTLOCK(screenReal
) ? SDL_LockSurface(screenReal
) == 0 : 0);
1044 vidBeforeFlipCB(screenReal
);
1045 if (needUnlock
) SDL_UnlockSurface(screenReal
);
1048 if (vid_textscr_active
) {
1049 const int needUnlock
= (SDL_MUSTLOCK(screenReal
) ? SDL_LockSurface(screenReal
) == 0 : 0);
1050 vidRenderTextScr(screenReal
);
1051 if (needUnlock
) SDL_UnlockSurface(screenReal
);
1054 SDL_Flip(screenReal
);
1056 if (vidBeforeFlipCB
) {
1057 const int needUnlock
= (SDL_MUSTLOCK(screen
) ? SDL_LockSurface(screen
) == 0 : 0);
1058 vidBeforeFlipCB(screen
);
1059 if (needUnlock
) SDL_UnlockSurface(screen
);
1062 if (vid_textscr_active
) {
1063 const int needUnlock
= (SDL_MUSTLOCK(screen
) ? SDL_LockSurface(screen
) == 0 : 0);
1064 vidRenderTextScr(screen
);
1065 if (needUnlock
) SDL_UnlockSurface(screen
);
1073 ////////////////////////////////////////////////////////////////////////////////
1074 void forcedShowFrame (void) {
1075 if (frameSfc
!= NULL
) {
1077 unlockSurface(&frameSfcLock
);
1079 lockSurface(&frameSfcLock
, screen
);
1084 void buildFrame (void) {
1086 if (frameCB
!= NULL
) {
1087 lockSurface(&frameSfcLock
, screen
);
1091 unlockSurface(&frameSfcLock
);
1093 if (!frameSfcRaped
) screenFlip();
1097 static Uint32
cbFrameTimer (Uint32 interval
, void *param
) {
1100 evt
.type
= SDL_USEREVENT
;
1102 //evt.user.type = SDL_USEREVENT;
1104 evt.user.data1 = NULL;
1105 evt.user.data2 = NULL;
1107 SDL_PushEvent(&evt
);
1108 //fprintf(stderr, "!\n");
1113 ////////////////////////////////////////////////////////////////////////////////
1114 void postQuitMessage (void) {
1117 evt
.type
= SDL_QUIT
;
1118 SDL_PushEvent(&evt
);
1122 ////////////////////////////////////////////////////////////////////////////////
1123 int msButtons
= 0, msLastX
= 0, msLastY
= 0, kbCtrl
= 0, kbAlt
= 0, kbShift
= 0;
1124 int kbLCtrl
= 0, kbRCtrl
= 0, kbLAlt
= 0, kbRAlt
= 0, kbLShift
= 0, kbRShift
= 0;
1125 int msAutoTimeMSFirst
= 500;
1126 int msAutoTimeMSRepeat
= 100;
1127 int msAutoTresholdX
= 2;
1128 int msAutoTresholdY
= 2;
1137 static MSPressInfo msbi
[5]; // left,right,middle
1146 static const KBCtrlKeyInfo kbCtrlKeys
[] = {
1147 {.key
=SDLK_LCTRL
, .var
=&kbLCtrl
},
1148 {.key
=SDLK_RCTRL
, .var
=&kbRCtrl
},
1149 {.key
=SDLK_LALT
, .var
=&kbLAlt
},
1150 {.key
=SDLK_RALT
, .var
=&kbRAlt
},
1151 {.key
=SDLK_LSHIFT
, .var
=&kbLShift
},
1152 {.key
=SDLK_RSHIFT
, .var
=&kbRShift
},
1156 static void initEventSystem (void) {
1157 memset(msbi
, 0, sizeof(msbi
));
1161 static void fixKbCtrl (SDLKey key
, int isdown
) {
1162 for (unsigned int f
= 0; f
< sizeof(kbCtrlKeys
)/sizeof(KBCtrlKeyInfo
); ++f
) {
1163 if (key
== kbCtrlKeys
[f
].key
) *(kbCtrlKeys
[f
].var
) = isdown
;
1165 kbCtrl
= kbLCtrl
||kbRCtrl
;
1166 kbAlt
= kbLAlt
||kbRAlt
;
1167 kbShift
= kbLShift
||kbRShift
;
1171 static void kbDepressCtrls (void) {
1172 for (unsigned int f
= 0; f
< sizeof(kbCtrlKeys
)/sizeof(KBCtrlKeyInfo
); ++f
) {
1173 if (*(kbCtrlKeys
[f
].var
)) {
1174 fixKbCtrl(kbCtrlKeys
[f
].key
, 0);
1178 event
.type
= SDL_KEYUP
;
1179 event
.key
.state
= SDL_RELEASED
;
1180 event
.key
.keysym
.scancode
= 0;
1181 event
.key
.keysym
.unicode
= 0;
1182 event
.key
.keysym
.sym
= kbCtrlKeys
[f
].key
;
1183 event
.key
.keysym
.mod
=
1184 (kbLCtrl
? KMOD_LCTRL
: 0) |
1185 (kbRCtrl
? KMOD_RCTRL
: 0) |
1186 (kbLAlt
? KMOD_LALT
: 0) |
1187 (kbRAlt
? KMOD_RALT
: 0) |
1188 (kbLShift
? KMOD_LSHIFT
: 0) |
1189 (kbRShift
? KMOD_RSHIFT
: 0) |
1198 static void doAutoMouse (void) {
1199 if (mouseButtonCB
&& msAutoTimeMSFirst
> 0) {
1200 int64_t t
= timerGetMS();
1202 for (int b
= 0; b
< 3; ++b
) {
1205 if (msbi
[n
].time
> 0) {
1206 if (!msbi
[n
].repeat
&& (abs(msLastX
-msbi
[n
].x
) > msAutoTresholdX
|| abs(msLastY
-msbi
[n
].y
) > msAutoTresholdY
)) {
1207 // mouse moved too far, stop autorepeating
1209 } else if ((msbi
[n
].repeat
&& t
-msbi
[n
].time
>= msAutoTimeMSRepeat
) ||
1210 (!msbi
[n
].repeat
&& t
-msbi
[n
].time
>= msAutoTimeMSFirst
)) {
1214 mouseButtonCB(msLastX
, msLastY
, (n
|MS_BUTTON_AUTO
), msButtons
);
1222 // -1: quit; 1: new frame
1223 int processEvents (int dowait
) {
1226 while ((dowait
? SDL_WaitEvent(&event
) : SDL_PollEvent(&event
))) {
1227 switch (event
.type
) {
1228 case SDL_QUIT
: // the user want to quit
1232 fixKbCtrl(event
.key
.keysym
.sym
, (event
.type
== SDL_KEYDOWN
));
1233 if (keyCB
) keyCB(&event
.key
);
1235 case SDL_MOUSEMOTION
: {
1237 int x
= event
.motion
.x
, y
= event
.motion
.y
, rx
= event
.motion
.xrel
, ry
= event
.motion
.yrel
;
1239 if (screenReal
!= NULL
) { x
/= 2; y
/= 2; }
1242 //SDLMB2VMB(event.motion.state);
1243 //msButtons = buttons;
1244 if (mouseCB
) mouseCB(x
, y
, rx
, ry
, msButtons
);
1246 case SDL_MOUSEBUTTONUP
:
1247 case SDL_MOUSEBUTTONDOWN
: {
1248 int x
= event
.button
.x
, y
= event
.button
.y
, btn
= 0;
1250 if (screenReal
!= NULL
) { x
/= 2; y
/= 2; }
1253 switch (event
.button
.button
) {
1254 case SDL_BUTTON_LEFT
: btn
= MS_BUTTON_LEFT
; break;
1255 case SDL_BUTTON_RIGHT
: btn
= MS_BUTTON_RIGHT
; break;
1256 case SDL_BUTTON_MIDDLE
: btn
= MS_BUTTON_MIDDLE
; break;
1257 case SDL_BUTTON_WHEELUP
: btn
= MS_BUTTON_WHEELUP
; break;
1258 case SDL_BUTTON_WHEELDOWN
: btn
= MS_BUTTON_WHEELDOWN
; break;
1261 //fprintf(stderr, "DOWN:%d; btn:%d; bt:%02x\n", (event.button.state == SDL_PRESSED), btn, msButtons);
1263 if (event
.button
.state
== SDL_PRESSED
) {
1265 if (btn
<= MS_BUTTON_MIDDLE
) {
1266 msbi
[btn
].time
= timerGetMS();
1269 msbi
[btn
].repeat
= 0;
1273 btn
|= MS_BUTTON_DEPRESSED
;
1274 if (btn
<= MS_BUTTON_MIDDLE
) msbi
[btn
].time
= 0;
1276 if (mouseButtonCB
) mouseButtonCB(x
, y
, btn
, msButtons
);
1279 case SDL_ACTIVEEVENT
:
1280 if (event
.active
.gain
) {
1281 vidWindowActivated
= 1;
1282 if (windowActivationCB
!= NULL
) windowActivationCB(1);
1284 vidWindowActivated
= 0;
1285 SDL_WM_GrabInput(SDL_GRAB_OFF
);
1288 if (msButtons
!= 0) {
1289 if (mouseButtonCB
!= NULL
) {
1290 for (unsigned int mask
= 0x01; mask
< MS_BUTTON_DEPRESSED
; mask
<<= 1) {
1291 if (msButtons
&mask
) {
1293 mouseButtonCB(msLastX
, msLastY
, mask
|MS_BUTTON_DEPRESSED
, msButtons
);
1299 if (windowActivationCB
!= NULL
) windowActivationCB(0);
1303 //while (SDL_PollEvent(NULL)) processEvents();
1314 ////////////////////////////////////////////////////////////////////////////////
1315 void mainLoop (void) {
1316 SDL_TimerID frameTimer
= SDL_AddTimer(20, cbFrameTimer
, NULL
);
1320 if (eres
> 0) buildFrame();
1321 eres
= processEvents(1);
1324 SDL_RemoveTimer(frameTimer
);
1328 ////////////////////////////////////////////////////////////////////////////////
1329 VOverlay
*createVO (int w
, int h
) {
1330 if (w
> 0 && h
> 0) {
1331 VOverlay
*res
= malloc(sizeof(VOverlay
));
1333 if ((res
->data
= malloc(w
*h
)) != NULL
) {
1345 void resizeVO (VOverlay
*v
, int w
, int h
) {
1346 if (v
&& w
> 0 && h
> 0 && (v
->w
!= w
|| v
->h
!= h
)) {
1347 v
->data
= realloc(v
->data
, w
*h
);
1348 if (!v
->data
) { fprintf(stderr
, "\bFATAL: out of memory!\n"); abort(); }
1355 VOverlay
*createVOFromIcon (const void *iconbuf
) {
1356 if (iconbuf
!= NULL
) {
1357 const uint8_t *ibuf
= (const uint8_t *)iconbuf
;
1358 VOverlay
*res
= createVO(ibuf
[0], ibuf
[1]);
1362 for (int y
= 0; y
< ibuf
[1]; ++y
) {
1363 for (int x
= 0; x
< ibuf
[0]; ++x
) {
1364 putPixelVO(res
, x
, y
, ibuf
[2+y
*ibuf
[0]+x
]);
1374 void freeVO (VOverlay
*v
) {
1376 if (v
->data
!= NULL
) free(v
->data
);
1381 void clearVO (VOverlay
*v
, Uint8 c
) {
1382 if (v
!= NULL
&& v
->w
> 0 && v
->h
> 0) memset(v
->data
, c
, v
->w
*v
->h
);
1386 ////////////////////////////////////////////////////////////////////////////////
1387 void drawChar6VO (VOverlay
*v
, char ch
, int x
, int y
, Uint8 fg
, Uint8 bg
) {
1388 if (v
!= NULL
&& x
> -6 && y
> -8 && x
< v
->w
+6 && y
< v
->h
+8) {
1389 int pos
= (ch
&0xff)*8;
1391 for (int dy
= 0; dy
< 8; ++dy
, ++y
) {
1392 uint8_t b
= font6x8
[pos
++];
1394 for (int dx
= 0; dx
< 6; ++dx
) {
1395 Uint8 c
= (b
&0x80 ? fg
: bg
);
1397 if (c
!= 255) putPixelVO(v
, x
+dx
, y
, c
);
1405 void drawStr6VO (VOverlay
*v
, const char *str
, int x
, int y
, Uint8 fg
, Uint8 bg
) {
1406 if (str
!= NULL
) for (; *str
; ++str
, x
+= 6) drawChar6VO(v
, *str
, x
, y
, fg
, bg
);
1410 void drawChar8VO (VOverlay
*v
, char ch
, int x
, int y
, Uint8 fg
, Uint8 bg
) {
1411 if (v
!= NULL
&& x
> -8 && y
> -8 && x
< v
->w
+8 && y
< v
->h
+8) {
1412 int pos
= (ch
&0xff)*8;
1414 for (int dy
= 0; dy
< 8; ++dy
, ++y
) {
1415 uint8_t b
= msxfont8x8
[pos
++];
1417 for (int dx
= 0; dx
< 8; ++dx
) {
1418 Uint8 c
= (b
&0x80 ? fg
: bg
);
1420 if (c
!= 255) putPixelVO(v
, x
+dx
, y
, c
);
1428 void drawStr8VO (VOverlay
*v
, const char *str
, int x
, int y
, Uint8 fg
, Uint8 bg
) {
1429 if (str
!= NULL
) for (; *str
; ++str
, x
+= 8) drawChar8VO(v
, *str
, x
, y
, fg
, bg
);
1433 void drawFrameVO (VOverlay
*v
, int x0
, int y0
, int w
, int h
, Uint8 c
) {
1434 if (v
!= NULL
&& w
> 0 && h
> 0 && x0
> -w
&& y0
> -h
&& x0
< v
->w
&& y0
< v
->h
) {
1435 if (x0
< 0) { if ((w
+= x0
) < 1) return; x0
= 0; }
1436 if (y0
< 0) { if ((h
+= y0
) < 1) return; y0
= 0; }
1437 if (x0
+w
> v
->w
) { if ((w
= v
->w
-x0
) < 1) return; }
1438 if (y0
+h
> v
->h
) { if ((h
= v
->h
-y0
) < 1) return; }
1440 memset(v
->data
+y0
*v
->w
+x0
, c
, w
);
1441 if (h
> 1) memset(v
->data
+(y0
+h
-1)*v
->w
+x0
, c
, w
);
1445 for (uint8_t *d
= v
->data
+(y0
+1)*v
->w
+x0
; h
> 0; --h
, d
+= v
->w
) d
[0] = d
[w
] = c
;
1451 void fillRectVO (VOverlay
*v
, int x0
, int y0
, int w
, int h
, Uint8 c
) {
1452 if (v
!= NULL
&& w
> 0 && h
> 0 && x0
> -w
&& y0
> -h
&& x0
< v
->w
&& y0
< v
->h
) {
1453 if (x0
< 0) { if ((w
+= x0
) < 1) return; x0
= 0; }
1454 if (y0
< 0) { if ((h
+= y0
) < 1) return; y0
= 0; }
1455 if (x0
+w
> v
->w
) { if ((w
= v
->w
-x0
) < 1) return; }
1456 if (y0
+h
> v
->h
) { if ((h
= v
->h
-y0
) < 1) return; }
1458 for (uint8_t *d
= v
->data
+y0
*v
->w
+x0
; h
> 0; --h
, d
+= v
->w
) memset(d
, c
, w
);
1463 ////////////////////////////////////////////////////////////////////////////////
1464 void blitVO (VOverlay
*v
, int x0
, int y0
, Uint8 alpha
) {
1465 if (v
!= NULL
&& x0
> -v
->w
&& y0
> -v
->h
&& x0
< frameSfc
->w
&& y0
< frameSfc
->h
&& alpha
> 0) {
1466 int w
= v
->w
, h
= v
->h
;
1467 const uint8_t *vs
= v
->data
;
1471 // skip invisible top part
1472 if ((h
+= y0
) < 1) return;
1476 if (y0
+h
> frameSfc
->h
) {
1477 // don't draw invisible bottom part
1478 if ((h
= frameSfc
->h
-y0
) < 1) return;
1482 // skip invisible left part
1483 if ((w
+= x0
) < 1) return;
1487 if (x0
+w
> frameSfc
->w
) {
1488 // don't draw invisible right part
1489 if ((w
= frameSfc
->w
-x0
) < 1) return;
1492 dest
= (((Uint8
*)frameSfc
->pixels
)+(y0
*frameSfc
->pitch
)+x0
*4);
1494 for (; h
> 0; --h
, dest
+= frameSfc
->pitch
, vs
+= v
->w
) {
1495 Uint32
*d
= (Uint32
*)dest
;
1496 const uint8_t *s
= vs
;
1498 for (int dx
= w
; dx
> 0; --dx
, ++d
, ++s
) if (*s
!= 255) *d
= palette
[*s
];
1501 for (; h
> 0; --h
, dest
+= frameSfc
->pitch
, vs
+= v
->w
) {
1503 const uint8_t *s
= vs
;
1505 for (int dx
= w
; dx
> 0; --dx
, d
+= 4, ++s
) {
1508 if ((c
= *s
) != 255) {
1509 uint8_t r
= d
[vidRIdx
], g
= d
[vidGIdx
], b
= d
[vidBIdx
];
1511 d
[vidRIdx
] = (((palRGB
[c
][0]-r
)*alpha
)>>8)+r
;
1512 d
[vidGIdx
] = (((palRGB
[c
][1]-g
)*alpha
)>>8)+g
;
1513 d
[vidBIdx
] = (((palRGB
[c
][2]-b
)*alpha
)>>8)+b
;
1522 ////////////////////////////////////////////////////////////////////////////////
1523 #include "videoex.c"