diff --git a/ui/virtual_input.cpp b/ui/virtual_input.cpp index e9d051397c..e6735773ff 100644 --- a/ui/virtual_input.cpp +++ b/ui/virtual_input.cpp @@ -1,4 +1,5 @@ #include +#include "base/logging.h" #include "gfx_es2/draw_buffer.h" #include "gfx/texture_atlas.h" #include "input/input_state.h" @@ -45,6 +46,67 @@ void TouchButton::draw(DrawBuffer &db, uint32_t color, uint32_t colorOverlay) db.DrawImageRotated(overlayImageIndex_, x_ + w_*scale_/2, y_ + h_*scale_/2, scale, rotationAngle_, colorOverlay); } +TouchCrossPad::TouchCrossPad(const Atlas *atlas, int arrowIndex, int overlayIndex) + : atlas_(atlas), arrowIndex_(arrowIndex), overlayIndex_(overlayIndex) +{ + +} + +void TouchCrossPad::update(InputState &input_state) +{ + float stick_size_ = radius_ * 2; + float inv_stick_size = 1.0f / (stick_size_ * scale_); + const float deadzone = 0.17f; + bool all_up = true; + + input_state.pad_buttons &= ~(PAD_BUTTON_LEFT | PAD_BUTTON_RIGHT | PAD_BUTTON_UP | PAD_BUTTON_DOWN); + + for (int i = 0; i < MAX_POINTERS; i++) { + if (input_state.pointer_down[i]) { + float dx = (input_state.pointer_x[i] - x_) * inv_stick_size; + float dy = (input_state.pointer_y[i] - y_) * inv_stick_size; + float rad = sqrtf(dx*dx+dy*dy); + if (rad < deadzone || rad > 1.0f) + continue; + + all_up = false; + + if (dx == 0 && dy == 0) + continue; + + int direction = (int)(floorf((atan2f(dy, dx) / (2 * M_PI) * 8) + 0.5f)) & 7; + + switch (direction) { + case 0: input_state.pad_buttons |= PAD_BUTTON_RIGHT; break; + case 1: input_state.pad_buttons |= PAD_BUTTON_RIGHT | PAD_BUTTON_DOWN; break; + case 2: input_state.pad_buttons |= PAD_BUTTON_DOWN; break; + case 3: input_state.pad_buttons |= PAD_BUTTON_DOWN | PAD_BUTTON_LEFT; break; + case 4: input_state.pad_buttons |= PAD_BUTTON_LEFT; break; + case 5: input_state.pad_buttons |= PAD_BUTTON_UP | PAD_BUTTON_LEFT; break; + case 6: input_state.pad_buttons |= PAD_BUTTON_UP; break; + case 7: input_state.pad_buttons |= PAD_BUTTON_UP | PAD_BUTTON_RIGHT; break; + } + } + } + down_ = input_state.pad_buttons & (PAD_BUTTON_LEFT | PAD_BUTTON_RIGHT | PAD_BUTTON_UP | PAD_BUTTON_DOWN); +} + +void TouchCrossPad::draw(DrawBuffer &db, uint32_t color, uint32_t colorOverlay) +{ + static const float xoff[4] = {1, 0, -1, 0}; + static const float yoff[4] = {0, 1, 0, -1}; + static const int dir[4] = {PAD_BUTTON_RIGHT, PAD_BUTTON_DOWN, PAD_BUTTON_LEFT, PAD_BUTTON_UP}; + for (int i = 0; i < 4; i++) { + float x = x_ + xoff[i] * scale_ * radius_; + float y = y_ + yoff[i] * scale_ * radius_; + float angle = i * M_PI / 2; + float imgScale = (down_ & dir[i]) ? scale_ * 2 : scale_; + db.DrawImageRotated(arrowIndex_, x, y, imgScale, angle + PI, color, false); + if (overlayIndex_ != -1) + db.DrawImageRotated(overlayIndex_, x, y, imgScale, angle + PI, colorOverlay); + } +} + TouchStick::TouchStick(const Atlas *atlas, int bgImageIndex, int stickImageIndex, int stick) : atlas_(atlas), bgImageIndex_(bgImageIndex), stickImageIndex_(stickImageIndex), stick_(stick) { diff --git a/ui/virtual_input.h b/ui/virtual_input.h index 41796fee89..a383cd467b 100644 --- a/ui/virtual_input.h +++ b/ui/virtual_input.h @@ -1,5 +1,6 @@ #pragma once +#include "math/math_util.h" #include "gfx/texture_atlas.h" class DrawBuffer; @@ -47,6 +48,35 @@ private: bool pointerDown[MAX_POINTERS]; }; +// 4-in-one directional pad, with support for single touch diagonals. +class TouchCrossPad +{ +public: + TouchCrossPad(const Atlas *atlas, int arrowIndex, int overlayIndex); + + void update(InputState &input_state); + void draw(DrawBuffer &db, uint32_t color, uint32_t colorOverlay); + + void setPos(float x, float y, float radius, float scale = 1.0f) { + x_ = x; + y_ = y; + radius_ = radius; + scale_ = scale; + } + +private: + const Atlas *atlas_; + + float x_; + float y_; + float radius_; + float scale_; + + int arrowIndex_; + int overlayIndex_; + int down_; +}; + // Multi-touch enabled virtual joystick // Many of these can be used simultaneously with multitouch.