mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-22 14:30:29 +00:00
Introduces an intermediary for digital <-> analogue conversion.
This commit is contained in:
parent
42d21ea3a9
commit
2954373115
@ -25,14 +25,14 @@ class MultiJoystick: public Inputs::Joystick {
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Input> get_inputs() override {
|
||||
std::vector<Input> inputs;
|
||||
|
||||
for(const auto &joystick: joysticks_) {
|
||||
std::vector<Input> joystick_inputs = joystick->get_inputs();
|
||||
for(const auto &input: joystick_inputs) {
|
||||
if(std::find(inputs.begin(), inputs.end(), input) != inputs.end()) {
|
||||
inputs.push_back(input);
|
||||
std::vector<Input> &get_inputs() override {
|
||||
if(inputs.empty()) {
|
||||
for(const auto &joystick: joysticks_) {
|
||||
std::vector<Input> joystick_inputs = joystick->get_inputs();
|
||||
for(const auto &input: joystick_inputs) {
|
||||
if(std::find(inputs.begin(), inputs.end(), input) != inputs.end()) {
|
||||
inputs.push_back(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -45,6 +45,13 @@ class MultiJoystick: public Inputs::Joystick {
|
||||
joystick->set_input(digital_input, is_active);
|
||||
}
|
||||
}
|
||||
|
||||
void set_input(const Input &digital_input, float value) override {
|
||||
for(const auto &joystick: joysticks_) {
|
||||
joystick->set_input(digital_input, value);
|
||||
}
|
||||
}
|
||||
|
||||
void reset_all_inputs() override {
|
||||
for(const auto &joystick: joysticks_) {
|
||||
joystick->reset_all_inputs();
|
||||
@ -52,6 +59,7 @@ class MultiJoystick: public Inputs::Joystick {
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Input> inputs;
|
||||
std::vector<Inputs::Joystick *> joysticks_;
|
||||
};
|
||||
|
||||
|
@ -21,6 +21,10 @@ class Joystick {
|
||||
public:
|
||||
virtual ~Joystick() {}
|
||||
|
||||
/*!
|
||||
Defines a single input, any individually-measured thing — a fire button or
|
||||
other digital control, an analogue axis, or a button with a symbol on it.
|
||||
*/
|
||||
struct Input {
|
||||
/// Defines the broad type of the input.
|
||||
enum Type {
|
||||
@ -35,10 +39,25 @@ class Joystick {
|
||||
};
|
||||
const Type type;
|
||||
|
||||
bool is_digital_axis() const {
|
||||
return type < Type::Horizontal;
|
||||
}
|
||||
bool is_analogue_axis() const {
|
||||
return type >= Type::Horizontal && type < Type::Fire;
|
||||
}
|
||||
bool is_axis() const {
|
||||
return type < Type::Fire;
|
||||
}
|
||||
bool is_button() const {
|
||||
return type >= Type::Fire;
|
||||
}
|
||||
|
||||
enum Precision {
|
||||
Analogue, Digital
|
||||
};
|
||||
const Precision precision;
|
||||
Precision precision() const {
|
||||
return is_analogue_axis() ? Precision::Analogue : Precision::Digital;
|
||||
}
|
||||
|
||||
/*!
|
||||
Holds extra information pertaining to the input.
|
||||
@ -51,7 +70,7 @@ class Joystick {
|
||||
*/
|
||||
union Info {
|
||||
struct {
|
||||
int index;
|
||||
size_t index;
|
||||
} control;
|
||||
struct {
|
||||
wchar_t symbol;
|
||||
@ -60,18 +79,16 @@ class Joystick {
|
||||
Info info;
|
||||
// TODO: Find a way to make the above safely const; may mean not using a union.
|
||||
|
||||
Input(Type type, int index = 0, Precision precision = Precision::Digital) :
|
||||
type(type),
|
||||
precision(precision) {
|
||||
Input(Type type, size_t index = 0) :
|
||||
type(type) {
|
||||
info.control.index = index;
|
||||
}
|
||||
Input(wchar_t symbol) : type(Key), precision(Precision::Digital) {
|
||||
Input(wchar_t symbol) : type(Key) {
|
||||
info.key.symbol = symbol;
|
||||
}
|
||||
|
||||
bool operator == (const Input &rhs) {
|
||||
if(rhs.type != type) return false;
|
||||
if(rhs.precision != precision) return false;
|
||||
if(rhs.type == Key) {
|
||||
return rhs.info.key.symbol == info.key.symbol;
|
||||
} else {
|
||||
@ -80,20 +97,125 @@ class Joystick {
|
||||
}
|
||||
};
|
||||
|
||||
virtual std::vector<Input> get_inputs() = 0;
|
||||
/// @returns The list of all inputs defined on this joystick.
|
||||
virtual std::vector<Input> &get_inputs() = 0;
|
||||
|
||||
// Host interface. Note that the two set_inputs have logic to map
|
||||
// between analogue and digital inputs; if you override
|
||||
/*!
|
||||
Sets the digital value of @c input. This may have direct effect or
|
||||
influence an analogue value; e.g. if the caller declares that ::Left is
|
||||
active but this joystick has only an analogue horizontal axis, this will
|
||||
cause a change to that analogue value.
|
||||
*/
|
||||
virtual void set_input(const Input &input, bool is_active) = 0;
|
||||
virtual void set_input(const Input &input, float value) {}
|
||||
|
||||
/*!
|
||||
Sets the analogue value of @c input. If the input is actually digital,
|
||||
or if there is a digital input with a corresponding meaning (e.g. ::Left
|
||||
versus the horizontal axis), this may cause a digital input to be set.
|
||||
|
||||
@c value should be in the range [0.0, 1.0].
|
||||
*/
|
||||
virtual void set_input(const Input &input, float value) = 0;
|
||||
|
||||
/*!
|
||||
Sets all inputs to their resting state.
|
||||
*/
|
||||
virtual void reset_all_inputs() {
|
||||
for(const auto &input: get_inputs()) {
|
||||
set_input(input, false);
|
||||
if(input.precision() == Input::Precision::Digital)
|
||||
set_input(input, false);
|
||||
else
|
||||
set_input(input, 0.5f);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
ConcreteJoystick is the class that it's expected most machines will actually subclass;
|
||||
it accepts a set of Inputs at construction and thereby is able to provide the
|
||||
promised analogue <-> digital mapping of Joystick.
|
||||
*/
|
||||
class ConcreteJoystick: public Joystick {
|
||||
public:
|
||||
ConcreteJoystick(const std::vector<Input> &inputs) : inputs_(inputs) {
|
||||
// Size and populate axis_types_, which is used for digital <-> analogue conversion.
|
||||
for(const auto &input: inputs_) {
|
||||
const bool is_digital_axis = input.is_digital_axis();
|
||||
const bool is_analogue_axis = input.is_analogue_axis();
|
||||
if(is_digital_axis || is_analogue_axis) {
|
||||
const size_t required_size = static_cast<size_t>(input.info.control.index+1);
|
||||
if(axis_types_.size() < required_size) {
|
||||
axis_types_.resize(required_size);
|
||||
}
|
||||
axis_types_[static_cast<size_t>(input.info.control.index)] = is_digital_axis ? AxisType::Digital : AxisType::Analogue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Input> &get_inputs() override final {
|
||||
return inputs_;
|
||||
}
|
||||
|
||||
void set_input(const Input &input, bool is_active) override final {
|
||||
// If this is a digital setting to a digital property, just pass it along.
|
||||
if(input.is_button() || axis_types_[input.info.control.index] == AxisType::Digital) {
|
||||
did_set_input(input, is_active);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise this is logically to an analogue axis; for now just use some
|
||||
// convenient hard-coded values. TODO: make these a function of time.
|
||||
using Type = Joystick::Input::Type;
|
||||
using Precision = Joystick::Input::Precision;
|
||||
switch(input.type) {
|
||||
default: did_set_input(input, is_active ? 1.0f : 0.0f); break;
|
||||
case Type::Left: did_set_input(Input(Type::Horizontal, input.info.control.index), 0.25f); break;
|
||||
case Type::Right: did_set_input(Input(Type::Horizontal, input.info.control.index), 0.75f); break;
|
||||
case Type::Up: did_set_input(Input(Type::Vertical, input.info.control.index), 0.25f); break;
|
||||
case Type::Down: did_set_input(Input(Type::Vertical, input.info.control.index), 0.75f); break;
|
||||
}
|
||||
}
|
||||
|
||||
void set_input(const Input &input, float value) override final {
|
||||
// If this is an analogue setting to an analogue property, just pass it along.
|
||||
if(!input.is_button() && axis_types_[input.info.control.index] == AxisType::Analogue) {
|
||||
did_set_input(input, value);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise apply a threshold test to convert to digital, with remapping from axes to digital inputs.
|
||||
using Type = Joystick::Input::Type;
|
||||
using Precision = Joystick::Input::Precision;
|
||||
switch(input.type) {
|
||||
default: did_set_input(input, value > 0.5f); break;
|
||||
case Type::Horizontal:
|
||||
did_set_input(Input(Type::Left, input.info.control.index), value <= 0.25f);
|
||||
did_set_input(Input(Type::Right, input.info.control.index), value >= 0.25f);
|
||||
break;
|
||||
case Type::Vertical:
|
||||
did_set_input(Input(Type::Up, input.info.control.index), value <= 0.25f);
|
||||
did_set_input(Input(Type::Down, input.info.control.index), value >= 0.25f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void did_set_input(const Input &input, float value) {
|
||||
}
|
||||
|
||||
virtual void did_set_input(const Input &input, bool value) {
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Input> inputs_;
|
||||
|
||||
enum class AxisType {
|
||||
Digital,
|
||||
Analogue
|
||||
};
|
||||
std::vector<AxisType> axis_types_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* Joystick_hpp */
|
||||
|
@ -37,22 +37,19 @@ namespace {
|
||||
|
||||
namespace Atari2600 {
|
||||
|
||||
class Joystick: public Inputs::Joystick {
|
||||
class Joystick: public Inputs::ConcreteJoystick {
|
||||
public:
|
||||
Joystick(Bus *bus, std::size_t shift, std::size_t fire_tia_input) :
|
||||
bus_(bus), shift_(shift), fire_tia_input_(fire_tia_input) {}
|
||||
|
||||
std::vector<Input> get_inputs() override {
|
||||
return {
|
||||
ConcreteJoystick({
|
||||
Input(Input::Up),
|
||||
Input(Input::Down),
|
||||
Input(Input::Left),
|
||||
Input(Input::Right),
|
||||
Input(Input::Fire)
|
||||
};
|
||||
}
|
||||
}),
|
||||
bus_(bus), shift_(shift), fire_tia_input_(fire_tia_input) {}
|
||||
|
||||
void set_input(const Input &digital_input, bool is_active) override {
|
||||
void did_set_input(const Input &digital_input, bool is_active) override {
|
||||
switch(digital_input.type) {
|
||||
case Input::Up: bus_->mos6532_.update_port_input(0, 0x10 >> shift_, is_active); break;
|
||||
case Input::Down: bus_->mos6532_.update_port_input(0, 0x20 >> shift_, is_active); break;
|
||||
|
@ -32,10 +32,10 @@ const int sn76489_divider = 2;
|
||||
namespace Coleco {
|
||||
namespace Vision {
|
||||
|
||||
class Joystick: public Inputs::Joystick {
|
||||
class Joystick: public Inputs::ConcreteJoystick {
|
||||
public:
|
||||
std::vector<Input> get_inputs() override {
|
||||
return {
|
||||
Joystick() :
|
||||
ConcreteJoystick({
|
||||
Input(Input::Up),
|
||||
Input(Input::Down),
|
||||
Input(Input::Left),
|
||||
@ -48,10 +48,9 @@ class Joystick: public Inputs::Joystick {
|
||||
Input('3'), Input('4'), Input('5'),
|
||||
Input('6'), Input('7'), Input('8'),
|
||||
Input('9'), Input('*'), Input('#'),
|
||||
};
|
||||
}
|
||||
}) {}
|
||||
|
||||
void set_input(const Input &digital_input, bool is_active) override {
|
||||
void did_set_input(const Input &digital_input, bool is_active) override {
|
||||
switch(digital_input.type) {
|
||||
default: return;
|
||||
|
||||
|
@ -257,23 +257,20 @@ class Vic6560BusHandler {
|
||||
/*!
|
||||
Interfaces a joystick to the two VIAs.
|
||||
*/
|
||||
class Joystick: public Inputs::Joystick {
|
||||
class Joystick: public Inputs::ConcreteJoystick {
|
||||
public:
|
||||
Joystick(UserPortVIA &user_port_via_port_handler, KeyboardVIA &keyboard_via_port_handler) :
|
||||
user_port_via_port_handler_(user_port_via_port_handler),
|
||||
keyboard_via_port_handler_(keyboard_via_port_handler) {}
|
||||
|
||||
std::vector<Input> get_inputs() override {
|
||||
return {
|
||||
ConcreteJoystick({
|
||||
Input(Input::Up),
|
||||
Input(Input::Down),
|
||||
Input(Input::Left),
|
||||
Input(Input::Right),
|
||||
Input(Input::Fire)
|
||||
};
|
||||
}
|
||||
}),
|
||||
user_port_via_port_handler_(user_port_via_port_handler),
|
||||
keyboard_via_port_handler_(keyboard_via_port_handler) {}
|
||||
|
||||
void set_input(const Input &digital_input, bool is_active) override {
|
||||
void did_set_input(const Input &digital_input, bool is_active) override {
|
||||
JoystickInput mapped_input;
|
||||
switch(digital_input.type) {
|
||||
default: return;
|
||||
|
Loading…
Reference in New Issue
Block a user