|
|
1.1 root 1: /*
2: Hatari - hostscreen.c
3:
4: This file is distributed under the GNU Public License, version 2 or at
5: your option any later version. Read the file gpl.txt for details.
6:
7: Host video routines. This file originally came from the Aranym project but
8: has been thoroughly reworked for Hatari. However, integration with the rest
9: of the Hatari source code is still bad and needs a lot of improvement...
10: */
1.1.1.3 ! root 11: const char HostScreen_rcsid[] = "Hatari $Id: hostscreen.c,v 1.21 2008-10-21 21:15:09 eerot Exp $";
1.1 root 12:
13: #include "main.h"
14: #include "configuration.h"
1.1.1.2 root 15: #include "control.h"
1.1 root 16: #include "sysdeps.h"
17: #include "stMemory.h"
18: #include "ioMem.h"
19: #include "hostscreen.h"
20: #include "screen.h"
1.1.1.2 root 21: #include "statusbar.h"
1.1 root 22:
23: #define VIDEL_DEBUG 0
24:
25: #if VIDEL_DEBUG
26: #define Dprintf(a) printf a
27: #else
28: #define Dprintf(a)
29: #endif
30:
31:
32: #define RGB_BLACK 0x00000000
33: #define RGB_BLUE 0x000000ff
34: #define RGB_GREEN 0x00ff0000
35: #define RGB_CYAN 0x00ff00ff
36: #define RGB_RED 0xff000000
37: #define RGB_MAGENTA 0xff0000ff
38: #define RGB_LTGRAY 0xbbbb00bb
39: #define RGB_GRAY 0x88880088
40: #define RGB_LTBLUE 0x000000aa
41: #define RGB_LTGREEN 0x00aa0000
42: #define RGB_LTCYAN 0x00aa00aa
43: #define RGB_LTRED 0xaa000000
44: #define RGB_LTMAGENTA 0xaa0000aa
45: #define RGB_YELLOW 0xffff0000
46: #define RGB_LTYELLOW 0xaaaa0000
47: #define RGB_WHITE 0xffff00ff
48:
49:
50: static SDL_Surface *mainSurface; // The main window surface
51: static SDL_Surface *surf; // pointer to actual surface
52:
53:
54: static SDL_mutex *screenLock;
1.1.1.2 root 55: static Uint32 sdl_videoparams;
56: static Uint32 hs_width, hs_height, hs_bpp;
57: static bool doUpdate; // the HW surface is available -> the SDL need not to update the surface after ->pixel access
1.1 root 58:
59: static struct { // TOS palette (bpp < 16) to SDL color mapping
60: SDL_Color standard[256];
1.1.1.2 root 61: Uint32 native[256];
1.1 root 62: } palette;
63:
64:
65: static const unsigned long default_palette[] = {
66: RGB_WHITE, RGB_RED, RGB_GREEN, RGB_YELLOW,
67: RGB_BLUE, RGB_MAGENTA, RGB_CYAN, RGB_LTGRAY,
68: RGB_GRAY, RGB_LTRED, RGB_LTGREEN, RGB_LTYELLOW,
69: RGB_LTBLUE, RGB_LTMAGENTA, RGB_LTCYAN, RGB_BLACK
70: };
71:
1.1.1.2 root 72: static int HostScreen_selectVideoMode(SDL_Rect **modes, Uint32 *width, Uint32 *height);
73: static void HostScreen_searchVideoMode( Uint32 *width, Uint32 *height, Uint32 *bpp );
1.1 root 74:
75:
76: void HostScreen_Init(void) {
77: int i;
78: for(i=0; i<256; i++) {
79: unsigned long color = default_palette[i%16];
80: palette.standard[i].r = color >> 24;
81: palette.standard[i].g = (color >> 16) & 0xff;
82: palette.standard[i].b = color & 0xff;
83: }
84:
85: screenLock = SDL_CreateMutex();
86:
87: mainSurface=NULL;
88: }
89:
90: void HostScreen_UnInit(void) {
91: SDL_DestroyMutex(screenLock);
92: }
93:
94:
95: void HostScreen_toggleFullScreen(void)
96: {
97: sdl_videoparams ^= SDL_FULLSCREEN;
1.1.1.2 root 98: if (sdl_videoparams & SDL_FULLSCREEN) {
99: /* un-embed the Hatari WM window for fullscreen */
100: Control_ReparentWindow(hs_width, hs_height, TRUE);
101: }
1.1 root 102: if(SDL_WM_ToggleFullScreen(mainSurface) == 0) {
103: // SDL_WM_ToggleFullScreen() did not work.
104: // We have to change video mode "by hand".
105: SDL_Surface *temp = SDL_ConvertSurface(mainSurface, mainSurface->format,
106: mainSurface->flags);
107: Dprintf(("toggleFullScreen: SDL_WM_ToggleFullScreen() not supported"
108: " -> using SDL_SetVideoMode()"));
109: if (temp == NULL)
110: bug("toggleFullScreen: Unable to save screen content.");
111:
112: #if 1
113: HostScreen_setWindowSize(hs_width, hs_height, hs_bpp);
114: #else
115: mainSurface = SDL_SetVideoMode(width, height, bpp, sdl_videoparams);
116: if (mainSurface == NULL)
117: bug("toggleFullScreen: Unable to set new video mode.");
118: if (mainSurface->format->BitsPerPixel <= 8)
119: SDL_SetColors(mainSurface, temp->format->palette->colors, 0,
120: temp->format->palette->ncolors);
121: #endif
122:
123: if (SDL_BlitSurface(temp, NULL, mainSurface, NULL) != 0)
124: bug("toggleFullScreen: Unable to restore screen content.");
125: SDL_FreeSurface(temp);
126:
127: /* refresh the screen */
128: HostScreen_update1(TRUE);
1.1.1.2 root 129: } else {
130: if (!(sdl_videoparams & SDL_FULLSCREEN)) {
131: /* re-embed the new Hatari SDL window */
132: Control_ReparentWindow(hs_width, hs_height, FALSE);
133: }
1.1 root 134: }
135: }
136:
1.1.1.2 root 137: static int HostScreen_selectVideoMode(SDL_Rect **modes, Uint32 *width, Uint32 *height)
1.1 root 138: {
139: int i, bestw, besth;
140:
141: /* Search the smallest nearest mode */
142: bestw = modes[0]->w;
143: besth = modes[0]->h;
144: for (i=0;modes[i]; ++i) {
145: if ((modes[i]->w >= *width) && (modes[i]->h >= *height)) {
146: if ((modes[i]->w < bestw) || (modes[i]->h < besth)) {
147: bestw = modes[i]->w;
148: besth = modes[i]->h;
149: }
150: }
151: }
152:
153: *width = bestw;
154: *height = besth;
155: Dprintf(("hostscreen: video mode found: %dx%d\n",*width,*height));
156:
157: return 1;
158: }
159:
1.1.1.2 root 160: static void HostScreen_searchVideoMode( Uint32 *width, Uint32 *height, Uint32 *bpp )
1.1 root 161: {
162: SDL_Rect **modes;
163: SDL_PixelFormat pixelformat;
164: int modeflags;
165:
166: /* Search in available modes the best suited */
167: Dprintf(("hostscreen: video mode asked: %dx%dx%d\n",*width,*height,*bpp));
168:
169: if ((*width == 0) || (*height == 0)) {
170: *width = 640;
171: *height = 480;
172: }
173:
174: /* Read available video modes */
175: modeflags = 0 /*SDL_HWSURFACE | SDL_HWPALETTE*/;
176: if (bInFullScreen)
177: modeflags |= SDL_FULLSCREEN;
178:
179: /*--- Search a video mode with asked bpp ---*/
180: if (*bpp != 0) {
181: pixelformat.BitsPerPixel = *bpp;
182: modes = SDL_ListModes(&pixelformat, modeflags);
183: if ((modes != (SDL_Rect **) 0) && (modes != (SDL_Rect **) -1)) {
184: Dprintf(("hostscreen: searching a good video mode (any bpp)\n"));
185: if (HostScreen_selectVideoMode(modes,width,height)) {
186: Dprintf(("hostscreen: video mode selected: %dx%dx%d\n",*width,*height,*bpp));
187: return;
188: }
189: }
190: }
191:
192: /*--- Search a video mode with any bpp ---*/
193: modes = SDL_ListModes(NULL, modeflags);
194: if ((modes != (SDL_Rect **) 0) && (modes != (SDL_Rect **) -1)) {
195: Dprintf(("hostscreen: searching a good video mode\n"));
196: if (HostScreen_selectVideoMode(modes,width,height)) {
197: Dprintf(("hostscreen: video mode selected: %dx%dx%d\n",*width,*height,*bpp));
198: return;
199: }
200: }
201:
202: if (modes == (SDL_Rect **) 0) {
203: Dprintf(("hostscreen: No modes available\n"));
204: }
205:
206: if (modes == (SDL_Rect **) -1) {
207: /* Any mode available */
208: Dprintf(("hostscreen: Any modes available\n"));
209: }
210:
211: Dprintf(("hostscreen: video mode selected: %dx%dx%d\n",*width,*height,*bpp));
212: }
213:
1.1.1.2 root 214: void HostScreen_setWindowSize( Uint32 width, Uint32 height, Uint32 bpp )
1.1 root 215: {
1.1.1.2 root 216: Uint32 screenheight;
217:
1.1 root 218: nScreenZoomX = 1;
219: nScreenZoomY = 1;
220: if (ConfigureParams.Screen.bZoomLowRes)
221: {
222: /* Ugly: 400x300 threshold is currently hard-coded. */
223: /* Should rather be selectable by the user! */
224: if (width <= 400)
225: {
226: nScreenZoomX = (800/width);
227: width *= nScreenZoomX;
228: }
229: if (height <= 300)
230: {
231: nScreenZoomY = (550/height);
232: height *= nScreenZoomY;
233: }
234: }
1.1.1.2 root 235: screenheight = height + Statusbar_SetHeight(width, height);
1.1 root 236:
237: // Select a correct video mode
1.1.1.2 root 238: HostScreen_searchVideoMode(&width, &screenheight, &bpp);
1.1 root 239:
1.1.1.2 root 240: hs_width = width;
1.1 root 241: hs_height = height;
242: hs_bpp = bpp;
243:
244: // SelectVideoMode();
1.1.1.2 root 245: if (bInFullScreen) {
246: /* un-embed the Hatari WM window for fullscreen */
247: Control_ReparentWindow(width, screenheight, bInFullScreen);
248:
1.1 root 249: sdl_videoparams = SDL_SWSURFACE|SDL_HWPALETTE|SDL_FULLSCREEN;
1.1.1.2 root 250: } else {
1.1 root 251: sdl_videoparams = SDL_SWSURFACE|SDL_HWPALETTE;
1.1.1.2 root 252: }
253: mainSurface = SDL_SetVideoMode(width, screenheight, bpp, sdl_videoparams);
254: if (!bInFullScreen) {
255: /* re-embed the new Hatari SDL window */
256: Control_ReparentWindow(width, screenheight, bInFullScreen);
257: }
1.1 root 258: sdlscrn = surf = mainSurface;
259:
260: // update the surface's palette
261: HostScreen_updatePalette( 256 );
262:
1.1.1.2 root 263: Statusbar_Init(mainSurface);
264:
1.1 root 265: Dprintf(("Surface Pitch = %d, width = %d, height = %d\n", surf->pitch, surf->w, surf->h));
266: Dprintf(("Must Lock? %s\n", SDL_MUSTLOCK(surf) ? "YES" : "NO"));
267:
268: // is the SDL_update needed?
269: doUpdate = ( surf->flags & SDL_HWSURFACE ) == 0;
270:
271: HostScreen_renderBegin();
272:
273: // VideoRAMBaseHost = (uint8 *) surf->pixels;
274: // InitVMEMBaseDiff(VideoRAMBaseHost, VideoRAMBase);
275: // Dprintf(("VideoRAM starts at %p (%08x)\n", VideoRAMBaseHost, VideoRAMBase));
276: Dprintf(("surf->pixels = %p, getVideoSurface() = %p\n",
277: surf->pixels, SDL_GetVideoSurface()->pixels));
278:
279: HostScreen_renderEnd();
280:
281: Dprintf(("Pixel format:bitspp=%d, tmasks r=%04x g=%04x b=%04x"
282: ", tshifts r=%d g=%d b=%d"
283: ", tlosses r=%d g=%d b=%d\n",
284: surf->format->BitsPerPixel,
285: surf->format->Rmask, surf->format->Gmask, surf->format->Bmask,
286: surf->format->Rshift, surf->format->Gshift, surf->format->Bshift,
287: surf->format->Rloss, surf->format->Gloss, surf->format->Bloss));
288: }
289:
290:
1.1.1.2 root 291: static void HostScreen_update5(Sint32 x, Sint32 y, Sint32 w, Sint32 h, bool forced)
1.1 root 292: {
293: if ( !forced && !doUpdate ) // the HW surface is available
294: return;
295:
296: // SDL_UpdateRect(SDL_GetVideoSurface(), 0, 0, width, height);
297: // SDL_UpdateRect(surf, x, y, w, h);
298: SDL_UpdateRect(mainSurface, x, y, w, h);
299: }
300:
1.1.1.2 root 301: void HostScreen_update1(bool forced)
1.1 root 302: {
303: HostScreen_update5( 0, 0, hs_width, hs_height, forced );
304: }
305:
306: void HostScreen_update0()
307: {
308: HostScreen_update5( 0, 0, hs_width, hs_height, FALSE );
309: }
310:
311:
1.1.1.2 root 312: Uint32 HostScreen_getBitsPerPixel(void)
1.1 root 313: {
314: return surf->format->BitsPerPixel;
315: }
316:
317:
1.1.1.2 root 318: Uint32 HostScreen_getBpp()
1.1 root 319: {
320: return surf->format->BytesPerPixel;
321: }
322:
1.1.1.2 root 323: Uint32 HostScreen_getPitch() {
1.1 root 324: return surf->pitch;
325: }
326:
1.1.1.2 root 327: Uint32 HostScreen_getWidth() {
1.1 root 328: return hs_width;
329: }
330:
1.1.1.2 root 331: Uint32 HostScreen_getHeight() {
1.1 root 332: return hs_height;
333: }
334:
1.1.1.2 root 335: Uint8 *HostScreen_getVideoramAddress() {
1.1 root 336: return surf->pixels; /* FIXME maybe this should be mainSurface? */
337: }
338:
1.1.1.2 root 339: void HostScreen_setPaletteColor(Uint8 idx, Uint32 red, Uint32 green, Uint32 blue ) {
1.1 root 340: // set the SDL standard RGB palette settings
341: palette.standard[idx].r = red;
342: palette.standard[idx].g = green;
343: palette.standard[idx].b = blue;
344: // convert the color to native
345: palette.native[idx] = SDL_MapRGB( surf->format, red, green, blue );
346: }
347:
1.1.1.2 root 348: Uint32 HostScreen_getPaletteColor(Uint8 idx) {
1.1 root 349: return palette.native[idx];
350: }
351:
1.1.1.2 root 352: void HostScreen_updatePalette( Uint16 colorCount ) {
1.1 root 353: SDL_SetColors( surf, palette.standard, 0, colorCount );
354: }
355:
1.1.1.2 root 356: Uint32 HostScreen_getColor( Uint32 red, Uint32 green, Uint32 blue ) {
1.1 root 357: return SDL_MapRGB( surf->format, red, green, blue );
358: }
359:
360: #if 0
361: void HostScreen_lock(void) {
362: while (SDL_mutexP(screenLock)==-1) {
363: SDL_Delay(20);
364: fprintf(stderr, "Couldn't lock mutex\n");
365: }
366: }
367:
368: void HostScreen_unlock(void) {
369: while (SDL_mutexV(screenLock)==-1) {
370: SDL_Delay(20);
371: fprintf(stderr, "Couldn't unlock mutex\n");
372: }
373: }
374: #endif
375:
1.1.1.2 root 376: bool HostScreen_renderBegin(void)
377: {
1.1 root 378: if (SDL_MUSTLOCK(surf))
379: if (SDL_LockSurface(surf) < 0) {
380: printf("Couldn't lock surface to refresh!\n");
381: return FALSE;
382: }
383:
384: return TRUE;
385: }
386:
387: void HostScreen_renderEnd() {
388: if (SDL_MUSTLOCK(surf))
389: SDL_UnlockSurface(surf);
1.1.1.2 root 390: Statusbar_Update(surf);
1.1 root 391: }
392:
393:
394:
395: /**
396: * Performs conversion from the TOS's bitplane word order (big endian) data
397: * into the native chunky color index.
398: */
1.1.1.2 root 399: void HostScreen_bitplaneToChunky(Uint16 *atariBitplaneData, Uint16 bpp, Uint8 colorValues[16] )
1.1 root 400: {
1.1.1.2 root 401: Uint32 a, b, c, d, x;
1.1 root 402:
403: /* Obviously the different cases can be broken out in various
404: * ways to lessen the amount of work needed for <8 bit modes.
405: * It's doubtful if the usage of those modes warrants it, though.
406: * The branches below should be ~100% correctly predicted and
407: * thus be more or less for free.
408: * Getting the palette values inline does not seem to help
409: * enough to worry about. The palette lookup is much slower than
410: * this code, though, so it would be nice to do something about it.
411: */
412: if (bpp >= 4) {
1.1.1.2 root 413: d = *(Uint32 *)&atariBitplaneData[0];
414: c = *(Uint32 *)&atariBitplaneData[2];
1.1 root 415: if (bpp == 4) {
416: a = b = 0;
417: } else {
1.1.1.2 root 418: b = *(Uint32 *)&atariBitplaneData[4];
419: a = *(Uint32 *)&atariBitplaneData[6];
1.1 root 420: }
421: } else {
422: a = b = c = 0;
423: if (bpp == 2) {
1.1.1.2 root 424: d = *(Uint32 *)&atariBitplaneData[0];
1.1 root 425: } else {
426: #if SDL_BYTEORDER == SDL_BIG_ENDIAN
427: d = atariBitplaneData[0]<<16;
428: #else
429: d = atariBitplaneData[0];
430: #endif
431: }
432: }
433:
434: x = a;
435: a = (a & 0xf0f0f0f0) | ((c & 0xf0f0f0f0) >> 4);
436: c = ((x & 0x0f0f0f0f) << 4) | (c & 0x0f0f0f0f);
437: x = b;
438: b = (b & 0xf0f0f0f0) | ((d & 0xf0f0f0f0) >> 4);
439: d = ((x & 0x0f0f0f0f) << 4) | (d & 0x0f0f0f0f);
440:
441: x = a;
442: a = (a & 0xcccccccc) | ((b & 0xcccccccc) >> 2);
443: b = ((x & 0x33333333) << 2) | (b & 0x33333333);
444: x = c;
445: c = (c & 0xcccccccc) | ((d & 0xcccccccc) >> 2);
446: d = ((x & 0x33333333) << 2) | (d & 0x33333333);
447:
448: #if SDL_BYTEORDER == SDL_BIG_ENDIAN
449: a = (a & 0x5555aaaa) | ((a & 0x00005555) << 17) | ((a & 0xaaaa0000) >> 17);
450: b = (b & 0x5555aaaa) | ((b & 0x00005555) << 17) | ((b & 0xaaaa0000) >> 17);
451: c = (c & 0x5555aaaa) | ((c & 0x00005555) << 17) | ((c & 0xaaaa0000) >> 17);
452: d = (d & 0x5555aaaa) | ((d & 0x00005555) << 17) | ((d & 0xaaaa0000) >> 17);
453:
454: colorValues[ 8] = a;
455: a >>= 8;
456: colorValues[ 0] = a;
457: a >>= 8;
458: colorValues[ 9] = a;
459: a >>= 8;
460: colorValues[ 1] = a;
461:
462: colorValues[10] = b;
463: b >>= 8;
464: colorValues[ 2] = b;
465: b >>= 8;
466: colorValues[11] = b;
467: b >>= 8;
468: colorValues[ 3] = b;
469:
470: colorValues[12] = c;
471: c >>= 8;
472: colorValues[ 4] = c;
473: c >>= 8;
474: colorValues[13] = c;
475: c >>= 8;
476: colorValues[ 5] = c;
477:
478: colorValues[14] = d;
479: d >>= 8;
480: colorValues[ 6] = d;
481: d >>= 8;
482: colorValues[15] = d;
483: d >>= 8;
484: colorValues[ 7] = d;
485: #else
486: a = (a & 0xaaaa5555) | ((a & 0x0000aaaa) << 15) | ((a & 0x55550000) >> 15);
487: b = (b & 0xaaaa5555) | ((b & 0x0000aaaa) << 15) | ((b & 0x55550000) >> 15);
488: c = (c & 0xaaaa5555) | ((c & 0x0000aaaa) << 15) | ((c & 0x55550000) >> 15);
489: d = (d & 0xaaaa5555) | ((d & 0x0000aaaa) << 15) | ((d & 0x55550000) >> 15);
490:
491: colorValues[ 1] = a;
492: a >>= 8;
493: colorValues[ 9] = a;
494: a >>= 8;
495: colorValues[ 0] = a;
496: a >>= 8;
497: colorValues[ 8] = a;
498:
499: colorValues[ 3] = b;
500: b >>= 8;
501: colorValues[11] = b;
502: b >>= 8;
503: colorValues[ 2] = b;
504: b >>= 8;
505: colorValues[10] = b;
506:
507: colorValues[ 5] = c;
508: c >>= 8;
509: colorValues[13] = c;
510: c >>= 8;
511: colorValues[ 4] = c;
512: c >>= 8;
513: colorValues[12] = c;
514:
515: colorValues[ 7] = d;
516: d >>= 8;
517: colorValues[15] = d;
518: d >>= 8;
519: colorValues[ 6] = d;
520: d >>= 8;
521: colorValues[14] = d;
522: #endif
523: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.