7badc935 |
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> |
cc56203b |
13 | |
14 | #include "libpicofe/input.h" |
15 | #include "libpicofe/in_sdl.h" |
16 | #include "libpicofe/menu.h" |
c9099d02 |
17 | #include "libpicofe/fonts.h" |
18 | #include "../plugins/gpulib/cspace.h" |
b07c18e8 |
19 | #include "plugin_lib.h" |
20 | #include "main.h" |
a8376201 |
21 | #include "menu.h" |
7badc935 |
22 | #include "plat.h" |
23 | #include "revision.h" |
24 | |
b07c18e8 |
25 | static const struct in_default_bind in_sdl_defbinds[] = { |
2e6189bc |
26 | { SDLK_UP, IN_BINDTYPE_PLAYER12, DKEY_UP }, |
27 | { SDLK_DOWN, IN_BINDTYPE_PLAYER12, DKEY_DOWN }, |
28 | { SDLK_LEFT, IN_BINDTYPE_PLAYER12, DKEY_LEFT }, |
29 | { SDLK_RIGHT, IN_BINDTYPE_PLAYER12, DKEY_RIGHT }, |
30 | { SDLK_d, IN_BINDTYPE_PLAYER12, DKEY_TRIANGLE }, |
31 | { SDLK_z, IN_BINDTYPE_PLAYER12, DKEY_CROSS }, |
32 | { SDLK_x, IN_BINDTYPE_PLAYER12, DKEY_CIRCLE }, |
33 | { SDLK_s, IN_BINDTYPE_PLAYER12, DKEY_SQUARE }, |
34 | { SDLK_v, IN_BINDTYPE_PLAYER12, DKEY_START }, |
35 | { SDLK_c, IN_BINDTYPE_PLAYER12, DKEY_SELECT }, |
36 | { SDLK_w, IN_BINDTYPE_PLAYER12, DKEY_L1 }, |
37 | { SDLK_r, IN_BINDTYPE_PLAYER12, DKEY_R1 }, |
38 | { SDLK_e, IN_BINDTYPE_PLAYER12, DKEY_L2 }, |
39 | { SDLK_t, IN_BINDTYPE_PLAYER12, DKEY_R2 }, |
40 | { SDLK_ESCAPE, IN_BINDTYPE_EMU, SACTION_ENTER_MENU }, |
456f1b86 |
41 | { SDLK_F1, IN_BINDTYPE_EMU, SACTION_SAVE_STATE }, |
42 | { SDLK_F2, IN_BINDTYPE_EMU, SACTION_LOAD_STATE }, |
43 | { SDLK_F3, IN_BINDTYPE_EMU, SACTION_PREV_SSLOT }, |
44 | { SDLK_F4, IN_BINDTYPE_EMU, SACTION_NEXT_SSLOT }, |
45 | { SDLK_F5, IN_BINDTYPE_EMU, SACTION_TOGGLE_FSKIP }, |
46 | { SDLK_F6, IN_BINDTYPE_EMU, SACTION_SCREENSHOT }, |
dde7da71 |
47 | { SDLK_F7, IN_BINDTYPE_EMU, SACTION_TOGGLE_FPS }, |
456f1b86 |
48 | { SDLK_F8, IN_BINDTYPE_EMU, SACTION_SWITCH_DISPMODE }, |
a8376201 |
49 | { SDLK_F11, IN_BINDTYPE_EMU, SACTION_TOGGLE_FULLSCREEN }, |
dde7da71 |
50 | { SDLK_BACKSPACE, IN_BINDTYPE_EMU, SACTION_FAST_FORWARD }, |
2e6189bc |
51 | { 0, 0, 0 } |
7badc935 |
52 | }; |
53 | |
a8376201 |
54 | // XXX: maybe determine this instead.. |
55 | #define WM_DECORATION_H 32 |
56 | |
7badc935 |
57 | static SDL_Surface *screen; |
a8376201 |
58 | static SDL_Overlay *overlay; |
59 | static int window_w, window_h; |
60 | static int fs_w, fs_h; |
61 | static int psx_w, psx_h; |
2e6189bc |
62 | static void *menubg_img; |
c9099d02 |
63 | static int in_menu, old_fullscreen; |
64 | |
65 | static void overlay_clear(void); |
7badc935 |
66 | |
67 | static int change_video_mode(int w, int h) |
68 | { |
a8376201 |
69 | psx_w = w; |
70 | psx_h = h; |
71 | |
72 | if (overlay != NULL) { |
73 | SDL_FreeYUVOverlay(overlay); |
74 | overlay = NULL; |
75 | } |
76 | |
77 | if (g_use_overlay && !in_menu) { |
78 | Uint32 flags = SDL_RESIZABLE; |
79 | int win_w = window_w; |
80 | int win_h = window_h; |
81 | |
82 | if (g_fullscreen) { |
83 | flags |= SDL_FULLSCREEN; |
84 | win_w = fs_w; |
85 | win_h = fs_h; |
86 | } |
87 | |
88 | screen = SDL_SetVideoMode(win_w, win_h, 0, flags); |
89 | if (screen == NULL) { |
90 | fprintf(stderr, "SDL_SetVideoMode failed: %s\n", SDL_GetError()); |
91 | return -1; |
92 | } |
93 | |
94 | overlay = SDL_CreateYUVOverlay(w, h, SDL_UYVY_OVERLAY, screen); |
95 | if (overlay != NULL) { |
96 | /*printf("overlay: fmt %x, planes: %d, pitch: %d, hw: %d\n", |
97 | overlay->format, overlay->planes, *overlay->pitches, |
98 | overlay->hw_overlay);*/ |
99 | |
100 | if ((long)overlay->pixels[0] & 3) |
101 | fprintf(stderr, "warning: overlay pointer is unaligned\n"); |
c9099d02 |
102 | |
6949dd2a |
103 | if (!overlay->hw_overlay) { |
104 | fprintf(stderr, "warning: video overlay is not hardware accelerated, " |
105 | "disabling it.\n"); |
106 | g_use_overlay = 0; |
107 | SDL_FreeYUVOverlay(overlay); |
108 | overlay = NULL; |
109 | } |
110 | else |
111 | overlay_clear(); |
a8376201 |
112 | } |
113 | else { |
114 | fprintf(stderr, "warning: could not create overlay.\n"); |
115 | } |
7badc935 |
116 | } |
117 | |
a8376201 |
118 | if (overlay == NULL) { |
119 | screen = SDL_SetVideoMode(w, h, 16, 0); |
120 | if (screen == NULL) { |
121 | fprintf(stderr, "SDL_SetVideoMode failed: %s\n", SDL_GetError()); |
122 | return -1; |
123 | } |
124 | |
125 | if (!in_menu) { |
126 | window_w = screen->w; |
127 | window_h = screen->h; |
128 | } |
129 | } |
130 | |
131 | old_fullscreen = g_fullscreen; |
7badc935 |
132 | return 0; |
133 | } |
134 | |
a8376201 |
135 | static void event_handler(void *event_) |
136 | { |
137 | SDL_Event *event = event_; |
138 | |
139 | if (event->type == SDL_VIDEORESIZE) { |
140 | //printf("%dx%d\n", event->resize.w, event->resize.h); |
141 | if (overlay != NULL && !g_fullscreen && !old_fullscreen) { |
142 | window_w = event->resize.w; |
143 | window_h = event->resize.h; |
c9099d02 |
144 | change_video_mode(psx_w, psx_h); |
a8376201 |
145 | } |
146 | } |
147 | } |
148 | |
7badc935 |
149 | void plat_init(void) |
150 | { |
a8376201 |
151 | const SDL_VideoInfo *info; |
152 | int ret, h; |
7badc935 |
153 | |
154 | ret = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE); |
155 | if (ret != 0) { |
156 | fprintf(stderr, "SDL_Init failed: %s\n", SDL_GetError()); |
157 | exit(1); |
158 | } |
159 | |
a8376201 |
160 | info = SDL_GetVideoInfo(); |
161 | if (info != NULL) { |
162 | fs_w = info->current_w; |
163 | fs_h = info->current_h; |
164 | } |
165 | |
166 | in_menu = 1; |
7badc935 |
167 | g_menuscreen_w = 640; |
a8376201 |
168 | if (fs_w != 0 && g_menuscreen_w > fs_w) |
169 | g_menuscreen_w = fs_w; |
7badc935 |
170 | g_menuscreen_h = 480; |
a8376201 |
171 | if (fs_h != 0) { |
172 | h = fs_h; |
173 | if (info && info->wm_available && h > WM_DECORATION_H) |
174 | h -= WM_DECORATION_H; |
175 | if (g_menuscreen_h > h) |
176 | g_menuscreen_h = h; |
177 | } |
178 | |
7badc935 |
179 | ret = change_video_mode(g_menuscreen_w, g_menuscreen_h); |
180 | if (ret != 0) { |
181 | ret = change_video_mode(0, 0); |
182 | if (ret != 0) |
183 | goto fail; |
184 | |
185 | if (screen->w < 320 || screen->h < 240) { |
186 | fprintf(stderr, "resolution %dx%d is too small, sorry.\n", |
187 | screen->w, screen->h); |
188 | goto fail; |
189 | } |
7badc935 |
190 | } |
a8376201 |
191 | g_menuscreen_w = window_w = screen->w; |
192 | g_menuscreen_h = window_h = screen->h; |
193 | |
7badc935 |
194 | SDL_WM_SetCaption("PCSX-ReARMed " REV, NULL); |
195 | |
2e6189bc |
196 | menubg_img = malloc(640 * 512 * 2); |
197 | if (menubg_img == NULL) |
198 | goto fail; |
199 | |
a8376201 |
200 | in_sdl_init(in_sdl_defbinds, event_handler); |
7badc935 |
201 | in_probe(); |
4ea7de6a |
202 | pl_rearmed_cbs.only_16bpp = 1; |
c9099d02 |
203 | |
204 | bgr_to_uyvy_init(); |
7badc935 |
205 | return; |
206 | |
207 | fail: |
208 | SDL_Quit(); |
209 | exit(1); |
210 | } |
211 | |
212 | void plat_finish(void) |
213 | { |
2e6189bc |
214 | free(menubg_img); |
215 | menubg_img = NULL; |
7badc935 |
216 | SDL_Quit(); |
217 | } |
218 | |
ab423939 |
219 | void plat_gvideo_open(int is_pal) |
7badc935 |
220 | { |
221 | } |
222 | |
c9099d02 |
223 | static void uyvy_to_rgb565(void *d, const void *s, int pixels) |
7badc935 |
224 | { |
c9099d02 |
225 | unsigned short *dst = d; |
226 | const unsigned int *src = s; |
227 | int v; |
228 | |
229 | // no colors, for now |
230 | for (; pixels > 0; src++, dst += 2, pixels -= 2) { |
231 | v = (*src >> 8) & 0xff; |
232 | v = (v - 16) * 255 / 219 / 8; |
233 | dst[0] = (v << 11) | (v << 6) | v; |
234 | |
235 | v = (*src >> 24) & 0xff; |
236 | v = (v - 16) * 255 / 219 / 8; |
237 | dst[1] = (v << 11) | (v << 6) | v; |
238 | } |
7badc935 |
239 | } |
240 | |
c9099d02 |
241 | static void overlay_clear(void) |
a8376201 |
242 | { |
c9099d02 |
243 | int pixels = overlay->w * overlay->h; |
244 | int *dst = (int *)overlay->pixels[0]; |
245 | int v = 0x10801080; |
246 | |
247 | for (; pixels > 0; dst += 4, pixels -= 2 * 4) |
248 | dst[0] = dst[1] = dst[2] = dst[3] = v; |
249 | |
250 | for (; pixels > 0; dst++, pixels -= 2) |
251 | *dst = v; |
252 | } |
253 | |
254 | static void overlay_blit(int doffs, const void *src_, int w, int h, |
255 | int sstride, int bgr24) |
256 | { |
257 | const unsigned short *src = src_; |
258 | unsigned short *dst; |
259 | int dstride = overlay->w; |
260 | |
261 | SDL_LockYUVOverlay(overlay); |
262 | dst = (void *)overlay->pixels[0]; |
263 | |
264 | dst += doffs; |
265 | if (bgr24) { |
266 | for (; h > 0; dst += dstride, src += sstride, h--) |
267 | bgr888_to_uyvy(dst, src, w); |
268 | } |
269 | else { |
270 | for (; h > 0; dst += dstride, src += sstride, h--) |
271 | bgr555_to_uyvy(dst, src, w); |
272 | } |
273 | |
274 | SDL_UnlockYUVOverlay(overlay); |
275 | } |
276 | |
277 | static void overlay_hud_print(int x, int y, const char *str, int bpp) |
278 | { |
279 | SDL_LockYUVOverlay(overlay); |
280 | basic_text_out_uyvy_nf(overlay->pixels[0], overlay->w, x, y, str); |
281 | SDL_UnlockYUVOverlay(overlay); |
282 | } |
283 | |
284 | void *plat_gvideo_set_mode(int *w, int *h, int *bpp) |
285 | { |
286 | change_video_mode(*w, *h); |
287 | if (overlay != NULL) { |
288 | pl_plat_clear = overlay_clear; |
289 | pl_plat_blit = overlay_blit; |
290 | pl_plat_hud_print = overlay_hud_print; |
291 | return NULL; |
292 | } |
293 | else { |
294 | pl_plat_clear = NULL; |
295 | pl_plat_blit = NULL; |
296 | pl_plat_hud_print = NULL; |
297 | return screen->pixels; |
a8376201 |
298 | } |
299 | } |
300 | |
7badc935 |
301 | void *plat_gvideo_flip(void) |
302 | { |
a8376201 |
303 | if (!in_menu && overlay != NULL) { |
304 | SDL_Rect dstrect = { 0, 0, screen->w, screen->h }; |
a8376201 |
305 | SDL_DisplayYUVOverlay(overlay, &dstrect); |
c9099d02 |
306 | return NULL; |
a8376201 |
307 | } |
c9099d02 |
308 | else { |
309 | // XXX: missing SDL_LockSurface() |
a8376201 |
310 | SDL_Flip(screen); |
c9099d02 |
311 | return screen->pixels; |
a8376201 |
312 | } |
7badc935 |
313 | } |
314 | |
315 | void plat_gvideo_close(void) |
316 | { |
317 | } |
318 | |
319 | void plat_video_menu_enter(int is_rom_loaded) |
320 | { |
a8376201 |
321 | in_menu = 1; |
322 | |
2e6189bc |
323 | /* surface will be lost, must adjust pl_vout_buf for menu bg */ |
c9099d02 |
324 | if (overlay != NULL) |
325 | uyvy_to_rgb565(menubg_img, overlay->pixels[0], psx_w * psx_h); |
326 | else |
327 | memcpy(menubg_img, screen->pixels, psx_w * psx_h * 2); |
2e6189bc |
328 | pl_vout_buf = menubg_img; |
329 | |
7badc935 |
330 | change_video_mode(g_menuscreen_w, g_menuscreen_h); |
331 | } |
332 | |
333 | void plat_video_menu_begin(void) |
334 | { |
335 | SDL_LockSurface(screen); |
336 | g_menuscreen_ptr = screen->pixels; |
337 | } |
338 | |
339 | void plat_video_menu_end(void) |
340 | { |
341 | SDL_UnlockSurface(screen); |
342 | SDL_Flip(screen); |
343 | g_menuscreen_ptr = NULL; |
344 | } |
345 | |
346 | void plat_video_menu_leave(void) |
347 | { |
a8376201 |
348 | in_menu = 0; |
7badc935 |
349 | } |
350 | |
351 | /* unused stuff */ |
352 | void *plat_prepare_screenshot(int *w, int *h, int *bpp) |
353 | { |
354 | return 0; |
355 | } |
356 | |
7badc935 |
357 | void plat_trigger_vibrate(int is_strong) |
358 | { |
359 | } |
360 | |
361 | void plat_minimize(void) |
362 | { |
363 | } |
364 | |
365 | // vim:shiftwidth=2:expandtab |