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