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