Commit | Line | Data |
---|---|---|
636d5f25 | 1 | /* |
2 | * PicoDrive | |
3 | * (C) notaz, 2013 | |
4 | * | |
5 | * This work is licensed under the terms of MAME license. | |
6 | * See COPYING file in the top-level directory. | |
7 | */ | |
8 | ||
9 | #include <stdio.h> | |
10 | ||
11 | #include "../libpicofe/input.h" | |
12 | #include "../libpicofe/plat_sdl.h" | |
13 | #include "../libpicofe/in_sdl.h" | |
14 | #include "../libpicofe/gl.h" | |
15 | #include "emu.h" | |
16 | #include "menu_pico.h" | |
17 | #include "input_pico.h" | |
18 | #include "version.h" | |
19 | ||
74e770b1 | 20 | #include <pico/pico.h> |
21 | ||
636d5f25 | 22 | static void *shadow_fb; |
23 | ||
4e3551a5 | 24 | const struct in_default_bind in_sdl_defbinds[] __attribute__((weak)) = { |
636d5f25 | 25 | { SDLK_UP, IN_BINDTYPE_PLAYER12, GBTN_UP }, |
26 | { SDLK_DOWN, IN_BINDTYPE_PLAYER12, GBTN_DOWN }, | |
27 | { SDLK_LEFT, IN_BINDTYPE_PLAYER12, GBTN_LEFT }, | |
28 | { SDLK_RIGHT, IN_BINDTYPE_PLAYER12, GBTN_RIGHT }, | |
29 | { SDLK_z, IN_BINDTYPE_PLAYER12, GBTN_A }, | |
30 | { SDLK_x, IN_BINDTYPE_PLAYER12, GBTN_B }, | |
31 | { SDLK_c, IN_BINDTYPE_PLAYER12, GBTN_C }, | |
32 | { SDLK_a, IN_BINDTYPE_PLAYER12, GBTN_X }, | |
33 | { SDLK_s, IN_BINDTYPE_PLAYER12, GBTN_Y }, | |
34 | { SDLK_d, IN_BINDTYPE_PLAYER12, GBTN_Z }, | |
35 | { SDLK_RETURN, IN_BINDTYPE_PLAYER12, GBTN_START }, | |
36 | { SDLK_f, IN_BINDTYPE_PLAYER12, GBTN_MODE }, | |
37 | { SDLK_ESCAPE, IN_BINDTYPE_EMU, PEVB_MENU }, | |
9db6a544 | 38 | { SDLK_TAB, IN_BINDTYPE_EMU, PEVB_RESET }, |
636d5f25 | 39 | { SDLK_F1, IN_BINDTYPE_EMU, PEVB_STATE_SAVE }, |
40 | { SDLK_F2, IN_BINDTYPE_EMU, PEVB_STATE_LOAD }, | |
41 | { SDLK_F3, IN_BINDTYPE_EMU, PEVB_SSLOT_PREV }, | |
42 | { SDLK_F4, IN_BINDTYPE_EMU, PEVB_SSLOT_NEXT }, | |
43 | { SDLK_F5, IN_BINDTYPE_EMU, PEVB_SWITCH_RND }, | |
44 | { SDLK_F6, IN_BINDTYPE_EMU, PEVB_PICO_PPREV }, | |
45 | { SDLK_F7, IN_BINDTYPE_EMU, PEVB_PICO_PNEXT }, | |
46 | { SDLK_F8, IN_BINDTYPE_EMU, PEVB_PICO_SWINP }, | |
47 | { SDLK_BACKSPACE, IN_BINDTYPE_EMU, PEVB_FF }, | |
48 | { 0, 0, 0 } | |
49 | }; | |
50 | ||
4e3551a5 PC |
51 | const struct menu_keymap in_sdl_key_map[] __attribute__((weak)) = |
52 | { | |
53 | { SDLK_UP, PBTN_UP }, | |
54 | { SDLK_DOWN, PBTN_DOWN }, | |
55 | { SDLK_LEFT, PBTN_LEFT }, | |
56 | { SDLK_RIGHT, PBTN_RIGHT }, | |
57 | { SDLK_RETURN, PBTN_MOK }, | |
58 | { SDLK_ESCAPE, PBTN_MBACK }, | |
59 | { SDLK_SEMICOLON, PBTN_MA2 }, | |
60 | { SDLK_QUOTE, PBTN_MA3 }, | |
61 | { SDLK_LEFTBRACKET, PBTN_L }, | |
62 | { SDLK_RIGHTBRACKET, PBTN_R }, | |
63 | }; | |
64 | ||
65 | const struct menu_keymap in_sdl_joy_map[] __attribute__((weak)) = | |
66 | { | |
67 | { SDLK_UP, PBTN_UP }, | |
68 | { SDLK_DOWN, PBTN_DOWN }, | |
69 | { SDLK_LEFT, PBTN_LEFT }, | |
70 | { SDLK_RIGHT, PBTN_RIGHT }, | |
71 | /* joystick */ | |
72 | { SDLK_WORLD_0, PBTN_MOK }, | |
73 | { SDLK_WORLD_1, PBTN_MBACK }, | |
74 | { SDLK_WORLD_2, PBTN_MA2 }, | |
75 | { SDLK_WORLD_3, PBTN_MA3 }, | |
76 | }; | |
77 | ||
d4bea61c PC |
78 | extern const char * const in_sdl_key_names[] __attribute__((weak)); |
79 | ||
4e3551a5 PC |
80 | static const struct in_pdata in_sdl_platform_data = { |
81 | .defbinds = in_sdl_defbinds, | |
82 | .key_map = in_sdl_key_map, | |
83 | .kmap_size = sizeof(in_sdl_key_map) / sizeof(in_sdl_key_map[0]), | |
84 | .joy_map = in_sdl_joy_map, | |
85 | .jmap_size = sizeof(in_sdl_joy_map) / sizeof(in_sdl_joy_map[0]), | |
d4bea61c | 86 | .key_names = in_sdl_key_names, |
4e3551a5 PC |
87 | }; |
88 | ||
636d5f25 | 89 | /* YUV stuff */ |
90 | static int yuv_ry[32], yuv_gy[32], yuv_by[32]; | |
91 | static unsigned char yuv_u[32 * 2], yuv_v[32 * 2]; | |
92 | ||
93 | void bgr_to_uyvy_init(void) | |
94 | { | |
95 | int i, v; | |
96 | ||
97 | /* init yuv converter: | |
98 | y0 = (int)((0.299f * r0) + (0.587f * g0) + (0.114f * b0)); | |
99 | y1 = (int)((0.299f * r1) + (0.587f * g1) + (0.114f * b1)); | |
100 | u = (int)(8 * 0.565f * (b0 - y0)) + 128; | |
101 | v = (int)(8 * 0.713f * (r0 - y0)) + 128; | |
102 | */ | |
103 | for (i = 0; i < 32; i++) { | |
104 | yuv_ry[i] = (int)(0.299f * i * 65536.0f + 0.5f); | |
105 | yuv_gy[i] = (int)(0.587f * i * 65536.0f + 0.5f); | |
106 | yuv_by[i] = (int)(0.114f * i * 65536.0f + 0.5f); | |
107 | } | |
108 | for (i = -32; i < 32; i++) { | |
109 | v = (int)(8 * 0.565f * i) + 128; | |
110 | if (v < 0) | |
111 | v = 0; | |
112 | if (v > 255) | |
113 | v = 255; | |
114 | yuv_u[i + 32] = v; | |
115 | v = (int)(8 * 0.713f * i) + 128; | |
116 | if (v < 0) | |
117 | v = 0; | |
118 | if (v > 255) | |
119 | v = 255; | |
120 | yuv_v[i + 32] = v; | |
121 | } | |
122 | } | |
123 | ||
124 | void rgb565_to_uyvy(void *d, const void *s, int pixels) | |
125 | { | |
126 | unsigned int *dst = d; | |
127 | const unsigned short *src = s; | |
128 | const unsigned char *yu = yuv_u + 32; | |
129 | const unsigned char *yv = yuv_v + 32; | |
130 | int r0, g0, b0, r1, g1, b1; | |
131 | int y0, y1, u, v; | |
132 | ||
133 | for (; pixels > 0; src += 2, dst++, pixels -= 2) | |
134 | { | |
135 | r0 = (src[0] >> 11) & 0x1f; | |
136 | g0 = (src[0] >> 6) & 0x1f; | |
137 | b0 = src[0] & 0x1f; | |
138 | r1 = (src[1] >> 11) & 0x1f; | |
139 | g1 = (src[1] >> 6) & 0x1f; | |
140 | b1 = src[1] & 0x1f; | |
141 | y0 = (yuv_ry[r0] + yuv_gy[g0] + yuv_by[b0]) >> 16; | |
142 | y1 = (yuv_ry[r1] + yuv_gy[g1] + yuv_by[b1]) >> 16; | |
143 | u = yu[b0 - y0]; | |
144 | v = yv[r0 - y0]; | |
145 | // valid Y range seems to be 16..235 | |
146 | y0 = 16 + 219 * y0 / 31; | |
147 | y1 = 16 + 219 * y1 / 31; | |
148 | ||
149 | *dst = (y1 << 24) | (v << 16) | (y0 << 8) | u; | |
150 | } | |
151 | } | |
152 | ||
153 | void plat_video_flip(void) | |
154 | { | |
155 | if (plat_sdl_overlay != NULL) { | |
156 | SDL_Rect dstrect = | |
157 | { 0, 0, plat_sdl_screen->w, plat_sdl_screen->h }; | |
158 | ||
159 | SDL_LockYUVOverlay(plat_sdl_overlay); | |
160 | rgb565_to_uyvy(plat_sdl_overlay->pixels[0], shadow_fb, | |
161 | g_screen_width * g_screen_height); | |
162 | SDL_UnlockYUVOverlay(plat_sdl_overlay); | |
163 | SDL_DisplayYUVOverlay(plat_sdl_overlay, &dstrect); | |
164 | } | |
165 | else if (plat_sdl_gl_active) { | |
166 | gl_flip(shadow_fb, g_screen_width, g_screen_height); | |
167 | } | |
168 | else { | |
eb7ce29e PC |
169 | if (SDL_MUSTLOCK(plat_sdl_screen)) |
170 | SDL_UnlockSurface(plat_sdl_screen); | |
636d5f25 | 171 | SDL_Flip(plat_sdl_screen); |
172 | g_screen_ptr = plat_sdl_screen->pixels; | |
eb7ce29e | 173 | PicoDrawSetOutBuf(g_screen_ptr, g_screen_width * 2); |
636d5f25 | 174 | } |
175 | } | |
176 | ||
177 | void plat_video_wait_vsync(void) | |
178 | { | |
179 | } | |
180 | ||
181 | void plat_video_menu_enter(int is_rom_loaded) | |
182 | { | |
183 | plat_sdl_change_video_mode(g_menuscreen_w, g_menuscreen_h, 0); | |
d438a8dd | 184 | g_screen_ptr = shadow_fb; |
636d5f25 | 185 | } |
186 | ||
187 | void plat_video_menu_begin(void) | |
188 | { | |
189 | if (plat_sdl_overlay != NULL || plat_sdl_gl_active) { | |
190 | g_menuscreen_ptr = shadow_fb; | |
191 | } | |
192 | else { | |
eb7ce29e PC |
193 | if (SDL_MUSTLOCK(plat_sdl_screen)) |
194 | SDL_LockSurface(plat_sdl_screen); | |
636d5f25 | 195 | g_menuscreen_ptr = plat_sdl_screen->pixels; |
196 | } | |
197 | } | |
198 | ||
199 | void plat_video_menu_end(void) | |
200 | { | |
201 | if (plat_sdl_overlay != NULL) { | |
202 | SDL_Rect dstrect = | |
203 | { 0, 0, plat_sdl_screen->w, plat_sdl_screen->h }; | |
204 | ||
205 | SDL_LockYUVOverlay(plat_sdl_overlay); | |
206 | rgb565_to_uyvy(plat_sdl_overlay->pixels[0], shadow_fb, | |
207 | g_menuscreen_w * g_menuscreen_h); | |
208 | SDL_UnlockYUVOverlay(plat_sdl_overlay); | |
209 | ||
210 | SDL_DisplayYUVOverlay(plat_sdl_overlay, &dstrect); | |
211 | } | |
212 | else if (plat_sdl_gl_active) { | |
213 | gl_flip(g_menuscreen_ptr, g_menuscreen_w, g_menuscreen_h); | |
214 | } | |
215 | else { | |
eb7ce29e PC |
216 | if (SDL_MUSTLOCK(plat_sdl_screen)) |
217 | SDL_UnlockSurface(plat_sdl_screen); | |
636d5f25 | 218 | SDL_Flip(plat_sdl_screen); |
219 | } | |
220 | g_menuscreen_ptr = NULL; | |
221 | ||
222 | } | |
223 | ||
224 | void plat_video_menu_leave(void) | |
225 | { | |
226 | } | |
227 | ||
228 | void plat_video_loop_prepare(void) | |
229 | { | |
230 | plat_sdl_change_video_mode(g_screen_width, g_screen_height, 0); | |
231 | ||
232 | if (plat_sdl_overlay != NULL || plat_sdl_gl_active) { | |
233 | g_screen_ptr = shadow_fb; | |
234 | } | |
235 | else { | |
eb7ce29e PC |
236 | if (SDL_MUSTLOCK(plat_sdl_screen)) |
237 | SDL_LockSurface(plat_sdl_screen); | |
636d5f25 | 238 | g_screen_ptr = plat_sdl_screen->pixels; |
239 | } | |
eb7ce29e | 240 | PicoDrawSetOutBuf(g_screen_ptr, g_screen_width * 2); |
636d5f25 | 241 | } |
242 | ||
243 | void plat_early_init(void) | |
244 | { | |
245 | } | |
246 | ||
bec84f92 | 247 | static void plat_sdl_quit(void) |
248 | { | |
249 | // for now.. | |
250 | exit(1); | |
251 | } | |
252 | ||
636d5f25 | 253 | void plat_init(void) |
254 | { | |
255 | int shadow_size; | |
256 | int ret; | |
257 | ||
258 | ret = plat_sdl_init(); | |
259 | if (ret != 0) | |
260 | exit(1); | |
261 | ||
bec84f92 | 262 | plat_sdl_quit_cb = plat_sdl_quit; |
263 | ||
fc11dd05 | 264 | SDL_WM_SetCaption("PicoDrive " VERSION, NULL); |
636d5f25 | 265 | |
266 | g_menuscreen_w = plat_sdl_screen->w; | |
267 | g_menuscreen_h = plat_sdl_screen->h; | |
268 | g_menuscreen_ptr = NULL; | |
269 | ||
270 | shadow_size = g_menuscreen_w * g_menuscreen_h * 2; | |
271 | if (shadow_size < 320 * 480 * 2) | |
272 | shadow_size = 320 * 480 * 2; | |
273 | ||
274 | shadow_fb = malloc(shadow_size); | |
275 | g_menubg_ptr = malloc(shadow_size); | |
276 | if (shadow_fb == NULL || g_menubg_ptr == NULL) { | |
277 | fprintf(stderr, "OOM\n"); | |
278 | exit(1); | |
279 | } | |
280 | ||
281 | g_screen_width = 320; | |
282 | g_screen_height = 240; | |
283 | g_screen_ptr = shadow_fb; | |
284 | ||
4e3551a5 | 285 | in_sdl_init(&in_sdl_platform_data, plat_sdl_event_handler); |
636d5f25 | 286 | in_probe(); |
287 | ||
288 | bgr_to_uyvy_init(); | |
289 | } | |
290 | ||
291 | void plat_finish(void) | |
292 | { | |
293 | free(shadow_fb); | |
294 | shadow_fb = NULL; | |
295 | free(g_menubg_ptr); | |
296 | g_menubg_ptr = NULL; | |
297 | plat_sdl_finish(); | |
298 | } |