diff --git a/Descent3/Controls.cpp b/Descent3/Controls.cpp index d956e13e9..f28ecf83a 100644 --- a/Descent3/Controls.cpp +++ b/Descent3/Controls.cpp @@ -1,5 +1,5 @@ /* -* Descent 3 +* Descent 3 * Copyright (C) 2024 Parallax Software * * This program is free software: you can redistribute it and/or modify @@ -879,25 +879,25 @@ void DoControllerMovement(game_controls *controls) { ct_packet ctl_pub, ctl_pdb, ctl_hlb, ctl_hrb, ctl_blb, ctl_brb; // read controls - Controller->get_packet(ctfFORWARD_THRUSTAXIS, &ctl_z); - Controller->get_packet(ctfUP_THRUSTAXIS, &ctl_y); - Controller->get_packet(ctfRIGHT_THRUSTAXIS, &ctl_x); - Controller->get_packet(ctfPITCH_DOWNAXIS, &ctl_p); - Controller->get_packet(ctfBANK_RIGHTAXIS, &ctl_b); - Controller->get_packet(ctfHEADING_RIGHTAXIS, &ctl_h); - Controller->get_packet(ctfUP_BUTTON, &ctl_povu); - Controller->get_packet(ctfDOWN_BUTTON, &ctl_povd); - Controller->get_packet(ctfRIGHT_BUTTON, &ctl_povr); - Controller->get_packet(ctfLEFT_BUTTON, &ctl_povl); - Controller->get_packet(ctfFORWARD_BUTTON, &ctl_fb); - Controller->get_packet(ctfREVERSE_BUTTON, &ctl_rb); - Controller->get_packet(ctfAFTERBURN_BUTTON, &ctl_afterburn); - Controller->get_packet(ctfHEADING_LEFTBUTTON, &ctl_hlb); - Controller->get_packet(ctfHEADING_RIGHTBUTTON, &ctl_hrb); - Controller->get_packet(ctfPITCH_UPBUTTON, &ctl_pub); - Controller->get_packet(ctfPITCH_DOWNBUTTON, &ctl_pdb); - Controller->get_packet(ctfBANK_LEFTBUTTON, &ctl_blb); - Controller->get_packet(ctfBANK_RIGHTBUTTON, &ctl_brb); + Controller->get_packet(ctfFORWARD_THRUSTAXIS, &ctl_z, ctAnalog); + Controller->get_packet(ctfUP_THRUSTAXIS, &ctl_y, ctAnalog); + Controller->get_packet(ctfRIGHT_THRUSTAXIS, &ctl_x, ctAnalog); + Controller->get_packet(ctfPITCH_DOWNAXIS, &ctl_p, ctAnalog); + Controller->get_packet(ctfBANK_RIGHTAXIS, &ctl_b, ctAnalog); + Controller->get_packet(ctfHEADING_RIGHTAXIS, &ctl_h, ctAnalog); + Controller->get_packet(ctfUP_BUTTON, &ctl_povu, ctAnalog); + Controller->get_packet(ctfDOWN_BUTTON, &ctl_povd, ctAnalog); + Controller->get_packet(ctfRIGHT_BUTTON, &ctl_povr, ctAnalog); + Controller->get_packet(ctfLEFT_BUTTON, &ctl_povl, ctAnalog); + Controller->get_packet(ctfFORWARD_BUTTON, &ctl_fb, ctAnalog); + Controller->get_packet(ctfREVERSE_BUTTON, &ctl_rb, ctAnalog); + Controller->get_packet(ctfAFTERBURN_BUTTON, &ctl_afterburn, ctAnalog); + Controller->get_packet(ctfHEADING_LEFTBUTTON, &ctl_hlb, ctAnalog); + Controller->get_packet(ctfHEADING_RIGHTBUTTON, &ctl_hrb, ctAnalog); + Controller->get_packet(ctfPITCH_UPBUTTON, &ctl_pub, ctAnalog); + Controller->get_packet(ctfPITCH_DOWNBUTTON, &ctl_pdb, ctAnalog); + Controller->get_packet(ctfBANK_LEFTBUTTON, &ctl_blb, ctAnalog); + Controller->get_packet(ctfBANK_RIGHTBUTTON, &ctl_brb, ctAnalog); // do x and y thrust controls->sideways_thrust += ctl_x.value; @@ -935,40 +935,40 @@ void DoControllerMovement(game_controls *controls) { } // do button heading - if (ctl_hlb.value) - controls->heading_thrust += (-1.0f); - if (ctl_hrb.value) - controls->heading_thrust += (1.0f); + if (ctl_hlb.value > 0.0f) + controls->heading_thrust += ctl_hlb.value; + if (ctl_hrb.value > 0.0f) + controls->heading_thrust -= ctl_hlb.value; // do button pitch - if (ctl_pub.value) - controls->pitch_thrust += (-1.0f); - if (ctl_pdb.value) - controls->pitch_thrust += (1.0f); + if (ctl_pub.value > 0.0f) + controls->pitch_thrust -= ctl_pub.value; + if (ctl_pdb.value > 0.0f) + controls->pitch_thrust += ctl_pdb.value; // do forward thrust based off of button values. controls->forward_thrust += ((ctl_fb.value - ctl_rb.value) / Frametime); // do button banking - if (ctl_blb.value) - controls->bank_thrust += (1.0f); - if (ctl_brb.value) - controls->bank_thrust += (-1.0f); + if (ctl_blb.value > 0.0f) + controls->bank_thrust += ctl_blb.value; + if (ctl_brb.value > 0.0f) + controls->bank_thrust -= ctl_blb.value; // do button sliding. use control frametime to set sliding times per frame. // note that vertical and sideways thrusts are dependent on what the keyboard controller // set these values to. so we save our own slidetimes. - if (ctl_povu.value) { - controls->vertical_thrust += (1.0f); + if (ctl_povu.value > 0.0f) { + controls->vertical_thrust += ctl_povu.value; } - if (ctl_povd.value) { - controls->vertical_thrust -= (1.0f); + if (ctl_povd.value > 0.0f) { + controls->vertical_thrust -= ctl_povd.value; } - if (ctl_povr.value) { - controls->sideways_thrust += (1.0f); + if (ctl_povr.value > 0.0f) { + controls->sideways_thrust += ctl_povr.value; } - if (ctl_povl.value) { - controls->sideways_thrust -= (1.0f); + if (ctl_povl.value > 0.0f) { + controls->sideways_thrust -= ctl_povl.value; } } diff --git a/Descent3/CtlCfgElem.cpp b/Descent3/CtlCfgElem.cpp index 3d9885720..c7e59afd4 100644 --- a/Descent3/CtlCfgElem.cpp +++ b/Descent3/CtlCfgElem.cpp @@ -1,5 +1,5 @@ /* -* Descent 3 +* Descent 3 * Copyright (C) 2024 Parallax Software * * This program is free software: you can redistribute it and/or modify @@ -491,6 +491,7 @@ const char *cfg_binding_text(ct_type ctype, uint8_t ctrl, uint8_t binding) { case ctPOV2: case ctPOV3: case ctPOV4: + case ctAnalogTrigger: case ctMouseButton: case ctButton: case ctMouseAxis: @@ -513,7 +514,7 @@ const char *cfg_binding_text(ct_type ctype, uint8_t ctrl, uint8_t binding) { class cfg_element_ui : public newuiMessageBox { uint8_t m_element; // element passed and returned. uint8_t m_controller; // controller. - int8_t m_alpha; // used for fx. + int8_t m_alpha; // used for fx. ct_type m_type; public: @@ -812,6 +813,7 @@ bool cfg_element::Configure(ct_type *new_elem_type, uint8_t *controller, uint8_t case ctPOV2: case ctPOV3: case ctPOV4: + case ctAnalogTrigger: case ctAxis: case ctMouseAxis: configure = true; @@ -872,6 +874,7 @@ void cfg_element_ui::Create(const char *title, ct_type type, uint8_t controller, case ctPOV2: case ctPOV3: case ctPOV4: + case ctAnalogTrigger: sheet->AddText(TXT_CTLBINDHELP2_0); sheet->AddText(TXT_CTLBINDHELP2_1); break; @@ -936,7 +939,8 @@ int cfg_element_ui::DoUI() { case ctPOV: case ctPOV2: case ctPOV3: - case ctPOV4: { + case ctPOV4: + case ctAnalogTrigger: { ct_config_data ccfgdata; ct_type new_type; @@ -960,6 +964,10 @@ int cfg_element_ui::DoUI() { if (!GCV_VALID_RESULT(ccfgdata)) { ccfgdata = Controller->get_controller_value(ctButton); // read hats before buttons new_type = ctButton; + if (!GCV_VALID_RESULT(ccfgdata)) { + ccfgdata = Controller->get_controller_value(ctAnalogTrigger); + new_type = ctAnalogTrigger; + } } } } diff --git a/Descent3/CtlCfgElem.h b/Descent3/CtlCfgElem.h index 2e5f34cff..6db85b9ed 100644 --- a/Descent3/CtlCfgElem.h +++ b/Descent3/CtlCfgElem.h @@ -131,6 +131,7 @@ static inline void parse_config_data(tCfgDataParts *parts, ct_type type0, ct_typ case ctPOV: case ctPOV2: case ctPOV3: + case ctAnalogTrigger: case ctPOV4: parts->bind_0 = CONTROLLER_CTL1_VALUE(CONTROLLER_VALUE(cfgdata)); break; @@ -150,6 +151,7 @@ static inline void parse_config_data(tCfgDataParts *parts, ct_type type0, ct_typ case ctPOV2: case ctPOV3: case ctPOV4: + case ctAnalogTrigger: parts->bind_1 = CONTROLLER_CTL2_VALUE(CONTROLLER_VALUE(cfgdata)); break; default: diff --git a/Descent3/ctlconfig.cpp b/Descent3/ctlconfig.cpp index 88bdb1dfc..7fde25181 100644 --- a/Descent3/ctlconfig.cpp +++ b/Descent3/ctlconfig.cpp @@ -1005,6 +1005,7 @@ void ctl_cfg_element_options_dialog(int16_t fnid) { case ctPOV2: case ctPOV3: case ctPOV4: + case ctAnalogTrigger: strcpy(str, TXT_CFGHELP_BTNS); break; default: diff --git a/ddio/controller.h b/ddio/controller.h index d4793cba2..f4d1d60fd 100644 --- a/ddio/controller.h +++ b/ddio/controller.h @@ -139,7 +139,8 @@ enum ct_type { ctMouseButton, ctPOV2, ctPOV3, - ctPOV4 // auxillary POV values. + ctPOV4, // auxillary POV values. + ctAnalogTrigger }; struct ct_function { diff --git a/ddio/sdlcontroller.cpp b/ddio/sdlcontroller.cpp index 35eadbb00..9baa5607d 100644 --- a/ddio/sdlcontroller.cpp +++ b/ddio/sdlcontroller.cpp @@ -241,6 +241,9 @@ const char *sdlgameController::get_binding_text(ct_type type, uint8_t ctrl, uint } break; } + case ctAnalogTrigger: + snprintf(binding_text, sizeof(binding_text), "J%d:trig%d", (ctrl - 2) + 1, bind); + break; case ctKey: break; @@ -305,62 +308,25 @@ ct_config_data sdlgameController::get_controller_value(ct_type type_req) { break; case ctAxis: - for (i = 2; i < m_NumControls; i++) { - float pos; - float limit; - unsigned ctl = CONTROLLER_CTL_INFO(i, NULL_CONTROLLER); - - if (m_ControlList[i].flags & CTF_V_AXIS) { - limit = (m_ControlList[i].sens[CT_V_AXIS - 1] > 1.5f) ? 0.95f - : (m_ControlList[i].sens[CT_V_AXIS - 1] > 1.0f) ? 0.80f - : (m_ControlList[i].sens[CT_V_AXIS - 1] / 2); - pos = get_axis_value(i, CT_V_AXIS, ctAnalog); - if (fabs(pos) > limit) - val = MAKE_CONFIG_DATA(ctl, CONTROLLER_CTL_VALUE(CT_V_AXIS, NULL_BINDING)); - } - if (m_ControlList[i].flags & CTF_U_AXIS) { - limit = (m_ControlList[i].sens[CT_U_AXIS - 1] > 1.5f) ? 0.95f - : (m_ControlList[i].sens[CT_U_AXIS - 1] > 1.0f) ? 0.80f - : (m_ControlList[i].sens[CT_U_AXIS - 1] / 2); - pos = get_axis_value(i, CT_U_AXIS, ctAnalog); - if (fabs(pos) > limit) - val = MAKE_CONFIG_DATA(ctl, CONTROLLER_CTL_VALUE(CT_U_AXIS, NULL_BINDING)); - } - if (m_ControlList[i].flags & CTF_R_AXIS) { - limit = (m_ControlList[i].sens[CT_R_AXIS - 1] > 1.5f) ? 0.95f - : (m_ControlList[i].sens[CT_R_AXIS - 1] > 1.0f) ? 0.80f - : (m_ControlList[i].sens[CT_R_AXIS - 1] / 2); - pos = get_axis_value(i, CT_R_AXIS, ctAnalog); - if (fabs(pos) > limit) - val = MAKE_CONFIG_DATA(ctl, CONTROLLER_CTL_VALUE(CT_R_AXIS, NULL_BINDING)); - } - if (m_ControlList[i].flags & CTF_Z_AXIS) { - limit = (m_ControlList[i].sens[CT_Z_AXIS - 1] > 1.5f) ? 0.95f - : (m_ControlList[i].sens[CT_Z_AXIS - 1] > 1.0f) ? 0.80f - : (m_ControlList[i].sens[CT_Z_AXIS - 1] / 2); - pos = get_axis_value(i, CT_Z_AXIS, ctAnalog); - if (fabs(pos) > limit) - val = MAKE_CONFIG_DATA(ctl, CONTROLLER_CTL_VALUE(CT_Z_AXIS, NULL_BINDING)); - } - if (m_ControlList[i].flags & CTF_Y_AXIS) { - limit = (m_ControlList[i].sens[CT_Y_AXIS - 1] > 1.5f) ? 0.95f - : (m_ControlList[i].sens[CT_Y_AXIS - 1] > 1.0f) ? 0.80f - : (m_ControlList[i].sens[CT_Y_AXIS - 1] / 2); - pos = get_axis_value(i, CT_Y_AXIS, ctAnalog); - if (fabs(pos) > limit) - val = MAKE_CONFIG_DATA(ctl, CONTROLLER_CTL_VALUE(CT_Y_AXIS, NULL_BINDING)); - } - if (m_ControlList[i].flags & CTF_X_AXIS) { - limit = (m_ControlList[i].sens[CT_X_AXIS - 1] > 1.5f) ? 0.95f - : (m_ControlList[i].sens[CT_X_AXIS - 1] > 1.0f) ? 0.80f - : (m_ControlList[i].sens[CT_X_AXIS - 1] / 2); - pos = get_axis_value(i, CT_X_AXIS, ctAnalog); - if (fabs(pos) > limit) - val = MAKE_CONFIG_DATA(ctl, CONTROLLER_CTL_VALUE(CT_X_AXIS, NULL_BINDING)); - } + for (int controllerId = 2; controllerId < m_NumControls; controllerId++) { + get_controller_axis_value(controllerId, CTF_V_AXIS, CT_V_AXIS, &val); + get_controller_axis_value(controllerId, CTF_U_AXIS, CT_U_AXIS, &val); + get_controller_axis_value(controllerId, CTF_R_AXIS, CT_R_AXIS, &val); + get_controller_axis_value(controllerId, CTF_Z_AXIS, CT_Z_AXIS, &val); + get_controller_axis_value(controllerId, CTF_Y_AXIS, CT_Y_AXIS, &val); + get_controller_axis_value(controllerId, CTF_X_AXIS, CT_X_AXIS, &val); + } + break; + case ctAnalogTrigger: + for (int controllerId = 2; controllerId < m_NumControls; controllerId++) { + get_controller_trigger_value(controllerId, CTF_V_AXIS, CT_V_AXIS, &val); + get_controller_trigger_value(controllerId, CTF_U_AXIS, CT_U_AXIS, &val); + get_controller_trigger_value(controllerId, CTF_R_AXIS, CT_R_AXIS, &val); + get_controller_trigger_value(controllerId, CTF_Z_AXIS, CT_Z_AXIS, &val); + get_controller_trigger_value(controllerId, CTF_Y_AXIS, CT_Y_AXIS, &val); + get_controller_trigger_value(controllerId, CTF_X_AXIS, CT_X_AXIS, &val); } break; - case ctMouseAxis: { float pos = 0.0f; int ctl = CONTROLLER_CTL_INFO(1, NULL_CONTROLLER), i = 1; @@ -369,34 +335,34 @@ ct_config_data sdlgameController::get_controller_value(ct_type type_req) { if (m_ControlList[i].flags & CTF_V_AXIS) { pos = get_axis_value(i, CT_V_AXIS, ctAnalog); - if (fabs(pos) >= 0.50f) + if (std::abs(pos) >= 0.50f) val = MAKE_CONFIG_DATA(ctl, CONTROLLER_CTL_VALUE(CT_V_AXIS, NULL_BINDING)); } if (m_ControlList[i].flags & CTF_U_AXIS) { pos = get_axis_value(i, CT_U_AXIS, ctAnalog); - if (fabs(pos) >= 0.50f) + if (std::abs(pos) >= 0.50f) val = MAKE_CONFIG_DATA(ctl, CONTROLLER_CTL_VALUE(CT_U_AXIS, NULL_BINDING)); } if (m_ControlList[i].flags & CTF_R_AXIS) { pos = get_axis_value(i, CT_R_AXIS, ctAnalog); - if (fabs(pos) >= 0.90f) + if (std::abs(pos) >= 0.90f) val = MAKE_CONFIG_DATA(ctl, CONTROLLER_CTL_VALUE(CT_R_AXIS, NULL_BINDING)); } if (m_ControlList[i].flags & CTF_Z_AXIS) { pos = get_axis_value(i, CT_Z_AXIS, ctAnalog); - if (fabs(pos) >= 0.50f) + if (std::abs(pos) >= 0.50f) val = MAKE_CONFIG_DATA(ctl, CONTROLLER_CTL_VALUE(CT_Z_AXIS, NULL_BINDING)); } if (m_ControlList[i].flags & CTF_Y_AXIS) { pos = get_axis_value(i, CT_Y_AXIS, ctAnalog); // mprintf(0, "y=%.2f ", pos); - if (fabs(pos) >= 0.90f) + if (std::abs(pos) >= 0.90f) val = MAKE_CONFIG_DATA(ctl, CONTROLLER_CTL_VALUE(CT_Y_AXIS, NULL_BINDING)); } if (m_ControlList[i].flags & CTF_X_AXIS) { pos = get_axis_value(i, CT_X_AXIS, ctAnalog); // mprintf(0, "x=%.2f\n", pos); - if (fabs(pos) >= 0.90f) + if (std::abs(pos) >= 0.90f) val = MAKE_CONFIG_DATA(ctl, CONTROLLER_CTL_VALUE(CT_X_AXIS, NULL_BINDING)); } } break; @@ -441,6 +407,37 @@ ct_config_data sdlgameController::get_controller_value(ct_type type_req) { return val; } +void sdlgameController::get_controller_axis_value(int controllerId, unsigned int axis_ctf_flag, uint8_t axis_ct_flag, + ct_config_data *val) { + + if ((m_ControlList[controllerId].flags & axis_ctf_flag) && + !(m_ControlList[controllerId].axis_is_trigger & axis_ctf_flag)) { + float limit = (m_ControlList[controllerId].sens[axis_ct_flag - 1] > 1.5f) ? 0.95f + : (m_ControlList[controllerId].sens[axis_ct_flag - 1] > 1.0f) + ? 0.80f + : (m_ControlList[controllerId].sens[axis_ct_flag - 1] / 2); + float pos = get_axis_value(controllerId, axis_ct_flag, ctAnalog); + if (std::abs(pos) > limit) + *val = MAKE_CONFIG_DATA(CONTROLLER_CTL_INFO(controllerId, NULL_CONTROLLER), + CONTROLLER_CTL_VALUE(axis_ct_flag, NULL_BINDING)); + } +} + +void sdlgameController::get_controller_trigger_value(int controllerId, unsigned int axis_ctf_flag, uint8_t axis_ct_flag, + ct_config_data *val) { + if ((m_ControlList[controllerId].flags & axis_ctf_flag) && + (m_ControlList[controllerId].axis_is_trigger & axis_ctf_flag)) { + float limit = (m_ControlList[controllerId].sens[axis_ct_flag - 1] > 1.5f) ? 0.5f + : (m_ControlList[controllerId].sens[axis_ct_flag - 1] > 1.0f) + ? 0.3f + : (m_ControlList[controllerId].sens[axis_ct_flag - 1] / 4); + float pos = get_axis_value(controllerId, axis_ct_flag, ctAnalog); + if (pos > limit) + *val = MAKE_CONFIG_DATA(CONTROLLER_CTL_INFO(controllerId, NULL_CONTROLLER), + CONTROLLER_CTL_VALUE(axis_ct_flag, NULL_BINDING)); + } +} + // sets the configuration of a function (type must be of an array == CTLBINDS_PER_FUNC) void sdlgameController::set_controller_function(int id, const ct_type *type, ct_config_data value, const uint8_t *flags) { @@ -528,6 +525,8 @@ bool sdlgameController::get_packet(int id, ct_packet *packet, ct_format alt_form case ctMouseAxis: packet->flags |= CTPK_MOUSE; + case ctAnalogTrigger: + val = get_trigger_value(controller, value, alt_format); case ctAxis: val = get_axis_value(controller, value, alt_format, (m_ElementList[id].flags[i] & CTFNF_INVERT) ? true : false); if (m_ElementList[id].flags[i] & CTFNF_INVERT) { @@ -538,7 +537,6 @@ bool sdlgameController::get_packet(int id, ct_packet *packet, ct_format alt_form } } break; - case ctMouseButton: packet->flags |= CTPK_MOUSE; case ctButton: @@ -611,6 +609,7 @@ void sdlgameController::set_axis_sensitivity(ct_type axis_type, uint8_t axis, fl } } +#include // assigns an individual function int sdlgameController::assign_function(ct_function *func) { // for now this is a straight forward translation (that is, no mapping of needs to controller @@ -628,6 +627,7 @@ int sdlgameController::assign_function(ct_function *func) { case ctKey: elem.ctl[i] = 0; break; + case ctAnalogTrigger: case ctAxis: elem.ctl[i] = get_axis_controller(func->value[i]); break; @@ -707,13 +707,9 @@ unsigned sdlgameController::get_joy_raw_values(int *x, int *y) { return 0; } -gameController *CreateController(int num_funcs, ct_function *funcs) { - return new sdlgameController(num_funcs, funcs); -} +gameController *CreateController(int num_funcs, ct_function *funcs) { return new sdlgameController(num_funcs, funcs); } -void DestroyController(gameController *ctl) { - delete ctl; -} +void DestroyController(gameController *ctl) { delete ctl; } // activates or deactivates mouse and or controller void sdlgameController::mask_controllers(bool joystick, bool mouse) { @@ -908,12 +904,21 @@ bool sdlgameController::enum_controllers() { ((jc.axes_mask & JOYFLAG_VVALID) ? CTF_V_AXIS : 0) | ((jc.axes_mask & JOYFLAG_POVVALID) ? CTF_POV : 0) | ((jc.axes_mask & JOYFLAG_POV2VALID) ? CTF_POV2 : 0) | ((jc.axes_mask & JOYFLAG_POV3VALID) ? CTF_POV3 : 0) | ((jc.axes_mask & JOYFLAG_POV4VALID) ? CTF_POV4 : 0); - m_ControlList[num_devs].normalizer[0] = (jc.maxx - jc.minx) / 2.0f; - m_ControlList[num_devs].normalizer[1] = (jc.maxy - jc.miny) / 2.0f; - m_ControlList[num_devs].normalizer[2] = (jc.maxz - jc.minz) / 2.0f; - m_ControlList[num_devs].normalizer[3] = (jc.maxr - jc.minr) / 2.0f; - m_ControlList[num_devs].normalizer[4] = (jc.maxu - jc.minu) / 2.0f; - m_ControlList[num_devs].normalizer[5] = (jc.maxv - jc.minv) / 2.0f; + + m_ControlList[num_devs].axis_is_trigger = ((jc.trigger_axis_mask & JOYFLAG_XVALID) ? CTF_X_AXIS : 0) | + ((jc.trigger_axis_mask & JOYFLAG_YVALID) ? CTF_Y_AXIS : 0) | + ((jc.trigger_axis_mask & JOYFLAG_ZVALID) ? CTF_Z_AXIS : 0) | + ((jc.trigger_axis_mask & JOYFLAG_RVALID) ? CTF_R_AXIS : 0) | + ((jc.trigger_axis_mask & JOYFLAG_UVALID) ? CTF_U_AXIS : 0) | + ((jc.trigger_axis_mask & JOYFLAG_VVALID) ? CTF_V_AXIS : 0); + + int minV = -32768, maxV = 32768; + m_ControlList[num_devs].normalizer[0] = (maxV - minV) / 2.0f; + m_ControlList[num_devs].normalizer[1] = (maxV - minV) / 2.0f; + m_ControlList[num_devs].normalizer[2] = (maxV - minV) / 2.0f; + m_ControlList[num_devs].normalizer[3] = (maxV - minV) / 2.0f; + m_ControlList[num_devs].normalizer[4] = (maxV - minV) / 2.0f; + m_ControlList[num_devs].normalizer[5] = (maxV - minV) / 2.0f; for (i = 0; i < CT_NUM_AXES; i++) { m_ControlList[num_devs].sens[i] = 1.0f; @@ -981,9 +986,14 @@ int8_t sdlgameController::get_axis_controller(uint8_t axis) { if (axis == NULL_BINDING) return NULL_LNXCONTROLLER; - for (int i = 2; i < m_NumControls; i++) - if ((m_ControlList[i].flags & (1 << (axis - 1))) && m_ControlList[i].id != CTID_INVALID) + int axis_mask = (1 << (axis - 1)); + + for (int i = 2; i < m_NumControls; i++) { + if ((m_ControlList[i].flags & axis_mask) && m_ControlList[i].id != CTID_INVALID && + !(m_ControlList[i].axis_is_trigger & axis_mask)) { return i; + } + } return NULL_LNXCONTROLLER; } @@ -1023,6 +1033,7 @@ void sdlgameController::assign_element(int id, ct_element *elem) { case ctPOV2: case ctPOV3: case ctPOV4: + case ctAnalogTrigger: // if (!(m_ControlList[elem->ctl[i]].flags & CTF_POV)) // m_ElementList[id].ctl[i] = NULL_WINCONTROLLER; break; @@ -1095,6 +1106,7 @@ float sdlgameController::get_button_value(int8_t controller, ct_format format, u break; case ctDigital: + case ctAnalog: if (m_ControlList[controller].id == CTID_MOUSE) { if (m_MseState.btnmask & (1 << button)) val = 1.0f; @@ -1274,6 +1286,85 @@ float sdlgameController::get_axis_value(int8_t controller, uint8_t axis, ct_form return val; } +float sdlgameController::get_trigger_value(int8_t controller, uint8_t axis, ct_format format) { + struct sdlgameController::t_controller *ctldev; + float val = 0.0f; + float normalizer, axisval = 0, nullzone; //, senszone; + + if (controller <= NULL_LNXCONTROLLER || controller >= CT_MAX_CONTROLLERS) { + return 0.0f; + } + + ctldev = &m_ControlList[controller]; + if (ctldev->id == CTID_INVALID) { + return 0.0f; + } + + // verify controller axis + if (!CHECK_FLAG(ctldev->flags, 1 << (axis - 1))) { + return val; + } + + // get raw value + switch (axis) { + case CT_X_AXIS: + axisval = m_ExtCtlStates[ctldev->id].x; + break; + case CT_Y_AXIS: + axisval = m_ExtCtlStates[ctldev->id].y; + break; + case CT_Z_AXIS: + axisval = m_ExtCtlStates[ctldev->id].z; + break; + case CT_R_AXIS: + axisval = (float)m_ExtCtlStates[ctldev->id].r; + break; + case CT_U_AXIS: + axisval = (float)m_ExtCtlStates[ctldev->id].u; + break; + case CT_V_AXIS: + axisval = (float)m_ExtCtlStates[ctldev->id].v; + break; + default: + Int3(); // NOT A VALID AXIS + } + + // create normalizer + axis--; + normalizer = ctldev->normalizer[axis]; + nullzone = (m_ControlList[controller].deadzone < 0.05f) ? 0.05f : m_ControlList[controller].deadzone; + + val = axisval / normalizer; + val = val - ((ctldev->id == CTID_MOUSE) ? 0.0f : 1.0f); // joystick needs to be normalized to -1.0 to 1.0 + + // calculate adjusted value + if (val > nullzone) { + val = (val - nullzone) / (1.0f - nullzone); + } else if (val < -nullzone) { + val = (val + nullzone) / (1.0f - nullzone); + } else { + val = 0.0f; + } + val = ctldev->sensmod[axis] * ctldev->sens[axis] * val; + val = val + 1.0f; + + val = std::clamp(val, 0.0f, 2.0f); + + // determine value based off requested format. + if (format == ctDigital) { + if (val < 0.5f) + val = 0.0f; + else + val = 1.0f; + } else if (format == ctAnalog) { + val = val - 1.0f; + } else { + val = 0.0f; + LOG_WARNING << "unsupported format for function sdlgameController::get_trigger_value."; + } + + return val; +} // do some pov stuff float sdlgameController::get_pov_value(int8_t controller, ct_format format, uint8_t pov_number, uint8_t pov) { float val = 0.0f; @@ -1308,6 +1399,7 @@ float sdlgameController::get_pov_value(int8_t controller, ct_format format, uint } break; + case ctAnalog: case ctDigital: { if (m_ExtCtlStates[m_ControlList[controller].id].pov[pov_number] == JOYPOV_CENTER) val = 0.0f; @@ -1396,12 +1488,12 @@ int CTLLex(const char *command) { // okay, now search for a '****.ctl' file in the Base_directories void sdlgameController::parse_ctl_file(int devnum, const char *ctlname) { - for (auto base_directories_iterator = Base_directories.rbegin(); - base_directories_iterator != Base_directories.rend(); + for (auto base_directories_iterator = Base_directories.rbegin(); base_directories_iterator != Base_directories.rend(); ++base_directories_iterator) { // parse each file until we find a name match, no name match, just return ddio_DoForeachFile( - *base_directories_iterator, std::regex(".*\\.ctl"), [this, &devnum, &ctlname](const std::filesystem::path &path) { + *base_directories_iterator, std::regex(".*\\.ctl"), + [this, &devnum, &ctlname](const std::filesystem::path &path) { InfFile file; bool found_name = false; diff --git a/ddio/sdlcontroller.h b/ddio/sdlcontroller.h index 0cb39e0a6..a09a816a3 100644 --- a/ddio/sdlcontroller.h +++ b/ddio/sdlcontroller.h @@ -70,6 +70,12 @@ class sdlgameController : public gameController { // returns the value of a requested controller type. make sure you flush the controller before polling. ct_config_data get_controller_value(ct_type type_req) override; + // fill `val` with the axis and controller values if axis value is over a threshold. Used for control mapping. + void get_controller_axis_value(int controllerId, unsigned int axis_ctf_flag, uint8_t axis_ct_flag, ct_config_data* val); + + // fill `val` with the axis and controller values if trigger value is over a threshold + void get_controller_trigger_value(int controllerId, unsigned int axis_ctf_flag, uint8_t axis_ct_flag, ct_config_data* val); + // sets the configuration of a function (type must be of an array == CTLBINDS_PER_FUNC) void set_controller_function(int id, const ct_type *type, ct_config_data value, const uint8_t *flags) override; @@ -112,6 +118,7 @@ class sdlgameController : public gameController { struct t_controller { int id = 0; uint16_t flags = 0; + uint16_t axis_is_trigger = 0; uint16_t buttons = 0; unsigned btnmask = 0; float normalizer[CT_NUM_AXES]{}; @@ -146,6 +153,9 @@ class sdlgameController : public gameController { // note controller is index into ControlList. float get_axis_value(int8_t controller, uint8_t axis, ct_format format, bool invert = false); + // get value of analog button/trigger + float get_trigger_value(int8_t controller, uint8_t axis, ct_format format); + // get value of button in seconds, presses, etc. float get_button_value(int8_t controller, ct_format format, uint8_t button); diff --git a/ddio/sdljoy.cpp b/ddio/sdljoy.cpp index eb59a2c57..304d9c694 100644 --- a/ddio/sdljoy.cpp +++ b/ddio/sdljoy.cpp @@ -1,5 +1,5 @@ /* -* Descent 3 +* Descent 3 * Copyright (C) 2024 Parallax Software * * This program is free software: you can redistribute it and/or modify @@ -67,7 +67,9 @@ */ #include +#include #include +#include #include // rcg06182000 need this for specific joystick stuff. @@ -150,36 +152,28 @@ static bool joy_InitStick(tJoystick joy, char *server_adr) { strncpy(caps.name, SDL_JoystickNameForIndex(joy), sizeof(caps.name) - 1); caps.num_btns = SDL_JoystickNumButtons(stick); int axes = SDL_JoystickNumAxes(stick); - switch (axes) { - default: - // Fall through to 6 axes - case 6: - caps.axes_mask |= JOYFLAG_VVALID; - caps.minv = -32767; - caps.maxv = 32768; - case 5: - caps.axes_mask |= JOYFLAG_UVALID; - caps.minu = -32767; - caps.maxu = 32768; - case 4: - caps.axes_mask |= JOYFLAG_RVALID; - caps.minr = -32767; - caps.maxr = 32768; - case 3: - caps.axes_mask |= JOYFLAG_ZVALID; - caps.minz = -32767; - caps.maxz = 32768; - case 2: - caps.axes_mask |= JOYFLAG_YVALID; - caps.miny = -32767; - caps.maxy = 32768; - case 1: - caps.axes_mask |= JOYFLAG_XVALID; - caps.minx = -32767; - caps.maxx = 32768; - case 0: - break; + + + + std::array axis_flags{JOYFLAG_XVALID, JOYFLAG_YVALID, JOYFLAG_ZVALID, + JOYFLAG_RVALID, JOYFLAG_UVALID, JOYFLAG_VVALID}; + for (int axis = 0; axis < SDL_JoystickNumAxes(stick); axis++) { + caps.axes_mask |= axis_flags[axis]; + + int16_t initialVal = 0; + SDL_JoystickGetAxisInitialState(stick, axis, &initialVal); + LOG_DEBUG << "Initial axis " << axis << " value is " << initialVal; + + if (initialVal < -32768 * 0.75) { + // Axis is an analog button/trigger, because it's initial value + // is at the start of the range and not in the middle + LOG_DEBUG << "Axis " << axis << " is an analog button"; + caps.trigger_axis_mask |= axis_flags[axis]; + } else { + LOG_DEBUG << "Axis " << axis << " is a bidirectional axis"; + } } + int hats = SDL_JoystickNumHats(stick); switch (hats) { default: diff --git a/lib/joystick.h b/lib/joystick.h index b0d07e46a..fb87c7c37 100644 --- a/lib/joystick.h +++ b/lib/joystick.h @@ -108,13 +108,8 @@ typedef int tJoystick; struct tJoyInfo { char name[128]; unsigned axes_mask; + unsigned trigger_axis_mask; unsigned num_btns; - int minx, maxx; - int miny, maxy; - int minz, maxz; - int minr, maxr; - int minu, maxu; - int minv, maxv; }; // shared between joystick remote server and local client.