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