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