Mercurial > repos > blastem
comparison io.c @ 487:c08a4efeee7f opengl
Update opengl branch from default. Fix build breakage unrelated to merge
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 26 Oct 2013 22:38:47 -0700 |
parents | 3e1573fa22cf |
children | 36c080ece4ed |
comparison
equal
deleted
inserted
replaced
449:7696d824489d | 487:c08a4efeee7f |
---|---|
1 /* | |
2 Copyright 2013 Michael Pavone | |
3 This file is part of BlastEm. | |
4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. | |
5 */ | |
1 #include "io.h" | 6 #include "io.h" |
2 #include "blastem.h" | 7 #include "blastem.h" |
3 #include "render.h" | 8 #include "render.h" |
4 | 9 |
5 enum { | 10 enum { |
10 }; | 15 }; |
11 | 16 |
12 typedef enum { | 17 typedef enum { |
13 UI_DEBUG_MODE_INC, | 18 UI_DEBUG_MODE_INC, |
14 UI_DEBUG_PAL_INC, | 19 UI_DEBUG_PAL_INC, |
15 UI_ENTER_DEBUGGER | 20 UI_ENTER_DEBUGGER, |
21 UI_SAVE_STATE, | |
22 UI_SET_SPEED, | |
23 UI_NEXT_SPEED, | |
24 UI_PREV_SPEED, | |
25 UI_EXIT | |
16 } ui_action; | 26 } ui_action; |
17 | 27 |
18 typedef struct { | 28 typedef struct { |
19 uint8_t bind_type; | 29 uint8_t bind_type; |
20 uint8_t subtype_a; | 30 uint8_t subtype_a; |
104 #define BUTTON_START GAMEPAD_BUTTON(GAMEPAD_TH0, GAMEPAD_NONE, 0x20) | 114 #define BUTTON_START GAMEPAD_BUTTON(GAMEPAD_TH0, GAMEPAD_NONE, 0x20) |
105 #define BUTTON_C GAMEPAD_BUTTON(GAMEPAD_TH1, GAMEPAD_NONE, 0x20) | 115 #define BUTTON_C GAMEPAD_BUTTON(GAMEPAD_TH1, GAMEPAD_NONE, 0x20) |
106 | 116 |
107 void bind_gamepad(int keycode, int gamepadnum, int button) | 117 void bind_gamepad(int keycode, int gamepadnum, int button) |
108 { | 118 { |
109 | 119 |
110 if (gamepadnum < 1 || gamepadnum > 2) { | 120 if (gamepadnum < 1 || gamepadnum > 2) { |
111 return; | 121 return; |
112 } | 122 } |
113 uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1; | 123 uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1; |
114 bind_key(keycode, bind_type, button >> 12, button >> 8 & 0xF, button & 0xFF); | 124 bind_key(keycode, bind_type, button >> 12, button >> 8 & 0xF, button & 0xFF); |
130 } | 140 } |
131 uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1; | 141 uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1; |
132 bind_dpad(joystick, dpad, direction, bind_type, button >> 12, button >> 8 & 0xF, button & 0xFF); | 142 bind_dpad(joystick, dpad, direction, bind_type, button >> 12, button >> 8 & 0xF, button & 0xFF); |
133 } | 143 } |
134 | 144 |
135 void bind_ui(int keycode, ui_action action) | 145 void bind_ui(int keycode, ui_action action, uint8_t param) |
136 { | 146 { |
137 bind_key(keycode, BIND_UI, action, 0, 0); | 147 bind_key(keycode, BIND_UI, action, 0, param); |
138 } | 148 } |
139 | 149 |
140 void handle_binding_down(keybinding * binding) | 150 void handle_binding_down(keybinding * binding) |
141 { | 151 { |
142 switch(binding->bind_type) | 152 switch(binding->bind_type) |
173 handle_binding_down(binding); | 183 handle_binding_down(binding); |
174 } | 184 } |
175 | 185 |
176 uint8_t ui_debug_mode = 0; | 186 uint8_t ui_debug_mode = 0; |
177 uint8_t ui_debug_pal = 0; | 187 uint8_t ui_debug_pal = 0; |
188 | |
189 int current_speed = 0; | |
190 int num_speeds = 1; | |
191 uint32_t * speeds = NULL; | |
178 | 192 |
179 void handle_binding_up(keybinding * binding) | 193 void handle_binding_up(keybinding * binding) |
180 { | 194 { |
181 switch(binding->bind_type) | 195 switch(binding->bind_type) |
182 { | 196 { |
195 case UI_DEBUG_MODE_INC: | 209 case UI_DEBUG_MODE_INC: |
196 ui_debug_mode++; | 210 ui_debug_mode++; |
197 if (ui_debug_mode == 4) { | 211 if (ui_debug_mode == 4) { |
198 ui_debug_mode = 0; | 212 ui_debug_mode = 0; |
199 } | 213 } |
200 render_debug_mode(ui_debug_mode); | 214 genesis->vdp->debug = ui_debug_mode; |
201 break; | 215 break; |
202 case UI_DEBUG_PAL_INC: | 216 case UI_DEBUG_PAL_INC: |
203 ui_debug_pal++; | 217 ui_debug_pal++; |
204 if (ui_debug_pal == 4) { | 218 if (ui_debug_pal == 4) { |
205 ui_debug_pal = 0; | 219 ui_debug_pal = 0; |
207 render_debug_pal(ui_debug_pal); | 221 render_debug_pal(ui_debug_pal); |
208 break; | 222 break; |
209 case UI_ENTER_DEBUGGER: | 223 case UI_ENTER_DEBUGGER: |
210 break_on_sync = 1; | 224 break_on_sync = 1; |
211 break; | 225 break; |
226 case UI_SAVE_STATE: | |
227 save_state = 1; | |
228 break; | |
229 case UI_NEXT_SPEED: | |
230 current_speed++; | |
231 if (current_speed >= num_speeds) { | |
232 current_speed = 0; | |
233 } | |
234 printf("Setting speed to %d: %d\n", current_speed, speeds[current_speed]); | |
235 set_speed_percent(genesis, speeds[current_speed]); | |
236 break; | |
237 case UI_PREV_SPEED: | |
238 current_speed--; | |
239 if (current_speed < 0) { | |
240 current_speed = num_speeds - 1; | |
241 } | |
242 printf("Setting speed to %d: %d\n", current_speed, speeds[current_speed]); | |
243 set_speed_percent(genesis, speeds[current_speed]); | |
244 break; | |
245 case UI_SET_SPEED: | |
246 if (binding->value < num_speeds) { | |
247 current_speed = binding->value; | |
248 printf("Setting speed to %d: %d\n", current_speed, speeds[current_speed]); | |
249 set_speed_percent(genesis, speeds[current_speed]); | |
250 } else { | |
251 printf("Setting speed to %d\n", speeds[current_speed]); | |
252 set_speed_percent(genesis, binding->value); | |
253 } | |
254 break; | |
255 case UI_EXIT: | |
256 exit(0); | |
212 } | 257 } |
213 break; | 258 break; |
214 } | 259 } |
215 } | 260 } |
216 | 261 |
250 handle_binding_up(dpad->bindings + i); | 295 handle_binding_up(dpad->bindings + i); |
251 } | 296 } |
252 } | 297 } |
253 } | 298 } |
254 | 299 |
300 int parse_binding_target(char * target, tern_node * padbuttons, int * ui_out, int * padnum_out, int * padbutton_out) | |
301 { | |
302 int gpadslen = strlen("gamepads."); | |
303 if (!memcmp(target, "gamepads.", gpadslen)) { | |
304 if (target[gpadslen] >= '1' && target[gpadslen] <= '8') { | |
305 int padnum = target[gpadslen] - '0'; | |
306 int button = tern_find_int(padbuttons, target + gpadslen + 1, 0); | |
307 if (button) { | |
308 *padnum_out = padnum; | |
309 *padbutton_out = button; | |
310 return 1; | |
311 } else { | |
312 if (target[gpadslen+1]) { | |
313 fprintf(stderr, "Gamepad mapping string '%s' refers to an invalid button '%s'\n", target, target + gpadslen + 1); | |
314 } else { | |
315 fprintf(stderr, "Gamepad mapping string '%s' has no button component\n", target); | |
316 } | |
317 } | |
318 } else { | |
319 fprintf(stderr, "Gamepad mapping string '%s' refers to an invalid gamepad number %c\n", target, target[gpadslen]); | |
320 } | |
321 } else if(!memcmp(target, "ui.", strlen("ui."))) { | |
322 *padbutton_out = 0; | |
323 if (!strcmp(target + 3, "vdp_debug_mode")) { | |
324 *ui_out = UI_DEBUG_MODE_INC; | |
325 } else if(!strcmp(target + 3, "vdp_debug_pal")) { | |
326 *ui_out = UI_DEBUG_PAL_INC; | |
327 } else if(!strcmp(target + 3, "enter_debugger")) { | |
328 *ui_out = UI_ENTER_DEBUGGER; | |
329 } else if(!strcmp(target + 3, "save_state")) { | |
330 *ui_out = UI_SAVE_STATE; | |
331 } else if(!memcmp(target + 3, "set_speed.", strlen("set_speed."))) { | |
332 *ui_out = UI_SET_SPEED; | |
333 *padbutton_out = atoi(target + 3 + strlen("set_speed.")); | |
334 } else if(!strcmp(target + 3, "next_speed")) { | |
335 *ui_out = UI_NEXT_SPEED; | |
336 } else if(!strcmp(target + 3, "prev_speed")) { | |
337 *ui_out = UI_PREV_SPEED; | |
338 } else if(!strcmp(target + 3, "exit")) { | |
339 *ui_out = UI_EXIT; | |
340 } else { | |
341 fprintf(stderr, "Unreconized UI binding type %s\n", target); | |
342 return 0; | |
343 } | |
344 return 2; | |
345 } else { | |
346 fprintf(stderr, "Unrecognized binding type %s\n", target); | |
347 } | |
348 return 0; | |
349 } | |
350 | |
351 void process_keys(tern_node * cur, tern_node * special, tern_node * padbuttons, char * prefix) | |
352 { | |
353 char * curstr = NULL; | |
354 int len; | |
355 if (!cur) { | |
356 return; | |
357 } | |
358 char onec[2]; | |
359 if (prefix) { | |
360 len = strlen(prefix); | |
361 curstr = malloc(len + 2); | |
362 memcpy(curstr, prefix, len); | |
363 } else { | |
364 curstr = onec; | |
365 len = 0; | |
366 } | |
367 curstr[len] = cur->el; | |
368 curstr[len+1] = 0; | |
369 if (cur->el) { | |
370 process_keys(cur->straight.next, special, padbuttons, curstr); | |
371 } else { | |
372 int keycode = tern_find_int(special, curstr, 0); | |
373 if (!keycode) { | |
374 keycode = curstr[0]; | |
375 if (curstr[1] != 0) { | |
376 fprintf(stderr, "%s is not recognized as a key identifier, truncating to %c\n", curstr, curstr[0]); | |
377 } | |
378 } | |
379 char * target = cur->straight.value.ptrval; | |
380 int ui_func, padnum, button; | |
381 int bindtype = parse_binding_target(target, padbuttons, &ui_func, &padnum, &button); | |
382 if (bindtype == 1) { | |
383 bind_gamepad(keycode, padnum, button); | |
384 } else if(bindtype == 2) { | |
385 bind_ui(keycode, ui_func, button); | |
386 } | |
387 } | |
388 process_keys(cur->left, special, padbuttons, prefix); | |
389 process_keys(cur->right, special, padbuttons, prefix); | |
390 if (curstr && len) { | |
391 free(curstr); | |
392 } | |
393 } | |
394 | |
395 void process_speeds(tern_node * cur, char * prefix) | |
396 { | |
397 char * curstr = NULL; | |
398 int len; | |
399 if (!cur) { | |
400 return; | |
401 } | |
402 char onec[2]; | |
403 if (prefix) { | |
404 len = strlen(prefix); | |
405 curstr = malloc(len + 2); | |
406 memcpy(curstr, prefix, len); | |
407 } else { | |
408 curstr = onec; | |
409 len = 0; | |
410 } | |
411 curstr[len] = cur->el; | |
412 curstr[len+1] = 0; | |
413 if (cur->el) { | |
414 process_speeds(cur->straight.next, curstr); | |
415 } else { | |
416 int speed_index = atoi(curstr); | |
417 if (speed_index < 1) { | |
418 if (!strcmp(curstr, "0")) { | |
419 fputs("Speed index 0 cannot be set to a custom value\n", stderr); | |
420 } else { | |
421 fprintf(stderr, "%s is not a valid speed index", curstr); | |
422 } | |
423 } else { | |
424 if (speed_index >= num_speeds) { | |
425 speeds = realloc(speeds, sizeof(uint32_t) * (speed_index+1)); | |
426 for(; num_speeds < speed_index + 1; num_speeds++) { | |
427 speeds[num_speeds] = 0; | |
428 } | |
429 } | |
430 speeds[speed_index] = atoi(cur->straight.value.ptrval); | |
431 } | |
432 } | |
433 process_speeds(cur->left, prefix); | |
434 process_speeds(cur->right, prefix); | |
435 if (curstr && len) { | |
436 free(curstr); | |
437 } | |
438 } | |
439 | |
255 void set_keybindings() | 440 void set_keybindings() |
256 { | 441 { |
257 bind_gamepad(RENDERKEY_UP, 1, DPAD_UP); | 442 tern_node * special = tern_insert_int(NULL, "up", RENDERKEY_UP); |
258 bind_gamepad(RENDERKEY_DOWN, 1, DPAD_DOWN); | 443 special = tern_insert_int(special, "down", RENDERKEY_DOWN); |
259 bind_gamepad(RENDERKEY_LEFT, 1, DPAD_LEFT); | 444 special = tern_insert_int(special, "left", RENDERKEY_LEFT); |
260 bind_gamepad(RENDERKEY_RIGHT, 1, DPAD_RIGHT); | 445 special = tern_insert_int(special, "right", RENDERKEY_RIGHT); |
261 bind_gamepad('a', 1, BUTTON_A); | 446 special = tern_insert_int(special, "enter", '\r'); |
262 bind_gamepad('s', 1, BUTTON_B); | 447 special = tern_insert_int(special, "esc", RENDERKEY_ESC); |
263 bind_gamepad('d', 1, BUTTON_C); | 448 |
264 bind_gamepad('q', 1, BUTTON_X); | 449 tern_node * padbuttons = tern_insert_int(NULL, ".up", DPAD_UP); |
265 bind_gamepad('w', 1, BUTTON_Y); | 450 padbuttons = tern_insert_int(padbuttons, ".down", DPAD_DOWN); |
266 bind_gamepad('e', 1, BUTTON_Z); | 451 padbuttons = tern_insert_int(padbuttons, ".left", DPAD_LEFT); |
267 bind_gamepad('\r', 1, BUTTON_START); | 452 padbuttons = tern_insert_int(padbuttons, ".right", DPAD_RIGHT); |
268 bind_gamepad('f', 1, BUTTON_MODE); | 453 padbuttons = tern_insert_int(padbuttons, ".a", BUTTON_A); |
269 bind_ui('[', UI_DEBUG_MODE_INC); | 454 padbuttons = tern_insert_int(padbuttons, ".b", BUTTON_B); |
270 bind_ui(']', UI_DEBUG_PAL_INC); | 455 padbuttons = tern_insert_int(padbuttons, ".c", BUTTON_C); |
271 bind_ui('u', UI_ENTER_DEBUGGER); | 456 padbuttons = tern_insert_int(padbuttons, ".x", BUTTON_X); |
272 | 457 padbuttons = tern_insert_int(padbuttons, ".y", BUTTON_Y); |
273 bind_dpad_gamepad(0, 0, RENDER_DPAD_UP, 2, DPAD_UP); | 458 padbuttons = tern_insert_int(padbuttons, ".z", BUTTON_Z); |
274 bind_dpad_gamepad(0, 0, RENDER_DPAD_DOWN, 2, DPAD_DOWN); | 459 padbuttons = tern_insert_int(padbuttons, ".start", BUTTON_START); |
275 bind_dpad_gamepad(0, 0, RENDER_DPAD_LEFT, 2, DPAD_LEFT); | 460 padbuttons = tern_insert_int(padbuttons, ".mode", BUTTON_MODE); |
276 bind_dpad_gamepad(0, 0, RENDER_DPAD_RIGHT, 2, DPAD_RIGHT); | 461 |
277 bind_button_gamepad(0, 0, 2, BUTTON_A); | 462 tern_node * keys = tern_find_prefix(config, "bindingskeys"); |
278 bind_button_gamepad(0, 1, 2, BUTTON_B); | 463 process_keys(keys, special, padbuttons, NULL); |
279 bind_button_gamepad(0, 2, 2, BUTTON_C); | 464 char prefix[] = "bindingspads00"; |
280 bind_button_gamepad(0, 3, 2, BUTTON_X); | 465 for (int i = 0; i < 100 && i < render_num_joysticks(); i++) |
281 bind_button_gamepad(0, 4, 2, BUTTON_Y); | 466 { |
282 bind_button_gamepad(0, 5, 2, BUTTON_Z); | 467 if (i < 10) { |
283 bind_button_gamepad(0, 6, 2, BUTTON_START); | 468 prefix[strlen("bindingspads")] = i + '0'; |
284 bind_button_gamepad(0, 7, 2, BUTTON_MODE); | 469 prefix[strlen("bindingspads")+1] = 0; |
470 } else { | |
471 prefix[strlen("bindingspads")] = i/10 + '0'; | |
472 prefix[strlen("bindingspads")+1] = i%10 + '0'; | |
473 } | |
474 tern_node * pad = tern_find_prefix(config, prefix); | |
475 if (pad) { | |
476 char dprefix[] = "dpads0"; | |
477 for (int dpad = 0; dpad < 10 && dpad < render_joystick_num_hats(i); dpad++) | |
478 { | |
479 dprefix[strlen("dpads")] = dpad + '0'; | |
480 tern_node * pad_dpad = tern_find_prefix(pad, dprefix); | |
481 char * dirs[] = {"up", "down", "left", "right"}; | |
482 int dirnums[] = {RENDER_DPAD_UP, RENDER_DPAD_DOWN, RENDER_DPAD_LEFT, RENDER_DPAD_RIGHT}; | |
483 for (int dir = 0; dir < sizeof(dirs)/sizeof(dirs[0]); dir++) { | |
484 char * target = tern_find_ptr(pad_dpad, dirs[dir]); | |
485 if (target) { | |
486 int ui_func, padnum, button; | |
487 int bindtype = parse_binding_target(target, padbuttons, &ui_func, &padnum, &button); | |
488 if (bindtype == 1) { | |
489 bind_dpad_gamepad(i, dpad, dirnums[dir], padnum, button); | |
490 } | |
491 //TODO: Handle UI bindings | |
492 } | |
493 } | |
494 } | |
495 char bprefix[] = "buttons00"; | |
496 for (int but = 0; but < 100 && but < render_joystick_num_buttons(i); but++) | |
497 { | |
498 if (but < 10) { | |
499 bprefix[strlen("buttons")] = but + '0'; | |
500 bprefix[strlen("buttons")+1] = 0; | |
501 } else { | |
502 bprefix[strlen("buttons")] = but/10 + '0'; | |
503 bprefix[strlen("buttons")+1] = but%10 + '0'; | |
504 } | |
505 char * target = tern_find_ptr(pad, bprefix); | |
506 if (target) { | |
507 int ui_func, padnum, button; | |
508 int bindtype = parse_binding_target(target, padbuttons, &ui_func, &padnum, &button); | |
509 if (bindtype == 1) { | |
510 bind_button_gamepad(i, but, padnum, button); | |
511 } | |
512 //TODO: Handle UI bindings | |
513 } | |
514 } | |
515 } | |
516 } | |
517 tern_node * speed_nodes = tern_find_prefix(config, "clocksspeeds"); | |
518 speeds = malloc(sizeof(uint32_t)); | |
519 speeds[0] = 100; | |
520 process_speeds(speed_nodes, NULL); | |
521 for (int i = 0; i < num_speeds; i++) { | |
522 if (!speeds[i]) { | |
523 fprintf(stderr, "Speed index %d was not set to a valid percentage!", i); | |
524 speeds[i] = 100; | |
525 } | |
526 } | |
285 } | 527 } |
286 | 528 |
287 #define TH 0x40 | 529 #define TH 0x40 |
288 #define TH_TIMEOUT 8000 | 530 #define TH_TIMEOUT 8000 |
289 | 531 |