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