Browse Source

Add structs for virtual gamepad

pull/2880/head
staphen 5 years ago committed by Anders Jenbo
parent
commit
fb4f1ed8fd
  1. 6
      CMakeLists.txt
  2. 140
      Source/controls/touch/gamepad.cpp
  3. 65
      Source/controls/touch/gamepad.h
  4. 5
      Source/diablo.cpp
  5. 21
      Source/engine/circle.hpp

6
CMakeLists.txt

@ -485,6 +485,11 @@ if(NOT NONET)
endif()
endif()
if (VIRTUAL_GAMEPAD)
list(APPEND libdevilutionx_SRCS
Source/controls/touch/gamepad.cpp)
endif()
set(BIN_TARGET devilutionx)
if(NINTENDO_SWITCH)
@ -681,6 +686,7 @@ foreach(
GPERF_HEAP_MAIN
GPERF_HEAP_FIRST_GAME_ITERATION
STREAM_ALL_AUDIO
VIRTUAL_GAMEPAD
)
if(${def_name})
list(APPEND def_list ${def_name})

140
Source/controls/touch/gamepad.cpp

@ -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

65
Source/controls/touch/gamepad.h

@ -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

5
Source/diablo.cpp

@ -19,6 +19,7 @@
#endif
#include "DiabloUI/diabloui.h"
#include "controls/keymapper.hpp"
#include "controls/touch/gamepad.h"
#include "diablo.h"
#include "doom.h"
#include "drlg_l1.h"
@ -956,6 +957,10 @@ void DiabloInit()
strncpy(sgOptions.Chat.szHotKeyMsgs[i], _(QuickMessages[i].message), MAX_SEND_STR_LEN);
}
#if defined(VIRTUAL_GAMEPAD) && !defined(USE_SDL1)
InitializeVirtualGamepad();
#endif
UiInitialize();
UiSetSpawned(gbIsSpawn);
was_ui_init = true;

21
Source/engine/circle.hpp

@ -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…
Cancel
Save