1 // Copyright 2019 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4 
5 #include "Core/HW/WiimoteEmu/Extension/DrawsomeTablet.h"
6 
7 #include <array>
8 #include <cassert>
9 
10 #include "Common/BitUtils.h"
11 #include "Common/Common.h"
12 #include "Common/CommonTypes.h"
13 #include "Core/HW/WiimoteEmu/WiimoteEmu.h"
14 
15 #include "InputCommon/ControllerEmu/Control/Input.h"
16 #include "InputCommon/ControllerEmu/ControlGroup/AnalogStick.h"
17 #include "InputCommon/ControllerEmu/ControlGroup/Triggers.h"
18 
19 namespace WiimoteEmu
20 {
21 constexpr std::array<u8, 6> drawsome_tablet_id{{0xff, 0x00, 0xa4, 0x20, 0x00, 0x13}};
22 
23 // i18n: The "Drawsome" (combination of "Draw" and "Awesome") tablet wiimote extension by Ubisoft.
DrawsomeTablet()24 DrawsomeTablet::DrawsomeTablet() : Extension3rdParty("Drawsome", _trans("Drawsome Tablet"))
25 {
26   // Stylus
27   groups.emplace_back(m_stylus = new ControllerEmu::AnalogStick(
28                           _trans("Stylus"), std::make_unique<ControllerEmu::SquareStickGate>(1.0)));
29 
30   // Touch
31   groups.emplace_back(m_touch = new ControllerEmu::Triggers(_trans("Touch")));
32   m_touch->AddInput(ControllerEmu::Translate, _trans("Pressure"));
33 }
34 
Update()35 void DrawsomeTablet::Update()
36 {
37   DataFormat tablet_data = {};
38 
39   // Stylus X/Y (calibrated values):
40   constexpr u16 MIN_X = 0x0000;
41   constexpr u16 MAX_X = 0x27ff;
42   // Note: While 0x15ff seems to be the ideal calibrated value,
43   // the "Drawsome" game expects you to go "off screen" a bit to access some menu items.
44   constexpr u16 MIN_Y = 0x15ff + 0x100;
45   constexpr u16 MAX_Y = 0x00;
46   constexpr double CENTER_X = (MAX_X + MIN_X) / 2.0;
47   constexpr double CENTER_Y = (MAX_Y + MIN_Y) / 2.0;
48 
49   const auto stylus_state = m_stylus->GetState();
50   const auto stylus_x = u16(std::lround(CENTER_X + stylus_state.x * (MAX_X - CENTER_X)));
51   const auto stylus_y = u16(std::lround(CENTER_Y + stylus_state.y * (MAX_Y - CENTER_Y)));
52 
53   tablet_data.stylus_x1 = u8(stylus_x);
54   tablet_data.stylus_x2 = u8(stylus_x >> 8);
55 
56   tablet_data.stylus_y1 = u8(stylus_y);
57   tablet_data.stylus_y2 = u8(stylus_y >> 8);
58 
59   // TODO: Expose the lifted stylus state in the UI.
60   // Note: Pen X/Y holds the last value when the pen is lifted.
61   const bool is_stylus_lifted = false;
62 
63   constexpr u8 NEUTRAL_STATUS = 0x8;
64   constexpr u8 PEN_LIFTED_BIT = 0x10;
65 
66   u8 status = NEUTRAL_STATUS;
67 
68   if (is_stylus_lifted)
69     status |= PEN_LIFTED_BIT;
70 
71   tablet_data.status = status;
72 
73   // Pressure (0 - 0x7ff):
74   constexpr u16 MAX_PRESSURE = 0x7ff;
75 
76   const auto touch_state = m_touch->GetState();
77   const auto pressure = u16(std::lround(touch_state.data[0] * MAX_PRESSURE));
78 
79   tablet_data.pressure1 = u8(pressure);
80   tablet_data.pressure2 = u8(pressure >> 8);
81 
82   Common::BitCastPtr<DataFormat>(&m_reg.controller_data) = tablet_data;
83 }
84 
Reset()85 void DrawsomeTablet::Reset()
86 {
87   EncryptedExtension::Reset();
88 
89   m_reg.identifier = drawsome_tablet_id;
90 
91   // Assuming calibration data is 0xff filled.
92   m_reg.calibration.fill(0xff);
93 }
94 
GetGroup(DrawsomeTabletGroup group)95 ControllerEmu::ControlGroup* DrawsomeTablet::GetGroup(DrawsomeTabletGroup group)
96 {
97   switch (group)
98   {
99   case DrawsomeTabletGroup::Stylus:
100     return m_stylus;
101   case DrawsomeTabletGroup::Touch:
102     return m_touch;
103   default:
104     assert(false);
105     return nullptr;
106   }
107 }
108 
109 }  // namespace WiimoteEmu
110