cdrom: change pause timing again
[pcsx_rearmed.git] / frontend / plat_sdl.c
1 /*
2  * (C) GraÅžvydas "notaz" Ignotas, 2011-2013
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>
12 #include <SDL.h>
13
14 #include "libpicofe/input.h"
15 #include "libpicofe/in_sdl.h"
16 #include "libpicofe/menu.h"
17 #include "libpicofe/fonts.h"
18 #include "libpicofe/plat_sdl.h"
19 #include "libpicofe/gl.h"
20 #include "cspace.h"
21 #include "plugin_lib.h"
22 #include "plugin.h"
23 #include "main.h"
24 #include "plat.h"
25 #include "revision.h"
26
27 static const struct in_default_bind in_sdl_defbinds[] = {
28   { SDLK_UP,     IN_BINDTYPE_PLAYER12, DKEY_UP },
29   { SDLK_DOWN,   IN_BINDTYPE_PLAYER12, DKEY_DOWN },
30   { SDLK_LEFT,   IN_BINDTYPE_PLAYER12, DKEY_LEFT },
31   { SDLK_RIGHT,  IN_BINDTYPE_PLAYER12, DKEY_RIGHT },
32   { SDLK_d,      IN_BINDTYPE_PLAYER12, DKEY_TRIANGLE },
33   { SDLK_z,      IN_BINDTYPE_PLAYER12, DKEY_CROSS },
34   { SDLK_x,      IN_BINDTYPE_PLAYER12, DKEY_CIRCLE },
35   { SDLK_s,      IN_BINDTYPE_PLAYER12, DKEY_SQUARE },
36   { SDLK_v,      IN_BINDTYPE_PLAYER12, DKEY_START },
37   { SDLK_c,      IN_BINDTYPE_PLAYER12, DKEY_SELECT },
38   { SDLK_w,      IN_BINDTYPE_PLAYER12, DKEY_L1 },
39   { SDLK_r,      IN_BINDTYPE_PLAYER12, DKEY_R1 },
40   { SDLK_e,      IN_BINDTYPE_PLAYER12, DKEY_L2 },
41   { SDLK_t,      IN_BINDTYPE_PLAYER12, DKEY_R2 },
42   { SDLK_ESCAPE, IN_BINDTYPE_EMU, SACTION_ENTER_MENU },
43   { SDLK_F1,     IN_BINDTYPE_EMU, SACTION_SAVE_STATE },
44   { SDLK_F2,     IN_BINDTYPE_EMU, SACTION_LOAD_STATE },
45   { SDLK_F3,     IN_BINDTYPE_EMU, SACTION_PREV_SSLOT },
46   { SDLK_F4,     IN_BINDTYPE_EMU, SACTION_NEXT_SSLOT },
47   { SDLK_F5,     IN_BINDTYPE_EMU, SACTION_TOGGLE_FSKIP },
48   { SDLK_F6,     IN_BINDTYPE_EMU, SACTION_SCREENSHOT },
49   { SDLK_F7,     IN_BINDTYPE_EMU, SACTION_TOGGLE_FPS },
50   { SDLK_F8,     IN_BINDTYPE_EMU, SACTION_SWITCH_DISPMODE },
51   { SDLK_F11,    IN_BINDTYPE_EMU, SACTION_TOGGLE_FULLSCREEN },
52   { SDLK_BACKSPACE, IN_BINDTYPE_EMU, SACTION_FAST_FORWARD },
53   { 0, 0, 0 }
54 };
55
56 const struct menu_keymap in_sdl_key_map[] =
57 {
58   { SDLK_UP,     PBTN_UP },
59   { SDLK_DOWN,   PBTN_DOWN },
60   { SDLK_LEFT,   PBTN_LEFT },
61   { SDLK_RIGHT,  PBTN_RIGHT },
62   { SDLK_RETURN, PBTN_MOK },
63   { SDLK_ESCAPE, PBTN_MBACK },
64   { SDLK_SEMICOLON,    PBTN_MA2 },
65   { SDLK_QUOTE,        PBTN_MA3 },
66   { SDLK_LEFTBRACKET,  PBTN_L },
67   { SDLK_RIGHTBRACKET, PBTN_R },
68 };
69
70 const struct menu_keymap in_sdl_joy_map[] =
71 {
72   { SDLK_UP,    PBTN_UP },
73   { SDLK_DOWN,  PBTN_DOWN },
74   { SDLK_LEFT,  PBTN_LEFT },
75   { SDLK_RIGHT, PBTN_RIGHT },
76   /* joystick */
77   { SDLK_WORLD_0, PBTN_MOK },
78   { SDLK_WORLD_1, PBTN_MBACK },
79   { SDLK_WORLD_2, PBTN_MA2 },
80   { SDLK_WORLD_3, PBTN_MA3 },
81 };
82
83 static const struct in_pdata in_sdl_platform_data = {
84   .defbinds  = in_sdl_defbinds,
85   .key_map   = in_sdl_key_map,
86   .kmap_size = sizeof(in_sdl_key_map) / sizeof(in_sdl_key_map[0]),
87   .joy_map   = in_sdl_joy_map,
88   .jmap_size = sizeof(in_sdl_joy_map) / sizeof(in_sdl_joy_map[0]),
89 };
90
91 static int psx_w = 256, psx_h = 240;
92 static void *shadow_fb, *menubg_img;
93 static int in_menu;
94
95 static void centered_clear(void);
96 static void *setup_blit_callbacks(int w);
97
98 static int change_video_mode(int force)
99 {
100   int w, h, ret;
101
102   if (in_menu) {
103     w = g_menuscreen_w;
104     h = g_menuscreen_h;
105   }
106   else {
107     w = psx_w;
108     h = psx_h;
109   }
110
111   ret = plat_sdl_change_video_mode(w, h, force);
112   if (ret == 0 && plat_sdl_overlay == NULL && !plat_sdl_gl_active)
113     centered_clear();
114   return ret;
115 }
116
117 static void resize_cb(int w, int h)
118 {
119   // used by some plugins..
120   pl_rearmed_cbs.screen_w = w;
121   pl_rearmed_cbs.screen_h = h;
122   pl_rearmed_cbs.gles_display = gl_es_display;
123   pl_rearmed_cbs.gles_surface = gl_es_surface;
124   plugin_call_rearmed_cbs();
125   setup_blit_callbacks(psx_w);
126 }
127
128 static void quit_cb(void)
129 {
130   emu_core_ask_exit();
131 }
132
133 static void get_layer_pos(int *x, int *y, int *w, int *h)
134 {
135   // always fill entire SDL window
136   *x = *y = 0;
137   *w = pl_rearmed_cbs.screen_w;
138   *h = pl_rearmed_cbs.screen_h;
139 }
140
141 void plat_init(void)
142 {
143   int shadow_size;
144   int ret;
145
146   plat_sdl_quit_cb = quit_cb;
147   plat_sdl_resize_cb = resize_cb;
148
149   ret = plat_sdl_init();
150   if (ret != 0)
151     exit(1);
152
153   in_menu = 1;
154   SDL_WM_SetCaption("PCSX-ReARMed " REV, NULL);
155
156   shadow_size = g_menuscreen_w * g_menuscreen_h * 2;
157   // alloc enough for double res. rendering
158   if (shadow_size < 1024 * 512 * 2)
159     shadow_size = 1024 * 512 * 2;
160
161   shadow_fb = malloc(shadow_size);
162   menubg_img = malloc(shadow_size);
163   if (shadow_fb == NULL || menubg_img == NULL) {
164     fprintf(stderr, "OOM\n");
165     exit(1);
166   }
167
168   in_sdl_init(&in_sdl_platform_data, plat_sdl_event_handler);
169   in_probe();
170   pl_rearmed_cbs.only_16bpp = 1;
171   pl_rearmed_cbs.pl_get_layer_pos = get_layer_pos;
172
173   bgr_to_uyvy_init();
174 }
175
176 void plat_finish(void)
177 {
178   free(shadow_fb);
179   shadow_fb = NULL;
180   free(menubg_img);
181   menubg_img = NULL;
182   plat_sdl_finish();
183 }
184
185 void plat_gvideo_open(int is_pal)
186 {
187 }
188
189 static void uyvy_to_rgb565(void *d, const void *s, int pixels)
190 {
191   unsigned short *dst = d;
192   const unsigned int *src = s;
193   int v;
194
195   // no colors, for now
196   for (; pixels > 0; src++, dst += 2, pixels -= 2) {
197     v = (*src >> 8) & 0xff;
198     v = (v - 16) * 255 / 219 / 8;
199     dst[0] = (v << 11) | (v << 6) | v;
200
201     v = (*src >> 24) & 0xff;
202     v = (v - 16) * 255 / 219 / 8;
203     dst[1] = (v << 11) | (v << 6) | v;
204   }
205 }
206
207 static void overlay_blit(int doffs, const void *src_, int w, int h,
208                          int sstride, int bgr24)
209 {
210   const unsigned short *src = src_;
211   unsigned short *dst;
212   int dstride = plat_sdl_overlay->w;
213
214   SDL_LockYUVOverlay(plat_sdl_overlay);
215   dst = (void *)plat_sdl_overlay->pixels[0];
216
217   dst += doffs;
218   if (bgr24) {
219     for (; h > 0; dst += dstride, src += sstride, h--)
220       bgr888_to_uyvy(dst, src, w);
221   }
222   else {
223     for (; h > 0; dst += dstride, src += sstride, h--)
224       bgr555_to_uyvy(dst, src, w);
225   }
226
227   SDL_UnlockYUVOverlay(plat_sdl_overlay);
228 }
229
230 static void overlay_hud_print(int x, int y, const char *str, int bpp)
231 {
232   SDL_LockYUVOverlay(plat_sdl_overlay);
233   basic_text_out_uyvy_nf(plat_sdl_overlay->pixels[0], plat_sdl_overlay->w, x, y, str);
234   SDL_UnlockYUVOverlay(plat_sdl_overlay);
235 }
236
237 static void centered_clear(void)
238 {
239   int dstride = plat_sdl_screen->pitch / 2;
240   int w = plat_sdl_screen->w;
241   int h = plat_sdl_screen->h;
242   unsigned short *dst;
243
244   SDL_LockSurface(plat_sdl_screen);
245   dst = plat_sdl_screen->pixels;
246
247   for (; h > 0; dst += dstride, h--)
248     memset(dst, 0, w * 2);
249
250   SDL_UnlockSurface(plat_sdl_screen);
251 }
252
253 static void centered_blit(int doffs, const void *src_, int w, int h,
254                           int sstride, int bgr24)
255 {
256   const unsigned short *src = src_;
257   unsigned short *dst;
258   int dstride;
259
260   SDL_LockSurface(plat_sdl_screen);
261   dst = plat_sdl_screen->pixels;
262   dstride = plat_sdl_screen->pitch / 2;
263
264   dst += doffs + (plat_sdl_screen->w - w) / 2;
265   dst += dstride * (plat_sdl_screen->h - h) / 2;
266   if (bgr24) {
267     for (; h > 0; dst += dstride, src += sstride, h--)
268       bgr888_to_rgb565(dst, src, w * 3);
269   }
270   else {
271     for (; h > 0; dst += dstride, src += sstride, h--)
272       bgr555_to_rgb565(dst, src, w * 2);
273   }
274
275   SDL_UnlockSurface(plat_sdl_screen);
276 }
277
278 static void centered_blit_menu(void)
279 {
280   const unsigned short *src = g_menuscreen_ptr;
281   int w = g_menuscreen_w;
282   int h = g_menuscreen_h;
283   unsigned short *dst;
284   int dstride;
285
286   SDL_LockSurface(plat_sdl_screen);
287   dst = plat_sdl_screen->pixels;
288   dstride = plat_sdl_screen->pitch / 2;
289
290   dst += (plat_sdl_screen->w - w) / 2;
291   dst += dstride * (plat_sdl_screen->h - h) / 2;
292   for (; h > 0; dst += dstride, src += g_menuscreen_pp, h--)
293     memcpy(dst, src, w * 2);
294
295   SDL_UnlockSurface(plat_sdl_screen);
296 }
297
298 static void centered_hud_print(int x, int y, const char *str, int bpp)
299 {
300   x += (plat_sdl_screen->w - psx_w) / 2;
301   y += (plat_sdl_screen->h - psx_h) / 2;
302   SDL_LockSurface(plat_sdl_screen);
303   basic_text_out16_nf(plat_sdl_screen->pixels, plat_sdl_screen->pitch / 2, x, y, str);
304   SDL_UnlockSurface(plat_sdl_screen);
305 }
306
307 static void *setup_blit_callbacks(int w)
308 {
309   pl_plat_clear = NULL;
310   pl_plat_blit = NULL;
311   pl_plat_hud_print = NULL;
312   if (plat_sdl_overlay != NULL) {
313     pl_plat_clear = plat_sdl_overlay_clear;
314     pl_plat_blit = overlay_blit;
315     pl_plat_hud_print = overlay_hud_print;
316   }
317   else if (plat_sdl_gl_active) {
318     return shadow_fb;
319   }
320   else {
321     if (w == plat_sdl_screen->w)
322       return plat_sdl_screen->pixels;
323     else {
324       pl_plat_clear = centered_clear;
325       pl_plat_blit = centered_blit;
326       pl_plat_hud_print = centered_hud_print;
327     }
328   }
329   return NULL;
330 }
331
332 void *plat_gvideo_set_mode(int *w, int *h, int *bpp)
333 {
334   psx_w = *w;
335   psx_h = *h;
336   change_video_mode(0);
337   if (plat_sdl_gl_active)
338     memset(shadow_fb, 0, psx_w * psx_h * 2);
339   return setup_blit_callbacks(*w);
340 }
341
342 void *plat_gvideo_flip(void)
343 {
344   if (plat_sdl_overlay != NULL) {
345     SDL_Rect dstrect = { 0, 0, plat_sdl_screen->w, plat_sdl_screen->h };
346     SDL_DisplayYUVOverlay(plat_sdl_overlay, &dstrect);
347     return NULL;
348   }
349   else if (plat_sdl_gl_active) {
350     gl_flip(shadow_fb, psx_w, psx_h);
351     return shadow_fb;
352   }
353   else {
354     // XXX: no locking, but should be fine with SDL_SWSURFACE?
355     SDL_Flip(plat_sdl_screen);
356     return plat_sdl_screen->pixels;
357   }
358 }
359
360 void plat_gvideo_close(void)
361 {
362 }
363
364 void plat_video_menu_enter(int is_rom_loaded)
365 {
366   int force_mode_change = 0;
367
368   in_menu = 1;
369
370   /* surface will be lost, must adjust pl_vout_buf for menu bg */
371   if (plat_sdl_overlay != NULL)
372     uyvy_to_rgb565(menubg_img, plat_sdl_overlay->pixels[0], psx_w * psx_h);
373   else if (plat_sdl_gl_active)
374     memcpy(menubg_img, shadow_fb, psx_w * psx_h * 2);
375   else
376     memcpy(menubg_img, plat_sdl_screen->pixels, psx_w * psx_h * 2);
377   pl_vout_buf = menubg_img;
378
379   /* gles plugin messes stuff up.. */
380   if (pl_rearmed_cbs.gpu_caps & GPU_CAP_OWNS_DISPLAY)
381     force_mode_change = 1;
382
383   change_video_mode(force_mode_change);
384 }
385
386 void plat_video_menu_begin(void)
387 {
388   g_menuscreen_ptr = shadow_fb;
389 }
390
391 void plat_video_menu_end(void)
392 {
393   if (plat_sdl_overlay != NULL) {
394     SDL_Rect dstrect = { 0, 0, plat_sdl_screen->w, plat_sdl_screen->h };
395
396     SDL_LockYUVOverlay(plat_sdl_overlay);
397     rgb565_to_uyvy(plat_sdl_overlay->pixels[0], shadow_fb,
398       g_menuscreen_w * g_menuscreen_h);
399     SDL_UnlockYUVOverlay(plat_sdl_overlay);
400
401     SDL_DisplayYUVOverlay(plat_sdl_overlay, &dstrect);
402   }
403   else if (plat_sdl_gl_active) {
404     gl_flip(g_menuscreen_ptr, g_menuscreen_w, g_menuscreen_h);
405   }
406   else {
407     centered_blit_menu();
408     SDL_Flip(plat_sdl_screen);
409   }
410   g_menuscreen_ptr = NULL;
411 }
412
413 void plat_video_menu_leave(void)
414 {
415   void *fb = NULL;
416   if (plat_sdl_overlay != NULL || plat_sdl_gl_active)
417     fb = shadow_fb;
418   else if (plat_sdl_screen)
419     fb = plat_sdl_screen->pixels;
420   if (fb)
421     memset(fb, 0, g_menuscreen_w * g_menuscreen_h * 2);
422   in_menu = 0;
423 }
424
425 /* unused stuff */
426 void *plat_prepare_screenshot(int *w, int *h, int *bpp)
427 {
428   return 0;
429 }
430
431 void plat_trigger_vibrate(int pad, int low, int high)
432 {
433 }
434
435 void plat_minimize(void)
436 {
437 }
438
439 // vim:shiftwidth=2:expandtab