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