From fd07ae8cec5c77ac60788350610739e6ac094547 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Sat, 26 Jan 2019 12:17:30 -0600 Subject: ExpressionParser: Move FunctionExpression type definitions into another file. --- .../ControlReference/FunctionExpression.cpp | 261 +++++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 Source/Core/InputCommon/ControlReference/FunctionExpression.cpp (limited to 'Source/Core/InputCommon/ControlReference/FunctionExpression.cpp') 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 -- cgit v1.2.3