Annotation of hatari/src/screen.c, revision 1.1.1.10

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.