frontend: change how exit is done
[pcsx_rearmed.git] / frontend / plat_sdl.c
1 /*
2  * (C) GraÅžvydas "notaz" Ignotas, 2011,2012
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 "../plugins/gpulib/cspace.h"
21 #include "plugin_lib.h"
22 #include "main.h"
23 #include "plat.h"
24 #include "revision.h"
25
26 static const struct in_default_bind in_sdl_defbinds[] = {
27   { SDLK_UP,     IN_BINDTYPE_PLAYER12, DKEY_UP },
28   { SDLK_DOWN,   IN_BINDTYPE_PLAYER12, DKEY_DOWN },
29   { SDLK_LEFT,   IN_BINDTYPE_PLAYER12, DKEY_LEFT },
30   { SDLK_RIGHT,  IN_BINDTYPE_PLAYER12, DKEY_RIGHT },
31   { SDLK_d,      IN_BINDTYPE_PLAYER12, DKEY_TRIANGLE },
32   { SDLK_z,      IN_BINDTYPE_PLAYER12, DKEY_CROSS },
33   { SDLK_x,      IN_BINDTYPE_PLAYER12, DKEY_CIRCLE },
34   { SDLK_s,      IN_BINDTYPE_PLAYER12, DKEY_SQUARE },
35   { SDLK_v,      IN_BINDTYPE_PLAYER12, DKEY_START },
36   { SDLK_c,      IN_BINDTYPE_PLAYER12, DKEY_SELECT },
37   { SDLK_w,      IN_BINDTYPE_PLAYER12, DKEY_L1 },
38   { SDLK_r,      IN_BINDTYPE_PLAYER12, DKEY_R1 },
39   { SDLK_e,      IN_BINDTYPE_PLAYER12, DKEY_L2 },
40   { SDLK_t,      IN_BINDTYPE_PLAYER12, DKEY_R2 },
41   { SDLK_ESCAPE, IN_BINDTYPE_EMU, SACTION_ENTER_MENU },
42   { SDLK_F1,     IN_BINDTYPE_EMU, SACTION_SAVE_STATE },
43   { SDLK_F2,     IN_BINDTYPE_EMU, SACTION_LOAD_STATE },
44   { SDLK_F3,     IN_BINDTYPE_EMU, SACTION_PREV_SSLOT },
45   { SDLK_F4,     IN_BINDTYPE_EMU, SACTION_NEXT_SSLOT },
46   { SDLK_F5,     IN_BINDTYPE_EMU, SACTION_TOGGLE_FSKIP },
47   { SDLK_F6,     IN_BINDTYPE_EMU, SACTION_SCREENSHOT },
48   { SDLK_F7,     IN_BINDTYPE_EMU, SACTION_TOGGLE_FPS },
49   { SDLK_F8,     IN_BINDTYPE_EMU, SACTION_SWITCH_DISPMODE },
50   { SDLK_F11,    IN_BINDTYPE_EMU, SACTION_TOGGLE_FULLSCREEN },
51   { SDLK_BACKSPACE, IN_BINDTYPE_EMU, SACTION_FAST_FORWARD },
52   { 0, 0, 0 }
53 };
54
55 static int psx_w, psx_h;
56 static void *shadow_fb, *menubg_img;
57 static int in_menu;
58
59 static int change_video_mode(void)
60 {
61   int w, h;
62
63   if (in_menu) {
64     w = g_menuscreen_w;
65     h = g_menuscreen_h;
66   }
67   else {
68     w = psx_w;
69     h = psx_h;
70   }
71
72   return plat_sdl_change_video_mode(w, h, 0);
73 }
74
75 static void quit_cb(void)
76 {
77   emu_core_ask_exit();
78 }
79
80 void plat_init(void)
81 {
82   int ret;
83
84   ret = plat_sdl_init();
85   if (ret != 0)
86     exit(1);
87
88   in_menu = 1;
89   SDL_WM_SetCaption("PCSX-ReARMed " REV, NULL);
90
91   shadow_fb = malloc(640 * 512 * 2);
92   menubg_img = malloc(640 * 512 * 2);
93   if (shadow_fb == NULL || menubg_img == NULL) {
94     fprintf(stderr, "OOM\n");
95     exit(1);
96   }
97
98   in_sdl_init(in_sdl_defbinds, plat_sdl_event_handler);
99   in_probe();
100   pl_rearmed_cbs.only_16bpp = 1;
101
102   bgr_to_uyvy_init();
103   plat_sdl_quit_cb = quit_cb;
104 }
105
106 void plat_finish(void)
107 {
108   free(shadow_fb);
109   shadow_fb = NULL;
110   free(menubg_img);
111   menubg_img = NULL;
112   plat_sdl_finish();
113 }
114
115 void plat_gvideo_open(int is_pal)
116 {
117 }
118
119 static void uyvy_to_rgb565(void *d, const void *s, int pixels)
120 {
121   unsigned short *dst = d;
122   const unsigned int *src = s;
123   int v;
124
125   // no colors, for now
126   for (; pixels > 0; src++, dst += 2, pixels -= 2) {
127     v = (*src >> 8) & 0xff;
128     v = (v - 16) * 255 / 219 / 8;
129     dst[0] = (v << 11) | (v << 6) | v;
130
131     v = (*src >> 24) & 0xff;
132     v = (v - 16) * 255 / 219 / 8;
133     dst[1] = (v << 11) | (v << 6) | v;
134   }
135 }
136
137 static void overlay_blit(int doffs, const void *src_, int w, int h,
138                          int sstride, int bgr24)
139 {
140   const unsigned short *src = src_;
141   unsigned short *dst;
142   int dstride = plat_sdl_overlay->w;
143
144   SDL_LockYUVOverlay(plat_sdl_overlay);
145   dst = (void *)plat_sdl_overlay->pixels[0];
146
147   dst += doffs;
148   if (bgr24) {
149     for (; h > 0; dst += dstride, src += sstride, h--)
150       bgr888_to_uyvy(dst, src, w);
151   }
152   else {
153     for (; h > 0; dst += dstride, src += sstride, h--)
154       bgr555_to_uyvy(dst, src, w);
155   }
156
157   SDL_UnlockYUVOverlay(plat_sdl_overlay);
158 }
159
160 static void overlay_hud_print(int x, int y, const char *str, int bpp)
161 {
162   SDL_LockYUVOverlay(plat_sdl_overlay);
163   basic_text_out_uyvy_nf(plat_sdl_overlay->pixels[0], plat_sdl_overlay->w, x, y, str);
164   SDL_UnlockYUVOverlay(plat_sdl_overlay);
165 }
166
167 void *plat_gvideo_set_mode(int *w, int *h, int *bpp)
168 {
169   psx_w = *w;
170   psx_h = *h;
171   change_video_mode();
172   if (plat_sdl_overlay != NULL) {
173     pl_plat_clear = plat_sdl_overlay_clear;
174     pl_plat_blit = overlay_blit;
175     pl_plat_hud_print = overlay_hud_print;
176     return NULL;
177   }
178   else {
179     pl_plat_clear = NULL;
180     pl_plat_blit = NULL;
181     pl_plat_hud_print = NULL;
182     if (plat_sdl_gl_active)
183       return shadow_fb;
184     else
185       return plat_sdl_screen->pixels;
186   }
187 }
188
189 void *plat_gvideo_flip(void)
190 {
191   if (plat_sdl_overlay != NULL) {
192     SDL_Rect dstrect = { 0, 0, plat_sdl_screen->w, plat_sdl_screen->h };
193     SDL_DisplayYUVOverlay(plat_sdl_overlay, &dstrect);
194     return NULL;
195   }
196   else if (plat_sdl_gl_active) {
197     gl_flip(shadow_fb, psx_w, psx_h);
198     return shadow_fb;
199   }
200   else {
201     // XXX: no locking, but should be fine with SDL_SWSURFACE?
202     SDL_Flip(plat_sdl_screen);
203     return plat_sdl_screen->pixels;
204   }
205 }
206
207 void plat_gvideo_close(void)
208 {
209 }
210
211 void plat_video_menu_enter(int is_rom_loaded)
212 {
213   in_menu = 1;
214
215   /* surface will be lost, must adjust pl_vout_buf for menu bg */
216   if (plat_sdl_overlay != NULL)
217     uyvy_to_rgb565(menubg_img, plat_sdl_overlay->pixels[0], psx_w * psx_h);
218   else if (plat_sdl_gl_active)
219     memcpy(menubg_img, shadow_fb, psx_w * psx_h * 2);
220   else
221     memcpy(menubg_img, plat_sdl_screen->pixels, psx_w * psx_h * 2);
222   pl_vout_buf = menubg_img;
223
224   change_video_mode();
225 }
226
227 void plat_video_menu_begin(void)
228 {
229   if (plat_sdl_overlay != NULL || plat_sdl_gl_active) {
230     g_menuscreen_ptr = shadow_fb;
231   }
232   else {
233     SDL_LockSurface(plat_sdl_screen);
234     g_menuscreen_ptr = plat_sdl_screen->pixels;
235   }
236 }
237
238 void plat_video_menu_end(void)
239 {
240   if (plat_sdl_overlay != NULL) {
241     SDL_Rect dstrect = { 0, 0, plat_sdl_screen->w, plat_sdl_screen->h };
242
243     SDL_LockYUVOverlay(plat_sdl_overlay);
244     rgb565_to_uyvy(plat_sdl_overlay->pixels[0], shadow_fb,
245       g_menuscreen_w * g_menuscreen_h);
246     SDL_UnlockYUVOverlay(plat_sdl_overlay);
247
248     SDL_DisplayYUVOverlay(plat_sdl_overlay, &dstrect);
249   }
250   else if (plat_sdl_gl_active) {
251     gl_flip(g_menuscreen_ptr, g_menuscreen_w, g_menuscreen_h);
252   }
253   else {
254     SDL_UnlockSurface(plat_sdl_screen);
255     SDL_Flip(plat_sdl_screen);
256   }
257   g_menuscreen_ptr = NULL;
258 }
259
260 void plat_video_menu_leave(void)
261 {
262   in_menu = 0;
263 }
264
265 /* unused stuff */
266 void *plat_prepare_screenshot(int *w, int *h, int *bpp)
267 {
268   return 0;
269 }
270
271 void plat_trigger_vibrate(int is_strong)
272 {
273 }
274
275 void plat_minimize(void)
276 {
277 }
278
279 // vim:shiftwidth=2:expandtab