|
|
1.1 root 1: /*
2: Hatari - hostscreen.c
3:
1.1.1.7 root 4: This file is distributed under the GNU General Public License, version 2
5: or at your option any later version. Read the file gpl.txt for details.
1.1 root 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.4 root 11: const char HostScreen_fileid[] = "Hatari hostscreen.c : " __DATE__ " " __TIME__;
1.1 root 12:
1.1.1.6 root 13: #include <SDL.h>
1.1 root 14: #include "main.h"
15: #include "configuration.h"
1.1.1.2 root 16: #include "control.h"
1.1 root 17: #include "sysdeps.h"
18: #include "stMemory.h"
19: #include "ioMem.h"
20: #include "hostscreen.h"
1.1.1.5 root 21: #include "resolution.h"
1.1 root 22: #include "screen.h"
1.1.1.2 root 23: #include "statusbar.h"
1.1 root 24:
25: #define VIDEL_DEBUG 0
26:
27: #if VIDEL_DEBUG
28: #define Dprintf(a) printf a
29: #else
30: #define Dprintf(a)
31: #endif
32:
33:
34: #define RGB_BLACK 0x00000000
35: #define RGB_BLUE 0x000000ff
36: #define RGB_GREEN 0x00ff0000
37: #define RGB_CYAN 0x00ff00ff
38: #define RGB_RED 0xff000000
39: #define RGB_MAGENTA 0xff0000ff
40: #define RGB_LTGRAY 0xbbbb00bb
41: #define RGB_GRAY 0x88880088
42: #define RGB_LTBLUE 0x000000aa
43: #define RGB_LTGREEN 0x00aa0000
44: #define RGB_LTCYAN 0x00aa00aa
45: #define RGB_LTRED 0xaa000000
46: #define RGB_LTMAGENTA 0xaa0000aa
47: #define RGB_YELLOW 0xffff0000
48: #define RGB_LTYELLOW 0xaaaa0000
49: #define RGB_WHITE 0xffff00ff
50:
51:
1.1.1.5 root 52: /* TODO: put these hostscreen globals to some struct */
1.1.1.2 root 53: static Uint32 sdl_videoparams;
1.1.1.8 ! root 54: static SDL_Rect hs_rect;
! 55: static int hs_width_req, hs_height_req, hs_bpp;
1.1.1.2 root 56: static bool doUpdate; // the HW surface is available -> the SDL need not to update the surface after ->pixel access
1.1 root 57:
1.1.1.6 root 58: static void HostScreen_remapPalette(void);
59:
1.1 root 60: static struct { // TOS palette (bpp < 16) to SDL color mapping
61: SDL_Color standard[256];
1.1.1.2 root 62: Uint32 native[256];
1.1 root 63: } palette;
64:
65:
1.1.1.6 root 66: static const Uint32 default_palette[] = {
1.1 root 67: RGB_WHITE, RGB_RED, RGB_GREEN, RGB_YELLOW,
68: RGB_BLUE, RGB_MAGENTA, RGB_CYAN, RGB_LTGRAY,
69: RGB_GRAY, RGB_LTRED, RGB_LTGREEN, RGB_LTYELLOW,
70: RGB_LTBLUE, RGB_LTMAGENTA, RGB_LTCYAN, RGB_BLACK
71: };
72:
73:
1.1.1.4 root 74: void HostScreen_Init(void)
75: {
1.1 root 76: int i;
1.1.1.6 root 77: for(i = 0; i < 256; i++) {
78: Uint32 color = default_palette[i%16];
1.1 root 79: palette.standard[i].r = color >> 24;
80: palette.standard[i].g = (color >> 16) & 0xff;
81: palette.standard[i].b = color & 0xff;
82: }
83: }
84:
1.1.1.4 root 85: void HostScreen_UnInit(void)
86: {
1.1 root 87: }
88:
89:
90: void HostScreen_toggleFullScreen(void)
91: {
92: sdl_videoparams ^= SDL_FULLSCREEN;
1.1.1.6 root 93: Dprintf(("Fullscreen = %s, width = %d, height = %d, bpp = %d\n",
94: sdl_videoparams&SDL_FULLSCREEN?"true":"false", hs_width_req, hs_height_req, hs_bpp));
1.1 root 95:
1.1.1.5 root 96: HostScreen_setWindowSize(hs_width_req, hs_height_req, hs_bpp);
1.1.1.6 root 97: /* force screen redraw */
1.1.1.8 ! root 98: HostScreen_update1(NULL, true);
1.1 root 99: }
100:
101:
1.1.1.5 root 102: void HostScreen_setWindowSize(int width, int height, int bpp)
1.1 root 103: {
1.1.1.8 ! root 104: const bool keep = ConfigureParams.Screen.bKeepResolution;
1.1.1.5 root 105: int screenwidth, screenheight, maxw, maxh;
106: int scalex, scaley, sbarheight;
1.1 root 107:
1.1.1.5 root 108: if (bpp == 24)
109: bpp = 32;
1.1 root 110:
1.1.1.6 root 111: /* constrain size request to user's desktop size */
112: Resolution_GetDesktopSize(&maxw, &maxh);
113: scalex = scaley = 1;
114: while (width > maxw*scalex) {
115: scalex *= 2;
116: }
117: while (height > maxh*scalex) {
118: scalex *= 2;
119: }
120: if (scalex * scaley > 1) {
121: fprintf(stderr, "WARNING: too large screen size %dx%d -> divided by %dx%d!\n",
122: width, height, scalex, scaley);
123: width /= scalex;
124: height /= scaley;
125: }
1.1 root 126:
1.1.1.8 ! root 127: Resolution_GetLimits(&maxw, &maxh, &bpp, keep);
1.1.1.5 root 128: nScreenZoomX = nScreenZoomY = 1;
129:
130: if (ConfigureParams.Screen.bAspectCorrect) {
131: /* Falcon (and TT) pixel scaling factors seem to 2^x
132: * (quarter/half pixel, interlace/double line), so
133: * do aspect correction as 2's exponent.
134: */
135: while (nScreenZoomX*width < height &&
136: 2*nScreenZoomX*width < maxw) {
137: nScreenZoomX *= 2;
1.1 root 138: }
1.1.1.5 root 139: while (2*nScreenZoomY*height < width &&
140: 2*nScreenZoomY*height < maxh) {
141: nScreenZoomY *= 2;
142: }
143: if (nScreenZoomX*nScreenZoomY > 2) {
144: fprintf(stderr, "WARNING: strange screen size %dx%d -> aspect corrected by %dx%d!\n",
145: width, height, nScreenZoomX, nScreenZoomY);
1.1 root 146: }
147: }
148:
1.1.1.5 root 149: /* then select scale as close to target size as possible
150: * without having larger size than it
151: */
152: scalex = maxw/(nScreenZoomX*width);
153: scaley = maxh/(nScreenZoomY*height);
154: if (scalex > 1 && scaley > 1) {
155: /* keep aspect ratio */
156: if (scalex < scaley) {
157: nScreenZoomX *= scalex;
158: nScreenZoomY *= scalex;
159: } else {
160: nScreenZoomX *= scaley;
161: nScreenZoomY *= scaley;
162: }
1.1 root 163: }
164:
1.1.1.5 root 165: hs_width_req = width;
166: hs_height_req = height;
167: width *= nScreenZoomX;
168: height *= nScreenZoomY;
169:
1.1.1.6 root 170: /* get statusbar size for this screen size */
1.1.1.5 root 171: sbarheight = Statusbar_GetHeightForSize(width, height);
172: screenheight = height + sbarheight;
173: screenwidth = width;
1.1.1.4 root 174:
1.1.1.6 root 175: /* get resolution corresponding to these */
1.1.1.8 ! root 176: Resolution_Search(&screenwidth, &screenheight, &bpp, keep);
1.1.1.6 root 177: /* re-calculate statusbar height for this resolution */
1.1.1.5 root 178: sbarheight = Statusbar_SetHeight(screenwidth, screenheight-sbarheight);
1.1.1.4 root 179:
1.1.1.5 root 180: hs_bpp = bpp;
181: /* videl.c might scale things differently in fullscreen than
182: * in windowed mode because this uses screensize instead of using
183: * the aspect scaled sizes directly, but it works better this way.
184: */
1.1.1.8 ! root 185: hs_rect.x = 0;
! 186: hs_rect.y = 0;
! 187: hs_rect.w = screenwidth;
! 188: hs_rect.h = screenheight - sbarheight;
1.1.1.5 root 189:
190: if (sdlscrn && (!bpp || sdlscrn->format->BitsPerPixel == bpp) &&
191: sdlscrn->w == (signed)screenwidth && sdlscrn->h == (signed)screenheight &&
192: (sdlscrn->flags&SDL_FULLSCREEN) == (sdl_videoparams&SDL_FULLSCREEN))
1.1 root 193: {
1.1.1.6 root 194: /* same host screen size despite Atari resolution change,
195: * -> no time consuming host video mode change needed
196: */
1.1.1.5 root 197: if (screenwidth > width || screenheight > height+sbarheight) {
198: /* Atari screen smaller than host -> clear screen */
199: SDL_Rect rect;
200: rect.x = 0;
201: rect.y = 0;
202: rect.w = sdlscrn->w;
203: rect.h = sdlscrn->h - sbarheight;
204: SDL_FillRect(sdlscrn, &rect, SDL_MapRGB(sdlscrn->format, 0, 0, 0));
1.1.1.6 root 205: /* re-calculate variables in case height + statusbar height
206: * don't anymore match SDL surface size (there's an assert
207: * for that)
208: */
209: Statusbar_Init(sdlscrn);
1.1 root 210: }
1.1.1.6 root 211: // check in case switched from VDI to Hostscreen
212: doUpdate = ( sdlscrn->flags & SDL_HWSURFACE ) == 0;
1.1.1.5 root 213: return;
1.1 root 214: }
215:
1.1.1.2 root 216: if (bInFullScreen) {
217: /* un-embed the Hatari WM window for fullscreen */
1.1.1.5 root 218: Control_ReparentWindow(screenwidth, screenheight, bInFullScreen);
1.1.1.2 root 219:
1.1 root 220: sdl_videoparams = SDL_SWSURFACE|SDL_HWPALETTE|SDL_FULLSCREEN;
1.1.1.2 root 221: } else {
1.1 root 222: sdl_videoparams = SDL_SWSURFACE|SDL_HWPALETTE;
1.1.1.2 root 223: }
1.1.1.5 root 224: #ifdef _MUDFLAP
225: if (sdlscrn) {
226: __mf_unregister(sdlscrn->pixels, sdlscrn->pitch*sdlscrn->h, __MF_TYPE_GUESS);
227: }
228: #endif
1.1.1.6 root 229: sdlscrn = SDL_SetVideoMode(screenwidth, screenheight, bpp, sdl_videoparams);
1.1.1.5 root 230: #ifdef _MUDFLAP
231: __mf_register(sdlscrn->pixels, sdlscrn->pitch*sdlscrn->h, __MF_TYPE_GUESS, "SDL pixels");
232: #endif
1.1.1.2 root 233: if (!bInFullScreen) {
234: /* re-embed the new Hatari SDL window */
1.1.1.5 root 235: Control_ReparentWindow(screenwidth, screenheight, bInFullScreen);
1.1.1.2 root 236: }
1.1 root 237:
1.1.1.6 root 238: // In case surface format changed, update SDL palette & remap the native palette
239: HostScreen_updatePalette(256);
240: HostScreen_remapPalette();
1.1 root 241:
1.1.1.5 root 242: // redraw statusbar
1.1.1.6 root 243: Statusbar_Init(sdlscrn);
1.1.1.2 root 244:
1.1.1.6 root 245: Dprintf(("Surface Pitch = %d, width = %d, height = %d\n", sdlscrn->pitch, sdlscrn->w, sdlscrn->h));
246: Dprintf(("Must Lock? %s\n", SDL_MUSTLOCK(sdlscrn) ? "YES" : "NO"));
1.1 root 247:
248: // is the SDL_update needed?
1.1.1.6 root 249: doUpdate = ( sdlscrn->flags & SDL_HWSURFACE ) == 0;
1.1 root 250:
251: Dprintf(("Pixel format:bitspp=%d, tmasks r=%04x g=%04x b=%04x"
252: ", tshifts r=%d g=%d b=%d"
253: ", tlosses r=%d g=%d b=%d\n",
1.1.1.6 root 254: sdlscrn->format->BitsPerPixel,
255: sdlscrn->format->Rmask, sdlscrn->format->Gmask, sdlscrn->format->Bmask,
256: sdlscrn->format->Rshift, sdlscrn->format->Gshift, sdlscrn->format->Bshift,
257: sdlscrn->format->Rloss, sdlscrn->format->Gloss, sdlscrn->format->Bloss));
1.1.1.5 root 258:
259: Main_WarpMouse(sdlscrn->w/2,sdlscrn->h/2);
1.1 root 260: }
261:
262:
1.1.1.8 ! root 263: void HostScreen_update1(SDL_Rect *extra, bool forced)
1.1 root 264: {
1.1.1.8 ! root 265: SDL_Rect rects[2];
! 266: int count = 1;
! 267:
1.1 root 268: if ( !forced && !doUpdate ) // the HW surface is available
269: return;
270:
1.1.1.8 ! root 271: rects[0] = hs_rect;
! 272: if (extra) {
! 273: rects[1] = *extra;
! 274: count = 2;
! 275: }
! 276: SDL_UpdateRects(sdlscrn, count, rects);
1.1 root 277: }
278:
279:
1.1.1.4 root 280: Uint32 HostScreen_getBpp(void)
1.1 root 281: {
1.1.1.6 root 282: return sdlscrn->format->BytesPerPixel;
1.1 root 283: }
284:
1.1.1.4 root 285: Uint32 HostScreen_getPitch(void)
286: {
1.1.1.6 root 287: return sdlscrn->pitch;
1.1 root 288: }
289:
1.1.1.4 root 290: Uint32 HostScreen_getWidth(void)
291: {
1.1.1.8 ! root 292: return hs_rect.w;
1.1 root 293: }
294:
1.1.1.4 root 295: Uint32 HostScreen_getHeight(void)
296: {
1.1.1.8 ! root 297: return hs_rect.h;
1.1 root 298: }
299:
1.1.1.4 root 300: Uint8 *HostScreen_getVideoramAddress(void)
301: {
1.1.1.6 root 302: return sdlscrn->pixels;
303: }
304:
305: SDL_PixelFormat *HostScreen_getFormat(void)
306: {
307: return sdlscrn->format;
1.1 root 308: }
309:
1.1.1.6 root 310: void HostScreen_setPaletteColor(Uint8 idx, Uint8 red, Uint8 green, Uint8 blue)
1.1.1.4 root 311: {
1.1 root 312: // set the SDL standard RGB palette settings
313: palette.standard[idx].r = red;
314: palette.standard[idx].g = green;
315: palette.standard[idx].b = blue;
316: // convert the color to native
1.1.1.6 root 317: palette.native[idx] = SDL_MapRGB( sdlscrn->format, red, green, blue );
1.1 root 318: }
319:
1.1.1.4 root 320: Uint32 HostScreen_getPaletteColor(Uint8 idx)
321: {
1.1 root 322: return palette.native[idx];
323: }
324:
1.1.1.6 root 325: void HostScreen_updatePalette(int colorCount)
1.1.1.4 root 326: {
1.1.1.6 root 327: SDL_SetColors( sdlscrn, palette.standard, 0, colorCount );
1.1 root 328: }
329:
1.1.1.6 root 330: static void HostScreen_remapPalette(void)
1.1.1.4 root 331: {
1.1.1.6 root 332: int i;
333: Uint32 *native = palette.native;
334: SDL_Color *standard = palette.standard;
335: SDL_PixelFormat *fmt = sdlscrn->format;
1.1 root 336:
1.1.1.6 root 337: for(i = 0; i < 256; i++, native++, standard++) {
338: *native = SDL_MapRGB(fmt, standard->r, standard->g, standard->b);
339: }
340: }
1.1 root 341:
1.1.1.2 root 342: bool HostScreen_renderBegin(void)
343: {
1.1.1.6 root 344: if (SDL_MUSTLOCK(sdlscrn))
345: if (SDL_LockSurface(sdlscrn) < 0) {
1.1 root 346: printf("Couldn't lock surface to refresh!\n");
1.1.1.4 root 347: return false;
1.1 root 348: }
349:
1.1.1.4 root 350: return true;
1.1 root 351: }
352:
1.1.1.8 ! root 353: /**
! 354: * Direct surface writes done, so unlock screen,
! 355: * check for statusbar updates and if there were such,
! 356: * return which area needs update.
! 357: */
! 358: SDL_Rect* HostScreen_renderEnd(void)
1.1.1.4 root 359: {
1.1.1.6 root 360: if (SDL_MUSTLOCK(sdlscrn))
361: SDL_UnlockSurface(sdlscrn);
1.1.1.8 ! root 362: return Statusbar_Update(sdlscrn, false);
1.1 root 363: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.