fix bug with memory card files being overwritten with RTC files
[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 static int psx_w, psx_h;
57 static void *shadow_fb, *menubg_img;
58 static int in_menu;
59
60 static int change_video_mode(int force)
61 {
62   int w, h;
63
64   if (in_menu) {
65     w = g_menuscreen_w;
66     h = g_menuscreen_h;
67   }
68   else {
69     w = psx_w;
70     h = psx_h;
71   }
72
73   return plat_sdl_change_video_mode(w, h, force);
74 }
75
76 static void resize_cb(int w, int h)
77 {
78   // used by some plugins..
79   pl_rearmed_cbs.screen_w = w;
80   pl_rearmed_cbs.screen_h = h;
81   pl_rearmed_cbs.gles_display = gl_es_display;
82   pl_rearmed_cbs.gles_surface = gl_es_surface;
83   plugin_call_rearmed_cbs();
84 }
85
86 static void quit_cb(void)
87 {
88   emu_core_ask_exit();
89 }
90
91 static void get_layer_pos(int *x, int *y, int *w, int *h)
92 {
93   // always fill entire SDL window
94   *x = *y = 0;
95   *w = pl_rearmed_cbs.screen_w;
96   *h = pl_rearmed_cbs.screen_h;
97 }
98
99 void plat_init(void)
100 {
101   int shadow_size;
102   int ret;
103
104   plat_sdl_quit_cb = quit_cb;
105   plat_sdl_resize_cb = resize_cb;
106
107   ret = plat_sdl_init();
108   if (ret != 0)
109     exit(1);
110
111   in_menu = 1;
112   SDL_WM_SetCaption("PCSX-ReARMed " REV, NULL);
113
114   shadow_size = g_menuscreen_w * g_menuscreen_h * 2;
115   if (shadow_size < 640 * 512 * 2)
116     shadow_size = 640 * 512 * 2;
117
118   shadow_fb = malloc(shadow_size);
119   menubg_img = malloc(shadow_size);
120   if (shadow_fb == NULL || menubg_img == NULL) {
121     fprintf(stderr, "OOM\n");
122     exit(1);
123   }
124
125   in_sdl_init(in_sdl_defbinds, plat_sdl_event_handler);
126   in_probe();
127   pl_rearmed_cbs.only_16bpp = 1;
128   pl_rearmed_cbs.pl_get_layer_pos = get_layer_pos;
129
130   bgr_to_uyvy_init();
131 }
132
133 void plat_finish(void)
134 {
135   free(shadow_fb);
136   shadow_fb = NULL;
137   free(menubg_img);
138   menubg_img = NULL;
139   plat_sdl_finish();
140 }
141
142 void plat_gvideo_open(int is_pal)
143 {
144 }
145
146 static void uyvy_to_rgb565(void *d, const void *s, int pixels)
147 {
148   unsigned short *dst = d;
149   const unsigned int *src = s;
150   int v;
151
152   // no colors, for now
153   for (; pixels > 0; src++, dst += 2, pixels -= 2) {
154     v = (*src >> 8) & 0xff;
155     v = (v - 16) * 255 / 219 / 8;
156     dst[0] = (v << 11) | (v << 6) | v;
157
158     v = (*src >> 24) & 0xff;
159     v = (v - 16) * 255 / 219 / 8;
160     dst[1] = (v << 11) | (v << 6) | v;
161   }
162 }
163
164 static void overlay_blit(int doffs, const void *src_, int w, int h,
165                          int sstride, int bgr24)
166 {
167   const unsigned short *src = src_;
168   unsigned short *dst;
169   int dstride = plat_sdl_overlay->w;
170
171   SDL_LockYUVOverlay(plat_sdl_overlay);
172   dst = (void *)plat_sdl_overlay->pixels[0];
173
174   dst += doffs;
175   if (bgr24) {
176     for (; h > 0; dst += dstride, src += sstride, h--)
177       bgr888_to_uyvy(dst, src, w);
178   }
179   else {
180     for (; h > 0; dst += dstride, src += sstride, h--)
181       bgr555_to_uyvy(dst, src, w);
182   }
183
184   SDL_UnlockYUVOverlay(plat_sdl_overlay);
185 }
186
187 static void overlay_hud_print(int x, int y, const char *str, int bpp)
188 {
189   SDL_LockYUVOverlay(plat_sdl_overlay);
190   basic_text_out_uyvy_nf(plat_sdl_overlay->pixels[0], plat_sdl_overlay->w, x, y, str);
191   SDL_UnlockYUVOverlay(plat_sdl_overlay);
192 }
193
194 void *plat_gvideo_set_mode(int *w, int *h, int *bpp)
195 {
196   psx_w = *w;
197   psx_h = *h;
198   change_video_mode(0);
199   if (plat_sdl_overlay != NULL) {
200     pl_plat_clear = plat_sdl_overlay_clear;
201     pl_plat_blit = overlay_blit;
202     pl_plat_hud_print = overlay_hud_print;
203     return NULL;
204   }
205   else {
206     pl_plat_clear = NULL;
207     pl_plat_blit = NULL;
208     pl_plat_hud_print = NULL;
209     if (plat_sdl_gl_active)
210       return shadow_fb;
211     else
212       return plat_sdl_screen->pixels;
213   }
214 }
215
216 void *plat_gvideo_flip(void)
217 {
218   if (plat_sdl_overlay != NULL) {
219     SDL_Rect dstrect = { 0, 0, plat_sdl_screen->w, plat_sdl_screen->h };
220     SDL_DisplayYUVOverlay(plat_sdl_overlay, &dstrect);
221     return NULL;
222   }
223   else if (plat_sdl_gl_active) {
224     gl_flip(shadow_fb, psx_w, psx_h);
225     return shadow_fb;
226   }
227   else {
228     // XXX: no locking, but should be fine with SDL_SWSURFACE?
229     SDL_Flip(plat_sdl_screen);
230     return plat_sdl_screen->pixels;
231   }
232 }
233
234 void plat_gvideo_close(void)
235 {
236 }
237
238 void plat_video_menu_enter(int is_rom_loaded)
239 {
240   int force_mode_change = 0;
241
242   in_menu = 1;
243
244   /* surface will be lost, must adjust pl_vout_buf for menu bg */
245   if (plat_sdl_overlay != NULL)
246     uyvy_to_rgb565(menubg_img, plat_sdl_overlay->pixels[0], psx_w * psx_h);
247   else if (plat_sdl_gl_active)
248     memcpy(menubg_img, shadow_fb, psx_w * psx_h * 2);
249   else
250     memcpy(menubg_img, plat_sdl_screen->pixels, psx_w * psx_h * 2);
251   pl_vout_buf = menubg_img;
252
253   /* gles plugin messes stuff up.. */
254   if (pl_rearmed_cbs.gpu_caps & GPU_CAP_OWNS_DISPLAY)
255     force_mode_change = 1;
256
257   change_video_mode(force_mode_change);
258 }
259
260 void plat_video_menu_begin(void)
261 {
262   if (plat_sdl_overlay != NULL || plat_sdl_gl_active) {
263     g_menuscreen_ptr = shadow_fb;
264   }
265   else {
266     SDL_LockSurface(plat_sdl_screen);
267     g_menuscreen_ptr = plat_sdl_screen->pixels;
268   }
269 }
270
271 void plat_video_menu_end(void)
272 {
273   if (plat_sdl_overlay != NULL) {
274     SDL_Rect dstrect = { 0, 0, plat_sdl_screen->w, plat_sdl_screen->h };
275
276     SDL_LockYUVOverlay(plat_sdl_overlay);
277     rgb565_to_uyvy(plat_sdl_overlay->pixels[0], shadow_fb,
278       g_menuscreen_w * g_menuscreen_h);
279     SDL_UnlockYUVOverlay(plat_sdl_overlay);
280
281     SDL_DisplayYUVOverlay(plat_sdl_overlay, &dstrect);
282   }
283   else if (plat_sdl_gl_active) {
284     gl_flip(g_menuscreen_ptr, g_menuscreen_w, g_menuscreen_h);
285   }
286   else {
287     SDL_UnlockSurface(plat_sdl_screen);
288     SDL_Flip(plat_sdl_screen);
289   }
290   g_menuscreen_ptr = NULL;
291 }
292
293 void plat_video_menu_leave(void)
294 {
295   in_menu = 0;
296 }
297
298 /* unused stuff */
299 void *plat_prepare_screenshot(int *w, int *h, int *bpp)
300 {
301   return 0;
302 }
303
304 void plat_trigger_vibrate(int is_strong)
305 {
306 }
307
308 void plat_minimize(void)
309 {
310 }
311
312 // vim:shiftwidth=2:expandtab