removing bool8_32 type
[drnoksnes] / platform / sdli.cpp
1 #include <SDL.h>
2 #include <math.h>
3
4 #include "platform.h"
5 #include "snes9x.h"
6 #include "sdlv.h" // Dispatching video-related events
7
8 #if CONF_ZEEMOTE
9 #include "zeemote.h"
10 #endif
11
12 struct TouchButton {
13         unsigned short mask;
14         unsigned short x, y;
15         unsigned short x2, y2;
16         double fx, fy;
17         double fw, fh;
18 };
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 #define TB(actions, x, y, w, h) \
27         {actions, 0, 0, 0, 0, x, y, w, h}
28 #define P(x) SNES_##x##_MASK
29         TB(P(TL), 0.0, 0.0, kCornerButtonWidth, kCornerButtonHeight),
30         TB(P(TR), 0.625, 0.0, kCornerButtonWidth, kCornerButtonHeight),
31         TB(P(LEFT) | P(UP), 0.0, kCornerButtonHeight, kBigButtonWidth, kBigButtonHeight),
32         TB(P(UP), kBigButtonWidth, kCornerButtonHeight, kBigButtonWidth, kBigButtonHeight),
33         TB(P(RIGHT) | P(UP), 2.0 * kBigButtonWidth, kCornerButtonHeight, kBigButtonWidth, kBigButtonHeight),
34         TB(P(LEFT), 0.0, kCornerButtonHeight + kBigButtonHeight, kBigButtonWidth, kBigButtonHeight),
35         TB(P(RIGHT), 2.0 * kBigButtonWidth, kCornerButtonHeight + kBigButtonHeight, kBigButtonWidth, kBigButtonHeight),
36         TB(P(LEFT) | P(DOWN), 0, 1.0 - (kCornerButtonHeight + kBigButtonHeight), kBigButtonWidth, kBigButtonHeight),
37         TB(P(DOWN), kBigButtonWidth, 1.0 - (kCornerButtonHeight + kBigButtonHeight), kBigButtonWidth, kBigButtonHeight),
38         TB(P(RIGHT) | P(DOWN), 2.0 * kBigButtonWidth, 1.0 - (kCornerButtonHeight + kBigButtonHeight), kBigButtonWidth, kBigButtonHeight),
39         TB(P(SELECT), 0.0, 1.0 - kCornerButtonHeight, kCornerButtonWidth, kCornerButtonHeight),
40         TB(P(X), 1.0 - 2.0 * kBigButtonWidth, kCornerButtonHeight, kBigButtonWidth, kBigButtonHeight),
41         TB(P(Y), 1.0 - 3.0 * kBigButtonWidth, kCornerButtonHeight + kBigButtonHeight, kBigButtonWidth, kBigButtonHeight),
42         TB(P(A), 1.0 - kBigButtonWidth, kCornerButtonHeight + kBigButtonHeight, kBigButtonWidth, kBigButtonHeight),
43         TB(P(B), 1.0 - 2.0 * kBigButtonWidth, 1.0 - (kCornerButtonHeight + kBigButtonHeight), kBigButtonWidth, kBigButtonHeight),
44         TB(P(START), 1.0 - kCornerButtonWidth, 1.0 - kCornerButtonHeight, kCornerButtonWidth, kCornerButtonHeight),
45 #undef P
46 #undef TB
47 };
48
49 static TouchButton* current = 0;
50
51 static uint32 joypads[2];
52 static struct {
53         unsigned x;
54         unsigned y;
55         bool enabled, pressed;
56 } mouse;
57
58 static TouchButton* getButtonFor(unsigned int x, unsigned int y) {
59         unsigned int i;
60
61         for (i = 0; i < sizeof(touchbuttons)/sizeof(TouchButton); i++) {
62                 if (x >= touchbuttons[i].x && x < touchbuttons[i].x2 &&
63                         y >= touchbuttons[i].y && y < touchbuttons[i].y2) {
64
65                         return &touchbuttons[i];
66                 }
67         }
68
69         return 0;
70 }
71
72 static inline void unpress(TouchButton* b) {
73         joypads[Config.touchscreenInput - 1] &= ~b->mask;
74 }
75 static inline void press(TouchButton* b) {
76         joypads[Config.touchscreenInput - 1] |= b->mask;
77 }
78
79 static void processMouse(unsigned int x, unsigned int y, int pressed = 0)
80 {
81 #if CONF_EXIT_BUTTON
82         /* no fullscreen escape button, we have to simulate one! */
83         /* TODO: don't hardcode sizes */
84         if (Config.fullscreen && x > (800 - 100) && y < 50 && pressed > 0) {
85                 S9xDoAction(kActionQuit);
86         }
87 #endif
88         if (Config.touchscreenInput) {
89                 if (pressed < 0) {
90                         // Button up.
91                         if (current) {
92                                 // Leaving button
93                                 unpress(current);
94                                 current = 0;
95                         }
96                 } else {
97                         // Button down, or mouse motion.
98                         TouchButton* b = getButtonFor(x, y);
99                         if (current && b && current != b) {
100                                 // Moving from button to button
101                                 unpress(current);
102                                 current = b;
103                                 press(current);
104                         } else if (current && !b) {
105                                 // Leaving button
106                                 unpress(current);
107                                 current = 0;
108                         } else if (!current && b) {
109                                 // Entering button
110                                 current = b;
111                                 press(current);
112                         }
113                 }
114         } else if (mouse.enabled) {
115                 mouse.x = x;
116                 mouse.y = y;
117
118                 if (mouse.x < GUI.RenderX) mouse.x = 0;
119                 else {
120                         mouse.x -= GUI.RenderX;
121                         if (mouse.x > GUI.RenderW) mouse.x = GUI.RenderW;
122                 }
123
124                 if (mouse.y < GUI.RenderY) mouse.y = 0;
125                 else {
126                         mouse.y -= GUI.RenderY;
127                         if (mouse.y > GUI.RenderH) mouse.y = GUI.RenderH;
128                 }
129
130                 // mouse.{x,y} are system coordinates.
131                 // Scale them to emulated screen coordinates.
132                 mouse.x = static_cast<unsigned int>(mouse.x / GUI.ScaleX);
133                 mouse.y = static_cast<unsigned int>(mouse.y / GUI.ScaleY);
134
135                 if (pressed > 0)
136                         mouse.pressed = true;
137                 else if (pressed < 0)
138                         mouse.pressed = false;
139         }
140 }
141
142 static void processEvent(const SDL_Event& event)
143 {
144         if (videoEventFilter(event)) return;
145
146         switch (event.type) 
147         {
148                 case SDL_KEYDOWN:
149                         if (Config.action[event.key.keysym.scancode]) 
150                                 S9xDoAction(Config.action[event.key.keysym.scancode]);
151                         joypads[0] |= Config.joypad1Mapping[event.key.keysym.scancode];
152                         joypads[1] |= Config.joypad2Mapping[event.key.keysym.scancode];
153                         break;
154                 case SDL_KEYUP:
155                         joypads[0] &= ~Config.joypad1Mapping[event.key.keysym.scancode];
156                         joypads[1] &= ~Config.joypad2Mapping[event.key.keysym.scancode];
157                         break;
158                 case SDL_MOUSEBUTTONUP:
159                 case SDL_MOUSEBUTTONDOWN:
160                         processMouse(event.button.x, event.button.y,
161                                         (event.button.state == SDL_PRESSED) ? 1 : - 1);
162                         break;
163                 case SDL_MOUSEMOTION:
164                         processMouse(event.motion.x, event.motion.y);
165                         break;
166                 case SDL_QUIT:
167                         Config.quitting = true;
168                         break;
169         }
170 }
171
172 /** This function is called to return a bit-wise mask of the state of one of the
173         five emulated SNES controllers.
174
175         @return 0 if you're not supporting controllers past a certain number or
176                 return the mask representing the current state of the controller number
177                 passed as a parameter or'ed with 0x80000000.
178 */
179
180 uint32 S9xReadJoypad (int which)
181 {
182         if (which < 0 || which >= 2) {
183                 // More joypads that we currently handle (could happen if bad conf)
184                 return 0;
185         }
186
187         return joypads[which];
188 }
189
190 /** Get the current position of the host pointing device, usually a mouse,
191         used to emulated the SNES mouse.
192
193         @param buttons The buttons return value is a bit-wise mask of the two SNES
194                 mouse buttons, bit 0 for button 1 (left) and bit 1 for button 2 (right).
195 */
196 bool8 S9xReadMousePosition(int which, int *x, int *y, uint32 *buttons)
197 {
198         if (which != 0) return FALSE;
199
200         *x = mouse.x;
201         *y = mouse.y;
202         *buttons = mouse.pressed ? 1 : 0;
203
204         return TRUE;
205 }
206
207 bool8 S9xReadSuperScopePosition(int *x, int *y, uint32 *buttons)
208 {
209         *x = mouse.x;
210         *y = mouse.y;
211         *buttons = mouse.pressed ? 8 : 0;
212
213         return TRUE;
214 }
215
216 /** Get and process system/input events.
217         @param block true to block, false to poll until the queue is empty.
218 */
219 void S9xProcessEvents(bool block)
220 {
221         SDL_Event event;
222
223 #if CONF_ZEEMOTE
224         // Wheter blocking or non blocking, poll zeemotes now.
225         ZeeRead(joypads);
226 #endif
227
228         if (block) {
229                 SDL_WaitEvent(&event);
230                 processEvent(event);
231         } else {
232                 while(SDL_PollEvent(&event)) {
233                         processEvent(event);
234                 }
235         }
236 }
237
238 void S9xInitInputDevices()
239 {
240         joypads[0] = 0;
241         joypads[1] = 0;
242         mouse.enabled = false;
243         mouse.pressed = false;
244
245 #if CONF_ZEEMOTE
246         ZeeInit();
247 #endif
248
249         if (Config.joypad1Enabled) {
250                 joypads[0] = 0x80000000UL;
251         }
252         if (Config.joypad2Enabled) {
253                 joypads[1] = 0x80000000UL;
254         }
255
256         // Pretty print some information
257         printf("Input: ");
258         if (Config.joypad1Enabled) {
259                 printf("Player 1 (joypad)");
260                 if (Config.joypad2Enabled) {
261                         printf("+ player 2 (joypad)");
262                 }
263         } else if (Config.joypad2Enabled) {
264                 printf("Player 2 (joypad)");
265         } else {
266                 printf("Nothing");
267         }
268         printf("\n");
269
270         // TODO Non-awful mouse & superscope support
271
272         S9xInputScreenChanged();
273 }
274
275 void S9xDeinitInputDevices()
276 {
277 #if CONF_ZEEMOTE
278         ZeeQuit();
279 #endif
280         joypads[0] = 0;
281         joypads[1] = 0;
282         mouse.enabled = false;
283         mouse.pressed = false;
284 }
285
286 void S9xInputScreenChanged()
287 {
288         unsigned int i = 0;
289         const unsigned int w = GUI.Width, h = GUI.Height;
290         for (i = 0; i < sizeof(touchbuttons)/sizeof(TouchButton); i++) {
291                 touchbuttons[i].x = (unsigned int)(touchbuttons[i].fx * w);
292                 touchbuttons[i].y = (unsigned int)(touchbuttons[i].fy * h);
293                 touchbuttons[i].x2 = (unsigned int)(touchbuttons[i].x + touchbuttons[i].fw * w);
294                 touchbuttons[i].y2 = (unsigned int)(touchbuttons[i].y + touchbuttons[i].fh * h);
295         }
296 }
297
298 template <typename T>
299 static void drawControls(T * buffer, const int pitch)
300 {
301         unsigned int i = 0;
302         int x, y;
303         const T black = static_cast<T>(0xFFFFFFFFU);
304         T* temp;
305
306         for (i = 0; i < sizeof(touchbuttons)/sizeof(TouchButton); i++) {
307                 temp = buffer + touchbuttons[i].y * pitch + touchbuttons[i].x;
308                 for (x = touchbuttons[i].x; x < touchbuttons[i].x2; x++) {
309                         *temp = black;
310                         temp++;
311                 }
312                 temp = buffer + touchbuttons[i].y2 * pitch + touchbuttons[i].x;
313                 for (x = touchbuttons[i].x; x < touchbuttons[i].x2; x++) {
314                         *temp = black;
315                         temp++;
316                 }
317                 temp = buffer + touchbuttons[i].y * pitch + touchbuttons[i].x;
318                 for (y = touchbuttons[i].y; y < touchbuttons[i].y2; y++) {
319                         *temp = black;
320                         temp+=pitch;
321                 }
322                 temp = buffer + touchbuttons[i].y * pitch + touchbuttons[i].x2;
323                 for (y = touchbuttons[i].y; y < touchbuttons[i].y2; y++) {
324                         *temp = black;
325                         temp+=pitch;
326                 }
327         }
328 }
329
330 void S9xInputScreenDraw(void * buffer, int pitch)
331 {
332         drawControls(reinterpret_cast<uint16*>(buffer), pitch / 2);
333 }
334