|
|
1.1 ! root 1: /* ! 2: Hatari - screen.c ! 3: ! 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. ! 21: */ ! 22: ! 23: #include <SDL.h> ! 24: ! 25: #include "main.h" ! 26: #include "configuration.h" ! 27: #include "m68000.h" ! 28: #include "memAlloc.h" ! 29: #include "misc.h" ! 30: #include "screen.h" ! 31: #include "screenConvert.h" ! 32: #include "video.h" ! 33: #include "scalebit.h" ! 34: ! 35: int len_main_palette; ! 36: unsigned short MainPalette[256]; ! 37: unsigned short CtrlPalette[16]; ! 38: ! 39: SCREENDRAW ScreenDraw; /* Set up with details of drawing functions */ ! 40: unsigned char *pScreenBitmap=NULL; /* Screen pixels in PC RGB format, allocated with 'CreateDIBSection' */ ! 41: unsigned char *pPCScreenDest; /* Destination PC buffer */ ! 42: int STScreenStartHorizLine,STScreenEndHorizLine; /* Start/End lines to be converted */ ! 43: int PCScreenBytesPerLine, STScreenWidthBytes, STScreenLeftSkipBytes; ! 44: BOOL bInFullScreen=FALSE; /* TRUE if in full screen */ ! 45: BOOL bFullScreenHold = FALSE; /* TRUE if hold display while full screen */ ! 46: BOOL bScreenContentsChanged; /* TRUE if buffer changed and requires blitting */ ! 47: BOOL bTooSlowSoSkipAFlip = FALSE; ! 48: int nDroppedFrames=0; /* Number of dropped frames during emulation run */ ! 49: int prevChosenDisplayMode = -1; ! 50: ! 51: int STScreenLineOffset[SCREEN_HEIGHT_HBL]; /* Offsets for ST screen lines eg, 0,160,320... */ ! 52: unsigned long MainRGBPalette[256]; ! 53: unsigned long CtrlRGBPalette[16]; ! 54: ! 55: SDL_Surface *sdlscrn; /* The SDL screen surface */ ! 56: BOOL bGrabMouse = FALSE; /* Grab the mouse cursor in the window */ ! 57: ! 58: ! 59: /*-----------------------------------------------------------------------*/ ! 60: /* ! 61: Set window size ! 62: */ ! 63: void Screen_SetWindowRes() ! 64: { ! 65: prevChosenDisplayMode = ConfigureParams.Screen.ChosenDisplayMode; ! 66: switch (ConfigureParams.Screen.ChosenDisplayMode) { ! 67: case DISPLAYMODE_HICOL_1X: ! 68: sdlscrn=SDL_SetVideoMode(320, 200, 16, SDL_DOUBLEBUF | SDL_ANYFORMAT); ! 69: break; ! 70: default: ! 71: sdlscrn=SDL_SetVideoMode(640, 400, 16, SDL_DOUBLEBUF | SDL_ANYFORMAT); ! 72: break; ! 73: } ! 74: if ((sdlscrn == NULL) || (sdlscrn->format->BytesPerPixel < 2)) ! 75: { ! 76: fprintf(stderr, "Could not set video mode:\n %s\n", SDL_GetError() ); ! 77: SDL_Quit(); ! 78: exit(-2); ! 79: } ! 80: pScreenBitmap=sdlscrn->pixels; ! 81: ! 82: if(!bGrabMouse) ! 83: { ! 84: SDL_WM_GrabInput(SDL_GRAB_OFF); /* Un-grab mouse pointer in windowed mode */ ! 85: } ! 86: Screen_SetDrawModes(); /* Set draw modes(store which modes to use!) */ ! 87: } ! 88: ! 89: /*-----------------------------------------------------------------------*/ ! 90: /* ! 91: Init Screen bitmap and buffers/tables needed for ST to PC screen conversion ! 92: */ ! 93: void Screen_Init(void) ! 94: { ! 95: Screen_SetWindowRes(); ! 96: ! 97: Screen_SetScreenLineOffsets(); /* Store offset to each horizontal line */ ! 98: ! 99: /* Configure some SDL stuff: */ ! 100: SDL_WM_SetCaption(PROG_NAME, "Frontier"); ! 101: SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE); ! 102: SDL_EventState(SDL_MOUSEBUTTONDOWN, SDL_ENABLE); ! 103: SDL_EventState(SDL_MOUSEBUTTONUP, SDL_ENABLE); ! 104: SDL_ShowCursor(SDL_DISABLE); ! 105: } ! 106: ! 107: ! 108: /*-----------------------------------------------------------------------*/ ! 109: /* ! 110: Free screen bitmap and allocated resources ! 111: */ ! 112: void Screen_UnInit(void) ! 113: { ! 114: } ! 115: ! 116: ! 117: /*-----------------------------------------------------------------------*/ ! 118: /* ! 119: Reset screen ! 120: */ ! 121: void Screen_Reset(void) ! 122: { ! 123: } ! 124: ! 125: /*-----------------------------------------------------------------------*/ ! 126: /* ! 127: Store Y offset for each horizontal line in our source ST screen for each reference in assembler(no multiply) ! 128: */ ! 129: void Screen_SetScreenLineOffsets(void) ! 130: { ! 131: int i; ! 132: ! 133: for(i=0; i<SCREEN_HEIGHT_HBL; i++) ! 134: STScreenLineOffset[i] = i * SCREENBYTES_LINE; ! 135: } ! 136: ! 137: ! 138: /*-----------------------------------------------------------------------*/ ! 139: ! 140: /*-----------------------------------------------------------------------*/ ! 141: /* ! 142: Enter Full screen mode ! 143: */ ! 144: ! 145: static SDL_Surface *set_new_sdl_fsmode() { ! 146: SDL_Surface *newsdlscrn; ! 147: ! 148: newsdlscrn = SDL_SetVideoMode(sdlscrn->w, sdlscrn->h, ! 149: ScreenDraw.BitDepth, SDL_DOUBLEBUF | SDL_ANYFORMAT | SDL_FULLSCREEN); ! 150: return newsdlscrn; ! 151: } ! 152: ! 153: void Screen_EnterFullScreen(void) ! 154: { ! 155: SDL_Surface *newsdlscrn; ! 156: ! 157: if (!bInFullScreen) ! 158: { ! 159: Main_PauseEmulation(); /* Hold things... */ ! 160: SDL_Delay(20); /* To give sound time to clear! */ ! 161: ! 162: newsdlscrn = set_new_sdl_fsmode(); ! 163: Screen_SetDrawModes(); /* Set draw modes(store which modes to use!) */ ! 164: ! 165: if( newsdlscrn==NULL ) ! 166: { ! 167: fprintf(stderr, "Could not set video mode:\n %s\n", SDL_GetError() ); ! 168: } ! 169: else ! 170: { ! 171: sdlscrn = newsdlscrn; ! 172: pScreenBitmap = newsdlscrn->pixels; ! 173: bInFullScreen = TRUE; ! 174: ! 175: Screen_ClearScreen(); /* Black out screen bitmap as will be invalid when return */ ! 176: } ! 177: Main_UnPauseEmulation(); /* And off we go... */ ! 178: ! 179: SDL_WM_GrabInput(SDL_GRAB_ON); /* Grab mouse pointer in fullscreen */ ! 180: } ! 181: } ! 182: ! 183: ! 184: /*-----------------------------------------------------------------------*/ ! 185: /* ! 186: Return from Full screen mode back to a window ! 187: */ ! 188: void Screen_ReturnFromFullScreen(void) ! 189: { ! 190: if (bInFullScreen) ! 191: { ! 192: Main_PauseEmulation(); /* Hold things... */ ! 193: SDL_Delay(20); /* To give sound time to clear! */ ! 194: ! 195: bInFullScreen = FALSE; ! 196: ! 197: Screen_SetWindowRes(); ! 198: Screen_SetDrawModes(); ! 199: ! 200: Main_UnPauseEmulation(); /* And off we go... */ ! 201: } ! 202: } ! 203: ! 204: ! 205: /*-----------------------------------------------------------------------*/ ! 206: /* ! 207: Clear Window display memory ! 208: */ ! 209: void Screen_ClearScreen(void) ! 210: { ! 211: SDL_FillRect(sdlscrn,NULL, SDL_MapRGB(sdlscrn->format, 0, 0, 0) ); ! 212: } ! 213: ! 214: /*-----------------------------------------------------------------------*/ ! 215: /* ! 216: */ ! 217: void Screen_SetDrawModes(void) ! 218: { ! 219: /* Clear out */ ! 220: Memory_Clear(&ScreenDraw,sizeof(SCREENDRAW)); ! 221: ! 222: ScreenDraw.pDrawFunction = screendrawfuncs[sdlscrn->format->BytesPerPixel][ConfigureParams.Screen.ChosenDisplayMode]; ! 223: /* Assign full-screen draw modes from chosen option under dialog */ ! 224: switch (ConfigureParams.Screen.ChosenDisplayMode) { ! 225: ! 226: case DISPLAYMODE_HICOL_1X: ! 227: ScreenDraw.Width = 320; ! 228: ScreenDraw.Height = 200; ! 229: ScreenDraw.BitDepth = sdlscrn->format->BitsPerPixel; ! 230: ScreenDraw.VertPixelsPerLine = 1; ! 231: ScreenDraw.PCStartHorizLine = 0; ! 232: ScreenDraw.MouseScale = 1; ! 233: break; ! 234: case DISPLAYMODE_HICOL_2X: ! 235: default: ! 236: ScreenDraw.Width = 640; ! 237: ScreenDraw.Height = 480; ! 238: ScreenDraw.BitDepth = sdlscrn->format->BitsPerPixel; ! 239: ScreenDraw.VertPixelsPerLine = 2; ! 240: ScreenDraw.PCStartHorizLine = 0; ! 241: ScreenDraw.MouseScale = 2; ! 242: break; ! 243: } ! 244: } ! 245: ! 246: ! 247: /*-----------------------------------------------------------------------*/ ! 248: /* ! 249: Set details for ST screen conversion(Window version) ! 250: */ ! 251: void Screen_SetWindowConvertDetails(void) ! 252: { ! 253: pPCScreenDest = pScreenBitmap; /* Destination PC screen */ ! 254: ! 255: STScreenStartHorizLine = 0; /* Full height */ ! 256: ! 257: /* Always draw to WHOLE screen including ALL borders */ ! 258: STScreenLeftSkipBytes = 0; /* Number of bytes to skip on ST screen for left(border) */ ! 259: STScreenWidthBytes = SCREENBYTES_LINE; /* Number of horizontal bytes in our ST screen */ ! 260: ! 261: STScreenEndHorizLine = SCREEN_HEIGHT_HBL; ! 262: ! 263: PCScreenBytesPerLine = sdlscrn->pitch; ! 264: } ! 265: ! 266: /*-----------------------------------------------------------------------*/ ! 267: /* ! 268: Set details for ST screen conversion (Full-Screen version) ! 269: */ ! 270: void Screen_SetFullScreenConvertDetails(void) ! 271: { ! 272: /* Only draw what can fit into full-screen and centre on Y */ ! 273: STScreenLeftSkipBytes = 0; ! 274: STScreenWidthBytes = SCREENBYTES_LINE; ! 275: ! 276: STScreenStartHorizLine = 0; ! 277: STScreenEndHorizLine = SCREEN_HEIGHT_HBL; ! 278: ! 279: PCScreenBytesPerLine = sdlscrn->pitch; ! 280: pPCScreenDest = (unsigned char *)sdlscrn->pixels; /* Destination PC screen */ ! 281: /* And offset on X */ ! 282: // pPCScreenDest += ScreenDraw.PCStartXOffset; ! 283: //pPCScreenDest += ScreenDraw.PCStartHorizLine * PCScreenBytesPerLine; ! 284: ! 285: /* Is non-interlaced? May need to double up on Y */ ! 286: bScrDoubleY = TRUE; ! 287: } ! 288: ! 289: ! 290: /*-----------------------------------------------------------------------*/ ! 291: /* ! 292: Lock full-screen for drawing ! 293: */ ! 294: BOOL Screen_Lock(void) ! 295: { ! 296: if(SDL_MUSTLOCK(sdlscrn)) ! 297: { ! 298: if(SDL_LockSurface(sdlscrn)) ! 299: { ! 300: Screen_ReturnFromFullScreen(); /* All OK? If not need to jump back to a window */ ! 301: return(FALSE); ! 302: } ! 303: } ! 304: ! 305: return(TRUE); ! 306: } ! 307: ! 308: /*-----------------------------------------------------------------------*/ ! 309: /* ! 310: UnLock full-screen ! 311: */ ! 312: void Screen_UnLock(void) ! 313: { ! 314: if( SDL_MUSTLOCK(sdlscrn) ) ! 315: SDL_UnlockSurface(sdlscrn); ! 316: } ! 317: ! 318: ! 319: /*-----------------------------------------------------------------------*/ ! 320: /* ! 321: Draw ST screen to window/full-screen framebuffer ! 322: */ ! 323: void Screen_DrawFrame(BOOL bForceFlip) ! 324: { ! 325: void *pDrawFunction; ! 326: ! 327: if ((!ConfigureParams.Screen.bFullScreen) && ! 328: (prevChosenDisplayMode != ConfigureParams.Screen.ChosenDisplayMode)) ! 329: Screen_SetWindowRes (); ! 330: ! 331: //if (!bScreenContentsChanged) return; ! 332: if (bTooSlowSoSkipAFlip) { ! 333: bTooSlowSoSkipAFlip = FALSE; ! 334: return; ! 335: } ! 336: ! 337: /* Lock screen ready for drawing */ ! 338: if (Screen_Lock()) { ! 339: bScreenContentsChanged = FALSE; ! 340: /* Set details */ ! 341: if (bInFullScreen) ! 342: Screen_SetFullScreenConvertDetails(); ! 343: else ! 344: Screen_SetWindowConvertDetails(); ! 345: /* Call drawing for full-screen */ ! 346: pDrawFunction = ScreenDraw.pDrawFunction; ! 347: ! 348: /* build RGB palettes */ ! 349: BuildRGBPalette (MainRGBPalette, MainPalette, len_main_palette); ! 350: BuildRGBPalette (CtrlRGBPalette, CtrlPalette, 16); ! 351: ! 352: if (pDrawFunction) ! 353: CALL_VAR(pDrawFunction) ! 354: ! 355: /* Unlock screen */ ! 356: Screen_UnLock(); ! 357: ! 358: SDL_Flip(sdlscrn); ! 359: } ! 360: } ! 361: ! 362: /*-----------------------------------------------------------------------*/ ! 363: /* ! 364: Draw ST screen to window/full-screen ! 365: This is now called from the 68k program's vblank handler, ! 366: since we need the vblank to update palettes appropriately ! 367: before drawing the screen (for frontier) ! 368: */ ! 369: void Screen_Draw(unsigned long _dummy) ! 370: { ! 371: /* Are we holding screen? Ie let user choose options while in full-screen mode using GDI */ ! 372: if (bInFullScreen && bFullScreenHold) ! 373: { ! 374: return; ! 375: } ! 376: ! 377: if (!bQuitProgram) ! 378: { ! 379: if(VideoBase) ! 380: { ! 381: Screen_DrawFrame(FALSE); ! 382: } ! 383: } ! 384: ! 385: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.