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