|
|
1.1 root 1: /*
1.1.1.6 root 2: Hatari - screen.c
1.1 root 3:
1.1.1.21 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.1.6 root 6:
1.1.1.17 root 7: This code converts a 1/2/4 plane ST format screen to either 8, 16 or 32-bit PC
1.1.1.11 root 8: format. An awful lot of processing is needed to do this conversion - we
1.1.1.6 root 9: cannot simply change palettes on interrupts as it is possible with DOS.
10: The main code processes the palette/resolution mask tables to find exactly
11: which lines need to updating and the conversion routines themselves only
12: update 16-pixel blocks which differ from the previous frame - this gives a
13: large performance increase.
14: Each conversion routine can convert any part of the source ST screen (which
15: includes the overscan border, usually set to colour zero) so they can be used
16: for both window and full-screen mode.
17: Note that in Hi-Resolution we have no overscan and just two colors so we can
1.1.1.17 root 18: optimise things further.
19: In color mode it seems possible to display 47 lines in the bottom border
20: with a second 60/50 Hz switch, but most programs consider there are 45
21: visible lines in the bottom border only, which gives a total of 274 lines
22: for a screen. So not displaying the last two lines fixes garbage that could
23: appear in the last two lines when displaying 47 lines (Digiworld 2 by ICE,
24: Tyranny by DHS).
1.1 root 25: */
1.1.1.15 root 26:
1.1.1.17 root 27: const char Screen_fileid[] = "Hatari screen.c : " __DATE__ " " __TIME__;
1.1 root 28:
29: #include <SDL.h>
1.1.1.11 root 30: #include <SDL_endian.h>
1.1.1.24 root 31: #include <assert.h>
1.1 root 32:
33: #include "main.h"
1.1.1.7 root 34: #include "configuration.h"
1.1.1.23 root 35: #include "avi_record.h"
1.1.1.13 root 36: #include "log.h"
37: #include "paths.h"
1.1.1.23 root 38: #include "options.h"
1.1 root 39: #include "screen.h"
1.1.1.24 root 40: #include "screenConvert.h"
1.1.1.15 root 41: #include "control.h"
1.1.1.11 root 42: #include "convert/routines.h"
1.1.1.18 root 43: #include "resolution.h"
1.1 root 44: #include "spec512.h"
1.1.1.15 root 45: #include "statusbar.h"
1.1 root 46: #include "vdi.h"
47: #include "video.h"
1.1.1.13 root 48: #include "falcon/videl.h"
1.1 root 49:
1.1.1.22 root 50: #define DEBUG 0
51:
52: #if DEBUG
53: # define DEBUGPRINT(x) printf x
54: #else
55: # define DEBUGPRINT(x)
56: #endif
1.1 root 57:
1.1.1.13 root 58: /* extern for several purposes */
59: SDL_Surface *sdlscrn = NULL; /* The SDL screen surface */
60: int nScreenZoomX, nScreenZoomY; /* Zooming factors, used for scaling mouse motions */
61: int nBorderPixelsLeft, nBorderPixelsRight; /* Pixels in left and right border */
1.1.1.23 root 62: static int nBorderPixelsTop, nBorderPixelsBottom; /* Lines in top and bottom border */
1.1.1.13 root 63:
1.1.1.24 root 64: /* extern for shortcuts etc. */
1.1.1.17 root 65: bool bGrabMouse = false; /* Grab the mouse cursor in the window */
66: bool bInFullScreen = false; /* true if in full screen */
1.1.1.13 root 67:
68: /* extern for spec512.c */
1.1.1.11 root 69: int STScreenLeftSkipBytes;
70: int STScreenStartHorizLine; /* Start lines to be converted */
71: Uint32 STRGBPalette[16]; /* Palette buffer used in conversion routines */
72: Uint32 ST2RGB[4096]; /* Table to convert ST 0x777 / STe 0xfff palette to PC format RGB551 (2 pixels each entry) */
1.1.1.13 root 73:
74: /* extern for video.c */
1.1.1.11 root 75: Uint8 *pSTScreen;
76: FRAMEBUFFER *pFrameBuffer; /* Pointer into current 'FrameBuffer' */
77:
78: static FRAMEBUFFER FrameBuffers[NUM_FRAMEBUFFERS]; /* Store frame buffer details to tell how to update */
79: static Uint8 *pSTScreenCopy; /* Keep track of current and previous ST screen data */
80: static Uint8 *pPCScreenDest; /* Destination PC buffer */
81: static int STScreenEndHorizLine; /* End lines to be converted */
82: static int PCScreenBytesPerLine;
83: static int STScreenWidthBytes;
1.1.1.20 root 84: static int PCScreenOffsetX; /* how many pixels to skip from left when drawing */
85: static int PCScreenOffsetY; /* how many pixels to skip from top when drawing */
1.1.1.15 root 86: static SDL_Rect STScreenRect; /* screen size without statusbar */
1.1 root 87:
1.1.1.11 root 88: static int STScreenLineOffset[NUM_VISIBLE_LINES]; /* Offsets for ST screen lines eg, 0,160,320... */
89: static Uint16 HBLPalette[16], PrevHBLPalette[16]; /* Current palette for line, also copy of first line */
1.1 root 90:
1.1.1.13 root 91: static void (*ScreenDrawFunctionsNormal[3])(void); /* Screen draw functions */
1.1.1.10 root 92:
1.1.1.17 root 93: static bool bScreenContentsChanged; /* true if buffer changed and requires blitting */
94: static bool bScrDoubleY; /* true if double on Y */
1.1.1.11 root 95: static int ScrUpdateFlag; /* Bit mask of how to update screen */
1.1.1.25! root 96: static bool bRGBTableInSync; /* Is RGB table up to date? */
1.1.1.11 root 97:
1.1.1.24 root 98: /* These are used for the generic screen conversion functions */
99: static int genconv_width_req, genconv_height_req, genconv_bpp;
100: static bool genconv_do_update; /* HW surface is available -> the SDL need not to update the surface after ->pixel access */
101:
1.1.1.10 root 102:
1.1.1.18 root 103: static bool Screen_DrawFrame(bool bForceFlip);
104:
1.1.1.23 root 105: #if WITH_SDL2
106:
107: SDL_Window *sdlWindow;
108: static SDL_Renderer *sdlRenderer;
109: static SDL_Texture *sdlTexture;
110:
111: void SDL_UpdateRects(SDL_Surface *screen, int numrects, SDL_Rect *rects)
112: {
1.1.1.25! root 113: if (ConfigureParams.Screen.bUseSdlRenderer)
! 114: {
! 115: SDL_UpdateTexture(sdlTexture, NULL, screen->pixels, screen->pitch);
! 116: SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL);
! 117: SDL_RenderPresent(sdlRenderer);
! 118: }
! 119: else
! 120: {
! 121: SDL_UpdateWindowSurfaceRects(sdlWindow, rects, numrects);
! 122: }
1.1.1.23 root 123: }
124:
125: void SDL_UpdateRect(SDL_Surface *screen, Sint32 x, Sint32 y, Sint32 w, Sint32 h)
126: {
1.1.1.25! root 127: SDL_Rect rect;
! 128:
! 129: if (w == 0 && h == 0) {
! 130: x = y = 0;
! 131: w = screen->w;
! 132: h = screen->h;
! 133: }
! 134:
! 135: rect.x = x; rect.y = y;
! 136: rect.w = w; rect.h = h;
1.1.1.23 root 137: SDL_UpdateRects(screen, 1, &rect);
138: }
139:
140: #endif
1.1.1.18 root 141:
1.1.1.10 root 142: /*-----------------------------------------------------------------------*/
1.1.1.13 root 143: /**
144: * Create ST 0x777 / STe 0xfff color format to 16 or 32 bits per pixel
145: * conversion table. Called each time when changed resolution or to/from
146: * fullscreen mode.
147: */
1.1.1.10 root 148: static void Screen_SetupRGBTable(void)
149: {
1.1.1.13 root 150: Uint16 STColor;
151: Uint32 RGBColor;
152: int r, g, b;
153: int rr, gg, bb;
154:
155: /* Do Red, Green and Blue for all 16*16*16 = 4096 STe colors */
156: for (r = 0; r < 16; r++)
157: {
158: for (g = 0; g < 16; g++)
159: {
160: for (b = 0; b < 16; b++)
161: {
162: /* STe 0xfff format */
163: STColor = (r<<8) | (g<<4) | (b);
1.1.1.20 root 164: rr = ((r & 0x7) << 1) | ((r & 0x8) >> 3);
165: rr |= rr << 4;
166: gg = ((g & 0x7) << 1) | ((g & 0x8) >> 3);
167: gg |= gg << 4;
168: bb = ((b & 0x7) << 1) | ((b & 0x8) >> 3);
169: bb |= bb << 4;
1.1.1.13 root 170: RGBColor = SDL_MapRGB(sdlscrn->format, rr, gg, bb);
171: if (sdlscrn->format->BitsPerPixel <= 16)
172: {
173: /* As longs, for speed (write two pixels at once) */
174: ST2RGB[STColor] = (RGBColor<<16) | RGBColor;
175: }
176: else
177: {
178: ST2RGB[STColor] = RGBColor;
179: }
180: }
181: }
182: }
1.1.1.10 root 183: }
184:
1.1.1.13 root 185:
186: /**
1.1.1.24 root 187: * Convert 640x400 monochrome screen
1.1.1.13 root 188: */
1.1.1.24 root 189: static void Screen_ConvertHighRes(void)
1.1.1.10 root 190: {
1.1.1.24 root 191: int linewidth = 640 / 16;
1.1.1.10 root 192:
1.1.1.24 root 193: Screen_GenConvert(pSTScreen, 640, 400, 1, linewidth, 0, 0, 0, 0, 0);
194: bScreenContentsChanged = true;
1.1.1.10 root 195: }
196:
1.1.1.13 root 197: /**
198: * Set screen draw functions.
199: */
1.1.1.18 root 200: static void Screen_SetDrawFunctions(int nBitCount, bool bDoubleLowRes)
1.1.1.10 root 201: {
1.1.1.24 root 202: if (nBitCount <= 16)
1.1.1.13 root 203: {
204: /* High color */
1.1.1.18 root 205: if (bDoubleLowRes)
1.1.1.13 root 206: ScreenDrawFunctionsNormal[ST_LOW_RES] = ConvertLowRes_640x16Bit;
207: else
208: ScreenDrawFunctionsNormal[ST_LOW_RES] = ConvertLowRes_320x16Bit;
209: ScreenDrawFunctionsNormal[ST_MEDIUM_RES] = ConvertMediumRes_640x16Bit;
210: }
211: else /* Assume 32 bit drawing functions */
212: {
213: /* True color */
1.1.1.18 root 214: if (bDoubleLowRes)
1.1.1.13 root 215: ScreenDrawFunctionsNormal[ST_LOW_RES] = ConvertLowRes_640x32Bit;
216: else
217: ScreenDrawFunctionsNormal[ST_LOW_RES] = ConvertLowRes_320x32Bit;
218: ScreenDrawFunctionsNormal[ST_MEDIUM_RES] = ConvertMediumRes_640x32Bit;
219: }
1.1.1.10 root 220: }
221:
222:
223: /*-----------------------------------------------------------------------*/
1.1.1.13 root 224: /**
1.1.1.18 root 225: * Set amount of border pixels
1.1.1.13 root 226: */
1.1.1.18 root 227: static void Screen_SetBorderPixels(int leftX, int leftY)
1.1.1.7 root 228: {
1.1.1.23 root 229: /* All screen widths need to be aligned to 16-bits */
230: nBorderPixelsLeft = Opt_ValueAlignMinMax(leftX/2, 16, 0, 48);
1.1.1.18 root 231: nBorderPixelsRight = nBorderPixelsLeft;
1.1.1.7 root 232:
1.1.1.18 root 233: /* assertain assumption of code below */
234: assert(OVERSCAN_TOP < MAX_OVERSCAN_BOTTOM);
235:
236: if (leftY > 2*OVERSCAN_TOP)
1.1.1.13 root 237: {
1.1.1.18 root 238: nBorderPixelsTop = OVERSCAN_TOP;
239: if (leftY >= OVERSCAN_TOP + MAX_OVERSCAN_BOTTOM)
240: nBorderPixelsBottom = MAX_OVERSCAN_BOTTOM;
241: else
242: nBorderPixelsBottom = leftY - OVERSCAN_TOP;
1.1.1.13 root 243: }
244: else
245: {
1.1.1.18 root 246: if (leftY > 0)
247: nBorderPixelsTop = nBorderPixelsBottom = leftY/2;
248: else
249: nBorderPixelsTop = nBorderPixelsBottom = 0;
1.1.1.13 root 250: }
1.1.1.18 root 251: }
252:
253: /*-----------------------------------------------------------------------*/
254: /**
255: * store Y offset for each horizontal line in our source ST screen for
256: * reference in the convert functions.
257: */
258: static void Screen_SetSTScreenOffsets(void)
259: {
260: int i;
1.1.1.13 root 261:
1.1.1.18 root 262: /* Store offset to each horizontal line, uses
263: * nBorderPixels* variables.
264: */
1.1.1.13 root 265: for (i = 0; i < NUM_VISIBLE_LINES; i++)
266: {
267: STScreenLineOffset[i] = i * SCREENBYTES_LINE;
268: }
1.1.1.7 root 269: }
270:
1.1.1.24 root 271: /**
272: * Return true if Falcon/TT/VDI generic screen convert functions
273: * need to be used instead of the ST/STE functions.
274: */
275: static bool Screen_UseGenConvScreen(void)
276: {
277: return Config_IsMachineFalcon() || Config_IsMachineTT()
278: || bUseHighRes || bUseVDIRes;
279: }
280:
281: static bool Screen_WantToKeepResolution(void)
282: {
283: #if WITH_SDL2
284: return ConfigureParams.Screen.bKeepResolution;
285: #else
286: if (Screen_UseGenConvScreen())
287: return ConfigureParams.Screen.bKeepResolution;
288: else
289: return ConfigureParams.Screen.bKeepResolutionST;
290: #endif
291: }
292:
1.1.1.23 root 293: #if WITH_SDL2
294: static void Screen_FreeSDL2Resources(void)
295: {
296: if (sdlTexture)
297: {
298: SDL_DestroyTexture(sdlTexture);
299: sdlTexture = NULL;
300: }
301: if (sdlscrn)
302: {
1.1.1.25! root 303: if (ConfigureParams.Screen.bUseSdlRenderer)
! 304: SDL_FreeSurface(sdlscrn);
1.1.1.23 root 305: sdlscrn = NULL;
306: }
307: if (sdlRenderer)
308: {
309: SDL_DestroyRenderer(sdlRenderer);
310: sdlRenderer = NULL;
311: }
312: }
313: #endif
314:
315: /**
316: * Change the SDL video mode.
317: * @return true if mode has been changed, false if change was not necessary
318: */
319: bool Screen_SetSDLVideoSize(int width, int height, int bitdepth, bool bForceChange)
320: {
321: Uint32 sdlVideoFlags;
322: #if WITH_SDL2
323: static int nPrevRenderScaleQuality = 0;
324: static bool bPrevUseVsync = false;
1.1.1.24 root 325: static bool bPrevInFullScreen;
326: int win_width, win_height;
1.1.1.23 root 327:
328: if (bitdepth == 0 || bitdepth == 24)
329: bitdepth = 32;
330: #endif
331: /* Check if we really have to change the video mode: */
332: if (sdlscrn != NULL && sdlscrn->w == width && sdlscrn->h == height
333: && sdlscrn->format->BitsPerPixel == bitdepth && !bForceChange)
334: return false;
335:
336: #ifdef _MUDFLAP
337: if (sdlscrn)
338: {
339: __mf_unregister(sdlscrn->pixels, sdlscrn->pitch*sdlscrn->h, __MF_TYPE_GUESS);
340: }
341: #endif
342: if (bInFullScreen)
343: {
344: /* unhide the Hatari WM window for fullscreen */
345: Control_ReparentWindow(width, height, bInFullScreen);
346: }
347:
348: #if WITH_SDL2
349:
350: /* SDL Video attributes: */
1.1.1.24 root 351: win_width = width;
352: win_height = height;
1.1.1.23 root 353: if (bInFullScreen)
354: {
1.1.1.24 root 355: sdlVideoFlags = SDL_WINDOW_BORDERLESS | SDL_WINDOW_INPUT_GRABBED;
356: if (ConfigureParams.Screen.bKeepResolution)
357: sdlVideoFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
358: else
359: sdlVideoFlags |= SDL_WINDOW_FULLSCREEN;
1.1.1.23 root 360: }
361: else
362: {
1.1.1.24 root 363: int deskw, deskh;
1.1.1.25! root 364: if (getenv("PARENT_WIN_ID") != NULL) /* Embedded window? */
! 365: sdlVideoFlags = SDL_WINDOW_BORDERLESS;
! 366: else if (ConfigureParams.Screen.bResizable
! 367: && ConfigureParams.Screen.bUseSdlRenderer)
! 368: sdlVideoFlags = SDL_WINDOW_RESIZABLE;
! 369: else
! 370: sdlVideoFlags = 0;
1.1.1.24 root 371: /* Make sure that window is not bigger than current desktop */
372: Resolution_GetDesktopSize(&deskw, &deskh);
373: if (win_width > deskw)
374: win_width = deskw;
375: if (win_height > deskh)
376: win_height = deskh;
1.1.1.23 root 377: }
378:
379: Screen_FreeSDL2Resources();
1.1.1.25! root 380: if (sdlWindow &&
! 381: ((bInFullScreen && !ConfigureParams.Screen.bKeepResolution) ||
! 382: (bPrevInFullScreen != bInFullScreen) ||
! 383: bForceChange
! 384: ))
1.1.1.24 root 385: {
386: SDL_DestroyWindow(sdlWindow);
387: sdlWindow = NULL;
388: }
389: bPrevInFullScreen = bInFullScreen;
1.1.1.23 root 390:
391: /* Set SDL2 video hints */
392: if (nPrevRenderScaleQuality != ConfigureParams.Screen.nRenderScaleQuality)
393: {
394: char hint[2] = { '0' + ConfigureParams.Screen.nRenderScaleQuality, 0 };
395: SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, hint, SDL_HINT_OVERRIDE);
396: nPrevRenderScaleQuality = ConfigureParams.Screen.nRenderScaleQuality;
397: }
398: if (bPrevUseVsync != ConfigureParams.Screen.bUseVsync)
399: {
400: char hint[2] = { '0' + ConfigureParams.Screen.bUseVsync, 0 };
401: SDL_SetHintWithPriority(SDL_HINT_RENDER_VSYNC, hint, SDL_HINT_OVERRIDE);
402: bPrevUseVsync = ConfigureParams.Screen.bUseVsync;
403: }
404:
1.1.1.25! root 405: #ifdef SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4 /* requires sdl >= 2.0.4 */
! 406: /* Disable closing Hatari with alt+F4 under Windows as alt+F4 can be used by some emulated programs */
! 407: SDL_SetHintWithPriority(SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4, "1", SDL_HINT_OVERRIDE);
! 408: #endif
! 409:
1.1.1.23 root 410: /* Set new video mode */
411: DEBUGPRINT(("SDL screen request: %d x %d @ %d (%s)\n", width, height,
412: bitdepth, bInFullScreen?"fullscreen":"windowed"));
413:
1.1.1.24 root 414: if (sdlWindow)
415: {
416: if ((SDL_GetWindowFlags(sdlWindow) & SDL_WINDOW_MAXIMIZED) == 0)
417: SDL_SetWindowSize(sdlWindow, win_width, win_height);
418: }
419: else
420: {
421: sdlWindow = SDL_CreateWindow("Hatari", SDL_WINDOWPOS_UNDEFINED,
422: SDL_WINDOWPOS_UNDEFINED,
423: win_width, win_height, sdlVideoFlags);
424: }
1.1.1.25! root 425: if (!sdlWindow)
1.1.1.23 root 426: {
1.1.1.25! root 427: fprintf(stderr, "Failed to create %dx%d window!\n",
! 428: win_width, win_height);
1.1.1.23 root 429: exit(-1);
430: }
1.1.1.25! root 431: if (ConfigureParams.Screen.bUseSdlRenderer)
1.1.1.23 root 432: {
433: int rm, bm, gm, pfmt;
1.1.1.24 root 434:
1.1.1.25! root 435: sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, 0);
! 436: if (!sdlRenderer)
! 437: {
! 438: fprintf(stderr,"Failed to create %dx%d renderer!\n",
! 439: win_width, win_height);
! 440: exit(1);
! 441: }
! 442:
1.1.1.24 root 443: if (bInFullScreen)
444: SDL_RenderSetLogicalSize(sdlRenderer, width, height);
445:
1.1.1.23 root 446: if (bitdepth == 16)
447: {
448: rm = 0xF800;
449: gm = 0x07E0;
450: bm = 0x001F;
451: pfmt = SDL_PIXELFORMAT_RGB565;
452: }
453: else
454: {
455: rm = 0x00FF0000;
456: gm = 0x0000FF00;
457: bm = 0x000000FF;
458: pfmt = SDL_PIXELFORMAT_RGB888;
459: }
460: sdlscrn = SDL_CreateRGBSurface(0, width, height, bitdepth,
461: rm, gm, bm, 0);
462: sdlTexture = SDL_CreateTexture(sdlRenderer, pfmt,
463: SDL_TEXTUREACCESS_STREAMING,
464: width, height);
465: if (!sdlTexture)
466: {
1.1.1.25! root 467: fprintf(stderr,"Failed to create %dx%d@%d texture!\n",
! 468: width, height, bitdepth);
1.1.1.23 root 469: exit(-3);
470: }
471: }
1.1.1.25! root 472: else
! 473: {
! 474: sdlscrn = SDL_GetWindowSurface(sdlWindow);
! 475: }
1.1.1.23 root 476:
477: #else /* WITH_SDL2 */
478:
479: /* SDL Video attributes: */
480: if (bInFullScreen)
481: {
482: sdlVideoFlags = SDL_HWSURFACE|SDL_FULLSCREEN/*|SDL_DOUBLEBUF*/;
483: /* SDL_DOUBLEBUF helps avoiding tearing and can be faster on suitable HW,
484: * but it doesn't work with partial screen updates done by the ST screen
485: * update code or the Hatari GUI, so double buffering is disabled. */
486: }
487: else
488: {
489: sdlVideoFlags = SDL_SWSURFACE;
490: }
491:
492: /* Set new video mode */
1.1.1.24 root 493: DEBUGPRINT(("SDL screen request: %d x %d @ %d (%s)\n", width, height, bitdepth,
494: bInFullScreen?"fullscreen":"windowed"));
1.1.1.23 root 495: sdlscrn = SDL_SetVideoMode(width, height, bitdepth, sdlVideoFlags);
496:
497: /* By default ConfigureParams.Screen.nForceBpp and therefore
498: * BitCount is zero which means "SDL color depth autodetection".
499: * In this case the SDL_SetVideoMode() call might return
500: * a 24 bpp resolution
501: */
502: if (sdlscrn && sdlscrn->format->BitsPerPixel == 24)
503: {
504: fprintf(stderr, "Unsupported color depth 24, trying 32 bpp instead...\n");
505: sdlscrn = SDL_SetVideoMode(width, height, 32, sdlVideoFlags);
506: }
507:
508: #endif /* WITH_SDL2 */
509:
510: /* Exit if we can not open a screen */
511: if (!sdlscrn)
512: {
513: fprintf(stderr, "Could not set video mode:\n %s\n", SDL_GetError() );
514: SDL_Quit();
515: exit(-2);
516: }
517:
518: DEBUGPRINT(("SDL screen granted: %d x %d @ %d\n", sdlscrn->w, sdlscrn->h,
519: sdlscrn->format->BitsPerPixel));
520:
521: #ifdef _MUDFLAP
522: __mf_register(sdlscrn->pixels, sdlscrn->pitch*sdlscrn->h, __MF_TYPE_GUESS, "SDL pixels");
523: #endif
524:
525: if (!bInFullScreen)
526: {
527: /* re-embed the new Hatari SDL window */
528: Control_ReparentWindow(width, height, bInFullScreen);
529: }
530:
1.1.1.25! root 531: Avi_SetSurface(sdlscrn);
! 532:
! 533: bRGBTableInSync = false;
! 534:
1.1.1.23 root 535: return true;
536: }
1.1.1.8 root 537:
1.1.1.24 root 538:
1.1.1.13 root 539: /**
1.1.1.24 root 540: * Initialize ST/STE screen resolution.
1.1.1.13 root 541: */
1.1.1.24 root 542: static void Screen_SetSTResolution(bool bForceChange)
1.1.1.11 root 543: {
1.1.1.18 root 544: int Width, Height, nZoom, SBarHeight, BitCount, maxW, maxH;
545: bool bDoubleLowRes = false;
1.1.1.13 root 546:
547: /* Bits per pixel */
1.1.1.24 root 548: BitCount = ConfigureParams.Screen.nForceBpp;
1.1.1.13 root 549:
1.1.1.18 root 550: nBorderPixelsTop = nBorderPixelsBottom = 0;
551: nBorderPixelsLeft = nBorderPixelsRight = 0;
552:
553: nScreenZoomX = 1;
554: nScreenZoomY = 1;
555:
1.1.1.24 root 556: if (STRes == ST_LOW_RES)
1.1.1.13 root 557: {
1.1.1.24 root 558: Width = 320;
559: Height = 200;
560: nZoom = 1;
1.1.1.13 root 561: }
1.1.1.24 root 562: else /* else use 640x400, also for med-rez */
1.1.1.13 root 563: {
1.1.1.24 root 564: Width = 640;
565: Height = 400;
566: nZoom = 2;
567: }
1.1.1.18 root 568:
1.1.1.24 root 569: /* Statusbar height for doubled screen size */
570: SBarHeight = Statusbar_GetHeightForSize(640, 400);
1.1.1.18 root 571:
1.1.1.24 root 572: Resolution_GetLimits(&maxW, &maxH, &BitCount, Screen_WantToKeepResolution());
573:
574: /* Zoom if necessary, factors used for scaling mouse motions */
575: if (STRes == ST_LOW_RES &&
576: 2*Width <= maxW && 2*Height+SBarHeight <= maxH)
577: {
578: nZoom = 2;
579: Width *= 2;
580: Height *= 2;
581: nScreenZoomX = 2;
582: nScreenZoomY = 2;
583: bDoubleLowRes = true;
584: }
585: else if (STRes == ST_MEDIUM_RES)
586: {
587: /* med-rez conversion functions want always
588: * to double vertically, they don't support
589: * skipping that (only leaving doubled lines
590: * black for the TV mode).
591: */
592: nScreenZoomX = 1;
593: nScreenZoomY = 2;
594: }
595:
596: /* Adjust width/height for overscan borders, if mono or VDI we have no overscan */
597: if (ConfigureParams.Screen.bAllowOverscan && !bUseHighRes)
598: {
599: int leftX = maxW - Width;
600: int leftY = maxH - (Height + Statusbar_GetHeightForSize(Width, Height));
601:
602: Screen_SetBorderPixels(leftX/nZoom, leftY/nZoom);
603: DEBUGPRINT(("resolution limit:\n\t%d x %d\nlimited resolution:\n\t", maxW, maxH));
604: DEBUGPRINT(("%d * (%d + %d + %d) x (%d + %d + %d)\n", nZoom,
605: nBorderPixelsLeft, Width/nZoom, nBorderPixelsRight,
606: nBorderPixelsTop, Height/nZoom, nBorderPixelsBottom));
607: Width += (nBorderPixelsRight + nBorderPixelsLeft)*nZoom;
608: Height += (nBorderPixelsTop + nBorderPixelsBottom)*nZoom;
609: DEBUGPRINT(("\t= %d x %d (+ statusbar)\n", Width, Height));
1.1.1.13 root 610: }
1.1.1.23 root 611:
1.1.1.18 root 612: Screen_SetSTScreenOffsets();
613: Height += Statusbar_SetHeight(Width, Height);
1.1.1.13 root 614:
1.1.1.20 root 615: PCScreenOffsetX = PCScreenOffsetY = 0;
616:
1.1.1.23 root 617: /* Video attributes: */
1.1.1.24 root 618: #if !WITH_SDL2
1.1.1.23 root 619: if (bInFullScreen && ConfigureParams.Screen.bKeepResolutionST)
1.1.1.13 root 620: {
1.1.1.23 root 621: /* use desktop resolution */
622: Resolution_GetDesktopSize(&maxW, &maxH);
623: SBarHeight = Statusbar_GetHeightForSize(maxW, maxH);
624: /* re-calculate statusbar height for this resolution */
625: Statusbar_SetHeight(maxW, maxH-SBarHeight);
626: /* center Atari screen to resolution */
627: PCScreenOffsetY = (maxH - Height)/2;
628: PCScreenOffsetX = (maxW - Width)/2;
629: /* and select desktop resolution */
630: Height = maxH;
631: Width = maxW;
1.1.1.13 root 632: }
1.1.1.24 root 633: #endif
1.1.1.13 root 634:
1.1.1.23 root 635: if (Screen_SetSDLVideoSize(Width, Height, BitCount, bForceChange))
1.1.1.13 root 636: {
1.1.1.15 root 637: Statusbar_Init(sdlscrn);
1.1.1.23 root 638:
1.1.1.15 root 639: /* screen area without the statusbar */
640: STScreenRect.x = 0;
641: STScreenRect.y = 0;
642: STScreenRect.w = sdlscrn->w;
643: STScreenRect.h = sdlscrn->h - Statusbar_GetHeight();
1.1.1.13 root 644: }
645:
1.1.1.25! root 646: if (!bRGBTableInSync)
! 647: {
! 648: Screen_SetupRGBTable(); /* Create color conversion table */
! 649: bRGBTableInSync = true;
! 650: }
! 651:
1.1.1.13 root 652: /* Set drawing functions */
1.1.1.18 root 653: Screen_SetDrawFunctions(sdlscrn->format->BitsPerPixel, bDoubleLowRes);
1.1.1.13 root 654:
655: Screen_SetFullUpdate(); /* Cause full update of screen */
1.1.1.11 root 656: }
657:
658:
1.1.1.24 root 659: /**
660: * Change resolution, according to the machine and display type
661: * that we're currently emulating.
662: */
663: static void Screen_ChangeResolution(bool bForceChange)
664: {
665: int hbpp = ConfigureParams.Screen.nForceBpp;
666:
667: if (bUseVDIRes)
668: {
669: Screen_SetGenConvSize(VDIWidth, VDIHeight, hbpp, bForceChange);
670: }
671: else if (Config_IsMachineFalcon())
672: {
1.1.1.25! root 673: Videl_ScreenModeChanged(bForceChange);
1.1.1.24 root 674: }
675: else if (Config_IsMachineTT())
676: {
677: int width, height, bpp;
678: Video_GetTTRes(&width, &height, &bpp);
679: Screen_SetGenConvSize(width, height, hbpp, bForceChange);
680: }
681: else if (bUseHighRes)
682: {
683: Screen_SetGenConvSize(640, 400, hbpp, bForceChange);
684: }
685: else
686: {
687: Screen_SetSTResolution(bForceChange);
688: }
689:
690: if (bInFullScreen || bGrabMouse)
691: SDL_WM_GrabInput(SDL_GRAB_ON);
692: else
693: SDL_WM_GrabInput(SDL_GRAB_OFF);
694: }
695:
696:
697: /**
698: * Change the resolution - but only if it was already initialized before
699: */
700: void Screen_ModeChanged(bool bForceChange)
701: {
702: if (sdlscrn) /* Do it only if we're already up and running */
703: {
704: Screen_ChangeResolution(bForceChange);
705: }
706: }
707:
708:
1.1.1.11 root 709: /*-----------------------------------------------------------------------*/
1.1.1.13 root 710: /**
711: * Init Screen bitmap and buffers/tables needed for ST to PC screen conversion
712: */
1.1 root 713: void Screen_Init(void)
714: {
1.1.1.13 root 715: int i;
716: SDL_Surface *pIconSurf;
717: char sIconFileName[FILENAME_MAX];
718:
719: /* Clear frame buffer structures and set current pointer */
720: memset(FrameBuffers, 0, NUM_FRAMEBUFFERS * sizeof(FRAMEBUFFER));
721:
722: /* Allocate previous screen check workspace. We are going to double-buffer a double-buffered screen. Oh. */
723: for (i = 0; i < NUM_FRAMEBUFFERS; i++)
724: {
1.1.1.21 root 725: FrameBuffers[i].pSTScreen = malloc(MAX_VDI_BYTES);
726: FrameBuffers[i].pSTScreenCopy = malloc(MAX_VDI_BYTES);
1.1.1.13 root 727: if (!FrameBuffers[i].pSTScreen || !FrameBuffers[i].pSTScreenCopy)
728: {
729: fprintf(stderr, "Failed to allocate frame buffer memory.\n");
730: exit(-1);
731: }
732: }
733: pFrameBuffer = &FrameBuffers[0];
734:
1.1.1.25! root 735: /* Set initial window resolution */
! 736: bInFullScreen = ConfigureParams.Screen.bFullScreen;
! 737: Screen_ChangeResolution(false);
! 738: ScreenDrawFunctionsNormal[ST_HIGH_RES] = Screen_ConvertHighRes;
! 739:
! 740: Video_SetScreenRasters(); /* Set rasters ready for first screen */
! 741:
1.1.1.13 root 742: /* Load and set icon */
743: snprintf(sIconFileName, sizeof(sIconFileName), "%s%chatari-icon.bmp",
744: Paths_GetDataDir(), PATHSEP);
745: pIconSurf = SDL_LoadBMP(sIconFileName);
746: if (pIconSurf)
747: {
1.1.1.23 root 748: #if WITH_SDL2
749: SDL_SetColorKey(pIconSurf, SDL_TRUE, SDL_MapRGB(pIconSurf->format, 255, 255, 255));
750: SDL_SetWindowIcon(sdlWindow, pIconSurf);
751: #else
1.1.1.13 root 752: SDL_SetColorKey(pIconSurf, SDL_SRCCOLORKEY, SDL_MapRGB(pIconSurf->format, 255, 255, 255));
753: SDL_WM_SetIcon(pIconSurf, NULL);
1.1.1.23 root 754: #endif
1.1.1.13 root 755: SDL_FreeSurface(pIconSurf);
756: }
757:
758: /* Configure some SDL stuff: */
759: SDL_ShowCursor(SDL_DISABLE);
1.1 root 760: }
761:
1.1.1.2 root 762:
1.1 root 763: /*-----------------------------------------------------------------------*/
1.1.1.13 root 764: /**
765: * Free screen bitmap and allocated resources
766: */
1.1 root 767: void Screen_UnInit(void)
768: {
1.1.1.13 root 769: int i;
1.1 root 770:
1.1.1.13 root 771: /* Free memory used for copies */
772: for (i = 0; i < NUM_FRAMEBUFFERS; i++)
773: {
774: free(FrameBuffers[i].pSTScreen);
775: free(FrameBuffers[i].pSTScreenCopy);
776: }
1.1.1.23 root 777:
778: #if WITH_SDL2
779: Screen_FreeSDL2Resources();
1.1.1.24 root 780: if (sdlWindow)
781: {
782: SDL_DestroyWindow(sdlWindow);
783: sdlWindow = NULL;
784: }
1.1.1.23 root 785: #endif
1.1 root 786: }
787:
1.1.1.2 root 788:
1.1 root 789: /*-----------------------------------------------------------------------*/
1.1.1.13 root 790: /**
791: * Reset screen
792: */
1.1 root 793: void Screen_Reset(void)
794: {
1.1.1.13 root 795: /* On re-boot, always correct ST resolution for monitor, eg Colour/Mono */
796: if (bUseVDIRes)
797: {
798: STRes = VDIRes;
799: }
800: else
801: {
802: if (bUseHighRes)
803: {
804: STRes = ST_HIGH_RES;
805: TTRes = TT_HIGH_RES;
806: }
807: else
808: {
809: STRes = ST_LOW_RES;
810: TTRes = TT_MEDIUM_RES;
811: }
812: }
813: /* Cause full update */
1.1.1.23 root 814: Screen_ModeChanged(false);
1.1 root 815: }
816:
817:
818: /*-----------------------------------------------------------------------*/
1.1.1.13 root 819: /**
820: * Set flags so screen will be TOTALLY re-drawn (clears whole of full-screen)
821: * next time around
822: */
1.1 root 823: void Screen_SetFullUpdate(void)
824: {
1.1.1.13 root 825: int i;
1.1 root 826:
1.1.1.13 root 827: /* Update frame buffers */
828: for (i = 0; i < NUM_FRAMEBUFFERS; i++)
1.1.1.17 root 829: FrameBuffers[i].bFullUpdate = true;
1.1 root 830: }
831:
1.1.1.5 root 832:
1.1 root 833: /*-----------------------------------------------------------------------*/
1.1.1.13 root 834: /**
835: * Clear Window display memory
836: */
1.1.1.11 root 837: static void Screen_ClearScreen(void)
838: {
1.1.1.15 root 839: SDL_FillRect(sdlscrn, &STScreenRect, SDL_MapRGB(sdlscrn->format, 0, 0, 0));
1.1.1.11 root 840: }
841:
1.1.1.18 root 842:
843: /*-----------------------------------------------------------------------*/
844: /**
845: * Force screen redraw. Does the right thing regardless of whether
846: * we're in ST/STe, Falcon or TT mode. Needed when switching modes
847: * while emulation is paused.
848: */
849: static void Screen_Refresh(void)
850: {
1.1.1.24 root 851: if (bUseVDIRes)
1.1.1.18 root 852: {
1.1.1.24 root 853: Screen_GenDraw(VideoBase, VDIWidth, VDIHeight, VDIPlanes,
854: VDIWidth * VDIPlanes / 16, 0, 0, 0, 0);
855: }
856: else if (Config_IsMachineFalcon())
857: {
858: VIDEL_renderScreen();
859: }
860: else if (Config_IsMachineTT())
861: {
862: Video_RenderTTScreen();
863: }
864: else
865: {
866: Screen_DrawFrame(true);
1.1.1.18 root 867: }
868: }
869:
870:
1.1.1.11 root 871: /*-----------------------------------------------------------------------*/
1.1.1.13 root 872: /**
873: * Enter Full screen mode
874: */
1.1 root 875: void Screen_EnterFullScreen(void)
876: {
1.1.1.18 root 877: bool bWasRunning;
878:
1.1.1.13 root 879: if (!bInFullScreen)
880: {
1.1.1.18 root 881: /* Hold things... */
882: bWasRunning = Main_PauseEmulation(false);
1.1.1.17 root 883: bInFullScreen = true;
1.1.1.2 root 884:
1.1.1.24 root 885: if (Screen_UseGenConvScreen())
1.1.1.13 root 886: {
1.1.1.24 root 887: Screen_SetGenConvSize(genconv_width_req, genconv_height_req,
888: genconv_bpp, true);
889: /* force screen redraw */
890: Screen_GenConvUpdate(NULL, true);
1.1.1.13 root 891: }
892: else
893: {
1.1.1.24 root 894: Screen_SetSTResolution(true);
1.1.1.13 root 895: Screen_ClearScreen(); /* Black out screen bitmap as will be invalid when return */
896: }
1.1 root 897:
1.1.1.24 root 898: if (!Screen_WantToKeepResolution())
899: {
900: /* Give monitor time to change to new resolution */
901: SDL_Delay(20);
902: }
903:
1.1.1.18 root 904: if (bWasRunning)
905: {
906: /* And off we go... */
907: Main_UnPauseEmulation();
908: }
909: else
910: {
911: Screen_Refresh();
912: }
1.1.1.13 root 913: SDL_WM_GrabInput(SDL_GRAB_ON); /* Grab mouse pointer in fullscreen */
914: }
1.1 root 915: }
916:
1.1.1.2 root 917:
1.1 root 918: /*-----------------------------------------------------------------------*/
1.1.1.13 root 919: /**
920: * Return from Full screen mode back to a window
921: */
1.1 root 922: void Screen_ReturnFromFullScreen(void)
923: {
1.1.1.18 root 924: bool bWasRunning;
925:
1.1.1.13 root 926: if (bInFullScreen)
927: {
1.1.1.18 root 928: /* Hold things... */
929: bWasRunning = Main_PauseEmulation(false);
1.1.1.17 root 930: bInFullScreen = false;
1.1.1.13 root 931:
1.1.1.24 root 932: if (Screen_UseGenConvScreen())
1.1.1.13 root 933: {
1.1.1.24 root 934: Screen_SetGenConvSize(genconv_width_req, genconv_height_req,
935: genconv_bpp, true);
936: /* force screen redraw */
937: Screen_GenConvUpdate(NULL, true);
1.1.1.13 root 938: }
939: else
940: {
1.1.1.24 root 941: Screen_SetSTResolution(true);
942: }
943:
944: if (!Screen_WantToKeepResolution())
945: {
946: /* Give monitor time to switch resolution */
947: SDL_Delay(20);
1.1.1.13 root 948: }
1.1.1.18 root 949:
950: if (bWasRunning)
951: {
952: /* And off we go... */
953: Main_UnPauseEmulation();
954: }
955: else
956: {
957: Screen_Refresh();
958: }
1.1.1.17 root 959:
960: if (!bGrabMouse)
1.1.1.18 root 961: {
1.1.1.17 root 962: /* Un-grab mouse pointer in windowed mode */
963: SDL_WM_GrabInput(SDL_GRAB_OFF);
1.1.1.18 root 964: }
1.1.1.13 root 965: }
966: }
1.1.1.2 root 967:
968:
1.1.1.13 root 969: /*-----------------------------------------------------------------------*/
970: /**
971: * Have we changed between low/med/high res?
972: */
973: static void Screen_DidResolutionChange(int new_res)
974: {
975: if (new_res != STRes)
976: {
977: STRes = new_res;
1.1.1.23 root 978: Screen_ModeChanged(false);
1.1.1.13 root 979: }
980: else
981: {
982: /* Did change overscan mode? Causes full update */
1.1.1.24 root 983: if (pFrameBuffer->VerticalOverscanCopy != VerticalOverscan)
1.1.1.17 root 984: pFrameBuffer->bFullUpdate = true;
1.1.1.13 root 985: }
1.1 root 986: }
987:
1.1.1.5 root 988:
1.1.1.13 root 989: /**
990: * Compare current resolution on line with previous, and set 'UpdateLine' accordingly
991: * Return if swap between low/medium resolution
992: */
1.1.1.15 root 993: static bool Screen_CompareResolution(int y, int *pUpdateLine, int oldres)
1.1 root 994: {
1.1.1.13 root 995: /* Check if wrote to resolution register */
996: if (HBLPaletteMasks[y]&PALETTEMASK_RESOLUTION) /* See 'Intercept_ShifterMode_WriteByte' */
997: {
998: int newres = (HBLPaletteMasks[y]>>16)&ST_MEDIUM_RES_BIT;
999: /* Did resolution change? */
1000: if (newres != (int)((pFrameBuffer->HBLPaletteMasks[y]>>16)&ST_MEDIUM_RES_BIT))
1001: *pUpdateLine |= PALETTEMASK_UPDATERES;
1002: else
1003: *pUpdateLine &= ~PALETTEMASK_UPDATERES;
1004: /* Have used any low/medium res mix? */
1005: return (newres != (oldres&ST_MEDIUM_RES_BIT));
1006: }
1.1.1.17 root 1007: return false;
1.1 root 1008: }
1009:
1.1.1.7 root 1010:
1.1.1.2 root 1011: /*-----------------------------------------------------------------------*/
1.1.1.13 root 1012: /**
1013: * Check to see if palette changes cause screen update and keep 'HBLPalette[]' up-to-date
1014: */
1.1.1.8 root 1015: static void Screen_ComparePalette(int y, int *pUpdateLine)
1.1 root 1016: {
1.1.1.17 root 1017: bool bPaletteChanged = false;
1.1.1.13 root 1018: int i;
1.1 root 1019:
1.1.1.13 root 1020: /* Did write to palette in this or previous frame? */
1021: if (((HBLPaletteMasks[y]|pFrameBuffer->HBLPaletteMasks[y])&PALETTEMASK_PALETTE)!=0)
1022: {
1023: /* Check and update ones which changed */
1024: for (i = 0; i < 16; i++)
1025: {
1026: if (HBLPaletteMasks[y]&(1<<i)) /* Update changes in ST palette */
1027: HBLPalette[i] = HBLPalettes[(y*16)+i];
1028: }
1029: /* Now check with same palette from previous frame for any differences(may be changing palette back) */
1030: for (i = 0; (i < 16) && (!bPaletteChanged); i++)
1031: {
1032: if (HBLPalette[i]!=pFrameBuffer->HBLPalettes[(y*16)+i])
1.1.1.17 root 1033: bPaletteChanged = true;
1.1.1.13 root 1034: }
1035: if (bPaletteChanged)
1036: *pUpdateLine |= PALETTEMASK_UPDATEPAL;
1037: else
1038: *pUpdateLine &= ~PALETTEMASK_UPDATEPAL;
1039: }
1.1 root 1040: }
1041:
1.1.1.7 root 1042:
1.1.1.2 root 1043: /*-----------------------------------------------------------------------*/
1.1.1.13 root 1044: /**
1045: * Check for differences in Palette and Resolution from Mask table and update
1046: * and store off which lines need updating and create full-screen palette.
1047: * (It is very important for these routines to check for colour changes with
1048: * the previous screen so only the very minimum parts are updated).
1049: * Return new STRes value.
1050: */
1051: static int Screen_ComparePaletteMask(int res)
1.1 root 1052: {
1.1.1.17 root 1053: bool bLowMedMix = false;
1.1.1.13 root 1054: int LineUpdate = 0;
1055: int y;
1056:
1057: /* Set for monochrome? */
1058: if (bUseHighRes)
1059: {
1.1.1.24 root 1060: VerticalOverscan = V_OVERSCAN_NONE;
1.1.1.13 root 1061:
1.1.1.24 root 1062: /* Just copy mono colors */
1.1.1.13 root 1063: if (HBLPalettes[0] & 0x777)
1064: {
1065: HBLPalettes[0] = 0x777;
1066: HBLPalettes[1] = 0x000;
1067: }
1068: else
1069: {
1070: HBLPalettes[0] = 0x000;
1071: HBLPalettes[1] = 0x777;
1072: }
1073:
1074: /* Colors changed? */
1075: if (HBLPalettes[0] != PrevHBLPalette[0])
1.1.1.17 root 1076: pFrameBuffer->bFullUpdate = true;
1.1.1.13 root 1077:
1078: /* Set bit to flag 'full update' */
1079: if (pFrameBuffer->bFullUpdate)
1080: ScrUpdateFlag = PALETTEMASK_UPDATEFULL;
1081: else
1082: ScrUpdateFlag = 0x00000000;
1083:
1084: /* Force to standard hi-resolution screen, without overscan */
1085: res = ST_HIGH_RES;
1086: }
1087: else /* Full colour */
1088: {
1089: /* Get resolution */
1090: //res = (HBLPaletteMasks[0]>>16)&ST_RES_MASK;
1091: /* [NP] keep only low/med bit (could be hires in case of overscan on the 1st line) */
1092: res = (HBLPaletteMasks[0]>>16)&ST_MEDIUM_RES_BIT;
1093:
1094: /* Do all lines - first is tagged as full-update */
1095: for (y = 0; y < NUM_VISIBLE_LINES; y++)
1096: {
1097: /* Find any resolution/palette change and update palette/mask buffer */
1098: /* ( LineUpdate has top two bits set to say if line needs updating due to palette or resolution change ) */
1099: bLowMedMix |= Screen_CompareResolution(y, &LineUpdate, res);
1100: Screen_ComparePalette(y,&LineUpdate);
1101: HBLPaletteMasks[y] = (HBLPaletteMasks[y]&(~PALETTEMASK_UPDATEMASK)) | LineUpdate;
1102: /* Copy palette and mask for next frame */
1103: memcpy(&pFrameBuffer->HBLPalettes[y*16],HBLPalette,sizeof(short int)*16);
1104: pFrameBuffer->HBLPaletteMasks[y] = HBLPaletteMasks[y];
1105: }
1106: /* Did mix/have medium resolution? */
1107: if (bLowMedMix || (res & ST_MEDIUM_RES_BIT))
1108: res = ST_MEDIUM_RES;
1109: }
1110:
1.1.1.24 root 1111: /* Copy old palette for compare */
1112: memcpy(PrevHBLPalette, HBLPalettes, sizeof(Uint16)*16);
1113:
1.1.1.13 root 1114: return res;
1115: }
1116:
1117:
1118: /*-----------------------------------------------------------------------*/
1119: /**
1120: * Update Palette Mask to show 'full-update' required. This is usually done after a resolution change
1121: * or when going between a Window and full-screen display
1122: */
1.1.1.8 root 1123: static void Screen_SetFullUpdateMask(void)
1.1 root 1124: {
1.1.1.13 root 1125: int y;
1.1 root 1126:
1.1.1.13 root 1127: for (y = 0; y < NUM_VISIBLE_LINES; y++)
1128: HBLPaletteMasks[y] |= PALETTEMASK_UPDATEFULL;
1.1 root 1129: }
1130:
1.1.1.7 root 1131:
1.1.1.2 root 1132: /*-----------------------------------------------------------------------*/
1.1.1.13 root 1133: /**
1134: * Set details for ST screen conversion.
1135: */
1.1.1.10 root 1136: static void Screen_SetConvertDetails(void)
1.1 root 1137: {
1.1.1.13 root 1138: pSTScreen = pFrameBuffer->pSTScreen; /* Source in ST memory */
1139: pSTScreenCopy = pFrameBuffer->pSTScreenCopy; /* Previous ST screen */
1140: pPCScreenDest = sdlscrn->pixels; /* Destination PC screen */
1141:
1142: PCScreenBytesPerLine = sdlscrn->pitch; /* Bytes per line */
1.1.1.20 root 1143:
1144: /* Center to available framebuffer */
1145: pPCScreenDest += PCScreenOffsetY * PCScreenBytesPerLine + PCScreenOffsetX * (sdlscrn->format->BitsPerPixel/8);
1146:
1.1.1.13 root 1147: pHBLPalettes = pFrameBuffer->HBLPalettes; /* HBL palettes pointer */
1148: /* Not in TV-Mode? Then double up on Y: */
1.1.1.15 root 1149: bScrDoubleY = !(ConfigureParams.Screen.nMonitorType == MONITOR_TYPE_TV);
1.1.1.13 root 1150:
1.1.1.24 root 1151: if (ConfigureParams.Screen.bAllowOverscan) /* Use borders? */
1.1.1.13 root 1152: {
1.1.1.24 root 1153: /* Always draw to WHOLE screen including ALL borders */
1154: STScreenLeftSkipBytes = 0; /* Number of bytes to skip on ST screen for left (border) */
1.1.1.13 root 1155:
1.1.1.24 root 1156: if (bUseHighRes)
1157: {
1158: pFrameBuffer->VerticalOverscanCopy = VerticalOverscan = V_OVERSCAN_NONE;
1159: STScreenStartHorizLine = 0;
1160: STScreenEndHorizLine = 400;
1.1.1.13 root 1161: }
1162: else
1163: {
1.1.1.24 root 1164: STScreenWidthBytes = SCREENBYTES_LINE; /* Number of horizontal bytes in our ST screen */
1165: STScreenStartHorizLine = OVERSCAN_TOP - nBorderPixelsTop;
1166: STScreenEndHorizLine = OVERSCAN_TOP + 200 + nBorderPixelsBottom;
1.1.1.13 root 1167: }
1168: }
1.1.1.24 root 1169: else
1170: {
1171: /* Only draw main area and centre on Y */
1172: STScreenLeftSkipBytes = SCREENBYTES_LEFT;
1173: STScreenWidthBytes = SCREENBYTES_MIDDLE;
1174: STScreenStartHorizLine = OVERSCAN_TOP;
1175: STScreenEndHorizLine = OVERSCAN_TOP + (bUseHighRes ? 400 : 200);
1176: }
1.1 root 1177: }
1178:
1.1.1.2 root 1179:
1180: /*-----------------------------------------------------------------------*/
1.1.1.13 root 1181: /**
1182: * Lock full-screen for drawing
1183: */
1.1.1.24 root 1184: bool Screen_Lock(void)
1.1 root 1185: {
1.1.1.13 root 1186: if (SDL_MUSTLOCK(sdlscrn))
1187: {
1188: if (SDL_LockSurface(sdlscrn))
1189: {
1190: Screen_ReturnFromFullScreen(); /* All OK? If not need to jump back to a window */
1.1.1.17 root 1191: return false;
1.1.1.13 root 1192: }
1193: }
1.1.1.2 root 1194:
1.1.1.17 root 1195: return true;
1.1 root 1196: }
1197:
1.1.1.2 root 1198: /*-----------------------------------------------------------------------*/
1.1.1.13 root 1199: /**
1200: * UnLock full-screen
1201: */
1.1.1.24 root 1202: void Screen_UnLock(void)
1.1 root 1203: {
1.1.1.13 root 1204: if ( SDL_MUSTLOCK(sdlscrn) )
1205: SDL_UnlockSurface(sdlscrn);
1.1 root 1206: }
1207:
1.1.1.2 root 1208:
1209: /*-----------------------------------------------------------------------*/
1.1.1.13 root 1210: /**
1211: * Blit our converted ST screen to window/full-screen
1212: */
1.1.1.22 root 1213: static void Screen_Blit(SDL_Rect *sbar_rect)
1.1 root 1214: {
1.1.1.13 root 1215: unsigned char *pTmpScreen;
1216:
1.1.1.25! root 1217: /* Don't update anything on screen if video output is disabled */
! 1218: if ( ConfigureParams.Screen.DisableVideo )
! 1219: return;
! 1220:
1.1.1.18 root 1221: #if 0 /* double buffering cannot be used with partial screen updates */
1222: # if NUM_FRAMEBUFFERS > 1
1223: if (bInFullScreen && (sdlscrn->flags & SDL_DOUBLEBUF))
1.1.1.13 root 1224: {
1225: /* Swap screen */
1.1.1.18 root 1226: if (pFrameBuffer==&FrameBuffers[0])
1227: pFrameBuffer = &FrameBuffers[1];
1228: else
1229: pFrameBuffer = &FrameBuffers[0];
1.1.1.15 root 1230: SDL_Flip(sdlscrn);
1.1.1.13 root 1231: }
1232: else
1.1.1.18 root 1233: # endif
1234: #endif
1.1.1.13 root 1235: {
1.1.1.22 root 1236: int count = 1;
1237: SDL_Rect rects[2];
1238: rects[0] = STScreenRect;
1239: if (sbar_rect)
1240: {
1241: rects[1] = *sbar_rect;
1242: count = 2;
1243: }
1244: SDL_UpdateRects(sdlscrn, count, rects);
1.1.1.13 root 1245: }
1246:
1247: /* Swap copy/raster buffers in screen. */
1248: pTmpScreen = pFrameBuffer->pSTScreenCopy;
1249: pFrameBuffer->pSTScreenCopy = pFrameBuffer->pSTScreen;
1250: pFrameBuffer->pSTScreen = pTmpScreen;
1.1 root 1251: }
1252:
1.1.1.3 root 1253:
1.1.1.2 root 1254: /*-----------------------------------------------------------------------*/
1.1.1.13 root 1255: /**
1256: * Draw ST screen to window/full-screen framebuffer
1.1.1.15 root 1257: * @param bForceFlip Force screen update, even if contents did not change
1.1.1.17 root 1258: * @return true if screen contents changed
1.1.1.13 root 1259: */
1.1.1.15 root 1260: static bool Screen_DrawFrame(bool bForceFlip)
1.1 root 1261: {
1.1.1.13 root 1262: int new_res;
1263: void (*pDrawFunction)(void);
1.1.1.17 root 1264: static bool bPrevFrameWasSpec512 = false;
1.1.1.22 root 1265: SDL_Rect *sbar_rect;
1.1.1.13 root 1266:
1.1.1.24 root 1267: assert(!bUseVDIRes);
1268:
1.1.1.13 root 1269: /* Scan palette/resolution masks for each line and build up palette/difference tables */
1270: new_res = Screen_ComparePaletteMask(STRes);
1271: /* Did we change resolution this frame - allocate new screen if did so */
1272: Screen_DidResolutionChange(new_res);
1273: /* Is need full-update, tag as such */
1274: if (pFrameBuffer->bFullUpdate)
1275: Screen_SetFullUpdateMask();
1276:
1.1.1.15 root 1277: /* restore area potentially left under overlay led
1278: * and saved by Statusbar_OverlayBackup()
1279: */
1280: Statusbar_OverlayRestore(sdlscrn);
1.1.1.22 root 1281:
1282: /* Lock screen for direct screen surface format writes */
1.1.1.13 root 1283: if (Screen_Lock())
1284: {
1.1.1.17 root 1285: bScreenContentsChanged = false; /* Did change (ie needs blit?) */
1.1.1.15 root 1286:
1.1.1.13 root 1287: /* Set details */
1288: Screen_SetConvertDetails();
1.1.1.24 root 1289:
1.1.1.13 root 1290: /* Clear screen on full update to clear out borders and also interleaved lines */
1.1.1.24 root 1291: if (pFrameBuffer->bFullUpdate)
1.1.1.13 root 1292: Screen_ClearScreen();
1.1.1.15 root 1293:
1.1.1.13 root 1294: /* Call drawing for full-screen */
1.1.1.24 root 1295: pDrawFunction = ScreenDrawFunctionsNormal[STRes];
1296: /* Check if is Spec512 image */
1297: if (Spec512_IsImage())
1298: {
1299: bPrevFrameWasSpec512 = true;
1300: /* What mode were we in? Keep to 320xH or 640xH */
1301: if (pDrawFunction==ConvertLowRes_320x16Bit)
1302: pDrawFunction = ConvertLowRes_320x16Bit_Spec;
1303: else if (pDrawFunction==ConvertLowRes_640x16Bit)
1304: pDrawFunction = ConvertLowRes_640x16Bit_Spec;
1305: else if (pDrawFunction==ConvertLowRes_320x32Bit)
1306: pDrawFunction = ConvertLowRes_320x32Bit_Spec;
1307: else if (pDrawFunction==ConvertLowRes_640x32Bit)
1308: pDrawFunction = ConvertLowRes_640x32Bit_Spec;
1309: else if (pDrawFunction==ConvertMediumRes_640x32Bit)
1310: pDrawFunction = ConvertMediumRes_640x32Bit_Spec;
1311: else if (pDrawFunction==ConvertMediumRes_640x16Bit)
1312: pDrawFunction = ConvertMediumRes_640x16Bit_Spec;
1313: }
1314: else if (bPrevFrameWasSpec512)
1315: {
1316: /* If we switch back from Spec512 mode to normal
1317: * screen rendering, we have to make sure to do
1318: * a full update of the screen. */
1319: Screen_SetFullUpdateMask();
1320: bPrevFrameWasSpec512 = false;
1.1.1.13 root 1321: }
1322:
1323: if (pDrawFunction)
1.1.1.15 root 1324: CALL_VAR(pDrawFunction);
1325:
1326: /* Unlock screen */
1327: Screen_UnLock();
1.1.1.13 root 1328:
1.1.1.22 root 1329: /* draw overlay led(s) or statusbar after unlock */
1.1.1.15 root 1330: Statusbar_OverlayBackup(sdlscrn);
1.1.1.22 root 1331: sbar_rect = Statusbar_Update(sdlscrn, false);
1.1.1.15 root 1332:
1.1.1.13 root 1333: /* Clear flags, remember type of overscan as if change need screen full update */
1.1.1.17 root 1334: pFrameBuffer->bFullUpdate = false;
1.1.1.24 root 1335: pFrameBuffer->VerticalOverscanCopy = VerticalOverscan;
1.1.1.13 root 1336:
1337: /* And show to user */
1.1.1.22 root 1338: if (bScreenContentsChanged || bForceFlip || sbar_rect)
1.1.1.15 root 1339: {
1.1.1.22 root 1340: Screen_Blit(sbar_rect);
1.1.1.15 root 1341: }
1.1.1.13 root 1342:
1.1.1.15 root 1343: return bScreenContentsChanged;
1.1.1.13 root 1344: }
1.1.1.15 root 1345:
1346: return false;
1.1 root 1347: }
1348:
1.1.1.9 root 1349:
1.1.1.2 root 1350: /*-----------------------------------------------------------------------*/
1.1.1.13 root 1351: /**
1352: * Draw ST screen to window/full-screen
1353: */
1.1.1.15 root 1354: bool Screen_Draw(void)
1.1 root 1355: {
1.1.1.25! root 1356: if (bQuitProgram)
1.1.1.13 root 1357: {
1.1.1.24 root 1358: return false;
1.1.1.13 root 1359: }
1.1.1.15 root 1360:
1.1.1.24 root 1361: /* And draw (if screen contents changed) */
1362: return Screen_DrawFrame(false);
1363: }
1364:
1365: /**
1366: * This is used to set the size of the SDL screen
1367: * when we're using the generic conversion functions.
1368: */
1369: void Screen_SetGenConvSize(int width, int height, int bpp, bool bForceChange)
1370: {
1371: const bool keep = ConfigureParams.Screen.bKeepResolution;
1372: int screenwidth, screenheight, maxw, maxh;
1373: int scalex, scaley, sbarheight;
1374:
1375: if (bpp == 24)
1376: bpp = 32;
1377:
1378: /* constrain size request to user's desktop size */
1379: Resolution_GetDesktopSize(&maxw, &maxh);
1380: #if !WITH_SDL2
1381: scalex = scaley = 1;
1382: while (width > maxw*scalex) {
1383: scalex *= 2;
1384: }
1385: while (height > maxh*scaley) {
1386: scaley *= 2;
1387: }
1388: if (scalex * scaley > 1) {
1389: fprintf(stderr, "WARNING: too large screen size %dx%d -> divided by %dx%d!\n",
1390: width, height, scalex, scaley);
1391: width /= scalex;
1392: height /= scaley;
1393: }
1394: #endif
1395:
1396: Resolution_GetLimits(&maxw, &maxh, &bpp, keep);
1397: nScreenZoomX = nScreenZoomY = 1;
1398:
1399: if (ConfigureParams.Screen.bAspectCorrect) {
1400: /* Falcon (and TT) pixel scaling factors seem to 2^x
1401: * (quarter/half pixel, interlace/double line), so
1402: * do aspect correction as 2's exponent.
1403: */
1404: while (nScreenZoomX*width < height &&
1405: 2*nScreenZoomX*width < maxw) {
1406: nScreenZoomX *= 2;
1407: }
1408: while (2*nScreenZoomY*height < width &&
1409: 2*nScreenZoomY*height < maxh) {
1410: nScreenZoomY *= 2;
1411: }
1412: if (nScreenZoomX*nScreenZoomY > 2) {
1413: fprintf(stderr, "WARNING: strange screen size %dx%d -> aspect corrected by %dx%d!\n",
1414: width, height, nScreenZoomX, nScreenZoomY);
1415: }
1416: }
1417:
1418: /* then select scale as close to target size as possible
1419: * without having larger size than it
1420: */
1421: scalex = maxw/(nScreenZoomX*width);
1422: scaley = maxh/(nScreenZoomY*height);
1423: if (scalex > 1 && scaley > 1) {
1424: /* keep aspect ratio */
1425: if (scalex < scaley) {
1426: nScreenZoomX *= scalex;
1427: nScreenZoomY *= scalex;
1428: } else {
1429: nScreenZoomX *= scaley;
1430: nScreenZoomY *= scaley;
1431: }
1432: }
1433:
1434: genconv_width_req = width;
1435: genconv_height_req = height;
1436: width *= nScreenZoomX;
1437: height *= nScreenZoomY;
1438:
1439: /* get statusbar size for this screen size */
1440: sbarheight = Statusbar_GetHeightForSize(width, height);
1441: screenheight = height + sbarheight;
1442: screenwidth = width;
1443:
1444: #if !WITH_SDL2
1445: /* get resolution corresponding to these */
1446: Resolution_Search(&screenwidth, &screenheight, &bpp, keep);
1447: #endif
1448: /* re-calculate statusbar height for this resolution */
1449: sbarheight = Statusbar_SetHeight(screenwidth, screenheight-sbarheight);
1450:
1451: genconv_bpp = bpp;
1452: /* screen area without the statusbar */
1453: STScreenRect.x = STScreenRect.y = 0;
1454: STScreenRect.w = screenwidth;
1455: STScreenRect.h = screenheight - sbarheight;
1456:
1457: if (!Screen_SetSDLVideoSize(screenwidth, screenheight, bpp, bForceChange))
1458: {
1459: /* same host screen size despite Atari resolution change,
1460: * -> no time consuming host video mode change needed
1461: */
1462: if (screenwidth > width || screenheight > height+sbarheight) {
1463: /* Atari screen smaller than host -> clear screen */
1464: Screen_ClearScreen();
1465: /* re-calculate variables in case height + statusbar height
1466: * don't anymore match SDL surface size (there's an assert
1467: * for that)
1468: */
1469: Statusbar_Init(sdlscrn);
1470: }
1471: #if WITH_SDL2
1472: genconv_do_update = true;
1473: #else
1474: genconv_do_update = ( sdlscrn->flags & SDL_HWSURFACE ) == 0;
1475: #endif
1476: return;
1477: }
1478:
1479: // In case surface format changed, remap the native palette
1480: Screen_RemapPalette();
1481:
1482: // redraw statusbar
1483: Statusbar_Init(sdlscrn);
1484:
1485: DEBUGPRINT(("Surface Pitch = %d, width = %d, height = %d\n", sdlscrn->pitch, sdlscrn->w, sdlscrn->h));
1486: DEBUGPRINT(("Must Lock? %s\n", SDL_MUSTLOCK(sdlscrn) ? "YES" : "NO"));
1487:
1488: #if WITH_SDL2
1489: genconv_do_update = true;
1490: #else
1491: // is the SDL_update needed?
1492: genconv_do_update = ( sdlscrn->flags & SDL_HWSURFACE ) == 0;
1493: #endif
1494:
1495: DEBUGPRINT(("Pixel format:bitspp=%d, tmasks r=%04x g=%04x b=%04x"
1496: ", tshifts r=%d g=%d b=%d"
1497: ", tlosses r=%d g=%d b=%d\n",
1498: sdlscrn->format->BitsPerPixel,
1499: sdlscrn->format->Rmask, sdlscrn->format->Gmask, sdlscrn->format->Bmask,
1500: sdlscrn->format->Rshift, sdlscrn->format->Gshift, sdlscrn->format->Bshift,
1501: sdlscrn->format->Rloss, sdlscrn->format->Gloss, sdlscrn->format->Bloss));
1502:
1503: Main_WarpMouse(sdlscrn->w/2,sdlscrn->h/2, false);
1504: }
1505:
1506: void Screen_GenConvUpdate(SDL_Rect *extra, bool forced)
1507: {
1508: SDL_Rect rects[2];
1509: int count = 1;
1510:
1.1.1.25! root 1511: /* Don't update anything on screen if video output is disabled */
! 1512: if ( ConfigureParams.Screen.DisableVideo )
! 1513: return;
! 1514:
1.1.1.24 root 1515: if (!forced && !genconv_do_update) // the HW surface is available
1516: return;
1517:
1518: rects[0] = STScreenRect;
1519: if (extra) {
1520: rects[1] = *extra;
1521: count = 2;
1522: }
1523: SDL_UpdateRects(sdlscrn, count, rects);
1524: }
1525:
1526: Uint32 Screen_GetGenConvWidth(void)
1527: {
1528: return STScreenRect.w;
1529: }
1530:
1531: Uint32 Screen_GetGenConvHeight(void)
1532: {
1533: return STScreenRect.h;
1.1 root 1534: }
1.1.1.11 root 1535:
1536:
1537: /* -------------- screen conversion routines --------------------------------
1538: Screen conversion routines. We have a number of routines to convert ST screen
1539: to PC format. We split these into Low, Medium and High each with 8/16-bit
1540: versions. To gain extra speed, as almost half of the processing time can be
1541: spent in these routines, we check for any changes from the previously
1542: displayed frame. AdjustLinePaletteRemap() sets a flag to tell the routines
1543: if we need to totally update a line (ie full update, or palette/res change)
1544: or if we just can do a difference check.
1545: We convert each screen 16 pixels at a time by use of a couple of look-up
1546: tables. These tables convert from 2-plane format to bbp and then we can add
1547: two of these together to get 4-planes. This keeps the tables small and thus
1548: improves speed. We then look these bbp values up as an RGB/Index value to
1549: copy to the screen.
1550: */
1551:
1552:
1.1.1.13 root 1553: /*-----------------------------------------------------------------------*/
1554: /**
1.1.1.11 root 1555: * Update the STRGBPalette[] array with current colours for this raster line.
1556: *
1557: * Return 'ScrUpdateFlag', 0x80000000=Full update, 0x40000000=Update
1558: * as palette changed
1559: */
1560: static int AdjustLinePaletteRemap(int y)
1561: {
1562: #if SDL_BYTEORDER == SDL_BIG_ENDIAN
1.1.1.13 root 1563: static const int endiantable[16] = {0,2,1,3,8,10,9,11,4,6,5,7,12,14,13,15};
1.1.1.11 root 1564: #endif
1.1.1.13 root 1565: Uint16 *actHBLPal;
1566: int i;
1.1.1.11 root 1567:
1.1.1.13 root 1568: /* Copy palette and convert to RGB in display format */
1569: actHBLPal = pHBLPalettes + (y<<4); /* offset in palette */
1570: for (i=0; i<16; i++)
1571: {
1.1.1.11 root 1572: #if SDL_BYTEORDER == SDL_BIG_ENDIAN
1.1.1.13 root 1573: STRGBPalette[endiantable[i]] = ST2RGB[*actHBLPal++];
1.1.1.11 root 1574: #else
1.1.1.13 root 1575: STRGBPalette[i] = ST2RGB[*actHBLPal++];
1.1.1.11 root 1576: #endif
1.1.1.13 root 1577: }
1578: ScrUpdateFlag = HBLPaletteMasks[y];
1579: return ScrUpdateFlag;
1.1.1.11 root 1580: }
1581:
1582:
1.1.1.13 root 1583: /*-----------------------------------------------------------------------*/
1584: /**
1.1.1.11 root 1585: * Run updates to palette(STRGBPalette[]) until get to screen line
1586: * we are to convert from
1587: */
1588: static void Convert_StartFrame(void)
1589: {
1.1.1.13 root 1590: int y = 0;
1591: /* Get #lines before conversion starts */
1592: int lines = STScreenStartHorizLine;
1593: while (lines--)
1594: AdjustLinePaletteRemap(y++); /* Update palette */
1.1.1.11 root 1595: }
1596:
1597: /* lookup tables and conversion macros */
1598: #include "convert/macros.h"
1599:
1600: /* Conversion routines */
1.1.1.13 root 1601:
1.1.1.19 root 1602: #include "convert/low320x16.c" /* LowRes To 320xH x 16-bit color */
1603: #include "convert/low640x16.c" /* LowRes To 640xH x 16-bit color */
1604: #include "convert/med640x16.c" /* MediumRes To 640xH x 16-bit color */
1605: #include "convert/low320x16_spec.c" /* LowRes Spectrum 512 To 320xH x 16-bit color */
1606: #include "convert/low640x16_spec.c" /* LowRes Spectrum 512 To 640xH x 16-bit color */
1607: #include "convert/med640x16_spec.c" /* MediumRes Spectrum 512 To 640xH x 16-bit color */
1608:
1609: #include "convert/low320x32.c" /* LowRes To 320xH x 32-bit color */
1610: #include "convert/low640x32.c" /* LowRes To 640xH x 32-bit color */
1611: #include "convert/med640x32.c" /* MediumRes To 640xH x 32-bit color */
1612: #include "convert/low320x32_spec.c" /* LowRes Spectrum 512 To 320xH x 32-bit color */
1613: #include "convert/low640x32_spec.c" /* LowRes Spectrum 512 To 640xH x 32-bit color */
1614: #include "convert/med640x32_spec.c" /* MediumRes Spectrum 512 To 640xH x 32-bit color */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.