Files
djhackersdev_bemanitools/src/main/geninput/mapper.c
T
2024-01-31 21:40:22 +01:00

659 lines
13 KiB
C

#include <math.h>
#include <stdbool.h>
#include "geninput/hid-mgr.h"
#include "geninput/mapper.h"
#include "util/array.h"
#include "util/log.h"
#include "util/mem.h"
struct action_iter {
struct mapper *mapper;
size_t i;
};
struct action_mapping {
struct mapped_action src;
uint8_t action;
uint8_t page;
uint8_t bit;
};
struct analog_mapping {
struct mapped_analog src;
int32_t sensitivity;
bool bound;
bool valid;
bool absolute;
bool invert;
double analog_min;
double analog_max;
double inv_analog_range;
uint8_t pos;
};
struct light_iter {
struct mapper *mapper;
size_t i;
};
struct light_mapping {
struct mapped_light dest;
uint8_t game_light;
bool bound;
bool valid;
double affine_scale;
int32_t affine_bias;
};
struct mapper {
struct array actions;
struct analog_mapping *analogs;
uint8_t nanalogs;
struct array light_maps;
uint8_t *lights;
uint8_t nlights;
};
static uint64_t action_mapping_update(struct action_mapping *am);
static void analog_mapping_bind(struct analog_mapping *am);
static void analog_mapping_update(struct analog_mapping *am);
static void light_mapping_bind(struct light_mapping *lm);
static void
light_mapping_send(struct light_mapping *lm, const struct mapper *m);
struct mapper *mapper_inst;
void action_iter_get_mapping(action_iter_t iter, struct mapped_action *ma)
{
struct action_mapping *am;
log_assert(action_iter_is_valid(iter));
am = array_item(struct action_mapping, &iter->mapper->actions, iter->i);
*ma = am->src;
}
uint8_t action_iter_get_action(action_iter_t iter)
{
struct action_mapping *am;
log_assert(action_iter_is_valid(iter));
am = array_item(struct action_mapping, &iter->mapper->actions, iter->i);
return am->action;
}
uint8_t action_iter_get_page(action_iter_t iter)
{
struct action_mapping *am;
log_assert(action_iter_is_valid(iter));
am = array_item(struct action_mapping, &iter->mapper->actions, iter->i);
return am->page;
}
uint8_t action_iter_get_bit(action_iter_t iter)
{
struct action_mapping *am;
log_assert(action_iter_is_valid(iter));
am = array_item(struct action_mapping, &iter->mapper->actions, iter->i);
return am->bit;
}
bool action_iter_is_valid(action_iter_t iter)
{
return iter->i < iter->mapper->actions.nitems;
}
void action_iter_next(action_iter_t iter)
{
iter->i++;
}
void action_iter_free(action_iter_t iter)
{
free(iter);
}
static uint64_t action_mapping_update(struct action_mapping *am)
{
int32_t value;
if (am->src.hid == NULL) {
return 0;
}
if (!hid_stub_get_value(am->src.hid, am->src.control_no, &value)) {
return 0;
}
if (value < am->src.value_min || value > am->src.value_max) {
return 0;
}
return 1ULL << am->bit;
}
static void analog_mapping_bind(struct analog_mapping *am)
{
const struct hid_control *ctl;
struct hid_control *controls;
size_t ncontrols;
am->bound = true;
am->valid = false;
if (am->src.hid == NULL) {
goto unbound_fail;
}
if (!hid_stub_get_controls(am->src.hid, NULL, &ncontrols)) {
goto size_fail;
}
if (am->src.control_no >= ncontrols) {
goto bounds_fail;
}
controls = xmalloc(sizeof(*controls) * ncontrols);
if (!hid_stub_get_controls(am->src.hid, controls, &ncontrols)) {
goto read_fail;
}
ctl = &controls[am->src.control_no];
am->analog_min = ctl->value_min;
am->analog_max = ctl->value_max;
am->inv_analog_range = 1.0 / ((int64_t)ctl->value_max - ctl->value_min);
am->absolute = !(ctl->flags & HID_FLAG_RELATIVE);
am->invert = false;
am->valid = true;
read_fail:
free(controls);
bounds_fail:
size_fail:
unbound_fail:
return;
}
static void analog_mapping_update(struct analog_mapping *am)
{
double tmp;
int32_t value;
int8_t delta;
if (!am->bound) {
analog_mapping_bind(am);
}
if (!am->valid) {
return;
}
if (!hid_stub_get_value(am->src.hid, am->src.control_no, &value)) {
return;
}
if (am->absolute) {
if (am->invert) {
tmp = am->analog_max - value;
} else {
tmp = value - am->analog_min;
}
// Scale the input value to [0,1] range
tmp *= am->inv_analog_range;
am->pos = (uint8_t) ((tmp + 0.5) * 256.0);
} else {
delta = (int8_t) (value * exp(am->sensitivity / 256.0));
if (am->invert) {
delta *= -1;
}
am->pos += delta;
}
}
void light_iter_get_mapping(light_iter_t iter, struct mapped_light *ml)
{
struct light_mapping *lm;
log_assert(light_iter_is_valid(iter));
lm = array_item(struct light_mapping, &iter->mapper->light_maps, iter->i);
*ml = lm->dest;
}
uint8_t light_iter_get_game_light(light_iter_t iter)
{
struct light_mapping *lm;
log_assert(light_iter_is_valid(iter));
lm = array_item(struct light_mapping, &iter->mapper->light_maps, iter->i);
return lm->game_light;
}
bool light_iter_is_valid(light_iter_t iter)
{
return iter->i < iter->mapper->light_maps.nitems;
}
void light_iter_next(light_iter_t iter)
{
iter->i++;
}
void light_iter_free(light_iter_t iter)
{
free(iter);
}
static void light_mapping_bind(struct light_mapping *lm)
{
const struct hid_light *light;
struct hid_light *light_defs;
size_t nlights;
lm->bound = true;
lm->valid = false;
if (lm->dest.hid == NULL) {
goto unbound_fail;
}
if (!hid_stub_get_lights(lm->dest.hid, NULL, &nlights)) {
goto size_fail;
}
if (lm->dest.light_no >= nlights) {
goto bounds_fail;
}
light_defs = xmalloc(sizeof(*light_defs) * nlights);
if (!hid_stub_get_lights(lm->dest.hid, light_defs, &nlights)) {
goto read_fail;
}
light = &light_defs[lm->dest.light_no];
lm->affine_bias = light->value_min;
lm->affine_scale = light->value_max - light->value_min;
lm->valid = true;
read_fail:
free(light_defs);
bounds_fail:
size_fail:
unbound_fail:
return;
}
static void light_mapping_send(struct light_mapping *lm, const struct mapper *m)
{
double tmp;
uint32_t value;
uint8_t intensity;
if (!lm->bound) {
light_mapping_bind(lm);
}
if (!lm->valid) {
return;
}
if (lm->game_light >= m->nlights) {
return;
}
intensity = m->lights[lm->game_light];
tmp = (intensity / 256.0) * lm->affine_scale;
value = (int32_t) (tmp + 0.5) + lm->affine_bias;
hid_stub_set_light(lm->dest.hid, lm->dest.light_no, value);
}
struct mapper *mapper_impl_create(void)
{
struct mapper *m;
m = xmalloc(sizeof(*m));
array_init(&m->actions);
m->analogs = NULL;
m->nanalogs = 0;
array_init(&m->light_maps);
m->lights = NULL;
m->nlights = 0;
return m;
}
void mapper_impl_clear_action_map(
struct mapper *m, uint8_t action, uint8_t page)
{
struct action_mapping *am;
size_t i;
for (i = 0; i < m->actions.nitems; i++) {
am = array_item(struct action_mapping, &m->actions, i);
if (am->action == action && am->page == page) {
array_remove(struct action_mapping, &m->actions, i);
return;
}
}
}
void mapper_impl_clear_light_map(
struct mapper *m, const struct mapped_light *ml)
{
struct light_mapping *lm;
size_t i;
for (i = 0; i < m->light_maps.nitems;) {
lm = array_item(struct light_mapping, &m->light_maps, i);
if (memcmp(&lm->dest, ml, sizeof(*ml)) == 0) {
array_remove(struct light_mapping, &m->light_maps, i);
} else {
i++;
}
}
}
bool mapper_impl_get_action_map(
struct mapper *m, uint8_t action, uint8_t page, struct mapped_action *ma)
{
const struct action_mapping *am;
size_t i;
for (i = 0; i < m->actions.nitems; i++) {
am = array_item(struct action_mapping, &m->actions, i);
if (am->action == action && am->page == page) {
*ma = am->src;
return true;
}
}
return false;
}
bool mapper_impl_get_analog_map(
struct mapper *m, uint8_t analog, struct mapped_analog *ma)
{
memset(ma, 0, sizeof(*ma));
if (analog >= m->nanalogs) {
return false;
}
*ma = m->analogs[analog].src;
return true;
}
int32_t mapper_impl_get_analog_sensitivity(struct mapper *m, uint8_t analog)
{
if (analog >= m->nanalogs) {
return 0;
}
return m->analogs[analog].sensitivity;
}
uint8_t mapper_impl_get_nanalogs(struct mapper *m)
{
return m->nanalogs;
}
uint8_t mapper_impl_get_nlights(struct mapper *m)
{
return m->nlights;
}
uint8_t mapper_impl_get_npages(struct mapper *m)
{
const struct action_mapping *am;
size_t i;
int max_page;
max_page = -1;
for (i = 0; i < m->actions.nitems; i++) {
am = array_item(struct action_mapping, &m->actions, i);
if (max_page < am->page) {
max_page = am->page;
}
}
return (uint8_t) (max_page + 1);
}
action_iter_t mapper_impl_iterate_actions(struct mapper *m)
{
struct action_iter *iter;
iter = xmalloc(sizeof(*iter));
iter->mapper = m;
iter->i = 0;
return iter;
}
light_iter_t mapper_impl_iterate_lights(struct mapper *m)
{
struct light_iter *iter;
iter = xmalloc(sizeof(*iter));
iter->mapper = m;
iter->i = 0;
return iter;
}
bool mapper_impl_is_analog_absolute(struct mapper *m, uint8_t analog)
{
struct analog_mapping *am;
if (analog >= m->nanalogs) {
return false;
}
am = &m->analogs[analog];
if (!am->bound) {
analog_mapping_bind(am);
}
return m->analogs[analog].absolute;
}
void mapper_impl_set_action_map(
struct mapper *m,
uint8_t action,
uint8_t page,
uint8_t bit,
const struct mapped_action *ma)
{
struct action_mapping *am;
size_t i;
for (i = 0; i < m->actions.nitems; i++) {
am = array_item(struct action_mapping, &m->actions, i);
if (am->action == action && am->page == page) {
am->src = *ma;
return;
}
}
am = array_append(struct action_mapping, &m->actions);
am->src = *ma;
am->action = action;
am->page = page;
am->bit = bit;
}
bool mapper_impl_set_analog_map(
struct mapper *m, uint8_t analog, const struct mapped_analog *ma)
{
struct analog_mapping *am;
if (analog >= m->nanalogs) {
return false;
}
am = &m->analogs[analog];
am->src = *ma;
am->bound = false;
return true;
}
bool mapper_impl_set_analog_sensitivity(
struct mapper *m, uint8_t analog, int32_t sensitivity)
{
if (analog >= m->nanalogs) {
return false;
}
m->analogs[analog].sensitivity = sensitivity;
return true;
}
bool mapper_impl_set_analog_invert(
struct mapper *m, uint8_t analog, bool invert)
{
if (analog >= m->nanalogs) {
return false;
}
m->analogs[analog].invert = invert;
return true;
}
void mapper_impl_set_light_map(
struct mapper *m, const struct mapped_light *ml, uint8_t game_light)
{
struct light_mapping *lm;
size_t i;
for (i = 0; i < m->light_maps.nitems; i++) {
lm = array_item(struct light_mapping, &m->light_maps, i);
if (memcmp(&lm->dest, ml, sizeof(*ml)) == 0) {
lm->game_light = game_light;
return;
}
}
lm = array_append(struct light_mapping, &m->light_maps);
memset(lm, 0, sizeof(*lm));
lm->dest = *ml;
lm->game_light = game_light;
}
void mapper_impl_set_nanalogs(struct mapper *m, uint8_t nanalogs)
{
free(m->analogs);
m->analogs = xcalloc(sizeof(*m->analogs) * nanalogs);
m->nanalogs = nanalogs;
}
void mapper_impl_set_nlights(struct mapper *m, uint8_t nlights)
{
free(m->lights);
m->lights = xcalloc(sizeof(*m->lights) * nlights);
m->nlights = nlights;
}
uint8_t mapper_impl_read_analog(struct mapper *m, uint8_t analog)
{
if (analog >= m->nanalogs) {
return 0;
}
return m->analogs[analog].pos;
}
uint64_t mapper_impl_update(struct mapper *m)
{
struct action_mapping *am;
struct light_mapping *lm;
size_t i;
uint64_t result;
hid_mgr_lock();
for (i = 0; i < m->light_maps.nitems; i++) {
lm = array_item(struct light_mapping, &m->light_maps, i);
light_mapping_send(lm, m);
}
for (i = 0; i < m->nanalogs; i++) {
analog_mapping_update(&m->analogs[i]);
}
result = 0;
for (i = 0; i < m->actions.nitems; i++) {
am = array_item(struct action_mapping, &m->actions, i);
result |= action_mapping_update(am);
}
hid_mgr_unlock();
return result;
}
void mapper_impl_write_light(struct mapper *m, uint8_t light, uint8_t intensity)
{
if (light >= m->nlights) {
return;
}
m->lights[light] = intensity;
}
void mapper_impl_destroy(struct mapper *m)
{
free(m->lights);
array_fini(&m->light_maps);
free(m->analogs);
array_fini(&m->actions);
free(m);
}