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