1 /*
2  * OpenBOR - http://www.chronocrash.com
3  * -----------------------------------------------------------------------
4  * All rights reserved, see LICENSE in OpenBOR root for details.
5  *
6  * Copyright (c) 2004 - 2014 OpenBOR Team
7  */
8 #if ANDROID
9 
10 // CRxTRDude - changed the directory for neatness.
11 #include "android/app/jni/openbor/video.c"
12 
13 #else
14 
15 #include "sdlport.h"
16 #include <math.h>
17 #include "types.h"
18 #include "video.h"
19 #include "vga.h"
20 #include "screen.h"
21 #include "opengl.h"
22 #include "savedata.h"
23 #include "gfxtypes.h"
24 #include "gfx.h"
25 #include "pngdec.h"
26 #include "videocommon.h"
27 #include "../resources/OpenBOR_Icon_32x32_png.h"
28 
29 SDL_Window *window = NULL;
30 static SDL_Renderer *renderer = NULL;
31 static SDL_Texture *texture = NULL;
32 s_videomodes stored_videomodes;
33 yuv_video_mode stored_yuv_mode;
34 int yuv_mode = 0;
35 char windowTitle[MAX_LABEL_LEN] = {"OpenBOR"};
36 int stretch = 0;
37 int opengl = 0; // OpenGL backend currently in use?
38 int nativeWidth, nativeHeight; // monitor resolution used in fullscreen mode
39 int brightness = 0;
40 
initSDL()41 void initSDL()
42 {
43 	SDL_DisplayMode video_info;
44 	int init_flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC;
45 
46     /*#if EE_CURRENT_PLATFORM == EE_PLATFORM_WINDOWS
47        SDL_setenv("SDL_AUDIODRIVER", "directsound", true);
48     #endif*/
49 
50 	if(SDL_Init(init_flags) < 0)
51 	{
52 		printf("SDL Failed to Init!!!! (%s)\n", SDL_GetError());
53 		borExit(0);
54 	}
55 	SDL_ShowCursor(SDL_DISABLE);
56 	//atexit(SDL_Quit); //White Dragon: use SDL_Quit() into sdlport.c it's best practice!
57 
58 #ifdef LOADGL
59 	if(SDL_GL_LoadLibrary(NULL) < 0)
60 	{
61 		printf("Warning: couldn't load OpenGL library (%s)\n", SDL_GetError());
62 	}
63 #endif
64 
65 	SDL_GetCurrentDisplayMode(0, &video_info);
66 	nativeWidth = video_info.w;
67 	nativeHeight = video_info.h;
68 	printf("debug:nativeWidth, nativeHeight, bpp, Hz  %d, %d, %d, %d\n", nativeWidth, nativeHeight, SDL_BITSPERPIXEL(video_info.format), video_info.refresh_rate);
69 }
70 
video_set_window_title(const char * title)71 void video_set_window_title(const char* title)
72 {
73 	if(window) SDL_SetWindowTitle(window, title);
74 	strncpy(windowTitle, title, sizeof(windowTitle)-1);
75 }
76 
77 static unsigned pixelformats[4] = {SDL_PIXELFORMAT_INDEX8, SDL_PIXELFORMAT_BGR565, SDL_PIXELFORMAT_BGR888, SDL_PIXELFORMAT_ABGR8888};
78 
SetVideoMode(int w,int h,int bpp,bool gl)79 int SetVideoMode(int w, int h, int bpp, bool gl)
80 {
81 	int flags = SDL_WINDOW_SHOWN | SDL_WINDOW_INPUT_FOCUS;
82 	static bool last_gl = false;
83 	static int last_x = SDL_WINDOWPOS_UNDEFINED;
84 	static int last_y = SDL_WINDOWPOS_UNDEFINED;
85 
86 	if(gl) flags |= SDL_WINDOW_OPENGL;
87 	if(savedata.fullscreen) flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
88 
89 	if(!(SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN_DESKTOP))
90 		SDL_GetWindowPosition(window, &last_x, &last_y);
91 
92 	if(window && gl != last_gl)
93 	{
94 		SDL_DestroyWindow(window);
95 		window = NULL;
96 	}
97 	last_gl = gl;
98 
99 	if(renderer) SDL_DestroyRenderer(renderer);
100 	if(texture)  SDL_DestroyTexture(texture);
101 	renderer = NULL;
102 	texture = NULL;
103 
104 	if(window)
105 	{
106 		if(savedata.fullscreen)
107 		{
108 			SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
109 		}
110 		else
111 		{
112 #ifndef WIN // hiding and showing the window is problematic on Windows
113 			if(SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN_DESKTOP)
114 				SDL_HideWindow(window);
115 #endif
116 			SDL_SetWindowFullscreen(window, 0);
117 			SDL_SetWindowSize(window, w, h);
118 			SDL_SetWindowPosition(window, last_x, last_y);
119 			SDL_ShowWindow(window);
120 		}
121 	}
122 	else
123 	{
124 		window = SDL_CreateWindow(windowTitle, last_x, last_y, w, h, flags);
125 		if(!window)
126 		{
127 			printf("Error: failed to create window: %s\n", SDL_GetError());
128 			return 0;
129 		}
130 		SDL_Surface* icon = (SDL_Surface*)pngToSurface((void*)openbor_icon_32x32_png.data);
131 		SDL_SetWindowIcon(window, icon);
132 		SDL_FreeSurface(icon);
133 		if(!savedata.fullscreen) SDL_GetWindowPosition(window, &last_x, &last_y);
134 	}
135 
136 	if(!gl)
137 	{
138 		renderer = SDL_CreateRenderer(window, -1, savedata.vsync ? SDL_RENDERER_PRESENTVSYNC : 0);
139 		if(!renderer)
140 		{
141 			printf("Error: failed to create renderer: %s\n", SDL_GetError());
142 			return 0;
143 		}
144 	}
145 
146 	return 1;
147 }
148 
video_set_mode(s_videomodes videomodes)149 int video_set_mode(s_videomodes videomodes)
150 {
151 	stored_videomodes = videomodes;
152 	yuv_mode = 0;
153 
154 	if(videomodes.hRes==0 && videomodes.vRes==0)
155 	{
156 		Term_Gfx();
157 		return 0;
158 	}
159 
160 	videomodes = setupPreBlitProcessing(videomodes);
161 
162 	// 8-bit color should be transparently converted to 32-bit
163 	assert(videomodes.pixel == 2 || videomodes.pixel == 4);
164 
165 	// try OpenGL initialization first
166 	if(savedata.usegl && video_gl_set_mode(videomodes)) return 1;
167 	else opengl = 0;
168 
169 	if(!SetVideoMode(videomodes.hRes * videomodes.hScale,
170 	                 videomodes.vRes * videomodes.vScale,
171 	                 videomodes.pixel * 8, false))
172 	{
173 		return 0;
174 	}
175 
176 	if(savedata.hwfilter ||
177 	   (videomodes.hScale == 1 && videomodes.vScale == 1 && !savedata.fullscreen))
178 		SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");
179 	else
180 		SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
181 
182 	texture = SDL_CreateTexture(renderer,
183 	                            pixelformats[videomodes.pixel-1],
184 	                            SDL_TEXTUREACCESS_STREAMING,
185 	                            videomodes.hRes, videomodes.vRes);
186 
187 	SDL_ShowCursor(SDL_DISABLE);
188 	SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
189 	video_stretch(savedata.stretch);
190 
191 	return 1;
192 }
193 
video_fullscreen_flip()194 void video_fullscreen_flip()
195 {
196 	int restore_yuv = yuv_mode;
197 	savedata.fullscreen ^= 1;
198 	if(window) video_set_mode(stored_videomodes);
199 	if(restore_yuv) video_setup_yuv_overlay(&stored_yuv_mode);
200 }
201 
blit()202 void blit()
203 {
204 	SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
205 	SDL_RenderClear(renderer);
206 	SDL_RenderCopy(renderer, texture, NULL, NULL);
207 
208 	if (brightness > 0)
209 		SDL_SetRenderDrawColor(renderer, 255, 255, 255, brightness-1);
210 	else if (brightness < 0)
211 		SDL_SetRenderDrawColor(renderer, 0, 0, 0, (-brightness)-1);
212 	SDL_RenderFillRect(renderer, NULL);
213 
214 	SDL_RenderPresent(renderer);
215 }
216 
video_copy_screen(s_screen * src)217 int video_copy_screen(s_screen* src)
218 {
219 	// do any needed scaling and color conversion
220 	s_videosurface *surface = getVideoSurface(src);
221 
222 	if(opengl) return video_gl_copy_screen(surface);
223 
224 	SDL_UpdateTexture(texture, NULL, surface->data, surface->pitch);
225 	blit();
226 
227 	return 1;
228 }
229 
video_clearscreen()230 void video_clearscreen()
231 {
232 	if(opengl) { video_gl_clearscreen(); return; }
233 
234 	SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
235 	SDL_RenderClear(renderer);
236 	SDL_RenderPresent(renderer);
237 }
238 
video_stretch(int enable)239 void video_stretch(int enable)
240 {
241 	stretch = enable;
242 	if(window && !opengl)
243 	{
244 		if(stretch)
245 			SDL_RenderSetLogicalSize(renderer, 0, 0);
246 		else
247 			SDL_RenderSetLogicalSize(renderer, stored_videomodes.hRes, stored_videomodes.vRes);
248 	}
249 }
250 
video_set_color_correction(int gm,int br)251 void video_set_color_correction(int gm, int br)
252 {
253 	brightness = br;
254 	if(opengl) video_gl_set_color_correction(gm, br);
255 }
256 
video_setup_yuv_overlay(const yuv_video_mode * mode)257 int video_setup_yuv_overlay(const yuv_video_mode *mode)
258 {
259 	stored_yuv_mode = *mode;
260 	yuv_mode = 1;
261 	if(opengl) return video_gl_setup_yuv_overlay(mode);
262 
263 	SDL_DestroyTexture(texture);
264 	SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
265 	texture = SDL_CreateTexture(renderer,
266 	                            SDL_PIXELFORMAT_YV12,
267 	                            SDL_TEXTUREACCESS_STREAMING,
268 	                            mode->width, mode->height);
269 	if(!stretch)
270 		SDL_RenderSetLogicalSize(renderer, mode->display_width, mode->display_height);
271 	return texture ? 1 : 0;
272 }
273 
video_prepare_yuv_frame(yuv_frame * src)274 int video_prepare_yuv_frame(yuv_frame *src)
275 {
276 	if(opengl) return video_gl_prepare_yuv_frame(src);
277 
278 	SDL_UpdateYUVTexture(texture, NULL, src->lum, stored_yuv_mode.width,
279 	        src->cr, stored_yuv_mode.width/2, src->cb, stored_yuv_mode.width/2);
280 	return 1;
281 }
282 
video_display_yuv_frame(void)283 int video_display_yuv_frame(void)
284 {
285 	if(opengl) return video_gl_display_yuv_frame();
286 
287 	blit();
288 	return 1;
289 }
290 
vga_vwait(void)291 void vga_vwait(void)
292 {
293 	static int prevtick = 0;
294 	int now = SDL_GetTicks();
295 	int wait = 1000/60 - (now - prevtick);
296 	if (wait>0)
297 	{
298 		SDL_Delay(wait);
299 	}
300 	else SDL_Delay(1);
301 	prevtick = now;
302 }
303 
304 #endif
305