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