simple onscreen buttons
[drnoksnes] / platform / sdli.cpp
1 #include <SDL.h>
2 #include <math.h>
3
4 #include "platform.h"
5 #include "snes9x.h"
6 #include "display.h"
7
8 struct TouchButton {
9         unsigned short mask;
10         unsigned short x, y;
11         unsigned short x2, y2;
12         float fx, fy;
13         float fw, fh;
14 };
15
16 #define TOUCH_BUTTON_INITIALIZER(name, x, y, w, h) \
17         {SNES_##name##_MASK, 0, 0, 0, 0, x, y, w, h}
18
19 static TouchButton touchbuttons[] = {
20         TOUCH_BUTTON_INITIALIZER(TL, 0, 0, 0.375, 0.0833),
21         TOUCH_BUTTON_INITIALIZER(TR, 0.625, 0, 0.375, 0.0833),
22         TOUCH_BUTTON_INITIALIZER(UP, 0.125, 0.0833, 0.125, 0.2777), //2
23         TOUCH_BUTTON_INITIALIZER(LEFT, 0.0, 0.3611, 0.125, 0.2777), //3
24         TOUCH_BUTTON_INITIALIZER(RIGHT, 0.25, 0.3611, 0.125, 0.2777), //4
25         TOUCH_BUTTON_INITIALIZER(DOWN, 0.125, 0.6388, 0.125, 0.2777), //5
26         TOUCH_BUTTON_INITIALIZER(START, 0, 0.9166, 0.375, 0.0833),
27         TOUCH_BUTTON_INITIALIZER(Y, 0.75, 0.0833, 0.125, 0.2777),
28         TOUCH_BUTTON_INITIALIZER(X, 0.625, 0.3611, 0.125, 0.2777),
29         TOUCH_BUTTON_INITIALIZER(A, 0.875, 0.3611, 0.125, 0.2777),
30         TOUCH_BUTTON_INITIALIZER(B, 0.75, 0.6388, 0.125, 0.2777),
31         TOUCH_BUTTON_INITIALIZER(SELECT, 0.625, 0.9166, 0.375, 0.0833),
32 };
33
34 static TouchButton* current = 0;
35
36 static uint32 joypads[2];
37 static struct {
38         unsigned x;
39         unsigned y;
40         bool enabled, pressed;
41 } mouse;
42
43 static TouchButton* getButtonFor(unsigned int x, unsigned int y) {
44         unsigned int i;
45
46         for (i = 0; i < sizeof(touchbuttons)/sizeof(TouchButton); i++) {
47                 if (x > touchbuttons[i].x && x < touchbuttons[i].x2 &&
48                         y > touchbuttons[i].y && y < touchbuttons[i].y2) {
49
50                         return &touchbuttons[i];
51                 }
52         }
53
54         return 0;
55 }
56
57 static inline void unpress(TouchButton* b) {
58         joypads[0] &= ~b->mask;
59 }
60 static inline void press(TouchButton* b) {
61         joypads[0] |= b->mask;
62 }
63
64 static void processMouse(unsigned int x, unsigned int y, int pressed = 0)
65 {
66         if (Config.touchscreenInput) {
67                 if (pressed < 0) {
68                         // Button up.
69                         if (current) {
70                                 // Leaving button
71                                 unpress(current);
72                                 current = 0;
73                         }
74                 } else {
75                         // Button down, or mouse motion.
76                         TouchButton* b = getButtonFor(x, y);
77                         if (current && b && current != b) {
78                                 // Moving from button to button
79                                 unpress(current);
80                                 current = b;
81                                 press(current);
82                         } else if (current && !b) {
83                                 // Leaving button
84                                 unpress(current);
85                                 current = 0;
86                         } else if (!current && b) {
87                                 // Entering button
88                                 current = b;
89                                 press(current);
90                         }
91                 }
92         } else if (mouse.enabled) {
93                 mouse.x = x;
94                 mouse.y = y;
95
96                 if (mouse.x < GUI.RenderX) mouse.x = 0;
97                 else {
98                         mouse.x -= GUI.RenderX;
99                         if (mouse.x > GUI.RenderW) mouse.x = GUI.RenderW;
100                 }
101
102                 if (mouse.y < GUI.RenderY) mouse.y = 0;
103                 else {
104                         mouse.y -= GUI.RenderY;
105                         if (mouse.y > GUI.RenderH) mouse.y = GUI.RenderH;
106                 }
107
108                 // Take care of scaling
109                 mouse.x /= GUI.Scale;
110                 mouse.y /= GUI.Scale;
111
112                 if (pressed > 0)
113                         mouse.pressed = true;
114                 else if (pressed < 0)
115                         mouse.pressed = false;
116         }
117 }
118
119 static void processEvent(const SDL_Event& event)
120 {
121         switch (event.type) 
122         {
123         case SDL_KEYDOWN:
124                 if (Config.action[event.key.keysym.scancode]) 
125                         S9xDoAction(Config.action[event.key.keysym.scancode]);
126                 joypads[0] |= Config.joypad1Mapping[event.key.keysym.scancode];
127                 break;
128         case SDL_KEYUP:
129                 joypads[0] &= ~Config.joypad1Mapping[event.key.keysym.scancode];
130                 break;
131         case SDL_MOUSEBUTTONUP:
132         case SDL_MOUSEBUTTONDOWN:
133                 processMouse(event.button.x, event.button.y,
134                                 (event.button.state == SDL_PRESSED) ? 1 : - 1);
135                 break;
136         case SDL_MOUSEMOTION:
137                 processMouse(event.motion.x, event.motion.y);
138                 break;
139         case SDL_QUIT:
140                 Config.quitting = true;
141                 break;
142         }
143 }
144
145 uint32 S9xReadJoypad (int which)
146 {
147         if (which < 0 || which > 2) {
148                 return 0;
149         }
150
151         return joypads[which];
152 }
153
154 bool8 S9xReadMousePosition(int which1, int& x, int& y, uint32& buttons)
155 {
156         if (which1 != 0) return FALSE;
157
158         x = mouse.x;
159         y = mouse.y;
160         buttons = mouse.pressed ? 1 : 0;
161
162         return TRUE;
163 }
164
165 bool8 S9xReadSuperScopePosition(int& x, int& y, uint32& buttons)
166 {
167         x = mouse.x;
168         y = mouse.y;
169         buttons = mouse.pressed ? 8 : 0;
170
171         return TRUE;
172 }
173
174 void S9xProcessEvents(bool8_32 block)
175 {
176         SDL_Event event;
177
178         if (block) {
179                 SDL_WaitEvent(&event);
180                 processEvent(event);
181         } else {
182                 while(SDL_PollEvent(&event)) 
183                 {      
184                         processEvent(event);
185                 }
186         }
187 }
188
189 void S9xInitInputDevices()
190 {
191         joypads[0] = 0;
192         joypads[1] = 0;
193
194         switch (Settings.ControllerOption) {
195                 case SNES_JOYPAD:
196                         joypads[0] = 0x80000000UL;
197                         printf("Input: 1 joypad, keyboard only\n");
198                         break;
199                 case SNES_MOUSE:
200                         joypads[0] = 0x80000000UL;
201                         mouse.enabled = true;
202                         printf("Input: 1 joypad + mouse\n");
203                         break;
204                 case SNES_MOUSE_SWAPPED:
205                         printf("Input: mouse\n");
206                         mouse.enabled = true;
207                         break;
208                 case SNES_SUPERSCOPE:
209                         joypads[0] = 0x80000000UL;
210                         mouse.enabled = true;
211                         printf("Input: 1 joypad + superscope\n");
212                         break;
213                 default:
214                         printf("Input: unknown\n");
215                         break;
216         }
217
218         S9xInputScreenChanged();
219 }
220
221 void S9xDeinitInputDevices()
222 {
223
224 }
225
226 void S9xInputScreenChanged()
227 {
228         unsigned int i = 0;
229         const unsigned int w = GUI.Width, h = GUI.Height;
230         for (i = 0; i < sizeof(touchbuttons)/sizeof(TouchButton); i++) {
231                 touchbuttons[i].x = (unsigned)round(touchbuttons[i].fx * w);
232                 touchbuttons[i].y = (unsigned)round(touchbuttons[i].fy * h);
233                 touchbuttons[i].x2 = (unsigned)round(touchbuttons[i].x + touchbuttons[i].fw * w);
234                 touchbuttons[i].y2 = (unsigned)round(touchbuttons[i].y + touchbuttons[i].fh * h);
235         }
236 }
237
238 template <typename T>
239 static void drawControls(T * buffer, const int pitch)
240 {
241         unsigned int i = 0;
242         int x, y;
243         T* temp;
244
245         for (i = 0; i < sizeof(touchbuttons)/sizeof(TouchButton); i++) {
246                 temp = buffer + touchbuttons[i].y * pitch + touchbuttons[i].x;
247                 for (x = touchbuttons[i].x; x < touchbuttons[i].x2; x++) {
248                         *temp = -1UL; // Black
249                         temp++;
250                 }
251                 temp = buffer + touchbuttons[i].y2 * pitch + touchbuttons[i].x;
252                 for (x = touchbuttons[i].x; x < touchbuttons[i].x2; x++) {
253                         *temp = -1UL; // Black
254                         temp++;
255                 }
256                 temp = buffer + touchbuttons[i].y * pitch + touchbuttons[i].x;
257                 for (y = touchbuttons[i].y; y < touchbuttons[i].y2; y++) {
258                         *temp = -1UL; // Black
259                         temp+=pitch;
260                 }
261                 temp = buffer + touchbuttons[i].y * pitch + touchbuttons[i].x2;
262                 for (y = touchbuttons[i].y; y < touchbuttons[i].y2; y++) {
263                         *temp = -1UL; // Black
264                         temp+=pitch;
265                 }
266         }
267 }
268
269 void S9xInputScreenDraw(int pixelSize, void * buffer, int pitch)
270 {
271         switch (pixelSize)
272         {
273                 case 1:
274                         drawControls(reinterpret_cast<uint8*>(buffer), pitch);
275                         break;
276                 case 2:
277                         drawControls(reinterpret_cast<uint16*>(buffer), pitch / 2);
278                         break;
279         }
280 }
281