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