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

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

unix.superglobalmegacorp.com

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