diff --git a/Source/Core/InputCommon/CMakeLists.txt b/Source/Core/InputCommon/CMakeLists.txt index df8fa6423c..b47503a9ae 100644 --- a/Source/Core/InputCommon/CMakeLists.txt +++ b/Source/Core/InputCommon/CMakeLists.txt @@ -45,6 +45,8 @@ add_library(inputcommon ControlReference/ControlReference.h ControlReference/ExpressionParser.cpp ControlReference/ExpressionParser.h + ControlReference/FunctionExpression.cpp + ControlReference/FunctionExpression.h ) target_link_libraries(inputcommon PUBLIC diff --git a/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp b/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp index 1c9ea370ce..b0704d3d8d 100644 --- a/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp +++ b/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp @@ -2,29 +2,24 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include #include -#include #include #include -#include -#include #include #include #include +#include #include -#include "Common/MathUtil.h" #include "Common/StringUtil.h" + #include "InputCommon/ControlReference/ExpressionParser.h" +#include "InputCommon/ControlReference/FunctionExpression.h" namespace ciface::ExpressionParser { using namespace ciface::Core; -constexpr int LOOP_MAX_REPS = 10000; -constexpr ControlState CONDITION_THRESHOLD = 0.5; - enum TokenType { TOK_DISCARD, @@ -420,253 +415,6 @@ public: } }; -class FunctionExpression : public Expression -{ -public: - int CountNumControls() const override - { - int result = 0; - - for (auto& arg : m_args) - result += arg->CountNumControls(); - - return result; - } - - void UpdateReferences(ControlEnvironment& env) override - { - for (auto& arg : m_args) - arg->UpdateReferences(env); - } - - operator std::string() const override - { - std::string result = '!' + GetFuncName(); - - for (auto& arg : m_args) - result += ' ' + static_cast(*arg); - - return result; - } - - bool SetArguments(std::vector>&& args) - { - m_args = std::move(args); - - return ValidateArguments(m_args); - } - -protected: - virtual std::string GetFuncName() const = 0; - virtual bool ValidateArguments(const std::vector>& args) = 0; - - Expression& GetArg(u32 number) { return *m_args[number]; } - const Expression& GetArg(u32 number) const { return *m_args[number]; } - -private: - std::vector> m_args; -}; - -// TODO: Return an oscillating value to make it apparent something was spelled wrong? -class UnknownFunctionExpression : public FunctionExpression -{ -private: - virtual bool ValidateArguments(const std::vector>& args) override - { - return false; - } - ControlState GetValue() const override { return 0.0; } - void SetValue(ControlState value) override {} - std::string GetFuncName() const override { return "unknown"; } -}; - -class ToggleExpression : public FunctionExpression -{ -private: - virtual bool ValidateArguments(const std::vector>& args) override - { - return 1 == args.size(); - } - - ControlState GetValue() const override - { - const ControlState inner_value = GetArg(0).GetValue(); - - if (inner_value < CONDITION_THRESHOLD) - { - m_released = true; - } - else if (m_released && inner_value > CONDITION_THRESHOLD) - { - m_released = false; - m_state ^= true; - } - - return m_state; - } - - void SetValue(ControlState value) override {} - std::string GetFuncName() const override { return "toggle"; } - - mutable bool m_released{}; - mutable bool m_state{}; -}; - -class NotExpression : public FunctionExpression -{ -private: - virtual bool ValidateArguments(const std::vector>& args) override - { - return 1 == args.size(); - } - - ControlState GetValue() const override { return 1.0 - GetArg(0).GetValue(); } - void SetValue(ControlState value) override { GetArg(0).SetValue(1.0 - value); } - std::string GetFuncName() const override { return ""; } -}; - -class SinExpression : public FunctionExpression -{ -private: - virtual bool ValidateArguments(const std::vector>& args) override - { - return 1 == args.size(); - } - - ControlState GetValue() const override { return std::sin(GetArg(0).GetValue()); } - void SetValue(ControlState value) override {} - std::string GetFuncName() const override { return "sin"; } -}; - -class TimerExpression : public FunctionExpression -{ -private: - virtual bool ValidateArguments(const std::vector>& args) override - { - return 1 == args.size(); - } - - ControlState GetValue() const override - { - const auto now = Clock::now(); - const auto elapsed = now - m_start_time; - - using FSec = std::chrono::duration; - - const ControlState val = GetArg(0).GetValue(); - - ControlState progress = std::chrono::duration_cast(elapsed).count() / val; - - if (std::isinf(progress)) - { - // User configured a 0.0 length timer. Reset the timer and return 0.0. - progress = 0.0; - m_start_time = now; - } - else if (progress >= 1.0) - { - const ControlState reset_count = std::floor(progress); - - m_start_time += std::chrono::duration_cast(FSec(val * reset_count)); - progress -= reset_count; - } - - return progress; - } - void SetValue(ControlState value) override {} - std::string GetFuncName() const override { return "timer"; } - -private: - using Clock = std::chrono::steady_clock; - mutable Clock::time_point m_start_time = Clock::now(); -}; - -class IfExpression : public FunctionExpression -{ -private: - virtual bool ValidateArguments(const std::vector>& args) override - { - return 3 == args.size(); - } - - ControlState GetValue() const override - { - return (GetArg(0).GetValue() > CONDITION_THRESHOLD) ? GetArg(1).GetValue() : - GetArg(2).GetValue(); - } - - void SetValue(ControlState value) override {} - std::string GetFuncName() const override { return "if"; } -}; - -class UnaryMinusExpression : public FunctionExpression -{ -private: - virtual bool ValidateArguments(const std::vector>& args) override - { - return 1 == args.size(); - } - - ControlState GetValue() const override - { - // Subtraction for clarity: - return 0.0 - GetArg(0).GetValue(); - } - - void SetValue(ControlState value) override {} - std::string GetFuncName() const override { return "minus"; } -}; - -class WhileExpression : public FunctionExpression -{ - virtual bool ValidateArguments(const std::vector>& args) override - { - return 2 == args.size(); - } - - ControlState GetValue() const override - { - // Returns 1.0 on successful loop, 0.0 on reps exceeded. Sensible? - - for (int i = 0; i != LOOP_MAX_REPS; ++i) - { - // Check condition of 1st argument: - const ControlState val = GetArg(0).GetValue(); - if (val < CONDITION_THRESHOLD) - return 1.0; - - // Evaluate 2nd argument: - GetArg(1).GetValue(); - } - - // Exceeded max reps: - return 0.0; - } - - void SetValue(ControlState value) override {} - std::string GetFuncName() const override { return "while"; } -}; - -std::unique_ptr MakeFunctionExpression(std::string name) -{ - if (name.empty()) - return std::make_unique(); - else if ("if" == name) - return std::make_unique(); - else if ("sin" == name) - return std::make_unique(); - else if ("timer" == name) - return std::make_unique(); - else if ("toggle" == name) - return std::make_unique(); - else if ("while" == name) - return std::make_unique(); - else if ("minus" == name) - return std::make_unique(); - else - return std::make_unique(); -} - class LiteralExpression : public Expression { public: diff --git a/Source/Core/InputCommon/ControlReference/ExpressionParser.h b/Source/Core/InputCommon/ControlReference/ExpressionParser.h index d9f7a5eb2b..0cb84af5cd 100644 --- a/Source/Core/InputCommon/ControlReference/ExpressionParser.h +++ b/Source/Core/InputCommon/ControlReference/ExpressionParser.h @@ -7,7 +7,7 @@ #include #include #include -#include + #include "InputCommon/ControllerInterface/Device.h" namespace ciface::ExpressionParser diff --git a/Source/Core/InputCommon/ControlReference/FunctionExpression.cpp b/Source/Core/InputCommon/ControlReference/FunctionExpression.cpp new file mode 100644 index 0000000000..15a66ec9d1 --- /dev/null +++ b/Source/Core/InputCommon/ControlReference/FunctionExpression.cpp @@ -0,0 +1,261 @@ +// Copyright 2019 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include +#include + +#include "InputCommon/ControlReference/FunctionExpression.h" + +namespace ciface +{ +namespace ExpressionParser +{ +constexpr int LOOP_MAX_REPS = 10000; +constexpr ControlState CONDITION_THRESHOLD = 0.5; + +// TODO: Return an oscillating value to make it apparent something was spelled wrong? +class UnknownFunctionExpression : public FunctionExpression +{ +private: + virtual bool ValidateArguments(const std::vector>& args) override + { + return false; + } + ControlState GetValue() const override { return 0.0; } + void SetValue(ControlState value) override {} + std::string GetFuncName() const override { return "unknown"; } +}; + +class ToggleExpression : public FunctionExpression +{ +private: + virtual bool ValidateArguments(const std::vector>& args) override + { + return 1 == args.size(); + } + + ControlState GetValue() const override + { + const ControlState inner_value = GetArg(0).GetValue(); + + if (inner_value < CONDITION_THRESHOLD) + { + m_released = true; + } + else if (m_released && inner_value > CONDITION_THRESHOLD) + { + m_released = false; + m_state ^= true; + } + + return m_state; + } + + void SetValue(ControlState value) override {} + std::string GetFuncName() const override { return "toggle"; } + + mutable bool m_released{}; + mutable bool m_state{}; +}; + +class NotExpression : public FunctionExpression +{ +private: + virtual bool ValidateArguments(const std::vector>& args) override + { + return 1 == args.size(); + } + + ControlState GetValue() const override { return 1.0 - GetArg(0).GetValue(); } + void SetValue(ControlState value) override { GetArg(0).SetValue(1.0 - value); } + std::string GetFuncName() const override { return ""; } +}; + +class SinExpression : public FunctionExpression +{ +private: + virtual bool ValidateArguments(const std::vector>& args) override + { + return 1 == args.size(); + } + + ControlState GetValue() const override { return std::sin(GetArg(0).GetValue()); } + void SetValue(ControlState value) override {} + std::string GetFuncName() const override { return "sin"; } +}; + +class TimerExpression : public FunctionExpression +{ +private: + virtual bool ValidateArguments(const std::vector>& args) override + { + return 1 == args.size(); + } + + ControlState GetValue() const override + { + const auto now = Clock::now(); + const auto elapsed = now - m_start_time; + + using FSec = std::chrono::duration; + + const ControlState val = GetArg(0).GetValue(); + + ControlState progress = std::chrono::duration_cast(elapsed).count() / val; + + if (std::isinf(progress)) + { + // User configured a 0.0 length timer. Reset the timer and return 0.0. + progress = 0.0; + m_start_time = now; + } + else if (progress >= 1.0) + { + const ControlState reset_count = std::floor(progress); + + m_start_time += std::chrono::duration_cast(FSec(val * reset_count)); + progress -= reset_count; + } + + return progress; + } + void SetValue(ControlState value) override {} + std::string GetFuncName() const override { return "timer"; } + +private: + using Clock = std::chrono::steady_clock; + mutable Clock::time_point m_start_time = Clock::now(); +}; + +class IfExpression : public FunctionExpression +{ +private: + virtual bool ValidateArguments(const std::vector>& args) override + { + return 3 == args.size(); + } + + ControlState GetValue() const override + { + return (GetArg(0).GetValue() > CONDITION_THRESHOLD) ? GetArg(1).GetValue() : + GetArg(2).GetValue(); + } + + void SetValue(ControlState value) override {} + std::string GetFuncName() const override { return "if"; } +}; + +class UnaryMinusExpression : public FunctionExpression +{ +private: + virtual bool ValidateArguments(const std::vector>& args) override + { + return 1 == args.size(); + } + + ControlState GetValue() const override + { + // Subtraction for clarity: + return 0.0 - GetArg(0).GetValue(); + } + + void SetValue(ControlState value) override {} + std::string GetFuncName() const override { return "minus"; } +}; + +class WhileExpression : public FunctionExpression +{ + virtual bool ValidateArguments(const std::vector>& args) override + { + return 2 == args.size(); + } + + ControlState GetValue() const override + { + // Returns 1.0 on successful loop, 0.0 on reps exceeded. Sensible? + + for (int i = 0; i != LOOP_MAX_REPS; ++i) + { + // Check condition of 1st argument: + const ControlState val = GetArg(0).GetValue(); + if (val < CONDITION_THRESHOLD) + return 1.0; + + // Evaluate 2nd argument: + GetArg(1).GetValue(); + } + + // Exceeded max reps: + return 0.0; + } + + void SetValue(ControlState value) override {} + std::string GetFuncName() const override { return "while"; } +}; + +std::unique_ptr MakeFunctionExpression(std::string name) +{ + if (name.empty()) + return std::make_unique(); + else if ("if" == name) + return std::make_unique(); + else if ("sin" == name) + return std::make_unique(); + else if ("timer" == name) + return std::make_unique(); + else if ("toggle" == name) + return std::make_unique(); + else if ("while" == name) + return std::make_unique(); + else if ("minus" == name) + return std::make_unique(); + else + return std::make_unique(); +} + +int FunctionExpression::CountNumControls() const +{ + int result = 0; + + for (auto& arg : m_args) + result += arg->CountNumControls(); + + return result; +} + +void FunctionExpression::UpdateReferences(ControlEnvironment& env) +{ + for (auto& arg : m_args) + arg->UpdateReferences(env); +} + +FunctionExpression::operator std::string() const +{ + std::string result = '!' + GetFuncName(); + + for (auto& arg : m_args) + result += ' ' + static_cast(*arg); + + return result; +} + +bool FunctionExpression::SetArguments(std::vector>&& args) +{ + m_args = std::move(args); + + return ValidateArguments(m_args); +} + +Expression& FunctionExpression::GetArg(u32 number) +{ + return *m_args[number]; +} + +const Expression& FunctionExpression::GetArg(u32 number) const +{ + return *m_args[number]; +} + +} // namespace ExpressionParser +} // namespace ciface diff --git a/Source/Core/InputCommon/ControlReference/FunctionExpression.h b/Source/Core/InputCommon/ControlReference/FunctionExpression.h new file mode 100644 index 0000000000..8ac7e9800c --- /dev/null +++ b/Source/Core/InputCommon/ControlReference/FunctionExpression.h @@ -0,0 +1,41 @@ +// Copyright 2019 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include + +#include "InputCommon/ControlReference/ExpressionParser.h" +#include "InputCommon/ControlReference/FunctionExpression.h" + +namespace ciface +{ +namespace ExpressionParser +{ +class FunctionExpression : public Expression +{ +public: + int CountNumControls() const override; + void UpdateReferences(ControlEnvironment& env) override; + operator std::string() const override; + + bool SetArguments(std::vector>&& args); + +protected: + virtual std::string GetFuncName() const = 0; + virtual bool ValidateArguments(const std::vector>& args) = 0; + + Expression& GetArg(u32 number); + const Expression& GetArg(u32 number) const; + +private: + std::vector> m_args; +}; + +std::unique_ptr MakeFunctionExpression(std::string name); + +} // namespace ExpressionParser +} // namespace ciface diff --git a/Source/Core/InputCommon/InputCommon.vcxproj b/Source/Core/InputCommon/InputCommon.vcxproj index 8d0b0b3759..a22ad21394 100644 --- a/Source/Core/InputCommon/InputCommon.vcxproj +++ b/Source/Core/InputCommon/InputCommon.vcxproj @@ -64,6 +64,7 @@ +