1 // blitter effects via SDL2
2 #include "burner.h"
3 #include "vid_support.h"
4 #include "vid_softfx.h"
5 
6 #ifdef INCLUDE_SWITCHRES
7 #include <switchres_wrapper.h>
8 #endif
9 
10 #include <SDL.h>
11 #include <SDL_image.h>
12 
13 extern int vsync;
14 extern char videofiltering[3];
15 
16 static unsigned char* VidMem = NULL;
17 extern SDL_Window* sdlWindow;
18 SDL_Renderer* sdlRenderer = NULL;
19 static SDL_Texture* sdlTexture = NULL;
20 static int  nRotateGame = 0;
21 static bool bFlipped = false;
22 static SDL_Rect dstrect;
23 static SDL_Rect title_texture_rect;
24 static SDL_Rect dest_title_texture_rect;
25 
26 static int screenh, screenw;
27 static char Windowtitle[512];
28 
29 
RenderMessage()30 void RenderMessage()
31 {
32 	// First render anything that is key-held based
33 	if (bAppDoFast)
34 	{
35 		inprint_shadowed(sdlRenderer, "FFWD", 10, 10);
36 	}
37 	if (bAppShowFPS)
38 	{
39 		if (bAppFullscreen)
40 		{
41 			inprint_shadowed(sdlRenderer, fpsstring, 10, 50);
42 		}
43 		else
44 		{
45 			sprintf(Windowtitle, "FBNeo - FPS: %s - %s - %s", fpsstring, BurnDrvGetTextA(DRV_NAME), BurnDrvGetTextA(DRV_FULLNAME));
46 			SDL_SetWindowTitle(sdlWindow, Windowtitle);
47 		}
48 	}
49 
50 	if (messageFrames > 1)
51 	{
52 		inprint_shadowed(sdlRenderer, lastMessage, 10, 30);
53 		messageFrames--;
54 	}
55 }
56 
Exit()57 static int Exit()
58 {
59 #ifdef INCLUDE_SWITCHRES
60 	sr_deinit();
61 #endif
62 	kill_inline_font(); //TODO: This is not supposed to be here
63 	SDL_DestroyTexture(sdlTexture);
64 	SDL_DestroyRenderer(sdlRenderer);
65 	SDL_DestroyWindow(sdlWindow);
66 
67 	if (VidMem)
68 	{
69 		free(VidMem);
70 	}
71 	return 0;
72 }
73 static int display_w = 400, display_h = 300;
74 
75 
Init()76 static int Init()
77 {
78 	int nMemLen = 0;
79 	int GameAspectX = 4, GameAspectY = 3;
80 
81 #ifdef INCLUDE_SWITCHRES
82 	sr_mode srm;
83 #endif
84 	if (SDL_Init(SDL_INIT_VIDEO) < 0)
85 	{
86 		printf("vid init error\n");
87 		SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError());
88 		return 3;
89 	}
90 
91 	nRotateGame = 0;
92 
93 	if (bDrvOkay)
94 	{
95 		// Get the game screen size
96 		BurnDrvGetVisibleSize(&nVidImageWidth, &nVidImageHeight);
97 		if (BurnDrvGetFlags() & BDF_ORIENTATION_VERTICAL)
98 		{
99 			BurnDrvGetAspect(&GameAspectY, &GameAspectX);
100 		}
101 		else
102 		{
103 			BurnDrvGetAspect(&GameAspectX, &GameAspectY);
104 		}
105 
106 		display_w = nVidImageWidth;
107 #ifdef INCLUDE_SWITCHRES
108 		sr_init();
109 		// Don't force 4:3 aspect-ratio, until there is a command-line switch
110 		display_h = nVidImageHeight;
111 		if (BurnDrvGetFlags() & BDF_ORIENTATION_VERTICAL)
112 		{
113 			BurnDrvGetVisibleSize(&nVidImageHeight, &nVidImageWidth);
114 			printf("Vertical\n");
115 			nRotateGame = 1;
116 			sr_set_rotation(1);
117 			display_w = nVidImageWidth;
118 			display_h = nVidImageHeight;
119 		}
120 #else
121 		display_h = nVidImageWidth * GameAspectY / GameAspectX;
122 
123 		if (BurnDrvGetFlags() & BDF_ORIENTATION_VERTICAL)
124 		{
125 			BurnDrvGetVisibleSize(&nVidImageHeight, &nVidImageWidth);
126 			printf("Vertical\n");
127 			nRotateGame = 1;
128 			display_w = nVidImageHeight * GameAspectX / GameAspectY;
129 			display_h = nVidImageHeight;
130 		}
131 #endif
132 
133 		if (BurnDrvGetFlags() & BDF_ORIENTATION_FLIPPED)
134 		{
135 			printf("Flipped\n");
136 			bFlipped = 1;
137 		}
138 	}
139 
140 	sprintf(Windowtitle, "FBNeo - %s - %s", BurnDrvGetTextA(DRV_NAME), BurnDrvGetTextA(DRV_FULLNAME));
141 
142 	Uint32 screenFlags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE;
143 
144 	if (bAppFullscreen)
145 	{
146 		screenFlags = SDL_WINDOW_SHOWN | SDL_WINDOW_FULLSCREEN_DESKTOP;
147 	}
148 
149 	dstrect.y = 0;
150 	dstrect.x = 0;
151 	dstrect.h = display_h;
152 	dstrect.w = display_w;
153 
154 	//Test refresh rate availability
155 	printf("Game resolution: %dx%d@%f\n", nVidImageWidth, nVidImageHeight, nBurnFPS/100.0);
156 
157 #ifdef INCLUDE_SWITCHRES
158 	unsigned char interlace = 0; // FBN doesn't handle interlace yet, force it to disabled
159 	double rr = nBurnFPS / 100.0;
160 	sr_init_disp();
161 	sr_add_mode(display_w, display_h, rr, interlace, &srm);
162 	sr_switch_to_mode(display_w, display_h, rr, interlace, &srm);
163 #endif
164 
165 	if (nRotateGame)
166 	{
167 		sdlWindow = SDL_CreateWindow(
168 			Windowtitle,
169 			SDL_WINDOWPOS_CENTERED,
170 			SDL_WINDOWPOS_CENTERED,
171 			display_h,
172 			display_w,
173 			screenFlags
174 		);
175 		dstrect.y = (display_w - display_h) / 2;
176 		dstrect.x = (display_h - display_w) / 2;
177 		dstrect.h = display_h;
178 		dstrect.w = display_w;
179 
180 	}
181 	else
182 	{
183 		sdlWindow = SDL_CreateWindow(
184 			Windowtitle,
185 			SDL_WINDOWPOS_CENTERED,
186 			SDL_WINDOWPOS_CENTERED,
187 			display_w,
188 			display_h,
189 			screenFlags
190 		);
191 	}
192 
193 	// Check that the window was successfully created
194 	if (sdlWindow == NULL)
195 	{
196 		// In the case that the window could not be made...
197 		printf("Could not create window: %s\n", SDL_GetError());
198 		return 1;
199 	}
200 
201 	Uint32 renderflags = SDL_RENDERER_ACCELERATED;
202 
203 	if (vsync)
204 	{
205 		renderflags = renderflags | SDL_RENDERER_PRESENTVSYNC;
206 	}
207 
208 	sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, renderflags);
209 	if (sdlRenderer == NULL)
210 	{
211 		sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_SOFTWARE);
212 		if (sdlRenderer == NULL)
213 		{
214 			// In the case that the window could not be made...
215 			printf("Could not create renderer: %s\n", SDL_GetError());
216 			return 1;
217 		}
218 	}
219 
220 	SDL_SetRenderDrawBlendMode(sdlRenderer, SDL_BLENDMODE_NONE);
221 
222 	nVidImageDepth = 32;
223 
224 	if (BurnDrvGetFlags() & BDF_16BIT_ONLY)
225 	{
226 		nVidImageDepth = 16;
227 		printf("Forcing 16bit color\n");
228 	}
229 	printf("bbp: %d\n", nVidImageDepth);
230 
231 	if (bIntegerScale)
232 	{
233 		SDL_RenderSetIntegerScale(sdlRenderer, SDL_TRUE);
234 	}
235 
236 	SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, videofiltering);
237 
238 	printf("setting logical size w: %d h: %d\n", display_w, display_h);
239 
240 	if (nRotateGame)
241 	{
242 		SDL_RenderSetLogicalSize(sdlRenderer, display_h, display_w);
243 	}
244 	else
245 	{
246 		SDL_RenderSetLogicalSize(sdlRenderer, display_w, display_h);
247 	}
248 
249 	// Force to scale * 2
250 	// TODO
251 	int w;
252 	int h;
253 	SDL_GetWindowSize(sdlWindow, &w, &h);
254 	SDL_SetWindowSize(sdlWindow, w*2, h*2);
255 	SDL_SetWindowPosition(sdlWindow, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
256 
257 	inrenderer(sdlRenderer); //TODO: this is not supposed to be here
258 	prepare_inline_font();   // TODO: BAD
259 	incolor(0xFFF000, 0);
260 
261 	if (nVidImageDepth == 32)
262 	{
263 		sdlTexture = SDL_CreateTexture(sdlRenderer,
264 			SDL_PIXELFORMAT_RGB888,
265 			SDL_TEXTUREACCESS_STREAMING,
266 			nVidImageWidth, nVidImageHeight);
267 	}
268 	else
269 	{
270 		sdlTexture = SDL_CreateTexture(sdlRenderer,
271 			SDL_PIXELFORMAT_RGB565,
272 			SDL_TEXTUREACCESS_STREAMING,
273 			nVidImageWidth, nVidImageHeight);
274 	}
275 	if (!sdlTexture)
276 	{
277 		SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create sdlTexture from surface: %s", SDL_GetError());
278 		return 3;
279 	}
280 
281 	nVidImageBPP = (nVidImageDepth + 7) >> 3;
282 	nBurnBpp = nVidImageBPP;
283 
284 	SetBurnHighCol(nVidImageDepth);
285 
286 	nVidImagePitch = nVidImageWidth * nVidImageBPP;
287 	nBurnPitch = nVidImagePitch;
288 
289 	nMemLen = nVidImageWidth * nVidImageHeight * nVidImageBPP;
290 
291 	printf("nVidImageWidth=%d nVidImageHeight=%d nVidImagePitch=%d\n", nVidImageWidth, nVidImageHeight, nVidImagePitch);
292 
293 	VidMem = (unsigned char*)malloc(nMemLen);
294 	if (VidMem)
295 	{
296 		memset(VidMem, 0, nMemLen);
297 		pVidImage = VidMem;
298 		printf("Malloc for video Ok %d\n", nMemLen);
299 		return 0;
300 	}
301 	else
302 	{
303 		pVidImage = NULL;
304 		return 1;
305 	}
306 
307 
308 	printf("done vid init");
309 	return 0;
310 }
311 
vidScale(RECT *,int,int)312 static int vidScale(RECT*, int, int)
313 {
314 	return 0;
315 }
316 
317 // Run one frame and render the screen
Frame(bool bRedraw)318 static int Frame(bool bRedraw)                                          // bRedraw = 0
319 {
320 	if (pVidImage == NULL)
321 	{
322 		return 1;
323 	}
324 
325 	VidFrameCallback(bRedraw);
326 
327 	return 0;
328 }
329 
330 // Paint the BlitFX surface onto the primary surface
Paint(int bValidate)331 static int Paint(int bValidate)
332 {
333 	void* pixels;
334 	int   pitch;
335 
336 	SDL_RenderClear(sdlRenderer);
337 	SDL_UpdateTexture(sdlTexture, NULL, pVidImage, nVidImagePitch);
338 	if (nRotateGame)
339 	{
340 		SDL_RenderCopyEx(sdlRenderer, sdlTexture, NULL, &dstrect, (bFlipped ? 90 : 270), NULL, SDL_FLIP_NONE);
341 	}
342 	else
343 	{
344 		if (bFlipped)
345 		{
346 			SDL_RenderCopyEx(sdlRenderer, sdlTexture, NULL, &dstrect, 180, NULL, SDL_FLIP_NONE);
347 		}
348 		else
349 		{
350 			SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &dstrect);
351 		}
352 	}
353 
354 	RenderMessage();
355 
356 	SDL_RenderPresent(sdlRenderer);
357 
358 	return 0;
359 }
360 
GetSettings(InterfaceInfo * pInfo)361 static int GetSettings(InterfaceInfo* pInfo)
362 {
363 	return 0;
364 }
365 
366 // The Video Output plugin:
367 struct VidOut VidOutSDL2 = { Init, Exit, Frame, Paint, vidScale, GetSettings, _T("SDL2 video output") };
368