|
|
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: */
8:
9: const char Screen_fileid[] = "Hatari screen.c : " __DATE__ " " __TIME__;
10:
11: #include <SDL.h>
12: #include <SDL_endian.h>
13:
14: #include "main.h"
15: #include "configuration.h"
16: #include "log.h"
17: #include "m68000.h"
1.1.1.4 ! root 18: #include "dimension.h"
1.1 root 19: #include "paths.h"
20: #include "screen.h"
21: #include "control.h"
22: #include "convert/routines.h"
23: #include "resolution.h"
24: #include "statusbar.h"
25: #include "video.h"
26:
27:
28: /* extern for several purposes */
1.1.1.4 ! root 29: SDL_Window *sdlWindow;
! 30: SDL_Renderer *sdlRenderer;
! 31: SDL_Texture *sdlTexture;
1.1 root 32: SDL_Surface *sdlscrn = NULL; /* The SDL screen surface */
33: int nScreenZoomX, nScreenZoomY; /* Zooming factors, used for scaling mouse motions */
34: int nBorderPixelsLeft, nBorderPixelsRight; /* Pixels in left and right border */
35: int nBorderPixelsTop, nBorderPixelsBottom; /* Lines in top and bottom border */
36:
37: /* extern for shortcuts and falcon/hostscreen.c */
1.1.1.4 ! root 38: volatile bool bGrabMouse = false; /* Grab the mouse cursor in the window */
! 39: volatile bool bInFullScreen = false; /* true if in full screen */
1.1 root 40:
41:
42: /* extern for video.c */
43: Uint8 pNEXTScreen[(1120*832)*2];
44: FRAMEBUFFER *pFrameBuffer; /* Pointer into current 'FrameBuffer' */
45:
46: static FRAMEBUFFER FrameBuffers[NUM_FRAMEBUFFERS]; /* Store frame buffer details to tell how to update */
47: static Uint8 *pNEXTScreenCopy; /* Keep track of current and previous ST screen data */
48: static Uint8 *pPCScreenDest; /* Destination PC buffer */
49: static int NEXTScreenEndHorizLine; /* End lines to be converted */
50: static int PCScreenBytesPerLine;
51: static int NEXTScreenWidthBytes;
52: static SDL_Rect NEXTScreenRect; /* screen size without statusbar */
53:
54: static int NEXTScreenLineOffset[910]; /* Offsets for ST screen lines eg, 0,160,320... */
55:
56: static void (*ScreenDrawFunctionsNormal[3])(void); /* Screen draw functions */
57:
58: static bool bScreenContentsChanged; /* true if buffer changed and requires blitting */
59: static bool bScrDoubleY; /* true if double on Y */
60: static int ScrUpdateFlag; /* Bit mask of how to update screen */
61:
62:
63: static bool Screen_DrawFrame(bool bForceFlip);
64:
1.1.1.4 ! root 65: #if 1 /* Translating to SDL2 */
! 66: void SDL_UpdateRects(SDL_Surface *screen, int numrects, SDL_Rect *rects)
! 67: {
! 68: //fprintf(stderr,"rendering %i %i %i %i %i\n", numrects, rects->x, rects->w, rects->w, rects->h);
! 69: SDL_UpdateTexture(sdlTexture, NULL, screen->pixels, screen->pitch);
! 70: SDL_RenderClear(sdlRenderer);
! 71: SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL);
! 72: SDL_RenderPresent(sdlRenderer);
! 73: }
! 74:
! 75: void SDL_UpdateRect(SDL_Surface *screen, Sint32 x, Sint32 y, Sint32 w, Sint32 h)
! 76: {
! 77: SDL_Rect rect = { x, y, w, h };
! 78: SDL_UpdateRects(screen, 1, &rect);
! 79: }
! 80: #endif
1.1 root 81:
82: /*-----------------------------------------------------------------------*/
83: /**
84: * Create ST 0x777 / STe 0xfff color format to 16 or 32 bits per pixel
85: * conversion table. Called each time when changed resolution or to/from
86: * fullscreen mode.
87: */
88: static void Screen_SetupRGBTable(void)
89: {
90: }
91:
92: SDL_Color sdlColors[16];
93: Uint32 colors[32];
94:
1.1.1.4 ! root 95: Uint32 hicolors[4096];
! 96:
1.1 root 97: /*-----------------------------------------------------------------------*/
98: /**
99: * Create new palette for display.
100: */
101: static void Screen_CreatePalette(void)
102: {
103:
104: sdlColors[0].r = sdlColors[0].g = sdlColors[0].b = 255;
1.1.1.4 ! root 105: sdlColors[1].r = sdlColors[1].g = sdlColors[1].b = 170;
! 106: sdlColors[2].r = sdlColors[2].g = sdlColors[2].b = 85;
1.1 root 107: sdlColors[3].r = sdlColors[3].g = sdlColors[3].b = 0;
108: }
109:
110:
111: /*-----------------------------------------------------------------------*/
112: /**
113: * Create 8-Bit palette for display if needed.
114: */
115: static void Screen_Handle8BitPalettes(void)
116: {
117: }
118:
119:
120: /*-----------------------------------------------------------------------*/
121: /**
122: * Set screen draw functions.
123: */
124: static void Screen_SetDrawFunctions(int nBitCount, bool bDoubleLowRes)
125: {
126: ScreenDrawFunctionsNormal[ST_HIGH_RES] = ConvertHighRes_640x8Bit;
127: }
128:
129:
130: /*-----------------------------------------------------------------------*/
131: /**
132: * Set amount of border pixels
133: */
134: static void Screen_SetBorderPixels(int leftX, int leftY)
135: {
136: }
137:
138: /*-----------------------------------------------------------------------*/
139: /**
140: * store Y offset for each horizontal line in our source ST screen for
141: * reference in the convert functions.
142: */
143: static void Screen_SetSTScreenOffsets(void)
144: {
145: }
146:
147:
148: /*-----------------------------------------------------------------------*/
149: /**
150: * Initialize SDL screen surface / set resolution.
151: */
152: static void Screen_SetResolution(void)
153: {
154: int Width, Height, nZoom, SBarHeight, BitCount, maxW, maxH;
155: bool bDoubleLowRes = false;
156:
1.1.1.4 ! root 157: BitCount = 0; /* host native */
1.1 root 158:
159: nBorderPixelsTop = nBorderPixelsBottom = 0;
160: nBorderPixelsLeft = nBorderPixelsRight = 0;
161:
162: nScreenZoomX = 1;
163: nScreenZoomY = 1;
164:
165: Width = 1120;
166: Height = 832;
167: nZoom = 1;
168:
169: /* Statusbar height for doubled screen size */
170: SBarHeight = Statusbar_GetHeightForSize(1120, 832);
171: Resolution_GetLimits(&maxW, &maxH, &BitCount);
172:
173:
174: Screen_SetSTScreenOffsets();
175: Height += Statusbar_SetHeight(Width, Height);
176:
177: /* Check if we really have to change the video mode: */
178: if (!sdlscrn || sdlscrn->w != Width || sdlscrn->h != Height
1.1.1.4 ! root 179: || (BitCount && sdlscrn->format->BitsPerPixel != BitCount))
1.1 root 180: {
181: #ifdef _MUDFLAP
182: if (sdlscrn) {
183: __mf_unregister(sdlscrn->pixels, sdlscrn->pitch*sdlscrn->h, __MF_TYPE_GUESS);
184: }
185: #endif
186: if (bInFullScreen)
187: {
188: /* unhide the Hatari WM window for fullscreen */
189: Control_ReparentWindow(Width, Height, bInFullScreen);
190: }
191:
192: /* Set new video mode */
1.1.1.4 ! root 193: SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
! 194:
! 195: fprintf(stderr, "SDL screen request: %d x %d @ %d (%s)\n", Width, Height, BitCount, bInFullScreen?"fullscreen":"windowed");
! 196: sdlWindow = SDL_CreateWindow(PROG_NAME,
! 197: SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
! 198: Width, Height, 0);
! 199: sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, 0);
! 200: if (!sdlWindow || !sdlRenderer)
1.1 root 201: {
1.1.1.4 ! root 202: fprintf(stderr,"Failed to create window or renderer!\n");
! 203: exit(-1);
1.1 root 204: }
1.1.1.4 ! root 205: SDL_RenderSetLogicalSize(sdlRenderer, Width, Height);
! 206: sdlscrn = SDL_CreateRGBSurface(SDL_SWSURFACE, Width, Height, 32,
! 207: 0x00FF0000, 0x0000FF00,
! 208: 0x000000FF, 0x00000000);
! 209: sdlTexture = SDL_CreateTexture(sdlRenderer,
! 210: SDL_PIXELFORMAT_RGB888,
! 211: SDL_TEXTUREACCESS_STREAMING,
! 212: Width, Height);
! 213: fprintf(stderr, "SDL screen granted: %d x %d @ %d\n", sdlscrn->w, sdlscrn->h, sdlscrn->format->BitsPerPixel);
1.1 root 214:
215: /* Exit if we can not open a screen */
216: if (!sdlscrn)
217: {
218: fprintf(stderr, "Could not set video mode:\n %s\n", SDL_GetError() );
219: SDL_Quit();
220: exit(-2);
221: }
222: #ifdef _MUDFLAP
223: __mf_register(sdlscrn->pixels, sdlscrn->pitch*sdlscrn->h, __MF_TYPE_GUESS, "SDL pixels");
224: #endif
225:
226: if (!bInFullScreen)
227: {
228: /* re-embed the new Hatari SDL window */
229: Control_ReparentWindow(Width, Height, bInFullScreen);
230: }
231:
232: /* Re-init screen palette: */
233: if (sdlscrn->format->BitsPerPixel == 8)
234: Screen_Handle8BitPalettes(); /* Initialize new 8 bit palette */
235: else
236: Screen_SetupRGBTable(); /* Create color convertion table */
237:
238: Statusbar_Init(sdlscrn);
239:
240: /* screen area without the statusbar */
241: NEXTScreenRect.x = 0;
242: NEXTScreenRect.y = 0;
243: NEXTScreenRect.w = sdlscrn->w;
244: NEXTScreenRect.h = sdlscrn->h - Statusbar_GetHeight();
245: }
246:
247: /* Set drawing functions */
248: Screen_SetDrawFunctions(sdlscrn->format->BitsPerPixel, bDoubleLowRes);
249:
250: Screen_SetFullUpdate(); /* Cause full update of screen */
251: }
252:
253:
254: /*-----------------------------------------------------------------------*/
255: /**
256: * Init Screen bitmap and buffers/tables needed for ST to PC screen conversion
257: */
258: void Screen_Init(void)
259: {
260: int i;
261:
262: /* Clear frame buffer structures and set current pointer */
263: memset(FrameBuffers, 0, NUM_FRAMEBUFFERS * sizeof(FRAMEBUFFER));
264:
265: /* Allocate previous screen check workspace. We are going to double-buffer a double-buffered screen. Oh. */
266: for (i = 0; i < NUM_FRAMEBUFFERS; i++)
267: {
268: FrameBuffers[i].pNEXTScreen = malloc(((1024)/8)*768);
269: FrameBuffers[i].pNEXTScreenCopy = malloc(((1024)/8)*768);
270: if (!FrameBuffers[i].pNEXTScreen || !FrameBuffers[i].pNEXTScreenCopy)
271: {
272: fprintf(stderr, "Failed to allocate frame buffer memory.\n");
273: exit(-1);
274: }
275: }
276: pFrameBuffer = &FrameBuffers[0];
277:
278: /* Set initial window resolution */
279: bInFullScreen = ConfigureParams.Screen.bFullScreen;
280: Screen_SetResolution();
281:
1.1.1.4 ! root 282: if (bGrabMouse) {
! 283: SDL_SetRelativeMouseMode(SDL_TRUE);
! 284: SDL_SetWindowGrab(sdlWindow, SDL_TRUE);
! 285: }
1.1 root 286:
287: Video_SetScreenRasters(); /* Set rasters ready for first screen */
288:
289: Screen_CreatePalette();
290: /* Configure some SDL stuff: */
291: SDL_ShowCursor(SDL_DISABLE);
292: }
293:
294:
295: /*-----------------------------------------------------------------------*/
296: /**
297: * Free screen bitmap and allocated resources
298: */
299: void Screen_UnInit(void)
300: {
301: int i;
302:
303: /* Free memory used for copies */
304: for (i = 0; i < NUM_FRAMEBUFFERS; i++)
305: {
306: free(FrameBuffers[i].pNEXTScreen);
307: free(FrameBuffers[i].pNEXTScreenCopy);
308: }
309: }
310:
311:
312: /*-----------------------------------------------------------------------*/
313: /**
314: * Reset screen
315: */
316: void Screen_Reset(void)
317: {
318: /* Cause full update */
319: Screen_ModeChanged();
320: }
321:
322:
323: /*-----------------------------------------------------------------------*/
324: /**
325: * Set flags so screen will be TOTALLY re-drawn (clears whole of full-screen)
326: * next time around
327: */
328: void Screen_SetFullUpdate(void)
329: {
330: int i;
331:
332: /* Update frame buffers */
333: for (i = 0; i < NUM_FRAMEBUFFERS; i++)
334: FrameBuffers[i].bFullUpdate = true;
1.1.1.4 ! root 335:
! 336: InvalidateScreenBuffer();
1.1 root 337: }
338:
339:
340: /*-----------------------------------------------------------------------*/
341: /**
342: * Clear Window display memory
343: */
344: static void Screen_ClearScreen(void)
345: {
346: SDL_FillRect(sdlscrn, &NEXTScreenRect, SDL_MapRGB(sdlscrn->format, 0, 0, 0));
347: }
348:
349:
350: /*-----------------------------------------------------------------------*/
351: /**
352: * Return true if (falcon/tt) hostscreen functions need to be used
353: * instead of the (st/ste) functions here.
354: */
355: static bool Screen_UseHostScreen(void)
356: {
357: return false;
358: }
359:
360: /*-----------------------------------------------------------------------*/
361: /**
362: * Force screen redraw. Does the right thing regardless of whether
363: * we're in ST/STe, Falcon or TT mode. Needed when switching modes
364: * while emulation is paused.
365: */
366: static void Screen_Refresh(void)
367: {
368: Screen_DrawFrame(true);
369: }
370:
371:
372: /*-----------------------------------------------------------------------*/
373: /**
374: * Enter Full screen mode
375: */
376: void Screen_EnterFullScreen(void)
377: {
378: bool bWasRunning;
379:
380: if (!bInFullScreen)
381: {
382: /* Hold things... */
383: bWasRunning = Main_PauseEmulation(false);
384: bInFullScreen = true;
385:
386: if (Screen_UseHostScreen())
387: {
388: // HostScreen_toggleFullScreen();
389: }
390: else
391: {
1.1.1.4 ! root 392: SDL_SetWindowFullscreen(sdlWindow, SDL_WINDOW_FULLSCREEN_DESKTOP);
! 393: //Screen_SetResolution();
! 394: //Screen_ClearScreen(); /* Black out screen bitmap as will be invalid when return */
1.1 root 395: }
396:
397: SDL_Delay(20); /* To give monitor time to change to new resolution */
398:
399: if (bWasRunning)
400: {
401: /* And off we go... */
402: Main_UnPauseEmulation();
403: }
404: else
405: {
406: Screen_Refresh();
407: }
1.1.1.4 ! root 408: SDL_SetRelativeMouseMode(SDL_TRUE);
! 409: SDL_SetWindowGrab(sdlWindow, SDL_TRUE);
1.1 root 410: }
411: }
412:
413:
414: /*-----------------------------------------------------------------------*/
415: /**
416: * Return from Full screen mode back to a window
417: */
418: void Screen_ReturnFromFullScreen(void)
419: {
420: bool bWasRunning;
421:
422: if (bInFullScreen)
423: {
424: /* Hold things... */
425: bWasRunning = Main_PauseEmulation(false);
426: bInFullScreen = false;
427:
428: if (Screen_UseHostScreen())
429: {
430: // HostScreen_toggleFullScreen();
431: }
432: else
433: {
1.1.1.4 ! root 434: SDL_SetWindowFullscreen(sdlWindow, 0);
! 435: //Screen_SetResolution();
1.1 root 436: }
437: SDL_Delay(20); /* To give monitor time to switch resolution */
438:
439: if (bWasRunning)
440: {
441: /* And off we go... */
442: Main_UnPauseEmulation();
443: }
444: else
445: {
446: Screen_Refresh();
447: }
448:
449: if (!bGrabMouse)
450: {
451: /* Un-grab mouse pointer in windowed mode */
1.1.1.4 ! root 452: SDL_SetRelativeMouseMode(SDL_FALSE);
! 453: SDL_SetWindowGrab(sdlWindow, SDL_FALSE);
1.1 root 454: }
455: }
456: }
457:
458:
459: /*-----------------------------------------------------------------------*/
460: /**
461: * Have we changed between low/med/high res?
462: */
463: static void Screen_DidResolutionChange(int new_res)
464: {
465: }
466:
467:
468: /*-----------------------------------------------------------------------*/
469: /**
470: * Force things associated with changing between low/medium/high res.
471: */
472: void Screen_ModeChanged(void)
473: {
474: if (!sdlscrn)
475: {
476: /* screen not yet initialized */
477: return;
478: }
479: /* Set new display mode, if differs from current */
480: Screen_SetResolution();
481: Screen_SetFullUpdate();
1.1.1.4 ! root 482: if (bInFullScreen || bGrabMouse) {
! 483: SDL_SetRelativeMouseMode(SDL_TRUE);
! 484: SDL_SetWindowGrab(sdlWindow, SDL_TRUE);
! 485: } else {
! 486: SDL_SetRelativeMouseMode(SDL_FALSE);
! 487: SDL_SetWindowGrab(sdlWindow, SDL_FALSE);
! 488: }
1.1 root 489: }
490:
491:
492: /*-----------------------------------------------------------------------*/
493: /**
494: * Compare current resolution on line with previous, and set 'UpdateLine' accordingly
495: * Return if swap between low/medium resolution
496: */
497: static bool Screen_CompareResolution(int y, int *pUpdateLine, int oldres)
498: {
499: return false;
500: }
501:
502:
503: /*-----------------------------------------------------------------------*/
504: /**
505: * Check to see if palette changes cause screen update and keep 'HBLPalette[]' up-to-date
506: */
507: static void Screen_ComparePalette(int y, int *pUpdateLine)
508: {
509: }
510:
511:
512: /*-----------------------------------------------------------------------*/
513: /**
514: * Check for differences in Palette and Resolution from Mask table and update
515: * and store off which lines need updating and create full-screen palette.
516: * (It is very important for these routines to check for colour changes with
517: * the previous screen so only the very minimum parts are updated).
518: * Return new STRes value.
519: */
520: static int Screen_ComparePaletteMask(int res)
521: {
522: return 0;
523: }
524:
525:
526: /*-----------------------------------------------------------------------*/
527: /**
528: * Update Palette Mask to show 'full-update' required. This is usually done after a resolution change
529: * or when going between a Window and full-screen display
530: */
531: static void Screen_SetFullUpdateMask(void)
532: {
533: }
534:
535:
536: /*-----------------------------------------------------------------------*/
537: /**
538: * Set details for ST screen conversion.
539: */
540: static void Screen_SetConvertDetails(void)
541: {
542: }
543:
544:
545: /*-----------------------------------------------------------------------*/
546: /**
547: * Lock full-screen for drawing
548: */
549: static bool Screen_Lock(void)
550: {
551: if (SDL_MUSTLOCK(sdlscrn))
552: {
553: if (SDL_LockSurface(sdlscrn))
554: {
555: Screen_ReturnFromFullScreen(); /* All OK? If not need to jump back to a window */
556: return false;
557: }
558: }
559:
560: return true;
561: }
562:
563: /*-----------------------------------------------------------------------*/
564: /**
565: * UnLock full-screen
566: */
567: static void Screen_UnLock(void)
568: {
569: if ( SDL_MUSTLOCK(sdlscrn) )
570: SDL_UnlockSurface(sdlscrn);
571: }
572:
573:
574: /*-----------------------------------------------------------------------*/
575: /**
576: * Blit our converted ST screen to window/full-screen
577: */
578: static void Screen_Blit(void)
579: {
580: unsigned char *pTmpScreen;
581:
582: {
583: SDL_UpdateRects(sdlscrn, 1, &NEXTScreenRect);
584: }
585:
586: /* Swap copy/raster buffers in screen. */
587: pTmpScreen = pFrameBuffer->pNEXTScreenCopy;
588: pFrameBuffer->pNEXTScreenCopy = pFrameBuffer->pNEXTScreen;
589: pFrameBuffer->pNEXTScreen = pTmpScreen;
590: }
591:
592:
593: /*-----------------------------------------------------------------------*/
594: /**
595: */
596: static bool Screen_DrawFrame(bool bForceFlip)
597: {
598: void (*pDrawFunction)(void);
599:
600: /* Lock screen ready for drawing */
601: if (Screen_Lock())
602: {
603:
604: pDrawFunction = ScreenDrawFunctionsNormal[ST_HIGH_RES];
605:
606: if (pDrawFunction)
607: CALL_VAR(pDrawFunction);
608:
609: /* Unlock screen */
610: Screen_UnLock();
611:
612: /* draw statusbar or overlay led(s) after unlock */
613: Statusbar_OverlayBackup(sdlscrn);
614: Statusbar_Update(sdlscrn);
615:
616: Screen_Blit();
617:
618: return bScreenContentsChanged;
619: }
620:
621: return false;
622: }
623:
624:
625: /*-----------------------------------------------------------------------*/
626: /**
627: * Draw ST screen to window/full-screen
628: */
629: bool Screen_Draw(void)
630: {
631: if (!bQuitProgram)
632: {
633: /* And draw (if screen contents changed) */
634: Screen_DrawFrame(false);
635: return true;
636: }
637:
638: return false;
639: }
640:
641:
642: /* -------------- screen conversion routines --------------------------------
643: */
644:
645:
646: /*-----------------------------------------------------------------------*/
647: /**
648: */
649: static int AdjustLinePaletteRemap(int y)
650: {
651: return true;
652: }
653:
654:
655: /*-----------------------------------------------------------------------*/
656: /**
657: */
658: static void Convert_StartFrame(void)
659: {
660: }
661:
662: /* lookup tables and conversion macros */
663: #include "convert/macros.h"
664:
665: /* Conversion routines */
666:
667: #include "convert/high640x8.c" /* HighRes To 640xH x 8-bit color */
668:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.