5 changed files with 237 additions and 0 deletions
@ -0,0 +1,140 @@
|
||||
#include <SDL.h> |
||||
|
||||
#include "controls/touch/gamepad.h" |
||||
#include "diablo.h" |
||||
#include "utils/display.h" |
||||
#include "utils/ui_fwd.h" |
||||
|
||||
namespace devilution { |
||||
|
||||
VirtualGamepad VirtualGamepadState; |
||||
|
||||
namespace { |
||||
|
||||
constexpr double Pi = 3.141592653589793; |
||||
|
||||
constexpr bool PointsUp(double angle) |
||||
{ |
||||
constexpr double UpAngle = Pi / 2; |
||||
constexpr double MinAngle = UpAngle - 3 * Pi / 8; |
||||
constexpr double MaxAngle = UpAngle + 3 * Pi / 8; |
||||
return MinAngle <= angle && angle <= MaxAngle; |
||||
} |
||||
|
||||
constexpr bool PointsDown(double angle) |
||||
{ |
||||
constexpr double DownAngle = -Pi / 2; |
||||
constexpr double MinAngle = DownAngle - 3 * Pi / 8; |
||||
constexpr double MaxAngle = DownAngle + 3 * Pi / 8; |
||||
return MinAngle <= angle && angle <= MaxAngle; |
||||
} |
||||
|
||||
constexpr bool PointsLeft(double angle) |
||||
{ |
||||
constexpr double MaxAngle = Pi - 3 * Pi / 8; |
||||
constexpr double MinAngle = -Pi + 3 * Pi / 8; |
||||
return !(MinAngle < angle && angle < MaxAngle); |
||||
} |
||||
|
||||
constexpr bool PointsRight(double angle) |
||||
{ |
||||
constexpr double MinAngle = -3 * Pi / 8; |
||||
constexpr double MaxAngle = 3 * Pi / 8; |
||||
return MinAngle <= angle && angle <= MaxAngle; |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
void InitializeVirtualGamepad() |
||||
{ |
||||
int screenPixels = std::min(gnScreenWidth, gnScreenHeight); |
||||
int inputMargin = screenPixels / 10; |
||||
int directionPadSize = screenPixels / 4; |
||||
int padButtonSize = round(1.1 * screenPixels / 10); |
||||
int padButtonSpacing = inputMargin / 3; |
||||
|
||||
#ifndef USE_SDL1 |
||||
float hdpi; |
||||
float vdpi; |
||||
int displayIndex = SDL_GetWindowDisplayIndex(ghMainWnd); |
||||
if (SDL_GetDisplayDPI(displayIndex, nullptr, &hdpi, &vdpi) == 0) { |
||||
int clientWidth; |
||||
int clientHeight; |
||||
SDL_GetWindowSize(ghMainWnd, &clientWidth, &clientHeight); |
||||
hdpi *= static_cast<float>(gnScreenWidth) / clientWidth; |
||||
vdpi *= static_cast<float>(gnScreenHeight) / clientHeight; |
||||
|
||||
float dpi = std::min(hdpi, vdpi); |
||||
inputMargin = round(0.25 * dpi); |
||||
directionPadSize = round(dpi); |
||||
padButtonSize = round(0.3 * dpi); |
||||
padButtonSpacing = round(0.1 * dpi); |
||||
} |
||||
#endif |
||||
|
||||
int padButtonAreaWidth = round(std::sqrt(2) * (padButtonSize + padButtonSpacing)); |
||||
|
||||
int padButtonRight = gnScreenWidth - inputMargin - padButtonSize / 2; |
||||
int padButtonLeft = padButtonRight - padButtonAreaWidth; |
||||
int padButtonBottom = gnScreenHeight - inputMargin - padButtonSize / 2; |
||||
int padButtonTop = padButtonBottom - padButtonAreaWidth; |
||||
|
||||
VirtualDirectionPad &directionPad = VirtualGamepadState.directionPad; |
||||
directionPad.area.position.x = inputMargin + directionPadSize / 2; |
||||
directionPad.area.position.y = gnScreenHeight - inputMargin - directionPadSize / 2; |
||||
directionPad.area.radius = directionPadSize / 2; |
||||
directionPad.position = directionPad.area.position; |
||||
|
||||
VirtualPadButton &primaryActionButton = VirtualGamepadState.primaryActionButton; |
||||
primaryActionButton.area.position.x = padButtonRight; |
||||
primaryActionButton.area.position.y = (padButtonTop + padButtonBottom) / 2; |
||||
primaryActionButton.area.radius = padButtonSize / 2; |
||||
|
||||
VirtualPadButton &secondaryActionButton = VirtualGamepadState.secondaryActionButton; |
||||
secondaryActionButton.area.position.x = (padButtonLeft + padButtonRight) / 2; |
||||
secondaryActionButton.area.position.y = padButtonTop; |
||||
secondaryActionButton.area.radius = padButtonSize / 2; |
||||
|
||||
VirtualPadButton &spellActionButton = VirtualGamepadState.spellActionButton; |
||||
spellActionButton.area.position.x = padButtonLeft; |
||||
spellActionButton.area.position.y = (padButtonTop + padButtonBottom) / 2; |
||||
spellActionButton.area.radius = padButtonSize / 2; |
||||
|
||||
VirtualPadButton &cancelButton = VirtualGamepadState.cancelButton; |
||||
cancelButton.area.position.x = (padButtonLeft + padButtonRight) / 2; |
||||
cancelButton.area.position.y = padButtonBottom; |
||||
cancelButton.area.radius = padButtonSize / 2; |
||||
} |
||||
|
||||
void VirtualDirectionPad::UpdatePosition(Point touchCoordinates) |
||||
{ |
||||
position = touchCoordinates; |
||||
|
||||
Displacement diff = position - area.position; |
||||
if (diff == Displacement { 0, 0 }) { |
||||
isUpPressed = false; |
||||
isDownPressed = false; |
||||
isLeftPressed = false; |
||||
isRightPressed = false; |
||||
return; |
||||
} |
||||
|
||||
if (!area.Contains(position)) { |
||||
int x = diff.deltaX; |
||||
int y = diff.deltaY; |
||||
double dist = sqrt(x * x + y * y); |
||||
x = round(x * area.radius / dist); |
||||
y = round(y * area.radius / dist); |
||||
position.x = area.position.x + x; |
||||
position.y = area.position.y + y; |
||||
} |
||||
|
||||
double angle = atan2(-diff.deltaY, diff.deltaX); |
||||
|
||||
isUpPressed = PointsUp(angle); |
||||
isDownPressed = PointsDown(angle); |
||||
isLeftPressed = PointsLeft(angle); |
||||
isRightPressed = PointsRight(angle); |
||||
} |
||||
|
||||
} // namespace devilution
|
||||
@ -0,0 +1,65 @@
|
||||
#pragma once |
||||
|
||||
#if defined(VIRTUAL_GAMEPAD) && !defined(USE_SDL1) |
||||
|
||||
#include "controls/controller_buttons.h" |
||||
#include "engine/circle.hpp" |
||||
#include "engine/point.hpp" |
||||
|
||||
namespace devilution { |
||||
|
||||
struct VirtualDirectionPad { |
||||
Circle area; |
||||
Point position; |
||||
bool isUpPressed; |
||||
bool isDownPressed; |
||||
bool isLeftPressed; |
||||
bool isRightPressed; |
||||
|
||||
VirtualDirectionPad() |
||||
: area({ { 0, 0 }, 0 }) |
||||
, position({ 0, 0 }) |
||||
, isUpPressed(false) |
||||
, isDownPressed(false) |
||||
, isLeftPressed(false) |
||||
, isRightPressed(false) |
||||
{ |
||||
} |
||||
|
||||
void UpdatePosition(Point touchCoordinates); |
||||
}; |
||||
|
||||
struct VirtualPadButton { |
||||
Circle area; |
||||
bool isHeld; |
||||
bool didStateChange; |
||||
|
||||
VirtualPadButton() |
||||
: area({ { 0, 0 }, 0 }) |
||||
, isHeld(false) |
||||
, didStateChange(false) |
||||
{ |
||||
} |
||||
}; |
||||
|
||||
struct VirtualGamepad { |
||||
VirtualDirectionPad directionPad; |
||||
VirtualPadButton primaryActionButton; |
||||
VirtualPadButton secondaryActionButton; |
||||
VirtualPadButton spellActionButton; |
||||
VirtualPadButton cancelButton; |
||||
|
||||
VirtualGamepad() |
||||
{ |
||||
} |
||||
|
||||
bool IsControllerButtonPressed(ControllerButton button) const; |
||||
}; |
||||
|
||||
void InitializeVirtualGamepad(); |
||||
|
||||
extern VirtualGamepad VirtualGamepadState; |
||||
|
||||
} // namespace devilution
|
||||
|
||||
#endif |
||||
@ -0,0 +1,21 @@
|
||||
#pragma once |
||||
|
||||
#include "engine/displacement.hpp" |
||||
#include "engine/point.hpp" |
||||
|
||||
namespace devilution { |
||||
|
||||
struct Circle { |
||||
Point position; |
||||
int radius; |
||||
|
||||
constexpr bool Contains(Point point) const |
||||
{ |
||||
Displacement diff = point - position; |
||||
int x = diff.deltaX; |
||||
int y = diff.deltaY; |
||||
return x * x + y * y < radius * radius; |
||||
} |
||||
}; |
||||
|
||||
} // namespace devilution
|
||||
Loading…
Reference in new issue