623 lines
13 KiB
C
623 lines
13 KiB
C
/* gameplaySP
|
|
*
|
|
* Copyright (C) 2006 Exophase <exophase@gmail.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of
|
|
* the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include "common.h"
|
|
|
|
// Special thanks to psp298 for the analog->dpad code!
|
|
|
|
void trigger_key(u32 key)
|
|
{
|
|
u32 p1_cnt = io_registers[REG_P1CNT];
|
|
|
|
if((p1_cnt >> 14) & 0x01)
|
|
{
|
|
u32 key_intersection = (p1_cnt & key) & 0x3FF;
|
|
|
|
if(p1_cnt >> 15)
|
|
{
|
|
if(key_intersection == (p1_cnt & 0x3FF))
|
|
raise_interrupt(IRQ_KEYPAD);
|
|
}
|
|
else
|
|
{
|
|
if(key_intersection)
|
|
raise_interrupt(IRQ_KEYPAD);
|
|
}
|
|
}
|
|
}
|
|
|
|
u32 key = 0;
|
|
|
|
u32 global_enable_analog = 1;
|
|
u32 analog_sensitivity_level = 4;
|
|
|
|
typedef enum
|
|
{
|
|
BUTTON_NOT_HELD,
|
|
BUTTON_HELD_INITIAL,
|
|
BUTTON_HELD_REPEAT
|
|
} button_repeat_state_type;
|
|
|
|
|
|
// These define autorepeat values (in microseconds), tweak as necessary.
|
|
|
|
#define BUTTON_REPEAT_START 200000
|
|
#define BUTTON_REPEAT_CONTINUE 50000
|
|
|
|
button_repeat_state_type button_repeat_state = BUTTON_NOT_HELD;
|
|
u32 button_repeat = 0;
|
|
gui_action_type cursor_repeat = CURSOR_NONE;
|
|
|
|
|
|
#ifdef PSP_BUILD
|
|
|
|
u32 gamepad_config_map[16] =
|
|
{
|
|
BUTTON_ID_MENU, // Triangle
|
|
BUTTON_ID_A, // Circle
|
|
BUTTON_ID_B, // Cross
|
|
BUTTON_ID_START, // Square
|
|
BUTTON_ID_L, // Ltrigger
|
|
BUTTON_ID_R, // Rtrigger
|
|
BUTTON_ID_DOWN, // Down
|
|
BUTTON_ID_LEFT, // Left
|
|
BUTTON_ID_UP, // Up
|
|
BUTTON_ID_RIGHT, // Right
|
|
BUTTON_ID_SELECT, // Select
|
|
BUTTON_ID_START, // Start
|
|
BUTTON_ID_UP, // Analog up
|
|
BUTTON_ID_DOWN, // Analog down
|
|
BUTTON_ID_LEFT, // Analog left
|
|
BUTTON_ID_RIGHT // Analog right
|
|
};
|
|
|
|
#define PSP_ALL_BUTTON_MASK 0xFFFF
|
|
|
|
gui_action_type get_gui_input()
|
|
{
|
|
SceCtrlData ctrl_data;
|
|
gui_action_type new_button = CURSOR_NONE;
|
|
u32 new_buttons;
|
|
|
|
static u32 last_buttons = 0;
|
|
static u64 button_repeat_timestamp;
|
|
|
|
delay_us(25000);
|
|
|
|
sceCtrlPeekBufferPositive(&ctrl_data, 1);
|
|
ctrl_data.Buttons &= PSP_ALL_BUTTON_MASK;
|
|
new_buttons = (last_buttons ^ ctrl_data.Buttons) & ctrl_data.Buttons;
|
|
last_buttons = ctrl_data.Buttons;
|
|
|
|
if(new_buttons & PSP_CTRL_LEFT)
|
|
new_button = CURSOR_LEFT;
|
|
|
|
if(new_buttons & PSP_CTRL_RIGHT)
|
|
new_button = CURSOR_RIGHT;
|
|
|
|
if(new_buttons & PSP_CTRL_UP)
|
|
new_button = CURSOR_UP;
|
|
|
|
if(new_buttons & PSP_CTRL_DOWN)
|
|
new_button = CURSOR_DOWN;
|
|
|
|
if(new_buttons & PSP_CTRL_START)
|
|
new_button = CURSOR_SELECT;
|
|
|
|
if(new_buttons & PSP_CTRL_CIRCLE)
|
|
new_button = CURSOR_SELECT;
|
|
|
|
if(new_buttons & PSP_CTRL_CROSS)
|
|
new_button = CURSOR_EXIT;
|
|
|
|
if(new_buttons & PSP_CTRL_SQUARE)
|
|
new_button = CURSOR_BACK;
|
|
|
|
if(new_button != CURSOR_NONE)
|
|
{
|
|
get_ticks_us(&button_repeat_timestamp);
|
|
button_repeat_state = BUTTON_HELD_INITIAL;
|
|
button_repeat = new_buttons;
|
|
cursor_repeat = new_button;
|
|
}
|
|
else
|
|
{
|
|
if(ctrl_data.Buttons & button_repeat)
|
|
{
|
|
u64 new_ticks;
|
|
get_ticks_us(&new_ticks);
|
|
|
|
if(button_repeat_state == BUTTON_HELD_INITIAL)
|
|
{
|
|
if((new_ticks - button_repeat_timestamp) >
|
|
BUTTON_REPEAT_START)
|
|
{
|
|
new_button = cursor_repeat;
|
|
button_repeat_timestamp = new_ticks;
|
|
button_repeat_state = BUTTON_HELD_REPEAT;
|
|
}
|
|
}
|
|
|
|
if(button_repeat_state == BUTTON_HELD_REPEAT)
|
|
{
|
|
if((new_ticks - button_repeat_timestamp) >
|
|
BUTTON_REPEAT_CONTINUE)
|
|
{
|
|
new_button = cursor_repeat;
|
|
button_repeat_timestamp = new_ticks;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return new_button;
|
|
}
|
|
|
|
#define PSP_CTRL_ANALOG_UP (1 << 28)
|
|
#define PSP_CTRL_ANALOG_DOWN (1 << 29)
|
|
#define PSP_CTRL_ANALOG_LEFT (1 << 30)
|
|
#define PSP_CTRL_ANALOG_RIGHT (1 << 31)
|
|
|
|
u32 button_psp_mask_to_config[] =
|
|
{
|
|
PSP_CTRL_TRIANGLE,
|
|
PSP_CTRL_CIRCLE,
|
|
PSP_CTRL_CROSS,
|
|
PSP_CTRL_SQUARE,
|
|
PSP_CTRL_LTRIGGER,
|
|
PSP_CTRL_RTRIGGER,
|
|
PSP_CTRL_DOWN,
|
|
PSP_CTRL_LEFT,
|
|
PSP_CTRL_UP,
|
|
PSP_CTRL_RIGHT,
|
|
PSP_CTRL_SELECT,
|
|
PSP_CTRL_START,
|
|
PSP_CTRL_ANALOG_UP,
|
|
PSP_CTRL_ANALOG_DOWN,
|
|
PSP_CTRL_ANALOG_LEFT,
|
|
PSP_CTRL_ANALOG_RIGHT
|
|
};
|
|
|
|
u32 button_id_to_gba_mask[] =
|
|
{
|
|
BUTTON_UP,
|
|
BUTTON_DOWN,
|
|
BUTTON_LEFT,
|
|
BUTTON_RIGHT,
|
|
BUTTON_A,
|
|
BUTTON_B,
|
|
BUTTON_L,
|
|
BUTTON_R,
|
|
BUTTON_START,
|
|
BUTTON_SELECT,
|
|
BUTTON_NONE,
|
|
BUTTON_NONE,
|
|
BUTTON_NONE,
|
|
BUTTON_NONE
|
|
};
|
|
|
|
gui_action_type get_gui_input_fs_hold(u32 button_id)
|
|
{
|
|
gui_action_type new_button = get_gui_input();
|
|
if((last_buttons & button_psp_mask_to_config[button_id]) == 0)
|
|
return CURSOR_BACK;
|
|
|
|
return new_button;
|
|
}
|
|
|
|
u32 rapidfire_flag = 1;
|
|
|
|
u32 update_input()
|
|
{
|
|
SceCtrlData ctrl_data;
|
|
u32 buttons;
|
|
u32 non_repeat_buttons;
|
|
u32 button_id;
|
|
u32 i;
|
|
u32 new_key = 0;
|
|
u32 analog_sensitivity = 92 - (analog_sensitivity_level * 4);
|
|
u32 inv_analog_sensitivity = 256 - analog_sensitivity;
|
|
|
|
sceCtrlPeekBufferPositive(&ctrl_data, 1);
|
|
|
|
buttons = ctrl_data.Buttons;
|
|
|
|
if(global_enable_analog)
|
|
{
|
|
if(ctrl_data.Lx < analog_sensitivity)
|
|
buttons |= PSP_CTRL_ANALOG_LEFT;
|
|
|
|
if(ctrl_data.Lx > inv_analog_sensitivity)
|
|
buttons |= PSP_CTRL_ANALOG_RIGHT;
|
|
|
|
if(ctrl_data.Ly < analog_sensitivity)
|
|
buttons |= PSP_CTRL_ANALOG_UP;
|
|
|
|
if(ctrl_data.Ly > inv_analog_sensitivity)
|
|
buttons |= PSP_CTRL_ANALOG_DOWN;
|
|
}
|
|
|
|
non_repeat_buttons = (last_buttons ^ buttons) & buttons;
|
|
last_buttons = buttons;
|
|
|
|
for(i = 0; i < 16; i++)
|
|
{
|
|
if(non_repeat_buttons & button_psp_mask_to_config[i])
|
|
button_id = gamepad_config_map[i];
|
|
else
|
|
button_id = BUTTON_ID_NONE;
|
|
|
|
switch(button_id)
|
|
{
|
|
case BUTTON_ID_MENU:
|
|
{
|
|
u16 *screen_copy = copy_screen();
|
|
u32 ret_val = menu(screen_copy);
|
|
free(screen_copy);
|
|
|
|
return ret_val;
|
|
}
|
|
|
|
case BUTTON_ID_LOADSTATE:
|
|
{
|
|
u8 current_savestate_filename[512];
|
|
get_savestate_filename_noshot(savestate_slot,
|
|
current_savestate_filename);
|
|
load_state(current_savestate_filename);
|
|
return 1;
|
|
}
|
|
|
|
case BUTTON_ID_SAVESTATE:
|
|
{
|
|
u8 current_savestate_filename[512];
|
|
u16 *current_screen = copy_screen();
|
|
get_savestate_filename_noshot(savestate_slot,
|
|
current_savestate_filename);
|
|
save_state(current_savestate_filename, current_screen);
|
|
free(current_screen);
|
|
return 0;
|
|
}
|
|
|
|
case BUTTON_ID_FASTFORWARD:
|
|
print_string("FASTFORWARD", 0xFFFF, 0x0000, 0, 50);
|
|
synchronize_flag ^= 1;
|
|
return 0;
|
|
}
|
|
|
|
if(buttons & button_psp_mask_to_config[i])
|
|
{
|
|
button_id = gamepad_config_map[i];
|
|
if(button_id < BUTTON_ID_MENU)
|
|
{
|
|
new_key |= button_id_to_gba_mask[button_id];
|
|
}
|
|
else
|
|
|
|
if((button_id >= BUTTON_ID_RAPIDFIRE_A) &&
|
|
(button_id <= BUTTON_ID_RAPIDFIRE_L))
|
|
{
|
|
rapidfire_flag ^= 1;
|
|
if(rapidfire_flag)
|
|
{
|
|
new_key |= button_id_to_gba_mask[button_id -
|
|
BUTTON_ID_RAPIDFIRE_A + BUTTON_ID_A];
|
|
}
|
|
else
|
|
{
|
|
new_key &= ~button_id_to_gba_mask[button_id -
|
|
BUTTON_ID_RAPIDFIRE_A + BUTTON_ID_A];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if((new_key | key) != key)
|
|
trigger_key(new_key);
|
|
|
|
key = new_key;
|
|
|
|
io_registers[REG_P1] = (~key) & 0x3FF;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void init_input()
|
|
{
|
|
sceCtrlSetSamplingCycle(0);
|
|
sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG);
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
#if defined(PC_BUILD)
|
|
|
|
u32 key_map(SDLKey key_sym)
|
|
{
|
|
switch(key_sym)
|
|
{
|
|
case SDLK_LSHIFT:
|
|
return BUTTON_L;
|
|
|
|
case SDLK_x:
|
|
return BUTTON_R;
|
|
|
|
case SDLK_DOWN:
|
|
return BUTTON_DOWN;
|
|
|
|
case SDLK_UP:
|
|
return BUTTON_UP;
|
|
|
|
case SDLK_LEFT:
|
|
return BUTTON_LEFT;
|
|
|
|
case SDLK_RIGHT:
|
|
return BUTTON_RIGHT;
|
|
|
|
case SDLK_RETURN:
|
|
return BUTTON_START;
|
|
|
|
case SDLK_RSHIFT:
|
|
return BUTTON_SELECT;
|
|
|
|
case SDLK_LCTRL:
|
|
return BUTTON_B;
|
|
|
|
case SDLK_LALT:
|
|
return BUTTON_A;
|
|
|
|
default:
|
|
return BUTTON_NONE;
|
|
}
|
|
}
|
|
|
|
u32 joy_map(u32 button)
|
|
{
|
|
switch(button)
|
|
{
|
|
case 4:
|
|
return BUTTON_L;
|
|
|
|
case 5:
|
|
return BUTTON_R;
|
|
|
|
case 2:
|
|
return BUTTON_START;
|
|
|
|
case 3:
|
|
return BUTTON_SELECT;
|
|
|
|
case 1:
|
|
return BUTTON_B;
|
|
|
|
case 0:
|
|
return BUTTON_A;
|
|
|
|
default:
|
|
return BUTTON_NONE;
|
|
}
|
|
}
|
|
|
|
gui_action_type get_gui_input()
|
|
{
|
|
SDL_Event event;
|
|
gui_action_type gui_action = CURSOR_NONE;
|
|
|
|
delay_us(30000);
|
|
|
|
while(SDL_PollEvent(&event))
|
|
{
|
|
switch(event.type)
|
|
{
|
|
case SDL_QUIT:
|
|
quit();
|
|
|
|
case SDL_KEYDOWN:
|
|
{
|
|
switch(event.key.keysym.sym)
|
|
{
|
|
case SDLK_ESCAPE:
|
|
gui_action = CURSOR_EXIT;
|
|
break;
|
|
|
|
case SDLK_DOWN:
|
|
gui_action = CURSOR_DOWN;
|
|
break;
|
|
|
|
case SDLK_UP:
|
|
gui_action = CURSOR_UP;
|
|
break;
|
|
|
|
case SDLK_LEFT:
|
|
gui_action = CURSOR_LEFT;
|
|
break;
|
|
|
|
case SDLK_RIGHT:
|
|
gui_action = CURSOR_RIGHT;
|
|
break;
|
|
|
|
case SDLK_RETURN:
|
|
gui_action = CURSOR_SELECT;
|
|
break;
|
|
|
|
case SDLK_BACKSPACE:
|
|
gui_action = CURSOR_BACK;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return gui_action;
|
|
}
|
|
|
|
u32 update_input()
|
|
{
|
|
SDL_Event event;
|
|
|
|
while(SDL_PollEvent(&event))
|
|
{
|
|
switch(event.type)
|
|
{
|
|
case SDL_QUIT:
|
|
quit();
|
|
|
|
case SDL_KEYDOWN:
|
|
{
|
|
if(event.key.keysym.sym == SDLK_ESCAPE)
|
|
{
|
|
quit();
|
|
}
|
|
#ifdef PC_BUILD
|
|
if(event.key.keysym.sym == SDLK_BACKSPACE)
|
|
#else
|
|
if(event.key.keysym.sym == SDLK_F10)
|
|
#endif
|
|
{
|
|
u16 *screen_copy = copy_screen();
|
|
u32 ret_val = menu(screen_copy);
|
|
free(screen_copy);
|
|
|
|
return ret_val;
|
|
}
|
|
else
|
|
#ifdef PC_BUILD
|
|
if(event.key.keysym.sym == SDLK_F1)
|
|
{
|
|
debug_on();
|
|
}
|
|
else
|
|
|
|
if(event.key.keysym.sym == SDLK_F2)
|
|
{
|
|
FILE *fp = fopen("palette_ram.bin", "wb");
|
|
printf("writing palette RAM\n");
|
|
fwrite(palette_ram, 1024, 1, fp);
|
|
fclose(fp);
|
|
printf("writing palette VRAM\n");
|
|
fp = fopen("vram.bin", "wb");
|
|
fwrite(vram, 1024 * 96, 1, fp);
|
|
fclose(fp);
|
|
printf("writing palette OAM RAM\n");
|
|
fp = fopen("oam_ram.bin", "wb");
|
|
fwrite(oam_ram, 1024, 1, fp);
|
|
fclose(fp);
|
|
printf("writing palette I/O registers\n");
|
|
fp = fopen("io_registers.bin", "wb");
|
|
fwrite(io_registers, 1024, 1, fp);
|
|
fclose(fp);
|
|
}
|
|
else
|
|
|
|
if(event.key.keysym.sym == SDLK_F3)
|
|
{
|
|
dump_translation_cache();
|
|
}
|
|
else
|
|
#endif
|
|
if(event.key.keysym.sym == SDLK_F5)
|
|
{
|
|
char current_savestate_filename[512];
|
|
u16 *current_screen = copy_screen();
|
|
get_savestate_filename_noshot(savestate_slot,
|
|
current_savestate_filename);
|
|
save_state(current_savestate_filename, current_screen);
|
|
free(current_screen);
|
|
}
|
|
else
|
|
|
|
if(event.key.keysym.sym == SDLK_F7)
|
|
{
|
|
char current_savestate_filename[512];
|
|
get_savestate_filename_noshot(savestate_slot,
|
|
current_savestate_filename);
|
|
load_state(current_savestate_filename);
|
|
debug_on();
|
|
return 1;
|
|
}
|
|
else
|
|
|
|
if(event.key.keysym.sym == SDLK_BACKQUOTE)
|
|
{
|
|
synchronize_flag ^= 1;
|
|
}
|
|
else
|
|
{
|
|
key |= key_map(event.key.keysym.sym);
|
|
trigger_key(key);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case SDL_KEYUP:
|
|
{
|
|
key &= ~(key_map(event.key.keysym.sym));
|
|
break;
|
|
}
|
|
|
|
case SDL_JOYBUTTONDOWN:
|
|
{
|
|
key |= joy_map(event.jbutton.button);
|
|
trigger_key(key);
|
|
break;
|
|
}
|
|
|
|
case SDL_JOYBUTTONUP:
|
|
{
|
|
key &= ~(joy_map(event.jbutton.button));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
io_registers[REG_P1] = (~key) & 0x3FF;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void init_input()
|
|
{
|
|
u32 joystick_count = SDL_NumJoysticks();
|
|
|
|
if(joystick_count > 0)
|
|
{
|
|
SDL_JoystickOpen(0);
|
|
SDL_JoystickEventState(SDL_ENABLE);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
#define input_savestate_builder(type) \
|
|
void input_##type##_savestate(file_tag_type savestate_file) \
|
|
{ \
|
|
file_##type##_variable(savestate_file, key); \
|
|
} \
|
|
|
|
input_savestate_builder(read);
|
|
input_savestate_builder(write_mem);
|
|
|