|
|
1.1 root 1: /*
1.1.1.6 root 2: Hatari - screen.c
1.1 root 3:
1.1.1.6 root 4: This file is distributed under the GNU Public License, version 2 or at your
5: option any later version. Read the file gpl.txt for details.
6:
7: This code converts a 1/2/4 plane ST format screen to either 8 or 16-bit PC
8: format. An awful lost of processing is needed to do this conversion - we
9: cannot simply change palettes on interrupts as it is possible with DOS.
10: The main code processes the palette/resolution mask tables to find exactly
11: which lines need to updating and the conversion routines themselves only
12: update 16-pixel blocks which differ from the previous frame - this gives a
13: large performance increase.
14: Each conversion routine can convert any part of the source ST screen (which
15: includes the overscan border, usually set to colour zero) so they can be used
16: for both window and full-screen mode.
17: Note that in Hi-Resolution we have no overscan and just two colors so we can
18: optimise things further. Also when running in maximum speed we make sure we
19: only convert the screen every 50 times a second - inbetween frames are not
20: processed.
1.1 root 21: */
1.1.1.10! root 22: char Screen_rcsid[] = "Hatari $Id: screen.c,v 1.39 2005/03/07 23:15:49 thothy Exp $";
1.1 root 23:
24: #include <SDL.h>
25:
26: #include "main.h"
1.1.1.7 root 27: #include "configuration.h"
1.1 root 28: #include "ikbd.h"
29: #include "m68000.h"
30: #include "misc.h"
31: #include "printer.h"
32: #include "screen.h"
33: #include "screenConvert.h"
34: #include "screenSnapShot.h"
35: #include "sound.h"
36: #include "spec512.h"
37: #include "vdi.h"
38: #include "video.h"
39:
40:
41: FRAMEBUFFER FrameBuffers[NUM_FRAMEBUFFERS]; /* Store frame buffer details to tell how to update */
42: FRAMEBUFFER *pFrameBuffer; /* Pointer into current 'FrameBuffer' */
43: unsigned char *pSTScreen,*pSTScreenCopy; /* Keep track of current and previous ST screen data */
44: unsigned char *pPCScreenDest; /* Destination PC buffer */
45: int STScreenStartHorizLine,STScreenEndHorizLine; /* Start/End lines to be converted */
1.1.1.5 root 46: int PCScreenBytesPerLine, STScreenWidthBytes, STScreenLeftSkipBytes;
1.1 root 47: BOOL bInFullScreen=FALSE; /* TRUE if in full screen */
48: BOOL bScreenContentsChanged; /* TRUE if buffer changed and requires blitting */
1.1.1.2 root 49: int STRes=ST_LOW_RES, PrevSTRes=ST_LOW_RES; /* Current and previous ST resolutions */
1.1 root 50:
51: int STScreenLineOffset[NUM_VISIBLE_LINES]; /* Offsets for ST screen lines eg, 0,160,320... */
52: unsigned long STRGBPalette[16]; /* Palette buffer used in assembler conversion routines */
53: unsigned long ST2RGB[2048]; /* Table to convert ST Palette 0x777 to PC format RGB551(2 pixels each entry) */
54: unsigned short int HBLPalette[16], PrevHBLPalette[16]; /* Current palette for line, also copy of first line */
55:
1.1.1.3 root 56: SDL_Surface *sdlscrn; /* The SDL screen surface */
1.1.1.5 root 57: BOOL bGrabMouse = FALSE; /* Grab the mouse cursor in the window */
1.1 root 58:
1.1.1.10! root 59: void *ScreenDrawFunctionsNormal[4]; /* Screen draw functions */
! 60: void *ScreenDrawFunctionsVDI[3] =
! 61: {
! 62: ConvertVDIRes_16Colour,
! 63: ConvertVDIRes_4Colour,
! 64: ConvertVDIRes_2Colour
! 65: };
! 66:
! 67:
! 68: /*-----------------------------------------------------------------------*/
! 69: /*
! 70: Create ST 777 colour format to 16-bits per pixel.
! 71: Called each time when changed resolution or to/from fullscreen mode.
! 72: */
! 73: static void Screen_SetupRGBTable(void)
! 74: {
! 75: unsigned int STColour, RGBColour;
! 76: unsigned int r, g, b;
! 77:
! 78: /* Do Red,Green and Blue for all 512 ST colours */
! 79: for(r=0; r<8; r++)
! 80: {
! 81: for(g=0; g<8; g++)
! 82: {
! 83: for(b=0; b<8; b++)
! 84: {
! 85: STColour = (r<<8) | (g<<4) | (b); /* ST format 0x777 */
! 86: RGBColour = SDL_MapRGB(sdlscrn->format, (r<<5), (g<<5), (b<<5));
! 87: ST2RGB[STColour] = (RGBColour<<16) | RGBColour; /* As longs, for speed (write two pixels at once) */
! 88: }
! 89: }
! 90: }
! 91: }
! 92:
! 93:
! 94: /*-----------------------------------------------------------------------*/
! 95: /*
! 96: Create new palette for display.
! 97: */
! 98: static void Screen_CreatePalette(void)
! 99: {
! 100: #if SDL_BYTEORDER == SDL_BIG_ENDIAN
! 101: static const int endiantable[16] = {0,2,1,3,8,10,9,11,4,6,5,7,12,14,13,15};
! 102: #endif
! 103: SDL_Color sdlColors[16];
! 104: int i, j;
! 105:
! 106: if (bUseHighRes)
! 107: {
! 108: /* Colors for monochrome screen mode emulation */
! 109: if (HBLPalettes[0])
! 110: {
! 111: sdlColors[0].r = sdlColors[0].g = sdlColors[0].b = 255;
! 112: sdlColors[1].r = sdlColors[1].g = sdlColors[1].b = 0;
! 113: }
! 114: else
! 115: {
! 116: sdlColors[0].r = sdlColors[0].g = sdlColors[0].b = 0;
! 117: sdlColors[1].r = sdlColors[1].g = sdlColors[1].b = 255;
! 118: }
! 119: SDL_SetColors(sdlscrn, sdlColors, 10, 2);
! 120: /*SDL_SetColors(sdlscrn, sdlColors, 0, 2);*/
! 121: }
! 122: else
! 123: {
! 124: /* Colors for color screen mode emulation */
! 125: for (i=0; i<16; i++)
! 126: {
! 127: #if SDL_BYTEORDER == SDL_BIG_ENDIAN
! 128: j = endiantable[i];
! 129: #else
! 130: j = i;
! 131: #endif
! 132: sdlColors[j].r = ((HBLPalettes[i]>>8)&0x7)<<5;
! 133: sdlColors[j].g = ((HBLPalettes[i]>>4)&0x7)<<5;
! 134: sdlColors[j].b = (HBLPalettes[i]&0x7)<<5;
! 135: }
! 136: SDL_SetColors(sdlscrn, sdlColors, 10, 16);
! 137: }
! 138: }
! 139:
! 140:
! 141: /*-----------------------------------------------------------------------*/
! 142: /*
! 143: Create 8-Bit palette for display if needed.
! 144: */
! 145: static void Screen_Handle8BitPalettes(void)
! 146: {
! 147: BOOL bPaletteChanged=FALSE;
! 148: int i;
! 149:
! 150: /* Do need to check for 8-Bit palette change? Ie, update whole screen */
! 151: /* VDI screens and monochrome modes are ALL 8-Bit at the moment! */
! 152: if (sdlscrn->format->BitsPerPixel == 8)
! 153: {
! 154: /* If using HiRes palette update with full update flag */
! 155: if (!bUseHighRes)
! 156: {
! 157: /* Check if palette of 16 colours changed from previous frame */
! 158: for (i=0; i<16 && !bPaletteChanged; i++)
! 159: {
! 160: /* Check with first line palette(stored in 'Screen_ComparePaletteMask') */
! 161: if (HBLPalettes[i] != PrevHBLPalette[i])
! 162: bPaletteChanged = TRUE;
! 163: }
! 164: }
! 165:
! 166: /* Did palette change or do we require a full update? */
! 167: if (bPaletteChanged || pFrameBuffer->bFullUpdate)
! 168: {
! 169: /* Create palette, for Full-Screen of Window */
! 170: Screen_CreatePalette();
! 171: /* Make sure update whole screen */
! 172: pFrameBuffer->bFullUpdate = TRUE;
! 173: }
! 174: }
! 175:
! 176: /* Copy old palette for 8-Bit compare as this routine writes over it */
! 177: memcpy(PrevHBLPalette,HBLPalettes, sizeof(short int)*16);
! 178: }
! 179:
1.1 root 180:
181: /*-----------------------------------------------------------------------*/
182: /*
1.1.1.10! root 183: Set screen draw functions.
1.1.1.7 root 184: */
1.1.1.10! root 185: static void Screen_SetDrawFunctions(void)
! 186: {
! 187: switch (ConfigureParams.Screen.ChosenDisplayMode)
! 188: {
! 189: case DISPLAYMODE_LOWCOL_LOWRES: /* low color, low resolution */
! 190: ScreenDrawFunctionsNormal[ST_LOW_RES] = ConvertLowRes_320x8Bit;
! 191: ScreenDrawFunctionsNormal[ST_MEDIUM_RES] = ConvertMediumRes_640x8Bit;
! 192: ScreenDrawFunctionsNormal[ST_HIGH_RES] = ConvertHighRes_640x8Bit;
! 193: ScreenDrawFunctionsNormal[ST_LOWMEDIUM_MIX_RES] = ConvertMediumRes_640x8Bit;
! 194: break;
! 195: case DISPLAYMODE_LOWCOL_HIGHRES: /* low color, zoomed resolution */
! 196: ScreenDrawFunctionsNormal[ST_LOW_RES] = ConvertLowRes_640x8Bit;
! 197: ScreenDrawFunctionsNormal[ST_MEDIUM_RES] = ConvertMediumRes_640x8Bit;
! 198: ScreenDrawFunctionsNormal[ST_HIGH_RES] = ConvertHighRes_640x8Bit;
! 199: ScreenDrawFunctionsNormal[ST_LOWMEDIUM_MIX_RES] = ConvertMediumRes_640x8Bit;
! 200: break;
! 201: case DISPLAYMODE_HICOL_LOWRES: /* high color, low resolution */
! 202: ScreenDrawFunctionsNormal[ST_LOW_RES] = ConvertLowRes_320x16Bit;
! 203: ScreenDrawFunctionsNormal[ST_MEDIUM_RES] = ConvertMediumRes_640x16Bit;
! 204: ScreenDrawFunctionsNormal[ST_HIGH_RES] = ConvertHighRes_640x8Bit;
! 205: ScreenDrawFunctionsNormal[ST_LOWMEDIUM_MIX_RES] = ConvertMediumRes_640x16Bit;
! 206: break;
! 207: case DISPLAYMODE_HICOL_HIGHRES: /* high color, zoomed resolution */
! 208: ScreenDrawFunctionsNormal[ST_LOW_RES] = ConvertLowRes_640x16Bit;
! 209: ScreenDrawFunctionsNormal[ST_MEDIUM_RES] = ConvertMediumRes_640x16Bit;
! 210: ScreenDrawFunctionsNormal[ST_HIGH_RES] = ConvertHighRes_640x8Bit;
! 211: ScreenDrawFunctionsNormal[ST_LOWMEDIUM_MIX_RES] = ConvertMediumRes_640x16Bit;
! 212: break;
! 213: default:
! 214: fprintf(stderr, "Illegal display mode: %i\n", ConfigureParams.Screen.ChosenDisplayMode);
! 215: ScreenDrawFunctionsNormal[ST_LOW_RES] = NULL;
! 216: ScreenDrawFunctionsNormal[ST_MEDIUM_RES] = NULL;
! 217: ScreenDrawFunctionsNormal[ST_HIGH_RES] = NULL;
! 218: ScreenDrawFunctionsNormal[ST_LOWMEDIUM_MIX_RES] = NULL;
! 219: break;
! 220: }
! 221: }
! 222:
! 223:
! 224: /*-----------------------------------------------------------------------*/
! 225: /*
! 226: Initialize SDL screen surface / set resolution.
! 227: */
! 228: static void Screen_SetResolution(void)
1.1.1.7 root 229: {
230: int Width, Height, BitCount;
1.1.1.10! root 231: unsigned int sdlVideoFlags;
1.1.1.7 root 232:
1.1.1.10! root 233: /* Determine which resolution to use */
1.1.1.9 root 234: if (bUseVDIRes)
235: {
1.1.1.7 root 236: Width = VDIWidth;
237: Height = VDIHeight;
1.1.1.9 root 238: }
239: else
240: {
1.1.1.10! root 241: if (STRes == ST_LOW_RES &&
! 242: (ConfigureParams.Screen.ChosenDisplayMode == DISPLAYMODE_LOWCOL_LOWRES
! 243: || ConfigureParams.Screen.ChosenDisplayMode == DISPLAYMODE_HICOL_LOWRES))
1.1.1.9 root 244: {
1.1.1.10! root 245: Width = 320;
! 246: Height = 200;
! 247: }
! 248: else /* else use 640x400 */
! 249: {
! 250: Width = 640;
! 251: Height = 400;
1.1.1.9 root 252: }
1.1.1.7 root 253:
1.1.1.10! root 254: /* Adjust width/height for overscan borders, if mono or VDI we have no overscan */
! 255: if (ConfigureParams.Screen.bAllowOverscan && !bUseHighRes)
! 256: {
! 257: int nZoom = ((Width == 640) ? 2 : 1);
! 258: /* Add in overscan borders (if 640x200 bitmap is double on Y) */
! 259: Width += (OVERSCAN_LEFT+OVERSCAN_RIGHT) * nZoom;
! 260: Height += (OVERSCAN_TOP+OVERSCAN_BOTTOM) * nZoom;
! 261: }
1.1.1.7 root 262: }
263:
264: /* Bits per pixel */
1.1.1.9 root 265: if (ConfigureParams.Screen.ChosenDisplayMode == DISPLAYMODE_LOWCOL_LOWRES
266: || ConfigureParams.Screen.ChosenDisplayMode == DISPLAYMODE_LOWCOL_HIGHRES
267: || STRes == ST_HIGH_RES || bUseVDIRes)
1.1.1.7 root 268: {
269: BitCount = 8;
270: }
271: else
272: {
273: BitCount = 16;
274: }
275:
1.1.1.10! root 276: /* SDL Video attributes: */
! 277: if (bInFullScreen)
1.1.1.7 root 278: {
1.1.1.10! root 279: sdlVideoFlags = SDL_HWSURFACE|SDL_FULLSCREEN|SDL_HWPALETTE/*|SDL_DOUBLEBUF*/;
! 280: /* SDL_DOUBLEBUF is a good idea, but the GUI doesn't work with double buffered
! 281: * screens yet, so double buffering is currently disabled. */
1.1.1.7 root 282: }
283: else
284: {
1.1.1.10! root 285: sdlVideoFlags = SDL_SWSURFACE|SDL_HWPALETTE;
1.1.1.7 root 286: }
287:
1.1.1.10! root 288: sdlscrn = SDL_SetVideoMode(Width, Height, BitCount, sdlVideoFlags);
! 289: if (!sdlscrn)
1.1.1.7 root 290: {
1.1.1.10! root 291: fprintf(stderr, "Could not set video mode:\n %s\n", SDL_GetError() );
! 292: SDL_Quit();
! 293: exit(-2);
1.1.1.7 root 294: }
1.1.1.10! root 295:
! 296: /* Re-init screen palette: */
! 297: if (BitCount == 8)
! 298: Screen_Handle8BitPalettes(); /* Initialize new 8 bit palette */
! 299: else
! 300: Screen_SetupRGBTable(); /* Create color convertion table */
! 301:
! 302: if (!bGrabMouse)
! 303: SDL_WM_GrabInput(SDL_GRAB_OFF); /* Un-grab mouse pointer in windowed mode */
! 304:
! 305: Screen_SetDrawFunctions(); /* Set draw functions */
! 306: Screen_SetFullUpdate(); /* Cause full update of screen */
1.1.1.7 root 307: }
308:
1.1.1.8 root 309:
1.1.1.7 root 310: /*-----------------------------------------------------------------------*/
311: /*
1.1 root 312: Init Screen bitmap and buffers/tables needed for ST to PC screen conversion
313: */
314: void Screen_Init(void)
315: {
316: int i;
317:
318: /* Clear frame buffer structures and set current pointer */
1.1.1.10! root 319: memset(FrameBuffers, 0, NUM_FRAMEBUFFERS * sizeof(FRAMEBUFFER));
1.1 root 320:
321: /* Allocate previous screen check workspace. We are going to double-buffer a double-buffered screen. Oh. */
1.1.1.5 root 322: for(i=0; i<NUM_FRAMEBUFFERS; i++)
323: {
1.1.1.10! root 324: FrameBuffers[i].pSTScreen = (unsigned char *)malloc(((MAX_VDI_WIDTH*MAX_VDI_PLANES)/8)*MAX_VDI_HEIGHT);
! 325: FrameBuffers[i].pSTScreenCopy = (unsigned char *)malloc(((MAX_VDI_WIDTH*MAX_VDI_PLANES)/8)*MAX_VDI_HEIGHT);
! 326: if (!FrameBuffers[i].pSTScreen || !FrameBuffers[i].pSTScreenCopy)
! 327: {
! 328: fprintf(stderr, "Failed to allocate frame buffer memory.\n");
! 329: exit(-1);
! 330: }
1.1 root 331: }
332: pFrameBuffer = &FrameBuffers[0];
333:
1.1.1.10! root 334: Screen_SetResolution();
1.1 root 335:
336: Video_SetScreenRasters(); /* Set rasters ready for first screen */
337:
338: Screen_SetScreenLineOffsets(); /* Store offset to each horizontal line */
339:
1.1.1.2 root 340: /* Configure some SDL stuff: */
1.1 root 341: SDL_WM_SetCaption(PROG_NAME, "Hatari");
342: SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);
343: SDL_EventState(SDL_MOUSEBUTTONDOWN, SDL_ENABLE);
344: SDL_EventState(SDL_MOUSEBUTTONUP, SDL_ENABLE);
1.1.1.4 root 345: SDL_ShowCursor(SDL_DISABLE);
1.1 root 346: }
347:
1.1.1.2 root 348:
1.1 root 349: /*-----------------------------------------------------------------------*/
350: /*
351: Free screen bitmap and allocated resources
352: */
353: void Screen_UnInit(void)
354: {
355: int i;
356:
1.1.1.3 root 357: /* Free memory used for copies */
1.1.1.7 root 358: for(i=0; i<NUM_FRAMEBUFFERS; i++)
359: {
1.1.1.10! root 360: free(FrameBuffers[i].pSTScreen);
! 361: free(FrameBuffers[i].pSTScreenCopy);
1.1 root 362: }
363: }
364:
1.1.1.2 root 365:
1.1 root 366: /*-----------------------------------------------------------------------*/
367: /*
368: Reset screen
369: */
370: void Screen_Reset(void)
371: {
372: /* On re-boot, always correct ST resolution for monitor, eg Colour/Mono */
1.1.1.5 root 373: if (bUseVDIRes)
374: {
1.1 root 375: STRes = VDIRes;
376: }
1.1.1.5 root 377: else
378: {
1.1 root 379: if (bUseHighRes)
380: STRes = ST_HIGH_RES;
381: else
382: STRes = ST_LOW_RES;
383: }
384: PrevSTRes = -1;
385: /* Cause full update */
386: Screen_SetFullUpdate();
387: }
388:
389: /*-----------------------------------------------------------------------*/
390: /*
391: Store Y offset for each horizontal line in our source ST screen for each reference in assembler(no multiply)
392: */
393: void Screen_SetScreenLineOffsets(void)
394: {
395: int i;
396:
397: for(i=0; i<NUM_VISIBLE_LINES; i++)
398: STScreenLineOffset[i] = i * SCREENBYTES_LINE;
399: }
400:
401:
402: /*-----------------------------------------------------------------------*/
403: /*
1.1.1.5 root 404: Set flags so screen will be TOTALLY re-drawn (clears whole of full-screen)
405: next time around
1.1 root 406: */
407: void Screen_SetFullUpdate(void)
408: {
409: int i;
410:
411: /* Update frame buffers */
412: for(i=0; i<NUM_FRAMEBUFFERS; i++)
413: FrameBuffers[i].bFullUpdate = TRUE;
414: }
415:
1.1.1.5 root 416:
1.1 root 417: /*-----------------------------------------------------------------------*/
418: /*
419: Enter Full screen mode
420: */
421: void Screen_EnterFullScreen(void)
422: {
1.1.1.5 root 423: if (!bInFullScreen)
424: {
1.1 root 425: Main_PauseEmulation(); /* Hold things... */
1.1.1.2 root 426:
1.1.1.10! root 427: bInFullScreen = TRUE;
! 428: Screen_SetResolution();
1.1 root 429:
1.1.1.10! root 430: SDL_Delay(20); /* To give monitor time to change to new resolution */
! 431: Screen_ClearScreen(); /* Black out screen bitmap as will be invalid when return */
1.1.1.2 root 432:
1.1.1.10! root 433: Main_UnPauseEmulation(); /* And off we go... */
1.1.1.3 root 434:
1.1.1.4 root 435: SDL_WM_GrabInput(SDL_GRAB_ON); /* Grab mouse pointer in fullscreen */
1.1 root 436: }
437: }
438:
1.1.1.2 root 439:
1.1 root 440: /*-----------------------------------------------------------------------*/
441: /*
442: Return from Full screen mode back to a window
443: */
444: void Screen_ReturnFromFullScreen(void)
445: {
1.1.1.7 root 446: if (bInFullScreen)
447: {
1.1.1.2 root 448: Main_PauseEmulation(); /* Hold things... */
449:
450: bInFullScreen = FALSE;
1.1.1.10! root 451: Screen_SetResolution();
1.1.1.2 root 452:
1.1.1.10! root 453: SDL_Delay(20); /* To give monitor time to switch resolution */
1.1.1.2 root 454:
1.1.1.10! root 455: Main_UnPauseEmulation(); /* And off we go... */
1.1 root 456: }
457: }
458:
1.1.1.5 root 459:
1.1.1.2 root 460: /*-----------------------------------------------------------------------*/
1.1 root 461: /*
462: Clear Window display memory
463: */
1.1.1.2 root 464: void Screen_ClearScreen(void)
1.1 root 465: {
1.1.1.2 root 466: SDL_FillRect(sdlscrn,NULL, SDL_MapRGB(sdlscrn->format, 0, 0, 0) );
1.1 root 467: }
468:
469:
1.1.1.2 root 470: /*-----------------------------------------------------------------------*/
1.1 root 471: /*
472: Have we changes beteen low/medium/high res?
473: */
474: void Screen_DidResolutionChange(void)
475: {
1.1.1.2 root 476: /* Did change res? */
1.1.1.5 root 477: if (STRes!=PrevSTRes)
478: {
1.1.1.10! root 479: /* Set new display mode, if differs from current */
! 480: Screen_SetResolution();
1.1 root 481: PrevSTRes = STRes;
482: }
483:
1.1.1.2 root 484: /* Did change overscan mode? Causes full update */
1.1.1.10! root 485: if (pFrameBuffer->OverscanModeCopy != OverscanMode)
1.1 root 486: pFrameBuffer->bFullUpdate = TRUE;
487: }
488:
1.1.1.2 root 489:
490: /*-----------------------------------------------------------------------*/
1.1 root 491: /*
492: Compare current resolution on line with previous, and set 'UpdateLine' accordingly
493: Also check if swap between low/medium resolution and return in 'bLowMedMix'
494: */
1.1.1.8 root 495: static void Screen_CompareResolution(int y, int *pUpdateLine, BOOL *pbLowMedMix)
1.1 root 496: {
497: int Resolution;
498:
1.1.1.2 root 499: /* Check if wrote to resolution register */
1.1.1.7 root 500: if (HBLPaletteMasks[y]&PALETTEMASK_RESOLUTION) /* See 'Intercept_ShifterMode_WriteByte' */
501: {
1.1 root 502: Resolution = (HBLPaletteMasks[y]>>16)&0x1;
1.1.1.2 root 503: /* Have used any low/medium res mix? */
1.1 root 504: if (Resolution!=(STRes&0x1))
505: *pbLowMedMix = TRUE;
1.1.1.2 root 506: /* Did change resolution */
1.1 root 507: if (Resolution!=(int)((pFrameBuffer->HBLPaletteMasks[y]>>16)&0x1))
508: *pUpdateLine |= PALETTEMASK_UPDATERES;
509: else
510: *pUpdateLine &= ~PALETTEMASK_UPDATERES;
511: }
512: }
513:
1.1.1.7 root 514:
1.1.1.2 root 515: /*-----------------------------------------------------------------------*/
1.1 root 516: /*
517: Check to see if palette changes cause screen update and keep 'HBLPalette[]' up-to-date
518: */
1.1.1.8 root 519: static void Screen_ComparePalette(int y, int *pUpdateLine)
1.1 root 520: {
521: BOOL bPaletteChanged = FALSE;
522: int i;
523:
1.1.1.2 root 524: /* Did write to palette in this or previous frame? */
1.1.1.7 root 525: if (((HBLPaletteMasks[y]|pFrameBuffer->HBLPaletteMasks[y])&PALETTEMASK_PALETTE)!=0)
526: {
1.1.1.2 root 527: /* Check and update ones which changed */
1.1.1.7 root 528: for(i=0; i<16; i++)
529: {
1.1.1.2 root 530: if (HBLPaletteMasks[y]&(1<<i)) /* Update changes in ST palette */
1.1 root 531: HBLPalette[i] = HBLPalettes[(y*16)+i];
532: }
1.1.1.2 root 533: /* Now check with same palette from previous frame for any differences(may be changing palette back) */
1.1.1.7 root 534: for(i=0; (i<16) && (!bPaletteChanged); i++)
535: {
1.1 root 536: if (HBLPalette[i]!=pFrameBuffer->HBLPalettes[(y*16)+i])
537: bPaletteChanged = TRUE;
538: }
539: if (bPaletteChanged)
540: *pUpdateLine |= PALETTEMASK_UPDATEPAL;
541: else
542: *pUpdateLine &= ~PALETTEMASK_UPDATEPAL;
543: }
544: }
545:
1.1.1.7 root 546:
1.1.1.2 root 547: /*-----------------------------------------------------------------------*/
1.1 root 548: /*
549: Check for differences in Palette and Resolution from Mask table and update and
550: store off which lines need updating and create full-screen palette.
551: (It is very important for these routines to check for colour changes with the previous
552: screen so only the very minimum parts are updated)
553: */
1.1.1.8 root 554: static int Screen_ComparePaletteMask(void)
1.1 root 555: {
556: BOOL bLowMedMix=FALSE;
557: int LineUpdate = 0;
558: int y;
559:
560: /* Set for monochrome? */
1.1.1.7 root 561: if (bUseHighRes)
562: {
1.1 root 563: OverscanMode = OVERSCANMODE_NONE;
564:
565: /* Just copy mono colours */
1.1.1.7 root 566: if (HBLPalettes[0]&0x777)
567: {
1.1 root 568: HBLPalettes[0] = 0x777; HBLPalettes[1] = 0x000;
569: }
1.1.1.7 root 570: else
571: {
1.1 root 572: HBLPalettes[0] = 0x000; HBLPalettes[1] = 0x777;
573: }
574:
1.1.1.7 root 575: /* Colors changed? */
576: if (HBLPalettes[0] != PrevHBLPalette[0])
577: pFrameBuffer->bFullUpdate = TRUE;
578:
1.1 root 579: /* Set bit to flag 'full update' */
580: if (pFrameBuffer->bFullUpdate)
581: ScrUpdateFlag = PALETTEMASK_UPDATEFULL;
582: else
583: ScrUpdateFlag = 0x00000000;
584: }
585:
586: /* Use VDI resolution? */
1.1.1.7 root 587: if (bUseVDIRes)
588: {
1.1 root 589: /* Force to VDI resolution screen, without overscan */
590: STRes = VDIRes;
591:
1.1.1.7 root 592: /* Colors changed? */
1.1 root 593: if (HBLPalettes[0]!=PrevHBLPalette[0])
594: pFrameBuffer->bFullUpdate = TRUE;
595:
596: /* Set bit to flag 'full update' */
597: if (pFrameBuffer->bFullUpdate)
598: ScrUpdateFlag = PALETTEMASK_UPDATEFULL;
599: else
600: ScrUpdateFlag = 0x00000000;
601: }
602: /* Are in Mono? Force to monochrome and no overscan */
1.1.1.7 root 603: else if (bUseHighRes)
604: {
1.1 root 605: /* Force to standard hi-resolution screen, without overscan */
606: STRes = ST_HIGH_RES;
607: }
1.1.1.7 root 608: else /* Full colour */
609: {
1.1 root 610: /* Get resolution */
611: STRes = (HBLPaletteMasks[0]>>16)&0x3;
612: /* Do all lines - first is tagged as full-update */
1.1.1.7 root 613: for(y=0; y<NUM_VISIBLE_LINES; y++)
614: {
1.1 root 615: /* Find any resolution/palette change and update palette/mask buffer */
616: /* ( LineUpdate has top two bits set to say if line needs updating due to palette or resolution change ) */
617: Screen_CompareResolution(y,&LineUpdate,&bLowMedMix);
618: Screen_ComparePalette(y,&LineUpdate);
619: HBLPaletteMasks[y] = (HBLPaletteMasks[y]&(~PALETTEMASK_UPDATEMASK)) | LineUpdate;
620: /* Copy palette and mask for next frame */
621: memcpy(&pFrameBuffer->HBLPalettes[y*16],HBLPalette,sizeof(short int)*16);
622: pFrameBuffer->HBLPaletteMasks[y] = HBLPaletteMasks[y];
623: }
624: /* Did mix resolution? */
625: if (bLowMedMix)
626: STRes = ST_LOWMEDIUM_MIX_RES;
627: }
628:
629: return(STRes);
630: }
631:
1.1.1.3 root 632:
1.1.1.2 root 633: /*-----------------------------------------------------------------------*/
1.1 root 634: /*
635: Update Palette Mask to show 'full-update' required. This is usually done after a resolution change
636: or when going between a Window and full-screen display
637: */
1.1.1.8 root 638: static void Screen_SetFullUpdateMask(void)
1.1 root 639: {
640: int y;
641:
642: for(y=0; y<NUM_VISIBLE_LINES; y++)
643: HBLPaletteMasks[y] |= PALETTEMASK_UPDATEFULL;
644: }
645:
1.1.1.7 root 646:
1.1.1.2 root 647: /*-----------------------------------------------------------------------*/
1.1 root 648: /*
1.1.1.10! root 649: Set details for ST screen conversion.
1.1 root 650: */
1.1.1.10! root 651: static void Screen_SetConvertDetails(void)
1.1 root 652: {
1.1.1.3 root 653: pSTScreen = pFrameBuffer->pSTScreen; /* Source in ST memory */
654: pSTScreenCopy = pFrameBuffer->pSTScreenCopy; /* Previous ST screen */
1.1.1.8 root 655: pPCScreenDest = sdlscrn->pixels; /* Destination PC screen */
1.1.1.3 root 656:
1.1.1.10! root 657: PCScreenBytesPerLine = sdlscrn->pitch; /* Bytes per line */
! 658: pHBLPalettes = pFrameBuffer->HBLPalettes; /* HBL palettes pointer */
! 659: bScrDoubleY = !ConfigureParams.Screen.bInterleavedScreen; /* non-interleaved? => double up on Y */
1.1.1.5 root 660:
1.1.1.10! root 661: if (bUseVDIRes)
1.1.1.5 root 662: {
1.1.1.10! root 663: /* Select screen draw for standard or VDI display */
! 664: STScreenLeftSkipBytes = 0;
! 665: STScreenWidthBytes = VDIWidth * VDIPlanes / 8;
! 666: STScreenStartHorizLine = 0;
! 667: STScreenEndHorizLine = VDIHeight;
1.1 root 668: }
669: else
670: {
1.1.1.10! root 671: if (ConfigureParams.Screen.bAllowOverscan) /* Use borders? */
1.1.1.5 root 672: {
1.1.1.10! root 673: /* Always draw to WHOLE screen including ALL borders */
! 674: STScreenLeftSkipBytes = 0; /* Number of bytes to skip on ST screen for left (border) */
! 675: STScreenStartHorizLine = 0; /* Full height */
! 676:
! 677: if (ConfigureParams.Screen.bUseHighRes)
! 678: {
! 679: pFrameBuffer->OverscanModeCopy = OverscanMode = OVERSCANMODE_NONE;
! 680: STScreenEndHorizLine = 400;
! 681: }
! 682: else
! 683: {
! 684: STScreenWidthBytes = SCREENBYTES_LINE; /* Number of horizontal bytes in our ST screen */
! 685: STScreenEndHorizLine = NUM_VISIBLE_LINES;
! 686: }
1.1.1.5 root 687: }
688: else
689: {
1.1.1.10! root 690: /* Only draw main area and centre on Y */
! 691: STScreenLeftSkipBytes = SCREENBYTES_LEFT;
! 692: STScreenWidthBytes = SCREENBYTES_MIDDLE;
! 693: STScreenStartHorizLine = OVERSCAN_TOP;
! 694: STScreenEndHorizLine = OVERSCAN_TOP + (bUseHighRes ? 400 : 200);
1.1 root 695: }
696: }
697: }
698:
1.1.1.2 root 699:
700: /*-----------------------------------------------------------------------*/
1.1 root 701: /*
702: Lock full-screen for drawing
703: */
1.1.1.8 root 704: static BOOL Screen_Lock(void)
1.1 root 705: {
1.1.1.7 root 706: if(SDL_MUSTLOCK(sdlscrn))
707: {
708: if(SDL_LockSurface(sdlscrn))
709: {
1.1.1.2 root 710: Screen_ReturnFromFullScreen(); /* All OK? If not need to jump back to a window */
1.1 root 711: return(FALSE);
712: }
713: }
1.1.1.2 root 714:
1.1 root 715: return(TRUE);
716: }
717:
1.1.1.2 root 718: /*-----------------------------------------------------------------------*/
1.1 root 719: /*
720: UnLock full-screen
721: */
1.1.1.8 root 722: static void Screen_UnLock(void)
1.1 root 723: {
1.1.1.2 root 724: if( SDL_MUSTLOCK(sdlscrn) )
1.1.1.3 root 725: SDL_UnlockSurface(sdlscrn);
1.1 root 726: }
727:
1.1.1.2 root 728:
729: /*-----------------------------------------------------------------------*/
1.1 root 730: /*
731: Blit our converted ST screen to window/full-screen
1.1.1.3 root 732: Note that our source image includes all borders so if have them disabled simply blit a smaller source rectangle!
1.1 root 733: */
734: void Screen_Blit(BOOL bSwapScreen)
735: {
1.1.1.3 root 736: /* Rectangle areas to Blit according to if overscan is enabled or not (source always includes all borders) */
1.1.1.7 root 737: /* static SDL_Rect SrcWindowBitmapSizes[] = */
738: /* { */
739: /* { OVERSCAN_LEFT,OVERSCAN_TOP, 320,200 }, /\* ST_LOW_RES *\/ */
740: /* { (OVERSCAN_LEFT<<1),(OVERSCAN_TOP<<1), 640,400 }, /\* ST_MEDIUM_RES *\/ */
741: /* { 0,0, 640,400 }, /\* ST_HIGH_RES *\/ */
742: /* { (OVERSCAN_LEFT<<1),(OVERSCAN_BOTTOM<<1), 640,400 }, /\* ST_LOWMEDIUM_MIX_RES *\/ */
743: /* }; */
744: static SDL_Rect SrcWindowBitmapSizes[] =
745: {
746: { 0,0, 320,200 }, /* ST_LOW_RES */
747: { 0,0, 640,400 }, /* ST_MEDIUM_RES */
1.1.1.5 root 748: { 0,0, 640,400 }, /* ST_HIGH_RES */
1.1.1.7 root 749: { 0,0, 640,400 }, /* ST_LOWMEDIUM_MIX_RES */
1.1 root 750: };
1.1.1.7 root 751:
752: static SDL_Rect SrcWindowOverscanBitmapSizes[] =
753: {
1.1.1.5 root 754: { 0,0, OVERSCAN_LEFT+320+OVERSCAN_RIGHT,OVERSCAN_TOP+200+OVERSCAN_BOTTOM },
755: { 0,0, (OVERSCAN_LEFT<<1)+640+(OVERSCAN_RIGHT<<1),(OVERSCAN_TOP<<1)+400+(OVERSCAN_BOTTOM<<1) },
756: { 0,0, 640,400 },
757: { 0,0, (OVERSCAN_LEFT<<1)+640+(OVERSCAN_RIGHT<<1),(OVERSCAN_TOP<<1)+400+(OVERSCAN_BOTTOM<<1) },
1.1 root 758: };
1.1.1.3 root 759:
1.1.1.10! root 760: unsigned char *pTmpScreen;
1.1.1.3 root 761: SDL_Rect *SrcRect;
1.1 root 762:
1.1.1.3 root 763: /* Blit to full screen or window? */
1.1.1.7 root 764: if (bInFullScreen)
765: {
1.1.1.3 root 766: /* Swap screen */
1.1 root 767: if (bSwapScreen)
1.1.1.3 root 768: SDL_Flip(sdlscrn);
1.1 root 769: }
1.1.1.7 root 770: else
771: {
1.1.1.3 root 772: /* VDI resolution? */
1.1.1.7 root 773: if (bUseVDIRes || ConfigureParams.Screen.bUseHighRes)
774: {
1.1.1.3 root 775: /* Show VDI or mono resolution, no overscan */
776: SDL_UpdateRect(sdlscrn, 0,0,0,0);
1.1 root 777: }
1.1.1.7 root 778: else
779: {
780: /* Find rectangle to draw from... */
781: if (ConfigureParams.Screen.bAllowOverscan)
782: SrcRect = &SrcWindowOverscanBitmapSizes[STRes];
783: else
784: SrcRect = &SrcWindowBitmapSizes[STRes];
785:
786: /* Blit image */
787: SDL_UpdateRect(sdlscrn, 0,0,0,0);
1.1.1.10! root 788: //SDL_UpdateRects(sdlscrn, 1, SrcRect); /* FIXME */
1.1 root 789: }
790: }
791:
1.1.1.3 root 792: /* Swap copy/raster buffers in screen. */
1.1.1.10! root 793: pTmpScreen = pFrameBuffer->pSTScreenCopy;
1.1 root 794: pFrameBuffer->pSTScreenCopy = pFrameBuffer->pSTScreen;
1.1.1.10! root 795: pFrameBuffer->pSTScreen = pTmpScreen;
1.1 root 796: }
797:
1.1.1.3 root 798:
1.1.1.2 root 799: /*-----------------------------------------------------------------------*/
1.1 root 800: /*
801: Swap ST Buffers, used for full-screen where have double-buffering
802: */
1.1.1.8 root 803: static void Screen_SwapSTBuffers(void)
1.1 root 804: {
1.1.1.7 root 805: #if NUM_FRAMEBUFFERS > 1
1.1.1.8 root 806: if (sdlscrn->flags & SDL_DOUBLEBUF)
1.1.1.7 root 807: {
1.1 root 808: if (pFrameBuffer==&FrameBuffers[0])
809: pFrameBuffer = &FrameBuffers[1];
810: else
811: pFrameBuffer = &FrameBuffers[0];
812: }
1.1.1.7 root 813: #endif
1.1 root 814: }
815:
816:
1.1.1.2 root 817: /*-----------------------------------------------------------------------*/
1.1 root 818: /*
819: Draw ST screen to window/full-screen framebuffer
820: */
821: void Screen_DrawFrame(BOOL bForceFlip)
822: {
823: void *pDrawFunction;
824:
1.1.1.2 root 825: /* Scan palette/resolution masks for each line and build up palette/difference tables */
1.1 root 826: STRes = Screen_ComparePaletteMask();
1.1.1.2 root 827: /* Do require palette? Check if changed and update */
1.1 root 828: Screen_Handle8BitPalettes();
1.1.1.2 root 829: /* Did we change resolution this frame - allocate new screen if did so */
1.1 root 830: Screen_DidResolutionChange();
1.1.1.2 root 831: /* Is need full-update, tag as such */
1.1 root 832: if (pFrameBuffer->bFullUpdate)
833: Screen_SetFullUpdateMask();
834:
835: /* Lock screen ready for drawing */
1.1.1.10! root 836: if (Screen_Lock())
! 837: {
! 838: bScreenContentsChanged = FALSE; /* Did change (ie needs blit?) */
1.1.1.7 root 839: /* Set details */
1.1.1.10! root 840: Screen_SetConvertDetails();
1.1.1.9 root 841: /* Clear screen on full update to clear out borders and also interleaved lines */
1.1.1.7 root 842: if (pFrameBuffer->bFullUpdate && !bUseVDIRes)
843: Screen_ClearScreen();
844: /* Call drawing for full-screen */
1.1.1.10! root 845: if (bUseVDIRes)
! 846: {
! 847: pDrawFunction = ScreenDrawFunctionsVDI[VDIRes];
1.1 root 848: }
1.1.1.10! root 849: else
! 850: {
! 851: pDrawFunction = ScreenDrawFunctionsNormal[STRes];
1.1.1.7 root 852: /* Check if is Spec512 image */
1.1.1.10! root 853: if (Spec512_IsImage())
! 854: {
! 855: /* What mode were we in? Keep to 320xH or 640xH */
! 856: if (pDrawFunction==ConvertLowRes_320x16Bit)
! 857: pDrawFunction = ConvertSpec512_320x16Bit;
! 858: else if (pDrawFunction==ConvertLowRes_640x16Bit)
! 859: pDrawFunction = ConvertSpec512_640x16Bit;
1.1 root 860: }
861: }
862:
1.1.1.7 root 863: if (pDrawFunction)
864: CALL_VAR(pDrawFunction)
865:
1.1.1.2 root 866: /* Unlock screen */
1.1 root 867: Screen_UnLock();
1.1.1.2 root 868: /* Clear flags, remember type of overscan as if change need screen full update */
1.1 root 869: pFrameBuffer->bFullUpdate = FALSE;
870: pFrameBuffer->OverscanModeCopy = OverscanMode;
871:
1.1.1.2 root 872: /* And show to user */
1.1.1.10! root 873: if (bScreenContentsChanged || bForceFlip)
! 874: {
1.1 root 875: if (bInFullScreen)
876: Screen_SwapSTBuffers();
877: Screen_Blit(TRUE);
878: }
879:
1.1.1.3 root 880: /* Grab any animation */
881: if(bRecordingAnimation)
1.1 root 882: ScreenSnapShot_RecordFrame(bScreenContentsChanged);
883: }
884: }
885:
1.1.1.9 root 886:
1.1.1.2 root 887: /*-----------------------------------------------------------------------*/
1.1 root 888: /*
889: Draw ST screen to window/full-screen
890: */
891: void Screen_Draw(void)
892: {
1.1.1.5 root 893: if (!bQuitProgram)
894: {
895: if(VideoBase)
1.1 root 896: {
897: /* And draw(if screen contents changed) */
898: Screen_DrawFrame(FALSE);
899:
900: /* And status bar */
1.1.1.4 root 901: /*StatusBar_UpdateIcons();*/ /* Sorry - no statusbar in Hatari yet */
1.1 root 902: }
903:
1.1.1.2 root 904: /* Check printer status */
1.1 root 905: Printer_CheckIdleStatus();
906: }
907: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.