RetroArch/gfx/state_tracker.c

298 lines
7.7 KiB
C
Raw Normal View History

2012-04-21 21:13:50 +00:00
/* RetroArch - A frontend for libretro.
2014-01-01 00:50:59 +00:00
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
*
2012-04-21 21:13:50 +00:00
* RetroArch 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 Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
2012-04-21 21:13:50 +00:00
* RetroArch 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.
*
2012-04-21 21:31:57 +00:00
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
2012-04-07 10:17:40 +00:00
#include "state_tracker.h"
#include <stdlib.h>
2012-03-16 22:26:57 +00:00
#include "../compat/strl.h"
2011-11-30 22:50:31 +00:00
#include "../general.h"
2012-04-07 10:17:40 +00:00
#include "../libretro.h"
#include "../input/input_common.h"
#ifdef HAVE_PYTHON
#include "py_state/py_state.h"
#endif
2012-04-07 10:17:40 +00:00
struct state_tracker_internal
{
char id[64];
2011-06-11 18:02:17 +00:00
bool is_input;
const uint16_t *input_ptr;
const uint8_t *ptr;
#ifdef HAVE_PYTHON
py_state_t *py;
#endif
uint32_t addr;
2012-02-12 17:05:33 +00:00
uint16_t mask;
uint16_t equal;
2012-04-07 10:17:40 +00:00
enum state_tracker_type type;
2011-06-11 18:02:17 +00:00
uint32_t prev[2];
int frame_count;
2011-06-07 19:07:00 +00:00
int frame_count_prev;
2011-06-11 18:02:17 +00:00
uint32_t old_value;
2011-06-06 19:32:10 +00:00
int transition_count;
};
2012-04-07 10:17:40 +00:00
struct state_tracker
{
2012-04-07 10:17:40 +00:00
struct state_tracker_internal *info;
unsigned info_elem;
2011-06-11 18:02:17 +00:00
uint16_t input_state[2];
#ifdef HAVE_PYTHON
py_state_t *py;
#endif
};
2012-04-07 10:17:40 +00:00
state_tracker_t* state_tracker_init(const struct state_tracker_info *info)
{
unsigned i;
2012-04-07 10:17:40 +00:00
state_tracker_t *tracker = (state_tracker_t*)calloc(1, sizeof(*tracker));
if (!tracker)
return NULL;
#ifdef HAVE_PYTHON
if (info->script)
{
2014-09-08 15:57:18 +00:00
tracker->py = py_state_new(info->script, info->script_is_file,
info->script_class ? info->script_class : "GameAware");
if (!tracker->py)
{
free(tracker);
2012-04-21 21:25:32 +00:00
RARCH_ERR("Failed to init Python script.\n");
return NULL;
}
}
#endif
2014-09-08 15:57:18 +00:00
tracker->info = (struct state_tracker_internal*)
calloc(info->info_elem, sizeof(struct state_tracker_internal));
tracker->info_elem = info->info_elem;
for (i = 0; i < info->info_elem; i++)
{
2014-09-08 15:57:18 +00:00
strlcpy(tracker->info[i].id, info->info[i].id,
sizeof(tracker->info[i].id));
2012-02-12 17:05:33 +00:00
tracker->info[i].addr = info->info[i].addr;
tracker->info[i].type = info->info[i].type;
2014-09-08 15:57:18 +00:00
tracker->info[i].mask = (info->info[i].mask == 0)
? 0xffff : info->info[i].mask;
2012-02-12 17:05:33 +00:00
tracker->info[i].equal = info->info[i].equal;
#ifdef HAVE_PYTHON
2012-04-21 21:25:32 +00:00
if (info->info[i].type == RARCH_STATE_PYTHON)
2012-11-18 20:23:34 +00:00
{
if (!tracker->py)
{
free(tracker->info);
free(tracker);
RARCH_ERR("Python semantic was requested, but Python tracker is not loaded.\n");
return NULL;
}
tracker->info[i].py = tracker->py;
2012-11-18 20:23:34 +00:00
}
#endif
2014-09-08 15:57:18 +00:00
/* If we don't have a valid pointer. */
static const uint8_t empty = 0;
switch (info->info[i].ram_type)
{
2012-04-21 21:25:32 +00:00
case RARCH_STATE_WRAM:
tracker->info[i].ptr = info->wram ? info->wram : &empty;
break;
2012-04-21 21:25:32 +00:00
case RARCH_STATE_INPUT_SLOT1:
2011-06-11 18:02:17 +00:00
tracker->info[i].input_ptr = &tracker->input_state[0];
tracker->info[i].is_input = true;
break;
2012-04-21 21:25:32 +00:00
case RARCH_STATE_INPUT_SLOT2:
2011-06-11 18:02:17 +00:00
tracker->info[i].input_ptr = &tracker->input_state[1];
tracker->info[i].is_input = true;
break;
default:
tracker->info[i].ptr = &empty;
}
}
return tracker;
}
2012-04-07 10:17:40 +00:00
void state_tracker_free(state_tracker_t *tracker)
{
free(tracker->info);
#ifdef HAVE_PYTHON
py_state_free(tracker->py);
#endif
free(tracker);
}
2012-04-07 10:17:40 +00:00
static inline uint16_t fetch(const struct state_tracker_internal *info)
2012-02-12 17:05:33 +00:00
{
uint16_t val = 0;
if (info->is_input)
val = *info->input_ptr;
else
val = info->ptr[info->addr];
val &= info->mask;
if (info->equal && val != info->equal)
val = 0;
return val;
}
2011-05-29 21:58:04 +00:00
static void update_element(
2012-04-07 10:17:40 +00:00
struct state_tracker_uniform *uniform,
struct state_tracker_internal *info,
unsigned frame_count)
{
uniform->id = info->id;
switch (info->type)
{
2012-04-21 21:25:32 +00:00
case RARCH_STATE_CAPTURE:
2012-02-12 17:05:33 +00:00
uniform->value = fetch(info);
break;
2012-04-21 21:25:32 +00:00
case RARCH_STATE_CAPTURE_PREV:
2012-02-12 17:05:33 +00:00
if (info->prev[0] != fetch(info))
2011-05-26 14:23:11 +00:00
{
info->prev[1] = info->prev[0];
2012-02-12 17:05:33 +00:00
info->prev[0] = fetch(info);
2011-05-26 14:23:11 +00:00
}
uniform->value = info->prev[1];
break;
2012-04-21 21:25:32 +00:00
case RARCH_STATE_TRANSITION:
2012-02-12 17:05:33 +00:00
if (info->old_value != fetch(info))
{
2012-02-12 17:05:33 +00:00
info->old_value = fetch(info);
info->frame_count = frame_count;
}
2011-05-26 14:23:11 +00:00
uniform->value = info->frame_count;
break;
2012-04-21 21:25:32 +00:00
case RARCH_STATE_TRANSITION_COUNT:
2012-02-12 17:05:33 +00:00
if (info->old_value != fetch(info))
2011-06-06 19:32:10 +00:00
{
2012-02-12 17:05:33 +00:00
info->old_value = fetch(info);
2011-06-06 19:32:10 +00:00
info->transition_count++;
}
uniform->value = info->transition_count;
break;
2012-04-21 21:25:32 +00:00
case RARCH_STATE_TRANSITION_PREV:
2012-02-12 17:05:33 +00:00
if (info->old_value != fetch(info))
{
2012-02-12 17:05:33 +00:00
info->old_value = fetch(info);
2011-06-07 19:07:00 +00:00
info->frame_count_prev = info->frame_count;
2011-05-26 14:23:11 +00:00
info->frame_count = frame_count;
}
2011-06-07 19:07:00 +00:00
uniform->value = info->frame_count_prev;
2011-05-26 14:23:11 +00:00
break;
#ifdef HAVE_PYTHON
2012-04-21 21:25:32 +00:00
case RARCH_STATE_PYTHON:
uniform->value = py_state_get(info->py, info->id, frame_count);
break;
#endif
default:
break;
}
}
2014-09-08 15:57:18 +00:00
/* Updates 16-bit input in same format as SNES itself. */
2012-04-07 10:17:40 +00:00
static void update_input(state_tracker_t *tracker)
2011-06-11 18:02:17 +00:00
{
unsigned i;
2012-02-20 22:44:56 +00:00
if (driver.input == NULL)
2011-06-11 18:02:17 +00:00
return;
static const unsigned buttons[] = {
2012-04-07 10:17:40 +00:00
RETRO_DEVICE_ID_JOYPAD_R,
RETRO_DEVICE_ID_JOYPAD_L,
RETRO_DEVICE_ID_JOYPAD_X,
RETRO_DEVICE_ID_JOYPAD_A,
RETRO_DEVICE_ID_JOYPAD_RIGHT,
RETRO_DEVICE_ID_JOYPAD_LEFT,
RETRO_DEVICE_ID_JOYPAD_DOWN,
RETRO_DEVICE_ID_JOYPAD_UP,
RETRO_DEVICE_ID_JOYPAD_START,
RETRO_DEVICE_ID_JOYPAD_SELECT,
RETRO_DEVICE_ID_JOYPAD_Y,
RETRO_DEVICE_ID_JOYPAD_B,
2011-06-11 18:02:17 +00:00
};
2014-09-08 15:57:18 +00:00
/* Only bind for up to two players for now. */
2012-07-07 15:19:32 +00:00
static const struct retro_keybind *binds[2] = {
2011-06-11 18:02:17 +00:00
g_settings.input.binds[0],
g_settings.input.binds[1],
};
for (i = 0; i < 2; i++)
2014-09-08 15:57:18 +00:00
input_push_analog_dpad(g_settings.input.binds[i],
g_settings.input.analog_dpad_mode[i]);
for (i = 0; i < MAX_PLAYERS; i++)
2014-09-08 15:57:18 +00:00
input_push_analog_dpad(g_settings.input.autoconf_binds[i],
g_settings.input.analog_dpad_mode[i]);
2011-06-11 18:02:17 +00:00
uint16_t state[2] = {0};
if (!driver.block_libretro_input)
2011-06-11 18:02:17 +00:00
{
for (i = 4; i < 16; i++)
{
2014-09-08 15:57:18 +00:00
state[0] |= (driver.input->input_state(
driver.input_data, binds, 0,
RETRO_DEVICE_JOYPAD, 0, buttons[i - 4]) ? 1 : 0) << i;
state[1] |= (driver.input->input_state(
driver.input_data, binds, 1,
RETRO_DEVICE_JOYPAD, 0, buttons[i - 4]) ? 1 : 0) << i;
}
2011-06-11 18:02:17 +00:00
}
for (i = 0; i < 2; i++)
input_pop_analog_dpad(g_settings.input.binds[i]);
for (i = 0; i < MAX_PLAYERS; i++)
input_pop_analog_dpad(g_settings.input.autoconf_binds[i]);
for (i = 0; i < 2; i++)
2011-06-11 18:02:17 +00:00
tracker->input_state[i] = state[i];
}
2014-09-08 15:57:18 +00:00
unsigned state_get_uniform(state_tracker_t *tracker,
struct state_tracker_uniform *uniforms,
unsigned elem, unsigned frame_count)
{
unsigned i, elems;
elems = tracker->info_elem < elem ? tracker->info_elem : elem;
2011-06-11 18:02:17 +00:00
update_input(tracker);
for (i = 0; i < elems; i++)
update_element(&uniforms[i], &tracker->info[i], frame_count);
return elems;
}