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