|
|
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: 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: 1.1.1.21! root 383: Resolution_GetLimits(&maxW, &maxH, &BitCount, ConfigureParams.Screen.bKeepResolutionST); 1.1.1.18 root 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 1.1.1.21! root 505: Screen_SetupRGBTable(); /* Create color conversion table */ 1.1.1.13 root 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: { 1.1.1.21! root 539: FrameBuffers[i].pSTScreen = malloc(MAX_VDI_BYTES); ! 540: FrameBuffers[i].pSTScreenCopy = malloc(MAX_VDI_BYTES); 1.1.1.13 root 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.