8b83934d165928a0db8a7072e96979e63c14ace2
[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 (Config.touchscreenInput) {
72                 if (pressed < 0) {
73                         // Button up.
74                         if (current) {
75                                 // Leaving button
76                                 unpress(current);
77                                 current = 0;
78                         }
79                 } else {
80                         // Button down, or mouse motion.
81                         TouchButton* b = getButtonFor(x, y);
82                         if (current && b && current != b) {
83                                 // Moving from button to button
84                                 unpress(current);
85                                 current = b;
86                                 press(current);
87                         } else if (current && !b) {
88                                 // Leaving button
89                                 unpress(current);
90                                 current = 0;
91                         } else if (!current && b) {
92                                 // Entering button
93                                 current = b;
94                                 press(current);
95                         }
96                 }
97         } else if (mouse.enabled) {
98                 mouse.x = x;
99                 mouse.y = y;
100
101                 if (mouse.x < GUI.RenderX) mouse.x = 0;
102                 else {
103                         mouse.x -= GUI.RenderX;
104                         if (mouse.x > GUI.RenderW) mouse.x = GUI.RenderW;
105                 }
106
107                 if (mouse.y < GUI.RenderY) mouse.y = 0;
108                 else {
109                         mouse.y -= GUI.RenderY;
110                         if (mouse.y > GUI.RenderH) mouse.y = GUI.RenderH;
111                 }
112
113                 // Take care of scaling
114                 mouse.x /= GUI.Scale;
115                 mouse.y /= GUI.Scale;
116
117                 if (pressed > 0)
118                         mouse.pressed = true;
119                 else if (pressed < 0)
120                         mouse.pressed = false;
121         }
122 }
123
124 static void processEvent(const SDL_Event& event)
125 {
126         switch (event.type) 
127         {
128         case SDL_KEYDOWN:
129                 if (Config.action[event.key.keysym.scancode]) 
130                         S9xDoAction(Config.action[event.key.keysym.scancode]);
131                 joypads[0] |= Config.joypad1Mapping[event.key.keysym.scancode];
132                 break;
133         case SDL_KEYUP:
134                 joypads[0] &= ~Config.joypad1Mapping[event.key.keysym.scancode];
135                 break;
136         case SDL_MOUSEBUTTONUP:
137         case SDL_MOUSEBUTTONDOWN:
138                 processMouse(event.button.x, event.button.y,
139                                 (event.button.state == SDL_PRESSED) ? 1 : - 1);
140                 break;
141         case SDL_MOUSEMOTION:
142                 processMouse(event.motion.x, event.motion.y);
143                 break;
144         case SDL_QUIT:
145                 Config.quitting = true;
146                 break;
147         }
148 }
149
150 uint32 S9xReadJoypad (int which)
151 {
152         if (which < 0 || which > 2) {
153                 return 0;
154         }
155
156         return joypads[which];
157 }
158
159 bool8 S9xReadMousePosition(int which1, int& x, int& y, uint32& buttons)
160 {
161         if (which1 != 0) return FALSE;
162
163         x = mouse.x;
164         y = mouse.y;
165         buttons = mouse.pressed ? 1 : 0;
166
167         return TRUE;
168 }
169
170 bool8 S9xReadSuperScopePosition(int& x, int& y, uint32& buttons)
171 {
172         x = mouse.x;
173         y = mouse.y;
174         buttons = mouse.pressed ? 8 : 0;
175
176         return TRUE;
177 }
178
179 void S9xProcessEvents(bool8_32 block)
180 {
181         SDL_Event event;
182
183         if (block) {
184                 SDL_WaitEvent(&event);
185                 processEvent(event);
186         } else {
187                 while(SDL_PollEvent(&event)) {
188                         processEvent(event);
189                 }
190         }
191 }
192
193 void S9xInitInputDevices()
194 {
195         joypads[0] = 0;
196         joypads[1] = 0;
197
198         switch (Settings.ControllerOption) {
199                 case SNES_JOYPAD:
200                         joypads[0] = 0x80000000UL;
201                         printf("Input: 1 joypad, keyboard only\n");
202                         break;
203                 case SNES_MOUSE:
204                         joypads[0] = 0x80000000UL;
205                         mouse.enabled = true;
206                         printf("Input: 1 joypad + mouse\n");
207                         break;
208                 case SNES_MOUSE_SWAPPED:
209                         printf("Input: mouse\n");
210                         mouse.enabled = true;
211                         break;
212                 case SNES_SUPERSCOPE:
213                         joypads[0] = 0x80000000UL;
214                         mouse.enabled = true;
215                         printf("Input: 1 joypad + superscope\n");
216                         break;
217                 default:
218                         printf("Input: unknown\n");
219                         break;
220         }
221
222         S9xInputScreenChanged();
223 }
224
225 void S9xDeinitInputDevices()
226 {
227
228 }
229
230 void S9xInputScreenChanged()
231 {
232         unsigned int i = 0;
233         const unsigned int w = GUI.Width, h = GUI.Height;
234         for (i = 0; i < sizeof(touchbuttons)/sizeof(TouchButton); i++) {
235                 touchbuttons[i].x = (unsigned int)(touchbuttons[i].fx * w);
236                 touchbuttons[i].y = (unsigned int)(touchbuttons[i].fy * h);
237                 touchbuttons[i].x2 = (unsigned int)(touchbuttons[i].x + touchbuttons[i].fw * w);
238                 touchbuttons[i].y2 = (unsigned int)(touchbuttons[i].y + touchbuttons[i].fh * h);
239         }
240 }
241
242 template <typename T>
243 static void drawControls(T * buffer, const int pitch)
244 {
245         unsigned int i = 0;
246         int x, y;
247         const T black = static_cast<T>(0xFFFFFFFFU);
248         T* temp;
249
250         for (i = 0; i < sizeof(touchbuttons)/sizeof(TouchButton); i++) {
251                 temp = buffer + touchbuttons[i].y * pitch + touchbuttons[i].x;
252                 for (x = touchbuttons[i].x; x < touchbuttons[i].x2; x++) {
253                         *temp = black;
254                         temp++;
255                 }
256                 temp = buffer + touchbuttons[i].y2 * pitch + touchbuttons[i].x;
257                 for (x = touchbuttons[i].x; x < touchbuttons[i].x2; x++) {
258                         *temp = black;
259                         temp++;
260                 }
261                 temp = buffer + touchbuttons[i].y * pitch + touchbuttons[i].x;
262                 for (y = touchbuttons[i].y; y < touchbuttons[i].y2; y++) {
263                         *temp = black;
264                         temp+=pitch;
265                 }
266                 temp = buffer + touchbuttons[i].y * pitch + touchbuttons[i].x2;
267                 for (y = touchbuttons[i].y; y < touchbuttons[i].y2; y++) {
268                         *temp = black;
269                         temp+=pitch;
270                 }
271         }
272 }
273
274 void S9xInputScreenDraw(int pixelSize, void * buffer, int pitch)
275 {
276         switch (pixelSize)
277         {
278                 case 1:
279                         drawControls(reinterpret_cast<uint8*>(buffer), pitch);
280                         break;
281                 case 2:
282                         drawControls(reinterpret_cast<uint16*>(buffer), pitch / 2);
283                         break;
284         }
285 }
286