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