|
|
1.1 root 1: /*
1.1.1.6 root 2: Hatari - screen.c
1.1 root 3:
1.1.1.6 root 4: This file is distributed under the GNU Public License, version 2 or at your
5: option any later version. Read the file gpl.txt for details.
6:
7: This code converts a 1/2/4 plane ST format screen to either 8 or 16-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
18: optimise things further. Also when running in maximum speed we make sure we
19: only convert the screen every 50 times a second - inbetween frames are not
20: processed.
1.1 root 21: */
1.1.1.14! root 22: const char Screen_rcsid[] = "Hatari $Id: screen.c,v 1.79 2008/03/26 20:16:26 eerot Exp $";
1.1 root 23:
24: #include <SDL.h>
1.1.1.11 root 25: #include <SDL_endian.h>
1.1 root 26:
27: #include "main.h"
1.1.1.7 root 28: #include "configuration.h"
1.1 root 29: #include "ikbd.h"
1.1.1.13 root 30: #include "log.h"
1.1 root 31: #include "m68000.h"
32: #include "misc.h"
1.1.1.13 root 33: #include "paths.h"
1.1 root 34: #include "screen.h"
1.1.1.11 root 35: #include "convert/routines.h"
1.1 root 36: #include "screenSnapShot.h"
37: #include "sound.h"
38: #include "spec512.h"
39: #include "vdi.h"
40: #include "video.h"
1.1.1.13 root 41: #include "falcon/videl.h"
42: #include "falcon/hostscreen.h"
1.1 root 43:
44:
1.1.1.13 root 45: /* extern for several purposes */
46: SDL_Surface *sdlscrn = NULL; /* The SDL screen surface */
47: int nScreenZoomX, nScreenZoomY; /* Zooming factors, used for scaling mouse motions */
48: int nBorderPixelsLeft, nBorderPixelsRight; /* Pixels in left and right border */
49: int nBorderPixelsBottom; /* Lines in bottom border */
50:
51: /* extern for shortcuts and falcon/hostscreen.c */
1.1.1.11 root 52: BOOL bGrabMouse = FALSE; /* Grab the mouse cursor in the window */
1.1.1.13 root 53: BOOL bInFullScreen = FALSE; /* TRUE if in full screen */
54:
55: /* extern for spec512.c */
1.1.1.11 root 56: int STScreenLeftSkipBytes;
57: int STScreenStartHorizLine; /* Start lines to be converted */
58: Uint32 STRGBPalette[16]; /* Palette buffer used in conversion routines */
59: Uint32 ST2RGB[4096]; /* Table to convert ST 0x777 / STe 0xfff palette to PC format RGB551 (2 pixels each entry) */
1.1.1.13 root 60:
61: /* extern for video.c */
1.1.1.11 root 62: Uint8 *pSTScreen;
63: FRAMEBUFFER *pFrameBuffer; /* Pointer into current 'FrameBuffer' */
64:
65: static FRAMEBUFFER FrameBuffers[NUM_FRAMEBUFFERS]; /* Store frame buffer details to tell how to update */
66: static Uint8 *pSTScreenCopy; /* Keep track of current and previous ST screen data */
67: static Uint8 *pPCScreenDest; /* Destination PC buffer */
68: static int STScreenEndHorizLine; /* End lines to be converted */
69: static int PCScreenBytesPerLine;
70: static int STScreenWidthBytes;
1.1 root 71:
1.1.1.11 root 72: static int STScreenLineOffset[NUM_VISIBLE_LINES]; /* Offsets for ST screen lines eg, 0,160,320... */
73: static Uint16 HBLPalette[16], PrevHBLPalette[16]; /* Current palette for line, also copy of first line */
1.1 root 74:
1.1.1.13 root 75: static void (*ScreenDrawFunctionsNormal[3])(void); /* Screen draw functions */
1.1.1.12 root 76: static void (*ScreenDrawFunctionsVDI[3])(void) =
1.1.1.10 root 77: {
1.1.1.13 root 78: ConvertVDIRes_16Colour,
79: ConvertVDIRes_4Colour,
80: ConvertVDIRes_2Colour
1.1.1.10 root 81: };
82:
1.1.1.11 root 83: static BOOL bScreenContentsChanged; /* TRUE if buffer changed and requires blitting */
84: static BOOL bScrDoubleY; /* TRUE if double on Y */
85: static int ScrUpdateFlag; /* Bit mask of how to update screen */
86:
1.1.1.10 root 87:
88: /*-----------------------------------------------------------------------*/
1.1.1.13 root 89: /**
90: * Create ST 0x777 / STe 0xfff color format to 16 or 32 bits per pixel
91: * conversion table. Called each time when changed resolution or to/from
92: * fullscreen mode.
93: */
1.1.1.10 root 94: static void Screen_SetupRGBTable(void)
95: {
1.1.1.13 root 96: Uint16 STColor;
97: Uint32 RGBColor;
98: int r, g, b;
99: int rr, gg, bb;
100:
101: /* Do Red, Green and Blue for all 16*16*16 = 4096 STe colors */
102: for (r = 0; r < 16; r++)
103: {
104: for (g = 0; g < 16; g++)
105: {
106: for (b = 0; b < 16; b++)
107: {
108: /* STe 0xfff format */
109: STColor = (r<<8) | (g<<4) | (b);
110: rr = ((r & 0x7) << 5) | ((r & 0x8) << 1);
111: gg = ((g & 0x7) << 5) | ((g & 0x8) << 1);
112: bb = ((b & 0x7) << 5) | ((b & 0x8) << 1);
113: RGBColor = SDL_MapRGB(sdlscrn->format, rr, gg, bb);
114: if (sdlscrn->format->BitsPerPixel <= 16)
115: {
116: /* As longs, for speed (write two pixels at once) */
117: ST2RGB[STColor] = (RGBColor<<16) | RGBColor;
118: }
119: else
120: {
121: ST2RGB[STColor] = RGBColor;
122: }
123: }
124: }
125: }
1.1.1.10 root 126: }
127:
1.1.1.13 root 128:
1.1.1.10 root 129: /*-----------------------------------------------------------------------*/
1.1.1.13 root 130: /**
131: * Create new palette for display.
132: */
1.1.1.10 root 133: static void Screen_CreatePalette(void)
134: {
135: #if SDL_BYTEORDER == SDL_BIG_ENDIAN
1.1.1.13 root 136: 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 137: #endif
1.1.1.13 root 138: SDL_Color sdlColors[16];
139: int i, j;
1.1.1.10 root 140:
1.1.1.13 root 141: if (bUseHighRes)
142: {
143: /* Colors for monochrome screen mode emulation */
144: if (HBLPalettes[0])
145: {
146: sdlColors[0].r = sdlColors[0].g = sdlColors[0].b = 255;
147: sdlColors[1].r = sdlColors[1].g = sdlColors[1].b = 0;
148: }
149: else
150: {
151: sdlColors[0].r = sdlColors[0].g = sdlColors[0].b = 0;
152: sdlColors[1].r = sdlColors[1].g = sdlColors[1].b = 255;
153: }
154: SDL_SetColors(sdlscrn, sdlColors, 10, 2);
155: /*SDL_SetColors(sdlscrn, sdlColors, 0, 2);*/
156: }
157: else
158: {
159: int r, g, b;
160: /* Colors for STe color screen mode emulation */
161: for (i = 0; i < 16; i++)
162: {
1.1.1.11 root 163: #if SDL_BYTEORDER == SDL_BIG_ENDIAN
1.1.1.13 root 164: j = endiantable[i];
1.1.1.11 root 165: #else
1.1.1.13 root 166: j = i;
1.1.1.11 root 167: #endif
1.1.1.13 root 168: /* normalize all to 0x1e0 */
169: r = HBLPalettes[i] >> 3;
170: g = HBLPalettes[i] << 1;
171: b = HBLPalettes[i] << 5;
172: /* move top bit of 0x1e0 to lowest in 0xf0 */
173: sdlColors[j].r = (r & 0xe0) | ((r & 0x100) >> 4);
174: sdlColors[j].g = (g & 0xe0) | ((g & 0x100) >> 4);
175: sdlColors[j].b = (b & 0xe0) | ((b & 0x100) >> 4);
176: }
177: SDL_SetColors(sdlscrn, sdlColors, 10, 16);
178: }
1.1.1.10 root 179: }
180:
181:
182: /*-----------------------------------------------------------------------*/
1.1.1.13 root 183: /**
184: * Create 8-Bit palette for display if needed.
185: */
1.1.1.10 root 186: static void Screen_Handle8BitPalettes(void)
187: {
1.1.1.13 root 188: BOOL bPaletteChanged=FALSE;
189: int i;
1.1.1.10 root 190:
1.1.1.13 root 191: /* Do need to check for 8-Bit palette change? Ie, update whole screen */
192: /* VDI screens and monochrome modes are ALL 8-Bit at the moment! */
193: if (sdlscrn->format->BitsPerPixel == 8)
194: {
195: /* If using HiRes palette update with full update flag */
196: if (!bUseHighRes)
197: {
198: /* Check if palette of 16 colours changed from previous frame */
199: for (i = 0; i < 16 && !bPaletteChanged; i++)
200: {
201: /* Check with first line palette (stored in 'Screen_ComparePaletteMask') */
202: if (HBLPalettes[i] != PrevHBLPalette[i])
203: bPaletteChanged = TRUE;
204: }
205: }
206:
207: /* Did palette change or do we require a full update? */
208: if (bPaletteChanged || pFrameBuffer->bFullUpdate)
209: {
210: /* Create palette, for Full-Screen of Window */
211: Screen_CreatePalette();
212: /* Make sure update whole screen */
213: pFrameBuffer->bFullUpdate = TRUE;
214: }
215: }
1.1.1.10 root 216:
1.1.1.13 root 217: /* Copy old palette for 8-Bit compare as this routine writes over it */
218: memcpy(PrevHBLPalette,HBLPalettes, sizeof(Uint16)*16);
1.1.1.10 root 219: }
220:
1.1 root 221:
222: /*-----------------------------------------------------------------------*/
1.1.1.13 root 223: /**
224: * Set screen draw functions.
225: */
226: static void Screen_SetDrawFunctions(int nBitCount)
1.1.1.10 root 227: {
1.1.1.14! root 228: if (nBitCount == 8)
1.1.1.13 root 229: {
230: /* Low color */
231: if (ConfigureParams.Screen.bZoomLowRes)
232: ScreenDrawFunctionsNormal[ST_LOW_RES] = ConvertLowRes_640x8Bit;
233: else
234: ScreenDrawFunctionsNormal[ST_LOW_RES] = ConvertLowRes_320x8Bit;
235: ScreenDrawFunctionsNormal[ST_MEDIUM_RES] = ConvertMediumRes_640x8Bit;
236: ScreenDrawFunctionsNormal[ST_HIGH_RES] = ConvertHighRes_640x8Bit;
237: }
238: else if (nBitCount <= 16)
239: {
240: /* High color */
241: if (ConfigureParams.Screen.bZoomLowRes)
242: ScreenDrawFunctionsNormal[ST_LOW_RES] = ConvertLowRes_640x16Bit;
243: else
244: ScreenDrawFunctionsNormal[ST_LOW_RES] = ConvertLowRes_320x16Bit;
245: ScreenDrawFunctionsNormal[ST_MEDIUM_RES] = ConvertMediumRes_640x16Bit;
246: ScreenDrawFunctionsNormal[ST_HIGH_RES] = ConvertHighRes_640x8Bit;
247: }
248: else /* Assume 32 bit drawing functions */
249: {
250: /* True color */
251: if (ConfigureParams.Screen.bZoomLowRes)
252: ScreenDrawFunctionsNormal[ST_LOW_RES] = ConvertLowRes_640x32Bit;
253: else
254: ScreenDrawFunctionsNormal[ST_LOW_RES] = ConvertLowRes_320x32Bit;
255: ScreenDrawFunctionsNormal[ST_MEDIUM_RES] = ConvertMediumRes_640x32Bit;
256: ScreenDrawFunctionsNormal[ST_HIGH_RES] = ConvertHighRes_640x8Bit;
257: }
1.1.1.10 root 258: }
259:
260:
261: /*-----------------------------------------------------------------------*/
1.1.1.13 root 262: /**
263: * Set amount of border pixels for windowed and full-screen mode and
264: * store Y offset for each horizontal line in our source ST screen for
265: * reference in tje convert functions.
266: */
267: static void Screen_SetSTScreenOffsets(void)
1.1.1.7 root 268: {
1.1.1.13 root 269: int i;
1.1.1.7 root 270:
1.1.1.13 root 271: /* Determine border pixels */
272: if (bInFullScreen)
273: {
274: nBorderPixelsLeft = ConfigureParams.Screen.nFullScreenBorderPixelsLeft;
275: nBorderPixelsRight = ConfigureParams.Screen.nFullScreenBorderPixelsRight;
276: nBorderPixelsBottom = ConfigureParams.Screen.nFullScreenBorderPixelsBottom;
277: }
278: else
279: {
280: nBorderPixelsLeft = ConfigureParams.Screen.nWindowBorderPixelsLeft;
281: nBorderPixelsRight = ConfigureParams.Screen.nWindowBorderPixelsRight;
282: nBorderPixelsBottom = ConfigureParams.Screen.nWindowBorderPixelsBottom;
283: }
284:
285: /* Store offset to each horizontal line */
286: for (i = 0; i < NUM_VISIBLE_LINES; i++)
287: {
288: STScreenLineOffset[i] = i * SCREENBYTES_LINE;
289: }
1.1.1.7 root 290: }
291:
1.1.1.8 root 292:
1.1.1.7 root 293: /*-----------------------------------------------------------------------*/
1.1.1.13 root 294: /**
295: * Initialize SDL screen surface / set resolution.
296: */
297: static void Screen_SetResolution(void)
1.1.1.11 root 298: {
1.1.1.13 root 299: int Width, Height, BitCount;
300: unsigned int sdlVideoFlags;
301:
302: Screen_SetSTScreenOffsets();
1.1.1.11 root 303:
1.1.1.13 root 304: /* Determine which resolution to use */
305: if (bUseVDIRes)
306: {
307: Width = VDIWidth;
308: Height = VDIHeight;
309: }
310: else
311: {
312: if (STRes == ST_LOW_RES && !ConfigureParams.Screen.bZoomLowRes)
313: {
314: Width = 320;
315: Height = 200;
316: }
317: else /* else use 640x400 */
318: {
319: Width = 640;
320: Height = 400;
321: }
322:
323: /* Adjust width/height for overscan borders, if mono or VDI we have no overscan */
324: if (ConfigureParams.Screen.bAllowOverscan && !bUseHighRes)
325: {
326: int nZoom = ((Width == 640) ? 2 : 1);
327: /* Add in overscan borders (if 640x200 bitmap is double on Y) */
328: Width += (nBorderPixelsLeft+nBorderPixelsRight) * nZoom;
329: Height += (OVERSCAN_TOP+nBorderPixelsBottom) * nZoom;
330: }
331: }
332:
333: /* Bits per pixel */
1.1.1.14! root 334: if (STRes == ST_HIGH_RES || bUseVDIRes)
1.1.1.13 root 335: {
336: BitCount = 8;
337: }
338: else
339: {
340: BitCount = ConfigureParams.Screen.nForceBpp;
341: }
342:
343: /* Set zoom factors, used for scaling mouse motions */
344: if (STRes == ST_LOW_RES && ConfigureParams.Screen.bZoomLowRes && !bUseVDIRes)
345: {
346: nScreenZoomX = 2;
347: nScreenZoomY = 2;
348: }
349: else if (STRes == ST_MEDIUM_RES && !bUseVDIRes)
350: {
351: nScreenZoomX = 1;
352: nScreenZoomY = 2;
353: }
354: else
355: {
356: nScreenZoomX = 1;
357: nScreenZoomY = 1;
358: }
359:
360: /* SDL Video attributes: */
361: if (bInFullScreen)
362: {
363: sdlVideoFlags = SDL_HWSURFACE|SDL_FULLSCREEN|SDL_HWPALETTE/*|SDL_DOUBLEBUF*/;
364: /* SDL_DOUBLEBUF is a good idea, but the GUI doesn't work with double buffered
365: * screens yet, so double buffering is currently disabled. */
366: }
367: else
368: {
369: sdlVideoFlags = SDL_SWSURFACE|SDL_HWPALETTE;
370: }
371:
372: /* Check if we really have to change the video mode: */
373: if (!sdlscrn || sdlscrn->w != Width || sdlscrn->h != Height
374: || sdlscrn->format->BitsPerPixel != BitCount
375: || (sdlscrn->flags&SDL_FULLSCREEN) != (sdlVideoFlags&SDL_FULLSCREEN))
376: {
377: /* Set new video mode */
378: //fprintf(stderr,"Requesting video mode %i %i %i\n", Width, Height, BitCount);
379: sdlscrn = SDL_SetVideoMode(Width, Height, BitCount, sdlVideoFlags);
380: //fprintf(stderr,"Got video mode %i %i %i\n", sdlscrn->w, sdlscrn->h, sdlscrn->format->BitsPerPixel);
381: /* We do not support 24 bpp (yet) */
382: if (sdlscrn && sdlscrn->format->BitsPerPixel == 24)
383: {
384: fprintf(stderr, "Unsupported color depth 24, trying 32 bpp instead...\n");
385: sdlscrn = SDL_SetVideoMode(Width, Height, 32, sdlVideoFlags);
386: }
387: /* Exit if we can not open a screen */
388: if (!sdlscrn)
389: {
390: fprintf(stderr, "Could not set video mode:\n %s\n", SDL_GetError() );
391: SDL_Quit();
392: exit(-2);
393: }
394:
395: /* Re-init screen palette: */
1.1.1.14! root 396: if (sdlscrn->format->BitsPerPixel == 8)
1.1.1.13 root 397: Screen_Handle8BitPalettes(); /* Initialize new 8 bit palette */
398: else
399: Screen_SetupRGBTable(); /* Create color convertion table */
400:
401: /* Un-grab mouse pointer in windowed mode: */
402: if (!bGrabMouse)
403: SDL_WM_GrabInput(SDL_GRAB_OFF);
404: }
405:
406: /* Set drawing functions */
407: Screen_SetDrawFunctions(sdlscrn->format->BitsPerPixel);
408:
409: Screen_SetFullUpdate(); /* Cause full update of screen */
1.1.1.11 root 410: }
411:
412:
413: /*-----------------------------------------------------------------------*/
1.1.1.13 root 414: /**
415: * Init Screen bitmap and buffers/tables needed for ST to PC screen conversion
416: */
1.1 root 417: void Screen_Init(void)
418: {
1.1.1.13 root 419: int i;
420: SDL_Surface *pIconSurf;
421: char sIconFileName[FILENAME_MAX];
422:
423: /* Clear frame buffer structures and set current pointer */
424: memset(FrameBuffers, 0, NUM_FRAMEBUFFERS * sizeof(FRAMEBUFFER));
425:
426: /* Allocate previous screen check workspace. We are going to double-buffer a double-buffered screen. Oh. */
427: for (i = 0; i < NUM_FRAMEBUFFERS; i++)
428: {
429: FrameBuffers[i].pSTScreen = malloc(((MAX_VDI_WIDTH*MAX_VDI_PLANES)/8)*MAX_VDI_HEIGHT);
430: FrameBuffers[i].pSTScreenCopy = malloc(((MAX_VDI_WIDTH*MAX_VDI_PLANES)/8)*MAX_VDI_HEIGHT);
431: if (!FrameBuffers[i].pSTScreen || !FrameBuffers[i].pSTScreenCopy)
432: {
433: fprintf(stderr, "Failed to allocate frame buffer memory.\n");
434: exit(-1);
435: }
436: }
437: pFrameBuffer = &FrameBuffers[0];
438:
439: /* Load and set icon */
440: snprintf(sIconFileName, sizeof(sIconFileName), "%s%chatari-icon.bmp",
441: Paths_GetDataDir(), PATHSEP);
442: pIconSurf = SDL_LoadBMP(sIconFileName);
443: if (pIconSurf)
444: {
445: SDL_SetColorKey(pIconSurf, SDL_SRCCOLORKEY, SDL_MapRGB(pIconSurf->format, 255, 255, 255));
446: SDL_WM_SetIcon(pIconSurf, NULL);
447: SDL_FreeSurface(pIconSurf);
448: }
449:
450: /* Set initial window resolution */
451: bInFullScreen = ConfigureParams.Screen.bFullScreen;
452: Screen_SetResolution();
453:
454: Video_SetScreenRasters(); /* Set rasters ready for first screen */
455:
456: /* Configure some SDL stuff: */
457: SDL_WM_SetCaption(PROG_NAME, "Hatari");
458: SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);
459: SDL_EventState(SDL_MOUSEBUTTONDOWN, SDL_ENABLE);
460: SDL_EventState(SDL_MOUSEBUTTONUP, SDL_ENABLE);
461: SDL_ShowCursor(SDL_DISABLE);
1.1 root 462: }
463:
1.1.1.2 root 464:
1.1 root 465: /*-----------------------------------------------------------------------*/
1.1.1.13 root 466: /**
467: * Free screen bitmap and allocated resources
468: */
1.1 root 469: void Screen_UnInit(void)
470: {
1.1.1.13 root 471: int i;
1.1 root 472:
1.1.1.13 root 473: /* Free memory used for copies */
474: for (i = 0; i < NUM_FRAMEBUFFERS; i++)
475: {
476: free(FrameBuffers[i].pSTScreen);
477: free(FrameBuffers[i].pSTScreenCopy);
478: }
1.1 root 479: }
480:
1.1.1.2 root 481:
1.1 root 482: /*-----------------------------------------------------------------------*/
1.1.1.13 root 483: /**
484: * Reset screen
485: */
1.1 root 486: void Screen_Reset(void)
487: {
1.1.1.13 root 488: /* On re-boot, always correct ST resolution for monitor, eg Colour/Mono */
489: if (bUseVDIRes)
490: {
491: STRes = VDIRes;
492: }
493: else
494: {
495: if (bUseHighRes)
496: {
497: STRes = ST_HIGH_RES;
498: TTRes = TT_HIGH_RES;
499: }
500: else
501: {
502: STRes = ST_LOW_RES;
503: TTRes = TT_MEDIUM_RES;
504: }
505: }
506: /* Cause full update */
507: Screen_ModeChanged();
1.1 root 508: }
509:
510:
511: /*-----------------------------------------------------------------------*/
1.1.1.13 root 512: /**
513: * Set flags so screen will be TOTALLY re-drawn (clears whole of full-screen)
514: * next time around
515: */
1.1 root 516: void Screen_SetFullUpdate(void)
517: {
1.1.1.13 root 518: int i;
1.1 root 519:
1.1.1.13 root 520: /* Update frame buffers */
521: for (i = 0; i < NUM_FRAMEBUFFERS; i++)
522: FrameBuffers[i].bFullUpdate = TRUE;
1.1 root 523: }
524:
1.1.1.5 root 525:
1.1 root 526: /*-----------------------------------------------------------------------*/
1.1.1.13 root 527: /**
528: * Clear Window display memory
529: */
1.1.1.11 root 530: static void Screen_ClearScreen(void)
531: {
1.1.1.13 root 532: SDL_FillRect(sdlscrn,NULL, SDL_MapRGB(sdlscrn->format, 0, 0, 0) );
1.1.1.11 root 533: }
534:
535: /*-----------------------------------------------------------------------*/
1.1.1.13 root 536: /**
537: * Enter Full screen mode
538: */
1.1 root 539: void Screen_EnterFullScreen(void)
540: {
1.1.1.13 root 541: if (!bInFullScreen)
542: {
543: Main_PauseEmulation(); /* Hold things... */
544: bInFullScreen = TRUE;
1.1.1.2 root 545:
1.1.1.13 root 546: if ((ConfigureParams.System.nMachineType == MACHINE_FALCON
547: || ConfigureParams.System.nMachineType == MACHINE_TT) && !bUseVDIRes)
548: {
549: HostScreen_toggleFullScreen();
550: }
551: else
552: {
553: Screen_SetResolution();
554: Screen_ClearScreen(); /* Black out screen bitmap as will be invalid when return */
555: }
1.1 root 556:
1.1.1.13 root 557: SDL_Delay(20); /* To give monitor time to change to new resolution */
558: Main_UnPauseEmulation(); /* And off we go... */
1.1.1.2 root 559:
1.1.1.13 root 560: SDL_WM_GrabInput(SDL_GRAB_ON); /* Grab mouse pointer in fullscreen */
561: }
1.1 root 562: }
563:
1.1.1.2 root 564:
1.1 root 565: /*-----------------------------------------------------------------------*/
1.1.1.13 root 566: /**
567: * Return from Full screen mode back to a window
568: */
1.1 root 569: void Screen_ReturnFromFullScreen(void)
570: {
1.1.1.13 root 571: if (bInFullScreen)
572: {
573: Main_PauseEmulation(); /* Hold things... */
574: bInFullScreen = FALSE;
575:
576: if ((ConfigureParams.System.nMachineType == MACHINE_FALCON
577: || ConfigureParams.System.nMachineType == MACHINE_TT) && !bUseVDIRes)
578: {
579: HostScreen_toggleFullScreen();
580: if (!bGrabMouse)
581: SDL_WM_GrabInput(SDL_GRAB_OFF); /* Un-grab mouse pointer in windowed mode */
582: }
583: else
584: {
585: Screen_SetResolution();
586: }
587:
588: SDL_Delay(20); /* To give monitor time to switch resolution */
589: Main_UnPauseEmulation(); /* And off we go... */
590: }
591: }
1.1.1.2 root 592:
593:
1.1.1.13 root 594: /*-----------------------------------------------------------------------*/
595: /**
596: * Have we changed between low/med/high res?
597: */
598: static void Screen_DidResolutionChange(int new_res)
599: {
600: if (new_res != STRes)
601: {
602: STRes = new_res;
603: Screen_ModeChanged();
604: }
605: else
606: {
607: /* Did change overscan mode? Causes full update */
608: if (pFrameBuffer->OverscanModeCopy != OverscanMode)
609: pFrameBuffer->bFullUpdate = TRUE;
610: }
1.1 root 611: }
612:
1.1.1.5 root 613:
1.1.1.2 root 614: /*-----------------------------------------------------------------------*/
1.1.1.13 root 615: /**
616: * Force things associated with changing between low/medium/high res.
617: */
618: void Screen_ModeChanged(void)
1.1 root 619: {
1.1.1.13 root 620: if (!sdlscrn)
621: {
622: /* screen not yet initialized */
623: return;
624: }
625: /* Don't run this function if Videl emulation is running! */
626: if (ConfigureParams.System.nMachineType == MACHINE_FALCON && !bUseVDIRes)
627: {
628: VIDEL_ZoomModeChanged();
629: return;
630: }
631: else if (ConfigureParams.System.nMachineType == MACHINE_TT && !bUseVDIRes)
632: {
633: int width, height, bpp;
634: Video_GetTTRes(&width, &height, &bpp);
635: HostScreen_setWindowSize(width, height, 8);
636: return;
637: }
638: /* Set new display mode, if differs from current */
639: Screen_SetResolution();
640: Screen_SetFullUpdate();
1.1 root 641: }
642:
1.1.1.2 root 643:
644: /*-----------------------------------------------------------------------*/
1.1.1.13 root 645: /**
646: * Compare current resolution on line with previous, and set 'UpdateLine' accordingly
647: * Return if swap between low/medium resolution
648: */
649: static BOOL Screen_CompareResolution(int y, int *pUpdateLine, int oldres)
1.1 root 650: {
1.1.1.13 root 651: /* Check if wrote to resolution register */
652: if (HBLPaletteMasks[y]&PALETTEMASK_RESOLUTION) /* See 'Intercept_ShifterMode_WriteByte' */
653: {
654: int newres = (HBLPaletteMasks[y]>>16)&ST_MEDIUM_RES_BIT;
655: /* Did resolution change? */
656: if (newres != (int)((pFrameBuffer->HBLPaletteMasks[y]>>16)&ST_MEDIUM_RES_BIT))
657: *pUpdateLine |= PALETTEMASK_UPDATERES;
658: else
659: *pUpdateLine &= ~PALETTEMASK_UPDATERES;
660: /* Have used any low/medium res mix? */
661: return (newres != (oldres&ST_MEDIUM_RES_BIT));
662: }
663: return FALSE;
1.1 root 664: }
665:
1.1.1.7 root 666:
1.1.1.2 root 667: /*-----------------------------------------------------------------------*/
1.1.1.13 root 668: /**
669: * Check to see if palette changes cause screen update and keep 'HBLPalette[]' up-to-date
670: */
1.1.1.8 root 671: static void Screen_ComparePalette(int y, int *pUpdateLine)
1.1 root 672: {
1.1.1.13 root 673: BOOL bPaletteChanged = FALSE;
674: int i;
1.1 root 675:
1.1.1.13 root 676: /* Did write to palette in this or previous frame? */
677: if (((HBLPaletteMasks[y]|pFrameBuffer->HBLPaletteMasks[y])&PALETTEMASK_PALETTE)!=0)
678: {
679: /* Check and update ones which changed */
680: for (i = 0; i < 16; i++)
681: {
682: if (HBLPaletteMasks[y]&(1<<i)) /* Update changes in ST palette */
683: HBLPalette[i] = HBLPalettes[(y*16)+i];
684: }
685: /* Now check with same palette from previous frame for any differences(may be changing palette back) */
686: for (i = 0; (i < 16) && (!bPaletteChanged); i++)
687: {
688: if (HBLPalette[i]!=pFrameBuffer->HBLPalettes[(y*16)+i])
689: bPaletteChanged = TRUE;
690: }
691: if (bPaletteChanged)
692: *pUpdateLine |= PALETTEMASK_UPDATEPAL;
693: else
694: *pUpdateLine &= ~PALETTEMASK_UPDATEPAL;
695: }
1.1 root 696: }
697:
1.1.1.7 root 698:
1.1.1.2 root 699: /*-----------------------------------------------------------------------*/
1.1.1.13 root 700: /**
701: * Check for differences in Palette and Resolution from Mask table and update
702: * and store off which lines need updating and create full-screen palette.
703: * (It is very important for these routines to check for colour changes with
704: * the previous screen so only the very minimum parts are updated).
705: * Return new STRes value.
706: */
707: static int Screen_ComparePaletteMask(int res)
1.1 root 708: {
1.1.1.13 root 709: BOOL bLowMedMix = FALSE;
710: int LineUpdate = 0;
711: int y;
712:
713: /* Set for monochrome? */
714: if (bUseHighRes)
715: {
716: OverscanMode = OVERSCANMODE_NONE;
717:
718: /* Just copy mono colours, 0x777 checked also in convert/vdi2.c */
719: if (HBLPalettes[0] & 0x777)
720: {
721: HBLPalettes[0] = 0x777;
722: HBLPalettes[1] = 0x000;
723: }
724: else
725: {
726: HBLPalettes[0] = 0x000;
727: HBLPalettes[1] = 0x777;
728: }
729:
730: /* Colors changed? */
731: if (HBLPalettes[0] != PrevHBLPalette[0])
732: pFrameBuffer->bFullUpdate = TRUE;
733:
734: /* Set bit to flag 'full update' */
735: if (pFrameBuffer->bFullUpdate)
736: ScrUpdateFlag = PALETTEMASK_UPDATEFULL;
737: else
738: ScrUpdateFlag = 0x00000000;
739: }
740:
741: /* Use VDI resolution? */
742: if (bUseVDIRes)
743: {
744: /* Force to VDI resolution screen, without overscan */
745: res = VDIRes;
746:
747: /* Colors changed? */
748: if (HBLPalettes[0] != PrevHBLPalette[0])
749: pFrameBuffer->bFullUpdate = TRUE;
750:
751: /* Set bit to flag 'full update' */
752: if (pFrameBuffer->bFullUpdate)
753: ScrUpdateFlag = PALETTEMASK_UPDATEFULL;
754: else
755: ScrUpdateFlag = 0x00000000;
756: }
757: /* Are in Mono? Force to monochrome and no overscan */
758: else if (bUseHighRes)
759: {
760: /* Force to standard hi-resolution screen, without overscan */
761: res = ST_HIGH_RES;
762: }
763: else /* Full colour */
764: {
765: /* Get resolution */
766: //res = (HBLPaletteMasks[0]>>16)&ST_RES_MASK;
767: /* [NP] keep only low/med bit (could be hires in case of overscan on the 1st line) */
768: res = (HBLPaletteMasks[0]>>16)&ST_MEDIUM_RES_BIT;
769:
770: /* Do all lines - first is tagged as full-update */
771: for (y = 0; y < NUM_VISIBLE_LINES; y++)
772: {
773: /* Find any resolution/palette change and update palette/mask buffer */
774: /* ( LineUpdate has top two bits set to say if line needs updating due to palette or resolution change ) */
775: bLowMedMix |= Screen_CompareResolution(y, &LineUpdate, res);
776: Screen_ComparePalette(y,&LineUpdate);
777: HBLPaletteMasks[y] = (HBLPaletteMasks[y]&(~PALETTEMASK_UPDATEMASK)) | LineUpdate;
778: /* Copy palette and mask for next frame */
779: memcpy(&pFrameBuffer->HBLPalettes[y*16],HBLPalette,sizeof(short int)*16);
780: pFrameBuffer->HBLPaletteMasks[y] = HBLPaletteMasks[y];
781: }
782: /* Did mix/have medium resolution? */
783: if (bLowMedMix || (res & ST_MEDIUM_RES_BIT))
784: res = ST_MEDIUM_RES;
785: }
786:
787: return res;
788: }
789:
790:
791: /*-----------------------------------------------------------------------*/
792: /**
793: * Update Palette Mask to show 'full-update' required. This is usually done after a resolution change
794: * or when going between a Window and full-screen display
795: */
1.1.1.8 root 796: static void Screen_SetFullUpdateMask(void)
1.1 root 797: {
1.1.1.13 root 798: int y;
1.1 root 799:
1.1.1.13 root 800: for (y = 0; y < NUM_VISIBLE_LINES; y++)
801: HBLPaletteMasks[y] |= PALETTEMASK_UPDATEFULL;
1.1 root 802: }
803:
1.1.1.7 root 804:
1.1.1.2 root 805: /*-----------------------------------------------------------------------*/
1.1.1.13 root 806: /**
807: * Set details for ST screen conversion.
808: */
1.1.1.10 root 809: static void Screen_SetConvertDetails(void)
1.1 root 810: {
1.1.1.13 root 811: pSTScreen = pFrameBuffer->pSTScreen; /* Source in ST memory */
812: pSTScreenCopy = pFrameBuffer->pSTScreenCopy; /* Previous ST screen */
813: pPCScreenDest = sdlscrn->pixels; /* Destination PC screen */
814:
815: PCScreenBytesPerLine = sdlscrn->pitch; /* Bytes per line */
816: pHBLPalettes = pFrameBuffer->HBLPalettes; /* HBL palettes pointer */
817: /* Not in TV-Mode? Then double up on Y: */
818: bScrDoubleY = !(ConfigureParams.Screen.MonitorType == MONITOR_TYPE_TV);
819:
820: if (bUseVDIRes)
821: {
822: /* Select screen draw for standard or VDI display */
823: STScreenLeftSkipBytes = 0;
824: STScreenWidthBytes = VDIWidth * VDIPlanes / 8;
825: STScreenStartHorizLine = 0;
826: STScreenEndHorizLine = VDIHeight;
827: }
828: else
829: {
830: if (ConfigureParams.Screen.bAllowOverscan) /* Use borders? */
831: {
832: /* Always draw to WHOLE screen including ALL borders */
833: STScreenLeftSkipBytes = 0; /* Number of bytes to skip on ST screen for left (border) */
834: STScreenStartHorizLine = 0; /* Full height */
835:
836: if (bUseHighRes)
837: {
838: pFrameBuffer->OverscanModeCopy = OverscanMode = OVERSCANMODE_NONE;
839: STScreenEndHorizLine = 400;
840: }
841: else
842: {
843: STScreenWidthBytes = SCREENBYTES_LINE; /* Number of horizontal bytes in our ST screen */
844: STScreenEndHorizLine = NUM_VISIBLE_LINES;
845: }
846: }
847: else
848: {
849: /* Only draw main area and centre on Y */
850: STScreenLeftSkipBytes = SCREENBYTES_LEFT;
851: STScreenWidthBytes = SCREENBYTES_MIDDLE;
852: STScreenStartHorizLine = OVERSCAN_TOP;
853: STScreenEndHorizLine = OVERSCAN_TOP + (bUseHighRes ? 400 : 200);
854: }
855: }
1.1 root 856: }
857:
1.1.1.2 root 858:
859: /*-----------------------------------------------------------------------*/
1.1.1.13 root 860: /**
861: * Lock full-screen for drawing
862: */
1.1.1.8 root 863: static BOOL Screen_Lock(void)
1.1 root 864: {
1.1.1.13 root 865: if (SDL_MUSTLOCK(sdlscrn))
866: {
867: if (SDL_LockSurface(sdlscrn))
868: {
869: Screen_ReturnFromFullScreen(); /* All OK? If not need to jump back to a window */
870: return(FALSE);
871: }
872: }
1.1.1.2 root 873:
1.1.1.13 root 874: return TRUE;
1.1 root 875: }
876:
1.1.1.2 root 877: /*-----------------------------------------------------------------------*/
1.1.1.13 root 878: /**
879: * UnLock full-screen
880: */
1.1.1.8 root 881: static void Screen_UnLock(void)
1.1 root 882: {
1.1.1.13 root 883: if ( SDL_MUSTLOCK(sdlscrn) )
884: SDL_UnlockSurface(sdlscrn);
1.1 root 885: }
886:
1.1.1.2 root 887:
888: /*-----------------------------------------------------------------------*/
1.1.1.13 root 889: /**
890: * Swap ST Buffers, used for full-screen where have double-buffering
891: */
1.1.1.11 root 892: static void Screen_SwapSTBuffers(void)
893: {
894: #if NUM_FRAMEBUFFERS > 1
1.1.1.13 root 895: if (sdlscrn->flags & SDL_DOUBLEBUF)
896: {
897: if (pFrameBuffer==&FrameBuffers[0])
898: pFrameBuffer = &FrameBuffers[1];
899: else
900: pFrameBuffer = &FrameBuffers[0];
901: }
1.1.1.11 root 902: #endif
903: }
904:
905:
906: /*-----------------------------------------------------------------------*/
1.1.1.13 root 907: /**
908: * Blit our converted ST screen to window/full-screen
909: * Note that our source image includes all borders so if have them disabled simply blit a smaller source rectangle!
910: */
1.1.1.11 root 911: static void Screen_Blit(BOOL bSwapScreen)
1.1 root 912: {
1.1.1.13 root 913: unsigned char *pTmpScreen;
914:
915: /* Blit to full screen or window? */
916: if (bInFullScreen)
917: {
918: Screen_SwapSTBuffers();
919: /* Swap screen */
920: if (bSwapScreen)
921: SDL_Flip(sdlscrn);
922: }
923: else
924: {
925: /* Blit image */
926: SDL_UpdateRect(sdlscrn, 0,0,0,0);
927: }
928:
929: /* Swap copy/raster buffers in screen. */
930: pTmpScreen = pFrameBuffer->pSTScreenCopy;
931: pFrameBuffer->pSTScreenCopy = pFrameBuffer->pSTScreen;
932: pFrameBuffer->pSTScreen = pTmpScreen;
1.1 root 933: }
934:
1.1.1.3 root 935:
1.1.1.2 root 936: /*-----------------------------------------------------------------------*/
1.1.1.13 root 937: /**
938: * Draw ST screen to window/full-screen framebuffer
939: */
1.1.1.11 root 940: static void Screen_DrawFrame(BOOL bForceFlip)
1.1 root 941: {
1.1.1.13 root 942: int new_res;
943: void (*pDrawFunction)(void);
944: static BOOL bPrevFrameWasSpec512 = FALSE;
945:
946: /* Scan palette/resolution masks for each line and build up palette/difference tables */
947: new_res = Screen_ComparePaletteMask(STRes);
948: /* Do require palette? Check if changed and update */
949: Screen_Handle8BitPalettes();
950: /* Did we change resolution this frame - allocate new screen if did so */
951: Screen_DidResolutionChange(new_res);
952: /* Is need full-update, tag as such */
953: if (pFrameBuffer->bFullUpdate)
954: Screen_SetFullUpdateMask();
955:
956: /* Lock screen ready for drawing */
957: if (Screen_Lock())
958: {
959: bScreenContentsChanged = FALSE; /* Did change (ie needs blit?) */
960: /* Set details */
961: Screen_SetConvertDetails();
962: /* Clear screen on full update to clear out borders and also interleaved lines */
963: if (pFrameBuffer->bFullUpdate && !bUseVDIRes)
964: Screen_ClearScreen();
965: /* Call drawing for full-screen */
966: if (bUseVDIRes)
967: {
968: pDrawFunction = ScreenDrawFunctionsVDI[VDIRes];
969: }
970: else
971: {
972: pDrawFunction = ScreenDrawFunctionsNormal[STRes];
973: /* Check if is Spec512 image */
974: if (Spec512_IsImage())
975: {
976: bPrevFrameWasSpec512 = TRUE;
977: /* What mode were we in? Keep to 320xH or 640xH */
978: if (pDrawFunction==ConvertLowRes_320x16Bit)
979: pDrawFunction = ConvertSpec512_320x16Bit;
980: else if (pDrawFunction==ConvertLowRes_640x16Bit)
981: pDrawFunction = ConvertSpec512_640x16Bit;
982: else if (pDrawFunction==ConvertLowRes_320x32Bit)
983: pDrawFunction = ConvertSpec512_320x32Bit;
984: else if (pDrawFunction==ConvertLowRes_640x32Bit)
985: pDrawFunction = ConvertSpec512_640x32Bit;
986: }
987: else if (bPrevFrameWasSpec512)
988: {
989: /* If we switch back from Spec512 mode to normal
990: * screen rendering, we have to make sure to do
991: * a full update of the screen. */
992: Screen_SetFullUpdateMask();
993: bPrevFrameWasSpec512 = FALSE;
994: }
995: }
996:
997: if (pDrawFunction)
998: CALL_VAR(pDrawFunction)
999:
1000: /* Unlock screen */
1001: Screen_UnLock();
1002: /* Clear flags, remember type of overscan as if change need screen full update */
1003: pFrameBuffer->bFullUpdate = FALSE;
1004: pFrameBuffer->OverscanModeCopy = OverscanMode;
1005:
1006: /* And show to user */
1007: if (bScreenContentsChanged || bForceFlip)
1008: Screen_Blit(TRUE);
1009:
1010: /* Grab any animation */
1011: if (bRecordingAnimation)
1012: ScreenSnapShot_RecordFrame(bScreenContentsChanged);
1013: }
1.1 root 1014: }
1015:
1.1.1.9 root 1016:
1.1.1.2 root 1017: /*-----------------------------------------------------------------------*/
1.1.1.13 root 1018: /**
1019: * Draw ST screen to window/full-screen
1020: */
1.1 root 1021: void Screen_Draw(void)
1022: {
1.1.1.13 root 1023: if (!bQuitProgram && VideoBase)
1024: {
1025: /* And draw (if screen contents changed) */
1026: Screen_DrawFrame(FALSE);
1027: }
1.1 root 1028: }
1.1.1.11 root 1029:
1030:
1031: /* -------------- screen conversion routines --------------------------------
1032: Screen conversion routines. We have a number of routines to convert ST screen
1033: to PC format. We split these into Low, Medium and High each with 8/16-bit
1034: versions. To gain extra speed, as almost half of the processing time can be
1035: spent in these routines, we check for any changes from the previously
1036: displayed frame. AdjustLinePaletteRemap() sets a flag to tell the routines
1037: if we need to totally update a line (ie full update, or palette/res change)
1038: or if we just can do a difference check.
1039: We convert each screen 16 pixels at a time by use of a couple of look-up
1040: tables. These tables convert from 2-plane format to bbp and then we can add
1041: two of these together to get 4-planes. This keeps the tables small and thus
1042: improves speed. We then look these bbp values up as an RGB/Index value to
1043: copy to the screen.
1044: */
1045:
1046:
1.1.1.13 root 1047: /*-----------------------------------------------------------------------*/
1048: /**
1.1.1.11 root 1049: * Update the STRGBPalette[] array with current colours for this raster line.
1050: *
1051: * Return 'ScrUpdateFlag', 0x80000000=Full update, 0x40000000=Update
1052: * as palette changed
1053: */
1054: static int AdjustLinePaletteRemap(int y)
1055: {
1056: #if SDL_BYTEORDER == SDL_BIG_ENDIAN
1.1.1.13 root 1057: 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 1058: #endif
1.1.1.13 root 1059: Uint16 *actHBLPal;
1060: int i;
1.1.1.11 root 1061:
1.1.1.13 root 1062: /* Copy palette and convert to RGB in display format */
1063: actHBLPal = pHBLPalettes + (y<<4); /* offset in palette */
1064: for (i=0; i<16; i++)
1065: {
1.1.1.11 root 1066: #if SDL_BYTEORDER == SDL_BIG_ENDIAN
1.1.1.13 root 1067: STRGBPalette[endiantable[i]] = ST2RGB[*actHBLPal++];
1.1.1.11 root 1068: #else
1.1.1.13 root 1069: STRGBPalette[i] = ST2RGB[*actHBLPal++];
1.1.1.11 root 1070: #endif
1.1.1.13 root 1071: }
1072: ScrUpdateFlag = HBLPaletteMasks[y];
1073: return ScrUpdateFlag;
1.1.1.11 root 1074: }
1075:
1076:
1.1.1.13 root 1077: /*-----------------------------------------------------------------------*/
1078: /**
1.1.1.11 root 1079: * Run updates to palette(STRGBPalette[]) until get to screen line
1080: * we are to convert from
1081: */
1082: static void Convert_StartFrame(void)
1083: {
1.1.1.13 root 1084: int y = 0;
1085: /* Get #lines before conversion starts */
1086: int lines = STScreenStartHorizLine;
1087: while (lines--)
1088: AdjustLinePaletteRemap(y++); /* Update palette */
1.1.1.11 root 1089: }
1090:
1091: /* lookup tables and conversion macros */
1092: #include "convert/macros.h"
1093:
1094: /* Conversion routines */
1.1.1.13 root 1095:
1096: #include "convert/low320x8.c" /* LowRes To 320xH x 8-bit color */
1097: #include "convert/low640x8.c" /* LowRes To 640xH x 8-bit color */
1098: #include "convert/med640x8.c" /* MediumRes To 640xH x 8-bit color */
1099: #include "convert/high640x8.c" /* HighRes To 640xH x 8-bit color */
1100:
1101: #include "convert/low320x16.c" /* LowRes To 320xH x 16-bit color */
1102: #include "convert/low640x16.c" /* LowRes To 640xH x 16-bit color */
1103: #include "convert/med640x16.c" /* MediumRes To 640xH x 16-bit color */
1104: #include "convert/spec320x16.c" /* Spectrum 512 To 320xH x 16-bit color */
1105: #include "convert/spec640x16.c" /* Spectrum 512 To 640xH x 16-bit color */
1106:
1107: #include "convert/low320x32.c" /* LowRes To 320xH x 32-bit color */
1108: #include "convert/low640x32.c" /* LowRes To 640xH x 32-bit color */
1109: #include "convert/med640x32.c" /* MediumRes To 640xH x 32-bit color */
1110: #include "convert/spec320x32.c" /* Spectrum 512 To 320xH x 32-bit color */
1111: #include "convert/spec640x32.c" /* Spectrum 512 To 640xH x 32-bit color */
1112:
1113: #include "convert/vdi16.c" /* VDI x 16 color */
1114: #include "convert/vdi4.c" /* VDI x 4 color */
1115: #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.