7badc935 |
1 | /* |
418caf43 |
2 | * (C) GraÅžvydas "notaz" Ignotas, 2011-2013 |
7badc935 |
3 | * |
4 | * This work is licensed under the terms of any of these licenses |
5 | * (at your option): |
6 | * - GNU GPL, version 2 or later. |
7 | * - GNU LGPL, version 2.1 or later. |
8 | * See the COPYING file in the top-level directory. |
9 | */ |
10 | |
11 | #include <stdio.h> |
81023939 |
12 | #include <assert.h> |
7badc935 |
13 | #include <SDL.h> |
cc56203b |
14 | |
c9b09029 |
15 | #include "../libpcsxcore/plugins.h" |
cc56203b |
16 | #include "libpicofe/input.h" |
17 | #include "libpicofe/in_sdl.h" |
18 | #include "libpicofe/menu.h" |
c9099d02 |
19 | #include "libpicofe/fonts.h" |
5b9aa749 |
20 | #include "libpicofe/plat_sdl.h" |
81023939 |
21 | #include "libpicofe/plat.h" |
5b9aa749 |
22 | #include "libpicofe/gl.h" |
c82f907a |
23 | #include "cspace.h" |
b07c18e8 |
24 | #include "plugin_lib.h" |
418caf43 |
25 | #include "plugin.h" |
81023939 |
26 | #include "menu.h" |
b07c18e8 |
27 | #include "main.h" |
7badc935 |
28 | #include "plat.h" |
29 | #include "revision.h" |
30 | |
81023939 |
31 | #include "libpicofe/plat_sdl.c" |
32 | |
b07c18e8 |
33 | static const struct in_default_bind in_sdl_defbinds[] = { |
2e6189bc |
34 | { SDLK_UP, IN_BINDTYPE_PLAYER12, DKEY_UP }, |
35 | { SDLK_DOWN, IN_BINDTYPE_PLAYER12, DKEY_DOWN }, |
36 | { SDLK_LEFT, IN_BINDTYPE_PLAYER12, DKEY_LEFT }, |
37 | { SDLK_RIGHT, IN_BINDTYPE_PLAYER12, DKEY_RIGHT }, |
38 | { SDLK_d, IN_BINDTYPE_PLAYER12, DKEY_TRIANGLE }, |
39 | { SDLK_z, IN_BINDTYPE_PLAYER12, DKEY_CROSS }, |
40 | { SDLK_x, IN_BINDTYPE_PLAYER12, DKEY_CIRCLE }, |
41 | { SDLK_s, IN_BINDTYPE_PLAYER12, DKEY_SQUARE }, |
42 | { SDLK_v, IN_BINDTYPE_PLAYER12, DKEY_START }, |
43 | { SDLK_c, IN_BINDTYPE_PLAYER12, DKEY_SELECT }, |
44 | { SDLK_w, IN_BINDTYPE_PLAYER12, DKEY_L1 }, |
45 | { SDLK_r, IN_BINDTYPE_PLAYER12, DKEY_R1 }, |
46 | { SDLK_e, IN_BINDTYPE_PLAYER12, DKEY_L2 }, |
47 | { SDLK_t, IN_BINDTYPE_PLAYER12, DKEY_R2 }, |
48 | { SDLK_ESCAPE, IN_BINDTYPE_EMU, SACTION_ENTER_MENU }, |
456f1b86 |
49 | { SDLK_F1, IN_BINDTYPE_EMU, SACTION_SAVE_STATE }, |
50 | { SDLK_F2, IN_BINDTYPE_EMU, SACTION_LOAD_STATE }, |
51 | { SDLK_F3, IN_BINDTYPE_EMU, SACTION_PREV_SSLOT }, |
52 | { SDLK_F4, IN_BINDTYPE_EMU, SACTION_NEXT_SSLOT }, |
53 | { SDLK_F5, IN_BINDTYPE_EMU, SACTION_TOGGLE_FSKIP }, |
54 | { SDLK_F6, IN_BINDTYPE_EMU, SACTION_SCREENSHOT }, |
dde7da71 |
55 | { SDLK_F7, IN_BINDTYPE_EMU, SACTION_TOGGLE_FPS }, |
456f1b86 |
56 | { SDLK_F8, IN_BINDTYPE_EMU, SACTION_SWITCH_DISPMODE }, |
a8376201 |
57 | { SDLK_F11, IN_BINDTYPE_EMU, SACTION_TOGGLE_FULLSCREEN }, |
dde7da71 |
58 | { SDLK_BACKSPACE, IN_BINDTYPE_EMU, SACTION_FAST_FORWARD }, |
2e6189bc |
59 | { 0, 0, 0 } |
7badc935 |
60 | }; |
61 | |
bcfc48e3 |
62 | const struct menu_keymap in_sdl_key_map[] = |
63 | { |
64 | { SDLK_UP, PBTN_UP }, |
65 | { SDLK_DOWN, PBTN_DOWN }, |
66 | { SDLK_LEFT, PBTN_LEFT }, |
67 | { SDLK_RIGHT, PBTN_RIGHT }, |
68 | { SDLK_RETURN, PBTN_MOK }, |
69 | { SDLK_ESCAPE, PBTN_MBACK }, |
70 | { SDLK_SEMICOLON, PBTN_MA2 }, |
71 | { SDLK_QUOTE, PBTN_MA3 }, |
72 | { SDLK_LEFTBRACKET, PBTN_L }, |
73 | { SDLK_RIGHTBRACKET, PBTN_R }, |
74 | }; |
75 | |
76 | const struct menu_keymap in_sdl_joy_map[] = |
77 | { |
78 | { SDLK_UP, PBTN_UP }, |
79 | { SDLK_DOWN, PBTN_DOWN }, |
80 | { SDLK_LEFT, PBTN_LEFT }, |
81 | { SDLK_RIGHT, PBTN_RIGHT }, |
82 | /* joystick */ |
83 | { SDLK_WORLD_0, PBTN_MOK }, |
84 | { SDLK_WORLD_1, PBTN_MBACK }, |
85 | { SDLK_WORLD_2, PBTN_MA2 }, |
86 | { SDLK_WORLD_3, PBTN_MA3 }, |
87 | }; |
88 | |
89 | static const struct in_pdata in_sdl_platform_data = { |
90 | .defbinds = in_sdl_defbinds, |
91 | .key_map = in_sdl_key_map, |
92 | .kmap_size = sizeof(in_sdl_key_map) / sizeof(in_sdl_key_map[0]), |
93 | .joy_map = in_sdl_joy_map, |
94 | .jmap_size = sizeof(in_sdl_joy_map) / sizeof(in_sdl_joy_map[0]), |
95 | }; |
96 | |
3a52f747 |
97 | static int psx_w = 256, psx_h = 240; |
5b9aa749 |
98 | static void *shadow_fb, *menubg_img; |
81023939 |
99 | static int vout_fullscreen_old; |
100 | static int forced_clears; |
101 | static int forced_flips; |
102 | static int sdl12_compat; |
c9b09029 |
103 | static int resized; |
5b9aa749 |
104 | static int in_menu; |
7badc935 |
105 | |
7192adbe |
106 | static int gl_w_prev, gl_h_prev, gl_quirks_prev; |
c9b09029 |
107 | static float gl_vertices[] = { |
108 | -1.0f, 1.0f, 0.0f, // 0 0 1 |
109 | 1.0f, 1.0f, 0.0f, // 1 ^ |
110 | -1.0f, -1.0f, 0.0f, // 2 | 2 3 |
111 | 1.0f, -1.0f, 0.0f, // 3 +--> |
112 | }; |
113 | |
114 | static void handle_window_resize(void); |
81023939 |
115 | static void handle_scaler_resize(int w, int h); |
3a52f747 |
116 | static void centered_clear(void); |
418caf43 |
117 | |
c9b09029 |
118 | static int plugin_owns_display(void) |
119 | { |
120 | // if true, a plugin is drawing and flipping |
121 | return (pl_rearmed_cbs.gpu_caps & GPU_CAP_OWNS_DISPLAY); |
122 | } |
123 | |
124 | static void plugin_update(void) |
418caf43 |
125 | { |
81023939 |
126 | // used by some plugins... |
c9b09029 |
127 | pl_rearmed_cbs.screen_w = plat_sdl_screen->w; |
128 | pl_rearmed_cbs.screen_h = plat_sdl_screen->h; |
418caf43 |
129 | pl_rearmed_cbs.gles_display = gl_es_display; |
130 | pl_rearmed_cbs.gles_surface = gl_es_surface; |
131 | plugin_call_rearmed_cbs(); |
81023939 |
132 | } |
133 | |
134 | static void sdl_event_handler(void *event_) |
135 | { |
136 | SDL_Event *event = event_; |
137 | |
138 | switch (event->type) { |
139 | case SDL_VIDEORESIZE: |
140 | if (window_w != (event->resize.w & ~3) || window_h != (event->resize.h & ~1)) { |
141 | window_w = event->resize.w & ~3; |
142 | window_h = event->resize.h & ~1; |
143 | resized = 1; |
c9b09029 |
144 | if (!in_menu && plat_sdl_gl_active && plugin_owns_display()) { |
145 | // the plugin flips by itself so resize has to be handled here |
146 | handle_window_resize(); |
147 | if (GPU_open != NULL) { |
148 | int ret = GPU_open(&gpuDisp, "PCSX", NULL); |
149 | if (ret) |
150 | fprintf(stderr, "GPU_open: %d\n", ret); |
151 | } |
152 | } |
81023939 |
153 | } |
154 | return; |
155 | case SDL_ACTIVEEVENT: |
156 | // no need to redraw? |
157 | return; |
158 | default: |
159 | break; |
160 | } |
161 | plat_sdl_event_handler(event_); |
a8376201 |
162 | } |
163 | |
69e482e3 |
164 | static void quit_cb(void) |
165 | { |
166 | emu_core_ask_exit(); |
167 | } |
168 | |
418caf43 |
169 | static void get_layer_pos(int *x, int *y, int *w, int *h) |
170 | { |
171 | // always fill entire SDL window |
172 | *x = *y = 0; |
173 | *w = pl_rearmed_cbs.screen_w; |
174 | *h = pl_rearmed_cbs.screen_h; |
175 | } |
176 | |
7badc935 |
177 | void plat_init(void) |
178 | { |
7192adbe |
179 | static const char *hwfilters[] = { "linear", "nearest", NULL }; |
81023939 |
180 | const SDL_version *ver; |
8e7632dd |
181 | int shadow_size; |
5b9aa749 |
182 | int ret; |
7badc935 |
183 | |
418caf43 |
184 | plat_sdl_quit_cb = quit_cb; |
418caf43 |
185 | |
7192adbe |
186 | old_fullscreen = -1; // hack |
187 | |
5b9aa749 |
188 | ret = plat_sdl_init(); |
189 | if (ret != 0) |
7badc935 |
190 | exit(1); |
a8376201 |
191 | |
81023939 |
192 | ver = SDL_Linked_Version(); |
193 | sdl12_compat = ver->patch >= 50; |
194 | printf("SDL %u.%u.%u compat=%d\n", ver->major, ver->minor, ver->patch, sdl12_compat); |
195 | |
a8376201 |
196 | in_menu = 1; |
7badc935 |
197 | SDL_WM_SetCaption("PCSX-ReARMed " REV, NULL); |
198 | |
8e7632dd |
199 | shadow_size = g_menuscreen_w * g_menuscreen_h * 2; |
af486d6e |
200 | // alloc enough for double res. rendering |
201 | if (shadow_size < 1024 * 512 * 2) |
202 | shadow_size = 1024 * 512 * 2; |
8e7632dd |
203 | |
204 | shadow_fb = malloc(shadow_size); |
205 | menubg_img = malloc(shadow_size); |
5b9aa749 |
206 | if (shadow_fb == NULL || menubg_img == NULL) { |
207 | fprintf(stderr, "OOM\n"); |
208 | exit(1); |
209 | } |
2e6189bc |
210 | |
81023939 |
211 | in_sdl_init(&in_sdl_platform_data, sdl_event_handler); |
7badc935 |
212 | in_probe(); |
4ea7de6a |
213 | pl_rearmed_cbs.only_16bpp = 1; |
418caf43 |
214 | pl_rearmed_cbs.pl_get_layer_pos = get_layer_pos; |
c9099d02 |
215 | |
216 | bgr_to_uyvy_init(); |
81023939 |
217 | |
c9b09029 |
218 | assert(plat_sdl_screen); |
219 | plugin_update(); |
220 | if (plat_target.vout_method == vout_mode_gl) |
221 | gl_w_prev = plat_sdl_screen->w, gl_h_prev = plat_sdl_screen->h; |
7192adbe |
222 | if (vout_mode_gl != -1) |
223 | plat_target.hwfilters = hwfilters; |
7badc935 |
224 | } |
225 | |
226 | void plat_finish(void) |
227 | { |
5b9aa749 |
228 | free(shadow_fb); |
229 | shadow_fb = NULL; |
2e6189bc |
230 | free(menubg_img); |
231 | menubg_img = NULL; |
5b9aa749 |
232 | plat_sdl_finish(); |
7badc935 |
233 | } |
234 | |
ab423939 |
235 | void plat_gvideo_open(int is_pal) |
7badc935 |
236 | { |
237 | } |
238 | |
81023939 |
239 | static void uyvy_to_rgb565(void *d, int pixels) |
7badc935 |
240 | { |
81023939 |
241 | const unsigned int *src = (const void *)plat_sdl_overlay->pixels[0]; |
242 | int x2 = plat_sdl_overlay->w >= psx_w * 2; |
c9099d02 |
243 | unsigned short *dst = d; |
c9099d02 |
244 | int v; |
245 | |
246 | // no colors, for now |
81023939 |
247 | if (x2) { |
248 | for (; pixels > 0; src++, dst++, pixels--) { |
249 | v = (*src >> 8) & 0xff; |
250 | v = (v - 16) * 255 / 219 / 8; |
251 | *dst = (v << 11) | (v << 6) | v; |
252 | } |
253 | } |
254 | else { |
255 | for (; pixels > 0; src++, dst += 2, pixels -= 2) { |
256 | v = (*src >> 8) & 0xff; |
257 | v = (v - 16) * 255 / 219 / 8; |
258 | dst[0] = (v << 11) | (v << 6) | v; |
259 | |
260 | v = (*src >> 24) & 0xff; |
261 | v = (v - 16) * 255 / 219 / 8; |
262 | dst[1] = (v << 11) | (v << 6) | v; |
263 | } |
264 | } |
265 | } |
266 | |
267 | static void overlay_resize(int force) |
268 | { |
269 | int x2_mul = !in_menu && plat_target.vout_method > 1 ? 2 : 1; // lame |
270 | int w = in_menu ? g_menuscreen_w : psx_w; |
271 | int h = in_menu ? g_menuscreen_h : psx_h; |
272 | |
273 | if (!force && plat_sdl_overlay && w * x2_mul == plat_sdl_overlay->w |
274 | && h == plat_sdl_overlay->h) |
275 | return; |
276 | if (plat_sdl_overlay) |
277 | SDL_FreeYUVOverlay(plat_sdl_overlay); |
278 | plat_sdl_overlay = SDL_CreateYUVOverlay(w * x2_mul, h, SDL_UYVY_OVERLAY, |
279 | plat_sdl_screen); |
280 | if (plat_sdl_overlay) { |
281 | //printf("overlay: %dx%d %08x hw=%d\n", plat_sdl_overlay->w, plat_sdl_overlay->h, |
282 | // plat_sdl_overlay->format, plat_sdl_overlay->hw_overlay); |
283 | if (SDL_LockYUVOverlay(plat_sdl_overlay) == 0) { |
284 | plat_sdl_overlay_clear(); |
285 | SDL_UnlockYUVOverlay(plat_sdl_overlay); |
286 | } |
287 | } |
c9b09029 |
288 | else { |
81023939 |
289 | fprintf(stderr, "overlay resize to %dx%d failed\n", w, h); |
c9b09029 |
290 | plat_target.vout_method = 0; |
c9099d02 |
291 | } |
c9b09029 |
292 | handle_scaler_resize(w, h); |
7badc935 |
293 | } |
294 | |
c9099d02 |
295 | static void overlay_blit(int doffs, const void *src_, int w, int h, |
296 | int sstride, int bgr24) |
297 | { |
298 | const unsigned short *src = src_; |
299 | unsigned short *dst; |
5b9aa749 |
300 | int dstride = plat_sdl_overlay->w; |
81023939 |
301 | int x2 = dstride >= 2 * w; |
c9099d02 |
302 | |
5b9aa749 |
303 | SDL_LockYUVOverlay(plat_sdl_overlay); |
304 | dst = (void *)plat_sdl_overlay->pixels[0]; |
c9099d02 |
305 | |
306 | dst += doffs; |
307 | if (bgr24) { |
308 | for (; h > 0; dst += dstride, src += sstride, h--) |
81023939 |
309 | bgr888_to_uyvy(dst, src, w, x2); |
c9099d02 |
310 | } |
311 | else { |
312 | for (; h > 0; dst += dstride, src += sstride, h--) |
81023939 |
313 | bgr555_to_uyvy(dst, src, w, x2); |
c9099d02 |
314 | } |
315 | |
5b9aa749 |
316 | SDL_UnlockYUVOverlay(plat_sdl_overlay); |
c9099d02 |
317 | } |
318 | |
319 | static void overlay_hud_print(int x, int y, const char *str, int bpp) |
320 | { |
81023939 |
321 | int x2; |
5b9aa749 |
322 | SDL_LockYUVOverlay(plat_sdl_overlay); |
81023939 |
323 | x2 = plat_sdl_overlay->w >= psx_w * 2; |
324 | if (x2) |
325 | x *= 2; |
5b9aa749 |
326 | basic_text_out_uyvy_nf(plat_sdl_overlay->pixels[0], plat_sdl_overlay->w, x, y, str); |
327 | SDL_UnlockYUVOverlay(plat_sdl_overlay); |
c9099d02 |
328 | } |
329 | |
c9b09029 |
330 | static void gl_finish_pl(void) |
331 | { |
332 | if (plugin_owns_display() && GPU_close != NULL) |
333 | GPU_close(); |
86e02a02 |
334 | gl_destroy(); |
c9b09029 |
335 | } |
336 | |
337 | static void gl_resize(void) |
338 | { |
339 | int w = in_menu ? g_menuscreen_w : psx_w; |
340 | int h = in_menu ? g_menuscreen_h : psx_h; |
341 | |
7192adbe |
342 | gl_quirks &= ~(GL_QUIRK_SCALING_NEAREST | GL_QUIRK_VSYNC_ON); |
343 | if (plat_target.hwfilter) // inverted from plat_sdl_gl_scaling() |
344 | gl_quirks |= GL_QUIRK_SCALING_NEAREST; |
345 | if (g_opts & OPT_VSYNC) |
346 | gl_quirks |= GL_QUIRK_VSYNC_ON; |
347 | |
c9b09029 |
348 | if (plugin_owns_display()) |
349 | w = plat_sdl_screen->w, h = plat_sdl_screen->h; |
350 | if (plat_sdl_gl_active) { |
7192adbe |
351 | if (w == gl_w_prev && h == gl_h_prev && gl_quirks == gl_quirks_prev) |
c9b09029 |
352 | return; |
353 | gl_finish_pl(); |
354 | } |
86e02a02 |
355 | plat_sdl_gl_active = (gl_create(window, &gl_quirks, w, h) == 0); |
c9b09029 |
356 | if (plat_sdl_gl_active) |
7192adbe |
357 | gl_w_prev = w, gl_h_prev = h, gl_quirks_prev = gl_quirks; |
c9b09029 |
358 | else { |
359 | fprintf(stderr, "warning: could not init GL.\n"); |
360 | plat_target.vout_method = 0; |
361 | } |
362 | handle_scaler_resize(w, h); |
363 | plugin_update(); |
364 | forced_flips = 0; // interferes with gl |
365 | } |
366 | |
367 | static void overlay_or_gl_check_enable(void) |
368 | { |
369 | int ovl_on = plat_target.vout_method == vout_mode_overlay || |
370 | plat_target.vout_method == vout_mode_overlay2x; |
371 | int gl_on = plat_target.vout_method == vout_mode_gl; |
372 | if (!gl_on && plat_sdl_gl_active) { |
373 | gl_finish_pl(); |
374 | pl_rearmed_cbs.gles_display = gl_es_display; |
375 | pl_rearmed_cbs.gles_surface = gl_es_surface; |
376 | plat_sdl_gl_active = 0; |
377 | } |
378 | if (!ovl_on && plat_sdl_overlay) { |
379 | SDL_FreeYUVOverlay(plat_sdl_overlay); |
380 | plat_sdl_overlay = NULL; |
381 | } |
382 | if (ovl_on) |
383 | overlay_resize(0); |
384 | else if (gl_on) |
385 | gl_resize(); |
386 | } |
387 | |
3a52f747 |
388 | static void centered_clear(void) |
c9099d02 |
389 | { |
3a52f747 |
390 | int dstride = plat_sdl_screen->pitch / 2; |
391 | int w = plat_sdl_screen->w; |
392 | int h = plat_sdl_screen->h; |
393 | unsigned short *dst; |
394 | |
c9b09029 |
395 | if (plat_sdl_gl_active) { |
396 | gl_clear(); |
397 | return; |
398 | } |
399 | |
81023939 |
400 | if (SDL_MUSTLOCK(plat_sdl_screen)) |
401 | SDL_LockSurface(plat_sdl_screen); |
3a52f747 |
402 | dst = plat_sdl_screen->pixels; |
403 | |
404 | for (; h > 0; dst += dstride, h--) |
405 | memset(dst, 0, w * 2); |
406 | |
81023939 |
407 | if (SDL_MUSTLOCK(plat_sdl_screen)) |
408 | SDL_UnlockSurface(plat_sdl_screen); |
409 | |
410 | if (plat_sdl_overlay != NULL) { |
411 | // apply the parts not covered by the overlay |
412 | forced_flips = 3; |
413 | } |
414 | } |
415 | |
416 | static int adj_src_dst(const SDL_Surface *sfc, int w, int pp, int *h, |
417 | unsigned short **dst, const unsigned short **src) |
418 | { |
419 | int line_w = w; |
420 | if (sfc->w > w) |
421 | *dst += (sfc->w - w) / 2; |
422 | else { |
423 | *src += (w - sfc->w) / 2; |
424 | line_w = sfc->w; |
425 | } |
426 | if (sfc->h > *h) |
427 | *dst += sfc->pitch * (sfc->h - *h) / 2 / 2; |
428 | else { |
429 | *src += pp * (*h - sfc->h) / 2; |
430 | *h = sfc->h; |
431 | } |
432 | return line_w; |
3a52f747 |
433 | } |
434 | |
435 | static void centered_blit(int doffs, const void *src_, int w, int h, |
436 | int sstride, int bgr24) |
437 | { |
438 | const unsigned short *src = src_; |
439 | unsigned short *dst; |
440 | int dstride; |
441 | |
81023939 |
442 | if (SDL_MUSTLOCK(plat_sdl_screen)) |
443 | SDL_LockSurface(plat_sdl_screen); |
3a52f747 |
444 | dst = plat_sdl_screen->pixels; |
445 | dstride = plat_sdl_screen->pitch / 2; |
81023939 |
446 | w = adj_src_dst(plat_sdl_screen, w, sstride, &h, &dst, &src); |
3a52f747 |
447 | |
3a52f747 |
448 | if (bgr24) { |
449 | for (; h > 0; dst += dstride, src += sstride, h--) |
450 | bgr888_to_rgb565(dst, src, w * 3); |
451 | } |
452 | else { |
453 | for (; h > 0; dst += dstride, src += sstride, h--) |
454 | bgr555_to_rgb565(dst, src, w * 2); |
455 | } |
456 | |
81023939 |
457 | if (SDL_MUSTLOCK(plat_sdl_screen)) |
458 | SDL_UnlockSurface(plat_sdl_screen); |
3a52f747 |
459 | } |
460 | |
461 | static void centered_blit_menu(void) |
462 | { |
463 | const unsigned short *src = g_menuscreen_ptr; |
464 | int w = g_menuscreen_w; |
465 | int h = g_menuscreen_h; |
466 | unsigned short *dst; |
81023939 |
467 | int dstride, len; |
468 | |
469 | if (SDL_MUSTLOCK(plat_sdl_screen)) |
470 | SDL_LockSurface(plat_sdl_screen); |
3a52f747 |
471 | |
3a52f747 |
472 | dst = plat_sdl_screen->pixels; |
473 | dstride = plat_sdl_screen->pitch / 2; |
81023939 |
474 | len = adj_src_dst(plat_sdl_screen, w, g_menuscreen_pp, &h, &dst, &src); |
3a52f747 |
475 | |
3a52f747 |
476 | for (; h > 0; dst += dstride, src += g_menuscreen_pp, h--) |
81023939 |
477 | memcpy(dst, src, len * 2); |
3a52f747 |
478 | |
81023939 |
479 | if (SDL_MUSTLOCK(plat_sdl_screen)) |
480 | SDL_UnlockSurface(plat_sdl_screen); |
3a52f747 |
481 | } |
482 | |
483 | static void centered_hud_print(int x, int y, const char *str, int bpp) |
484 | { |
81023939 |
485 | int w_diff, h_diff; |
486 | if (SDL_MUSTLOCK(plat_sdl_screen)) |
487 | SDL_LockSurface(plat_sdl_screen); |
488 | w_diff = plat_sdl_screen->w - psx_w; |
489 | h_diff = plat_sdl_screen->h - psx_h; |
490 | if (w_diff > 0) x += w_diff / 2; |
491 | if (h_diff > 0) y += h_diff / 2; |
492 | if (h_diff < 0) y += h_diff; |
493 | if (w_diff < 0 && x > 32) x += w_diff; |
3a52f747 |
494 | basic_text_out16_nf(plat_sdl_screen->pixels, plat_sdl_screen->pitch / 2, x, y, str); |
81023939 |
495 | if (SDL_MUSTLOCK(plat_sdl_screen)) |
496 | SDL_UnlockSurface(plat_sdl_screen); |
3a52f747 |
497 | } |
498 | |
81023939 |
499 | static void *setup_blit_callbacks(int w, int h) |
3a52f747 |
500 | { |
501 | pl_plat_clear = NULL; |
502 | pl_plat_blit = NULL; |
503 | pl_plat_hud_print = NULL; |
5b9aa749 |
504 | if (plat_sdl_overlay != NULL) { |
505 | pl_plat_clear = plat_sdl_overlay_clear; |
c9099d02 |
506 | pl_plat_blit = overlay_blit; |
507 | pl_plat_hud_print = overlay_hud_print; |
3a52f747 |
508 | } |
509 | else if (plat_sdl_gl_active) { |
510 | return shadow_fb; |
c9099d02 |
511 | } |
512 | else { |
81023939 |
513 | pl_plat_clear = centered_clear; |
514 | |
515 | if (!SDL_MUSTLOCK(plat_sdl_screen) && w == plat_sdl_screen->w && |
516 | h == plat_sdl_screen->h) |
5b9aa749 |
517 | return plat_sdl_screen->pixels; |
81023939 |
518 | |
519 | pl_plat_blit = centered_blit; |
520 | pl_plat_hud_print = centered_hud_print; |
521 | } |
522 | return NULL; |
523 | } |
524 | |
525 | // not using plat_sdl_change_video_mode() since we need |
526 | // different size overlay vs plat_sdl_screen layer |
527 | static void change_mode(int w, int h) |
528 | { |
c9b09029 |
529 | int set_w = w, set_h = h, had_overlay = 0, had_gl = 0; |
81023939 |
530 | if (plat_target.vout_fullscreen && (plat_target.vout_method != 0 || !sdl12_compat)) |
531 | set_w = fs_w, set_h = fs_h; |
532 | if (plat_sdl_screen->w != set_w || plat_sdl_screen->h != set_h || |
533 | plat_target.vout_fullscreen != vout_fullscreen_old) |
534 | { |
535 | Uint32 flags = plat_sdl_screen->flags; |
536 | if (plat_target.vout_fullscreen) |
537 | flags |= SDL_FULLSCREEN; |
3a52f747 |
538 | else { |
81023939 |
539 | flags &= ~SDL_FULLSCREEN; |
540 | if (plat_sdl_is_windowed()) |
541 | flags |= SDL_RESIZABLE; // sdl12-compat 1.2.68 loses this flag |
542 | } |
543 | if (plat_sdl_overlay) { |
544 | SDL_FreeYUVOverlay(plat_sdl_overlay); |
545 | plat_sdl_overlay = NULL; |
546 | had_overlay = 1; |
3a52f747 |
547 | } |
c9b09029 |
548 | if (plat_sdl_gl_active) { |
549 | gl_finish_pl(); |
550 | plat_sdl_gl_active = 0; |
551 | had_gl = 1; |
552 | } |
81023939 |
553 | SDL_PumpEvents(); |
554 | plat_sdl_screen = SDL_SetVideoMode(set_w, set_h, 16, flags); |
555 | //printf("mode: %dx%d %x -> %dx%d\n", set_w, set_h, flags, |
556 | // plat_sdl_screen->w, plat_sdl_screen->h); |
557 | assert(plat_sdl_screen); |
558 | if (vout_fullscreen_old && !plat_target.vout_fullscreen) |
559 | // why is this needed?? (on 1.2.68) |
560 | SDL_WM_GrabInput(SDL_GRAB_OFF); |
c9b09029 |
561 | if (vout_mode_gl != -1) |
562 | update_wm_display_window(); |
81023939 |
563 | // overlay needs the latest plat_sdl_screen |
564 | if (had_overlay) |
565 | overlay_resize(1); |
c9b09029 |
566 | if (had_gl) |
567 | gl_resize(); |
81023939 |
568 | centered_clear(); |
c9b09029 |
569 | plugin_update(); |
81023939 |
570 | vout_fullscreen_old = plat_target.vout_fullscreen; |
571 | } |
572 | } |
573 | |
574 | static void handle_scaler_resize(int w, int h) |
575 | { |
576 | int ww = plat_sdl_screen->w; |
577 | int wh = plat_sdl_screen->h; |
578 | int layer_w_old = g_layer_w; |
579 | int layer_h_old = g_layer_h; |
c9b09029 |
580 | float w_mul, h_mul; |
581 | int x, y; |
81023939 |
582 | pl_update_layer_size(w, h, ww, wh); |
583 | if (layer_w_old != g_layer_w || layer_h_old != g_layer_h) |
584 | forced_clears = 3; |
c9b09029 |
585 | |
586 | w_mul = 2.0f / ww; |
587 | h_mul = 2.0f / wh; |
588 | x = (ww - g_layer_w) / 2; |
589 | y = (wh - g_layer_h) / 2; |
590 | gl_vertices[3*0+0] = gl_vertices[3*2+0] = -1.0f + x * w_mul; |
591 | gl_vertices[3*1+0] = gl_vertices[3*3+0] = -1.0f + (x + g_layer_w) * w_mul; |
592 | gl_vertices[3*2+1] = gl_vertices[3*3+1] = -1.0f + y * h_mul; |
593 | gl_vertices[3*0+1] = gl_vertices[3*1+1] = -1.0f + (y + g_layer_h) * h_mul; |
81023939 |
594 | } |
595 | |
596 | static void handle_window_resize(void) |
597 | { |
598 | // sdl12-compat: a hack to take advantage of sdl2 scaling |
599 | if (resized && (plat_target.vout_method != 0 || !sdl12_compat)) { |
600 | change_mode(window_w, window_h); |
601 | setup_blit_callbacks(psx_w, psx_h); |
602 | forced_clears = 3; |
a8376201 |
603 | } |
c9b09029 |
604 | resized = 0; |
3a52f747 |
605 | } |
606 | |
607 | void *plat_gvideo_set_mode(int *w, int *h, int *bpp) |
608 | { |
609 | psx_w = *w; |
610 | psx_h = *h; |
81023939 |
611 | |
c9b09029 |
612 | if (plat_sdl_gl_active && plugin_owns_display()) |
613 | return NULL; |
614 | |
81023939 |
615 | if (plat_sdl_overlay != NULL) |
616 | overlay_resize(0); |
c9b09029 |
617 | else if (plat_sdl_gl_active) { |
81023939 |
618 | memset(shadow_fb, 0, (*w) * (*h) * 2); |
c9b09029 |
619 | gl_resize(); |
620 | } |
81023939 |
621 | else if (plat_target.vout_method == 0) // && sdl12_compat |
622 | change_mode(*w, *h); |
623 | |
624 | handle_scaler_resize(*w, *h); // override the value from pl_vout_set_mode() |
625 | return setup_blit_callbacks(*w, *h); |
a8376201 |
626 | } |
627 | |
7badc935 |
628 | void *plat_gvideo_flip(void) |
629 | { |
81023939 |
630 | void *ret = NULL; |
631 | int do_flip = 0; |
5b9aa749 |
632 | if (plat_sdl_overlay != NULL) { |
81023939 |
633 | SDL_Rect dstrect = { |
634 | (plat_sdl_screen->w - g_layer_w) / 2, |
635 | (plat_sdl_screen->h - g_layer_h) / 2, |
636 | g_layer_w, g_layer_h |
637 | }; |
5b9aa749 |
638 | SDL_DisplayYUVOverlay(plat_sdl_overlay, &dstrect); |
a8376201 |
639 | } |
5b9aa749 |
640 | else if (plat_sdl_gl_active) { |
c9b09029 |
641 | gl_flip_v(shadow_fb, psx_w, psx_h, g_scaler != SCALE_FULLSCREEN ? gl_vertices : NULL); |
81023939 |
642 | ret = shadow_fb; |
5b9aa749 |
643 | } |
81023939 |
644 | else |
645 | do_flip |= 2; |
646 | |
647 | if (forced_flips > 0) { |
648 | forced_flips--; |
649 | do_flip |= 1; |
650 | } |
651 | if (do_flip) |
5b9aa749 |
652 | SDL_Flip(plat_sdl_screen); |
81023939 |
653 | handle_window_resize(); |
654 | if (do_flip) { |
655 | if (forced_clears > 0) { |
656 | forced_clears--; |
657 | centered_clear(); |
658 | } |
659 | if (!SDL_MUSTLOCK(plat_sdl_screen) && plat_sdl_screen->w == psx_w && |
660 | plat_sdl_screen->h == psx_h && (do_flip & 2)) { |
661 | ret = plat_sdl_screen->pixels; |
662 | } |
a8376201 |
663 | } |
81023939 |
664 | assert(ret || pl_plat_clear != NULL); |
665 | return ret; |
7badc935 |
666 | } |
667 | |
668 | void plat_gvideo_close(void) |
669 | { |
670 | } |
671 | |
672 | void plat_video_menu_enter(int is_rom_loaded) |
673 | { |
3a998763 |
674 | int d; |
675 | |
a8376201 |
676 | in_menu = 1; |
677 | |
2e6189bc |
678 | /* surface will be lost, must adjust pl_vout_buf for menu bg */ |
5b9aa749 |
679 | if (plat_sdl_overlay != NULL) |
81023939 |
680 | uyvy_to_rgb565(menubg_img, psx_w * psx_h); |
5b9aa749 |
681 | else if (plat_sdl_gl_active) |
682 | memcpy(menubg_img, shadow_fb, psx_w * psx_h * 2); |
81023939 |
683 | else { |
684 | unsigned short *dst = menubg_img; |
685 | const unsigned short *src; |
686 | int h; |
687 | if (SDL_MUSTLOCK(plat_sdl_screen)) |
688 | SDL_LockSurface(plat_sdl_screen); |
689 | src = plat_sdl_screen->pixels; |
690 | src += (plat_sdl_screen->w - psx_w) / 2; |
691 | src += plat_sdl_screen->pitch * (plat_sdl_screen->h - psx_h) / 2 / 2; |
692 | for (h = psx_h; h > 0; dst += psx_w, src += plat_sdl_screen->pitch / 2, h--) |
693 | memcpy(dst, src, psx_w * 2); |
694 | if (SDL_MUSTLOCK(plat_sdl_screen)) |
695 | SDL_UnlockSurface(plat_sdl_screen); |
696 | } |
2e6189bc |
697 | pl_vout_buf = menubg_img; |
698 | |
81023939 |
699 | if (plat_target.vout_method == 0) |
700 | change_mode(g_menuscreen_w, g_menuscreen_h); |
701 | else |
c9b09029 |
702 | overlay_or_gl_check_enable(); |
81023939 |
703 | centered_clear(); |
3a998763 |
704 | |
705 | for (d = 0; d < IN_MAX_DEVS; d++) |
706 | in_set_config_int(d, IN_CFG_ANALOG_MAP_ULDR, 1); |
7badc935 |
707 | } |
708 | |
709 | void plat_video_menu_begin(void) |
710 | { |
81023939 |
711 | void *old_ovl = plat_sdl_overlay; |
712 | static int g_scaler_old; |
713 | int scaler_changed = g_scaler_old != g_scaler; |
714 | g_scaler_old = g_scaler; |
715 | if (plat_target.vout_fullscreen != vout_fullscreen_old || |
716 | (plat_target.vout_fullscreen && scaler_changed)) { |
717 | change_mode(g_menuscreen_w, g_menuscreen_h); |
718 | } |
7192adbe |
719 | overlay_or_gl_check_enable(); |
81023939 |
720 | handle_scaler_resize(g_menuscreen_w, g_menuscreen_h); |
721 | |
722 | if (old_ovl != plat_sdl_overlay || scaler_changed) |
723 | centered_clear(); |
3a52f747 |
724 | g_menuscreen_ptr = shadow_fb; |
7badc935 |
725 | } |
726 | |
727 | void plat_video_menu_end(void) |
728 | { |
81023939 |
729 | int do_flip = 0; |
730 | |
5b9aa749 |
731 | if (plat_sdl_overlay != NULL) { |
81023939 |
732 | SDL_Rect dstrect = { |
733 | (plat_sdl_screen->w - g_layer_w) / 2, |
734 | (plat_sdl_screen->h - g_layer_h) / 2, |
735 | g_layer_w, g_layer_h |
736 | }; |
5b9aa749 |
737 | |
738 | SDL_LockYUVOverlay(plat_sdl_overlay); |
739 | rgb565_to_uyvy(plat_sdl_overlay->pixels[0], shadow_fb, |
740 | g_menuscreen_w * g_menuscreen_h); |
741 | SDL_UnlockYUVOverlay(plat_sdl_overlay); |
742 | |
743 | SDL_DisplayYUVOverlay(plat_sdl_overlay, &dstrect); |
744 | } |
745 | else if (plat_sdl_gl_active) { |
c9b09029 |
746 | gl_flip_v(g_menuscreen_ptr, g_menuscreen_w, g_menuscreen_h, |
747 | g_scaler != SCALE_FULLSCREEN ? gl_vertices : NULL); |
5b9aa749 |
748 | } |
749 | else { |
3a52f747 |
750 | centered_blit_menu(); |
81023939 |
751 | do_flip |= 2; |
5b9aa749 |
752 | } |
81023939 |
753 | |
754 | if (forced_flips > 0) { |
755 | forced_flips--; |
756 | do_flip |= 1; |
757 | } |
758 | if (do_flip) |
759 | SDL_Flip(plat_sdl_screen); |
760 | |
761 | handle_window_resize(); |
7badc935 |
762 | g_menuscreen_ptr = NULL; |
763 | } |
764 | |
765 | void plat_video_menu_leave(void) |
766 | { |
3a998763 |
767 | int d; |
768 | |
a8376201 |
769 | in_menu = 0; |
81023939 |
770 | if (plat_sdl_overlay != NULL || plat_sdl_gl_active) |
771 | memset(shadow_fb, 0, g_menuscreen_w * g_menuscreen_h * 2); |
772 | |
773 | if (plat_target.vout_fullscreen) |
774 | change_mode(fs_w, fs_h); |
7192adbe |
775 | overlay_or_gl_check_enable(); |
81023939 |
776 | centered_clear(); |
b2ba218e |
777 | setup_blit_callbacks(psx_w, psx_h); |
3a998763 |
778 | |
779 | for (d = 0; d < IN_MAX_DEVS; d++) |
780 | in_set_config_int(d, IN_CFG_ANALOG_MAP_ULDR, 0); |
7badc935 |
781 | } |
782 | |
7badc935 |
783 | void *plat_prepare_screenshot(int *w, int *h, int *bpp) |
784 | { |
1ae743b1 |
785 | if (plat_sdl_screen && !SDL_MUSTLOCK(plat_sdl_screen) && |
786 | plat_sdl_overlay == NULL && !plat_sdl_gl_active) |
787 | { |
788 | *w = plat_sdl_screen->pitch / 2; |
789 | *h = plat_sdl_screen->h; |
790 | *bpp = 16; |
791 | return plat_sdl_screen->pixels; |
792 | } |
793 | fprintf(stderr, "screenshot not implemented in current mode\n"); |
794 | return NULL; |
7badc935 |
795 | } |
796 | |
d71c7095 |
797 | void plat_trigger_vibrate(int pad, int low, int high) |
7badc935 |
798 | { |
799 | } |
800 | |
801 | void plat_minimize(void) |
802 | { |
803 | } |
804 | |
805 | // vim:shiftwidth=2:expandtab |