1 /*
2  * OpenBOR - http://www.LavaLit.com
3  * -----------------------------------------------------------------------
4  * All rights reserved, see LICENSE in OpenBOR root for details.
5  *
6  * Copyright (c) 2004 - 2011 OpenBOR Team
7  */
8 
9 #include <SDL_framerate.h>
10 #include <math.h>
11 #include "types.h"
12 #include "video.h"
13 #include "vga.h"
14 #include "screen.h"
15 #include "sdlport.h"
16 #include "opengl.h"
17 #include "openbor.h"
18 #include "gfxtypes.h"
19 #include "gfx.h"
20 
21 extern int videoMode;
22 
23 #if GP2X || DARWIN || DINGOO || WII
24 #define SKIP_CODE
25 #endif
26 
27 #ifndef SKIP_CODE
28 #include "pngdec.h"
29 #include "../resources/OpenBOR_Icon_32x32_png.h"
30 #endif
31 
32 FPSmanager framerate_manager;
33 s_videomodes stored_videomodes;
34 static SDL_Surface *screen = NULL;
35 static SDL_Surface *bscreen = NULL;
36 static SDL_Surface *bscreen2 = NULL;
37 #ifdef DINGOO
38 static SDL_Surface *screen_dingoo = NULL;
39 #endif
40 static SDL_Color colors[256];
41 static int bytes_per_pixel = 1;
42 int stretch = 0;
43 int opengl = 0; // OpenGL backend currently in use?
44 int nativeWidth, nativeHeight; // monitor resolution used in fullscreen mode
45 u8 pDeltaBuffer[480 * 2592];
46 
initSDL()47 void initSDL()
48 {
49 	const SDL_VideoInfo* video_info;
50 	int init_flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER | SDL_INIT_JOYSTICK;
51 
52 #ifdef CUSTOM_SIGNAL_HANDLER
53 	init_flags |= SDL_INIT_NOPARACHUTE;
54 #endif
55 
56 	if(SDL_Init(init_flags) < 0)
57 	{
58 		printf("SDL Failed to Init!!!! (%s)\n", SDL_GetError());
59 		borExit(0);
60 	}
61 	SDL_ShowCursor(SDL_DISABLE);
62 	atexit(SDL_Quit);
63 #ifndef SKIP_CODE
64 	SDL_WM_SetCaption("OpenBOR", NULL);
65 	SDL_WM_SetIcon((SDL_Surface*)pngToSurface((void*)openbor_icon_32x32_png.data), NULL);
66 #endif
67 #if WIN || LINUX && !DARWIN && !defined(GLES)
68 	if(SDL_GL_LoadLibrary(NULL) < 0)
69 	{
70 		printf("Warning: couldn't load OpenGL library (%s)\n", SDL_GetError());
71 	}
72 #endif
73 
74 	// Store the monitor's current resolution before setting the video mode for the first time
75 	video_info = SDL_GetVideoInfo();
76 #ifndef GP2X
77 	nativeWidth = video_info->current_w;
78 	nativeHeight = video_info->current_h;
79 #endif
80 
81 	SDL_initFramerate(&framerate_manager);
82 	SDL_setFramerate(&framerate_manager, 200);
83 }
84 
85 static unsigned masks[4][4] = {{0,0,0,0},{0x1F,0x07E0,0xF800,0},{0xFF,0xFF00,0xFF0000,0},{0xFF,0xFF00,0xFF0000,0}};
86 
video_set_mode(s_videomodes videomodes)87 int video_set_mode(s_videomodes videomodes)
88 {
89 	stored_videomodes = videomodes;
90 
91 	if(screen) SDL_FreeAndNullVideoSurface(screen);
92 	if(bscreen) { SDL_FreeSurface(bscreen); bscreen=NULL; }
93 	if(bscreen2) { SDL_FreeSurface(bscreen2); bscreen2=NULL; }
94 
95 	// try OpenGL initialization first
96 	if((savedata.usegl[savedata.fullscreen]) && video_gl_set_mode(videomodes)) return 1;
97 	else opengl = 0;
98 
99 	// FIXME: OpenGL surfaces aren't freed when switching from OpenGL to SDL
100 
101 	bytes_per_pixel = videomodes.pixel;
102 	if(videomodes.hRes==0 && videomodes.vRes==0)
103 	{
104 		Term_Gfx();
105 		return 0;
106 	}
107 
108 	if(savedata.screen[videoMode][0])
109 	{
110 #ifdef DINGOO
111 	screen_dingoo = SDL_SetVideoMode(videomodes.hRes*savedata.screen[videoMode][0],videomodes.vRes*savedata.screen[videoMode][0],16,SDL_SWSURFACE);
112 	screen = SDL_AllocSurface(SDL_SWSURFACE,videomodes.hRes*savedata.screen[videoMode][0],videomodes.vRes*savedata.screen[videoMode][0], 16,0,0,0,0);
113 #else
114 		screen = SDL_SetVideoMode(videomodes.hRes*savedata.screen[videoMode][0],videomodes.vRes*savedata.screen[videoMode][0],16,savedata.fullscreen?(SDL_SWSURFACE|SDL_DOUBLEBUF|SDL_FULLSCREEN):(SDL_SWSURFACE|SDL_DOUBLEBUF));
115 #endif
116 		SDL_ShowCursor(SDL_DISABLE);
117 		bscreen = SDL_AllocSurface(SDL_SWSURFACE, videomodes.hRes, videomodes.vRes, 8*bytes_per_pixel, masks[bytes_per_pixel-1][0], masks[bytes_per_pixel-1][1], masks[bytes_per_pixel-1][2], masks[bytes_per_pixel-1][3]); // 24bit mask
118 		bscreen2 = SDL_AllocSurface(SDL_SWSURFACE, videomodes.hRes+4, videomodes.vRes+8, 16, masks[1][2], masks[1][1], masks[1][0], masks[1][3]);
119 		Init_Gfx(565, 16);
120 		memset(pDeltaBuffer, 0x00, 1244160);
121 		if(bscreen==NULL || bscreen2==NULL) return 0;
122 	}
123 	else
124 	{
125 		if(bytes_per_pixel>1)
126 		{
127 			bscreen = SDL_AllocSurface(SDL_SWSURFACE, videomodes.hRes, videomodes.vRes, 8*bytes_per_pixel, masks[bytes_per_pixel-1][0], masks[bytes_per_pixel-1][1], masks[bytes_per_pixel-1][2], masks[bytes_per_pixel-1][3]); // 24bit mask
128 			if(!bscreen) return 0;
129 		}
130 #ifdef DINGOO
131 		screen_dingoo = SDL_SetVideoMode(videomodes.hRes,videomodes.vRes,16,SDL_SWSURFACE);
132 		screen = SDL_AllocSurface(SDL_SWSURFACE,videomodes.hRes,videomodes.vRes, 8*bytes_per_pixel,0,0,0,0);
133 #else
134 		screen = SDL_SetVideoMode(videomodes.hRes,videomodes.vRes,8*bytes_per_pixel,savedata.fullscreen?(SDL_SWSURFACE|SDL_DOUBLEBUF|SDL_FULLSCREEN):(SDL_SWSURFACE|SDL_DOUBLEBUF));
135 #endif
136 		SDL_ShowCursor(SDL_DISABLE);
137 	}
138 
139 	if(bytes_per_pixel==1)
140 	{
141 		SDL_SetColors(screen,colors,0,256);
142 		if(bscreen) SDL_SetColors(bscreen,colors,0,256);
143 	}
144 
145 	if(screen==NULL) return 0;
146 
147 	video_clearscreen();
148 	return 1;
149 }
150 
video_fullscreen_flip()151 void video_fullscreen_flip()
152 {
153 	size_t w, h;
154 	if(savedata.usegl) { video_gl_fullscreen_flip(); return; }
155 	savedata.fullscreen ^= 1;
156 
157 	if(savedata.fullscreen)
158 	{
159 		// OpenGL has better fullscreen than SDL
160 		if(video_set_mode(stored_videomodes)) return;
161 	}
162 	else if(opengl)
163 	{
164 		// switch from OpenGL fullscreen to SDL windowed
165 		if(video_set_mode(stored_videomodes)) return;
166 		return;
167 	}
168 
169 	// switch between SDL fullscreen and SDL windowed
170 	if(screen) {
171 		w = screen->w;
172 		h = screen->h;
173 		SDL_FreeVideoSurface(screen);
174 	} else {
175 		w = 320;
176 		h = 240;
177 	}
178 
179 	if(savedata.screen[videoMode][0])
180 		screen = SDL_SetVideoMode(w,h,16,savedata.fullscreen?(SDL_SWSURFACE|SDL_DOUBLEBUF|SDL_FULLSCREEN):(SDL_SWSURFACE|SDL_DOUBLEBUF));
181 	else
182 		screen = SDL_SetVideoMode(w,h,8*bytes_per_pixel,savedata.fullscreen?(SDL_SWSURFACE|SDL_DOUBLEBUF|SDL_FULLSCREEN):(SDL_SWSURFACE|SDL_DOUBLEBUF));
183 	SDL_ShowCursor(SDL_DISABLE);
184 	SDL_SetColors(screen,colors,0,256);
185 	if(bscreen) SDL_SetColors(bscreen,colors,0,256);
186 }
187 
188 //16bit, scale 2x 4x 8x ...
_stretchblit(SDL_Surface * src,SDL_Rect * srcrect,SDL_Surface * dst,SDL_Rect * dstrect)189 void _stretchblit(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect)
190 {
191 	SDL_Rect rect;
192 	int dst_x, dst_y, dst_w, dst_h, dst_row, src_row;
193 	int i;
194 	Uint16* psrc, *pdst;
195 
196 	if(!srcrect)
197 	{
198 		rect.x = rect.y = 0;
199 		rect.w = src->w;
200 		rect.h = src->h;
201 		srcrect = &rect;
202 	}
203 	dst_w = savedata.screen[videoMode][0] * srcrect->w;
204 	dst_h = savedata.screen[videoMode][0] * srcrect->h;
205 	if(!dstrect)
206 	{
207 		dst_x = dst_y = 0;
208 		if(dst_w>dst->w) dst_w = dst->w;
209 		if(dst_h>dst->h) dst_h = dst->h;
210 	}
211 	else
212 	{
213 		dst_x = dstrect->x;
214 		dst_y = dstrect->y;
215 		if(dst_w>dstrect->w) dst_w = dstrect->w;
216 		if(dst_h>dstrect->h) dst_h = dstrect->h;
217 	}
218 	psrc = (Uint16*)src->pixels + srcrect->x + srcrect->y * src->pitch/2;
219 	pdst = (Uint16*)dst->pixels + dst_x + dst_y*dst->pitch/2;
220 	dst_row = dst->pitch/2;
221 	src_row = src->pitch/2;
222 	while(dst_h>0)
223 	{
224 		for(i=0; i<dst_w; i++)
225 		{
226 			*(pdst + i) = *(psrc+(i/savedata.screen[videoMode][0]));
227 		}
228 
229 		for(i=1, pdst += dst_row; i<savedata.screen[videoMode][0] && dst_h; i++, dst_h--, pdst += dst_row)
230 		{
231 			memcpy(pdst, pdst-dst_row, dst_w<<1);
232 		}
233 		dst_h--;
234 		psrc += src_row;
235 	}
236 }
237 
video_copy_screen(s_screen * src)238 int video_copy_screen(s_screen* src)
239 {
240 	unsigned char *sp;
241 	char *dp;
242 	int width, height, linew, slinew;
243 	int h;
244 	SDL_Surface* ds = NULL;
245 	SDL_Rect rectdes, rectsrc;
246 
247 	// use video_gl_copy_screen if in OpenGL mode
248 	if(opengl) return video_gl_copy_screen(src);
249 
250 	width = screen->w;
251 	if(width > src->width) width = src->width;
252 	height = screen->h;
253 	if(height > src->height) height = src->height;
254 	if(!width || !height) return 0;
255 	h = height;
256 
257 	if(bscreen)
258 	{
259 		rectdes.x = rectdes.y = 0;
260 		rectdes.w = width*savedata.screen[videoMode][0]; rectdes.h = height*savedata.screen[videoMode][0];
261 		if(bscreen2) {rectsrc.x = 2; rectsrc.y = 4;}
262 		else         {rectsrc.x = 0; rectsrc.y = 0;}
263 		rectsrc.w = width; rectsrc.h = height;
264 		if(SDL_MUSTLOCK(bscreen)) SDL_LockSurface(bscreen);
265 	}
266 
267 	// Copy to linear video ram
268 	if(SDL_MUSTLOCK(screen)) SDL_LockSurface(screen);
269 
270 	sp = (unsigned char*)src->data;
271 	ds = (bscreen?bscreen:screen);
272 	dp = ds->pixels;
273 
274 	linew = width*bytes_per_pixel;
275 	slinew = src->width*bytes_per_pixel;
276 
277 	do{
278 		memcpy(dp, sp, linew);
279 		sp += slinew;
280 		dp += ds->pitch;
281 	}while(--h);
282 
283 	if(SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen);
284 
285 	if(bscreen)
286 	{
287 		if(SDL_MUSTLOCK(bscreen)) SDL_UnlockSurface(bscreen);
288 		if(bscreen2) SDL_BlitSurface(bscreen, NULL, bscreen2, &rectsrc);
289 		else         SDL_BlitSurface(bscreen, NULL, screen, &rectsrc);
290 		if(bscreen2)
291 		{
292 			if(bscreen2 && SDL_MUSTLOCK(bscreen2)) SDL_LockSurface(bscreen2);
293 			if(SDL_MUSTLOCK(screen)) SDL_LockSurface(screen);
294 
295 			if(savedata.screen[videoMode][0]==2) (*GfxBlitters[(int)savedata.screen[videoMode][1]])((u8*)bscreen2->pixels+bscreen2->pitch*4+4, bscreen2->pitch, pDeltaBuffer+bscreen2->pitch, (u8*)screen->pixels, screen->pitch, screen->w>>1, screen->h>>1);
296 			else _stretchblit(bscreen2, &rectsrc, screen, &rectdes);
297 
298 			if(SDL_MUSTLOCK(bscreen2)) SDL_UnlockSurface(bscreen2);
299 			if(SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen);
300 		}
301 	}
302 #ifdef DINGOO
303 	SDL_BlitSurface(screen,NULL,screen_dingoo,NULL);
304 	SDL_Flip(screen_dingoo);
305 #else
306 	SDL_Flip(screen);
307 #endif
308 
309 #if WIN || LINUX
310 	SDL_framerateDelay(&framerate_manager);
311 #endif
312 
313 	return 1;
314 }
315 
video_clearscreen()316 void video_clearscreen()
317 {
318 	if(opengl) { video_gl_clearscreen(); return; }
319 
320 	if(SDL_MUSTLOCK(screen)) SDL_LockSurface(screen);
321 	memset(screen->pixels, 0, screen->pitch*screen->h);
322 	if(SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen);
323 	if(bscreen)
324 	{
325 		if(SDL_MUSTLOCK(bscreen)) SDL_LockSurface(bscreen);
326 		memset(bscreen->pixels, 0, bscreen->pitch*bscreen->h);
327 		if(SDL_MUSTLOCK(bscreen)) SDL_UnlockSurface(bscreen);
328 	}
329 }
330 
video_stretch(int enable)331 void video_stretch(int enable)
332 {
333 	if(screen || opengl) video_clearscreen();
334 	stretch = enable;
335 }
336 
vga_vwait(void)337 void vga_vwait(void)
338 {
339 #ifdef GP2X
340 	gp2x_video_wait_vsync();
341 #else
342 	static int prevtick = 0;
343 	int now = SDL_GetTicks();
344 	int wait = 1000/60 - (now - prevtick);
345 	if (wait>0)
346 	{
347 		SDL_Delay(wait);
348 	}
349 	else SDL_Delay(1);
350 	prevtick = now;
351 #endif
352 }
353 
vga_setpalette(unsigned char * palette)354 void vga_setpalette(unsigned char* palette)
355 {
356 	int i;
357 	video_gl_setpalette(palette);
358 	for(i=0;i<256;i++){
359 		colors[i].r=palette[0];
360 		colors[i].g=palette[1];
361 		colors[i].b=palette[2];
362 		palette+=3;
363 	}
364 	if(!opengl)
365 	{
366 		SDL_SetColors(screen,colors,0,256);
367 		if(bscreen) SDL_SetColors(bscreen,colors,0,256);
368 	}
369 }
370 
371 // TODO: give this function a boolean (int) return type denoting success/failure
vga_set_color_correction(int gm,int br)372 void vga_set_color_correction(int gm, int br)
373 {
374 	if(opengl) video_gl_set_color_correction(gm, br);
375 }
376 
377