diff --git a/rsc/images/icons.dds b/rsc/images/icons.dds index 02e1613..5322571 100644 Binary files a/rsc/images/icons.dds and b/rsc/images/icons.dds differ diff --git a/src/MousePointer.cpp b/src/MousePointer.cpp index 75cc0ca..0f82159 100644 --- a/src/MousePointer.cpp +++ b/src/MousePointer.cpp @@ -17,6 +17,7 @@ * along with this program. If not, see . **/ +#include #include // for diskRand #include "imgui.h" @@ -37,6 +38,7 @@ std::vector< std::tuple > Pointer::Modes = { { ICON_POINTER_LINEAR, "Line", "Speed" }, { ICON_POINTER_SPRING, "Spring", "Mass" }, { ICON_POINTER_WIGGLY, "Wiggly", "Radius" }, + { ICON_POINTER_BROWNIAN, "Brownian", "Radius" }, { ICON_POINTER_METRONOME, "Metronome", "Jump" } }; @@ -138,6 +140,49 @@ void PointerWiggly::draw() ImGui::GetBackgroundDrawList()->AddCircle(IMVEC_IO(current_), max * 0.5f, color, 0, 2.f + 4.f * strength_); } +void PointerBrownian::update(const glm::vec2 &pos, float) +{ + current_ = pos; + radius_ = (POINTER_WIGGLY_MAX_RADIUS - POINTER_WIGGLY_MIN_RADIUS) * strength_; + radius_ += POINTER_WIGGLY_MIN_RADIUS; + + // Brownian motion: add small random displacement in 2D + // Generate random step using gaussian distribution for each axis + glm::vec2 random_step = glm::gaussRand(glm::vec2(0.0f), glm::vec2(1.f) ); + + // Scale by radius and apply damping to keep motion bounded + float factor = 0.3f; + if (TabletInput::instance().hasPressure() && TabletInput::instance().isPressed()) { + factor *= TabletInput::instance().getPressure(); + } + float damping = 0.92f; + brownian_offset_ = brownian_offset_ * damping + random_step * radius_ * factor; + + // Clamp offset to stay within maximum radius + float offset_length = glm::length(brownian_offset_); + if (offset_length > radius_) { + brownian_offset_ = brownian_offset_ * (radius_ / offset_length); + } + + glm::vec2 p = pos + brownian_offset_; + + // smooth a little and apply + const float emaexp = 2.0 / float( POINTER_WIGGLY_SMOOTHING + 1); + target_ = emaexp * p + (1.f - emaexp) * target_; +} + +void PointerBrownian::draw() +{ + const ImU32 color = ImGui::GetColorU32(ImGuiCol_HeaderActive); + ImGui::GetBackgroundDrawList()->AddLine(IMVEC_IO(current_), IMVEC_IO(target_), color, 5.f); + + const float max = POINTER_WIGGLY_MIN_RADIUS + (POINTER_WIGGLY_MAX_RADIUS - POINTER_WIGGLY_MIN_RADIUS) * strength_; + if (TabletInput::instance().hasPressure() && TabletInput::instance().isPressed()) + ImGui::GetBackgroundDrawList()->AddCircle(IMVEC_IO(current_), radius_ * 0.8f, color, 0); + ImGui::GetBackgroundDrawList()->AddCircle(IMVEC_IO(current_), max * 0.8f, color, 0, 2.f + 4.f * strength_); +} + + #define POINTER_METRONOME_RADIUS 36.f void PointerMetronome::initiate(const glm::vec2 &pos) @@ -256,6 +301,7 @@ MousePointer::MousePointer() : mode_(Pointer::POINTER_DEFAULT) pointer_[Pointer::POINTER_LINEAR] = new PointerLinear; pointer_[Pointer::POINTER_SPRING] = new PointerSpring; pointer_[Pointer::POINTER_WIGGLY] = new PointerWiggly; + pointer_[Pointer::POINTER_BROWNIAN] = new PointerBrownian; pointer_[Pointer::POINTER_METRONOME] = new PointerMetronome; } @@ -266,5 +312,6 @@ MousePointer::~MousePointer() delete pointer_[Pointer::POINTER_LINEAR]; delete pointer_[Pointer::POINTER_SPRING]; delete pointer_[Pointer::POINTER_WIGGLY]; + delete pointer_[Pointer::POINTER_BROWNIAN]; delete pointer_[Pointer::POINTER_METRONOME]; } diff --git a/src/MousePointer.h b/src/MousePointer.h index 73fc9d1..e2d524d 100644 --- a/src/MousePointer.h +++ b/src/MousePointer.h @@ -12,6 +12,7 @@ #define ICON_POINTER_LINEAR 14, 9 #define ICON_POINTER_GRID 15, 9 #define ICON_POINTER_WIGGLY 16, 9 +#define ICON_POINTER_BROWNIAN 11, 9 #define ICON_POINTER_METRONOME 6, 13 /// @@ -33,6 +34,7 @@ public: POINTER_LINEAR, POINTER_SPRING, POINTER_WIGGLY, + POINTER_BROWNIAN, POINTER_METRONOME, POINTER_INVALID } Mode; @@ -104,7 +106,21 @@ class PointerWiggly : public Pointer { float radius_; public: - PointerWiggly() {} + PointerWiggly() : radius_(0.0f) {} + void update(const glm::vec2 &pos, float) override; + void draw() override; +}; + +/// +/// \brief The PointerBrownian moves with a Brownian movement +/// Strength modulates the radius of the movement +/// +class PointerBrownian : public Pointer +{ + float radius_; + glm::vec2 brownian_offset_; +public: + PointerBrownian() : brownian_offset_(0.0f, 0.0f) {} void update(const glm::vec2 &pos, float) override; void draw() override; };