Mercurial > repos > simple16
annotate src/system_sdl.c @ 38:3b7910575a00
Implemented basic keyboard support
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Mon, 04 Apr 2016 09:13:14 -0700 |
parents | c677507682e3 |
children | 8e39a877c651 |
rev | line source |
---|---|
15 | 1 #include <SDL.h> |
2 #include <stdint.h> | |
16
ae58e7c3c328
Poll events regularly to avoid unresponsive app warnings. Handle quit event
Michael Pavone <pavone@retrodev.com>
parents:
15
diff
changeset
|
3 #include <stdlib.h> |
28
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
4 #include "controller.h" |
15 | 5 |
6 | |
24 | 7 static SDL_Window *window; |
8 static SDL_Renderer *renderer; | |
9 static SDL_Texture *texture; | |
10 static int sample_rate; | |
11 static int buffer_size; | |
12 static uint8_t quitting; | |
13 | |
14 static SDL_mutex * audio_mutex; | |
15 static SDL_cond * source_ready; | |
16 static SDL_cond * output_ready; | |
17 static int16_t *source_buffer; | |
15 | 18 |
24 | 19 static void audio_callback(void * userdata, uint8_t *stream, int len) |
20 { | |
21 uint8_t local_quit; | |
22 int16_t *local_source; | |
23 SDL_LockMutex(audio_mutex); | |
24 local_source = NULL; | |
25 do { | |
26 if (!local_source) { | |
27 local_source = source_buffer; | |
28 source_buffer = NULL; | |
29 SDL_CondSignal(output_ready); | |
30 } | |
31 if (!quitting && !local_source) { | |
32 SDL_CondWait(source_ready, audio_mutex); | |
33 } | |
34 } while (!quitting && !local_source); | |
35 local_quit = quitting; | |
36 SDL_UnlockMutex(audio_mutex); | |
37 if (!local_quit) { | |
38 fflush(stdout); | |
39 memcpy(stream, local_source, len); | |
40 } | |
41 } | |
42 | |
43 static void close_audio() | |
15 | 44 { |
24 | 45 SDL_LockMutex(audio_mutex); |
46 quitting = 1; | |
47 SDL_CondSignal(source_ready); | |
48 SDL_UnlockMutex(audio_mutex); | |
49 SDL_CloseAudio(); | |
50 } | |
51 | |
52 void system_present_audio(int16_t *buffer) | |
53 { | |
54 SDL_LockMutex(audio_mutex); | |
55 while (source_buffer) { | |
56 SDL_CondWait(output_ready, audio_mutex); | |
57 } | |
58 source_buffer = buffer; | |
59 SDL_CondSignal(source_ready); | |
60 SDL_UnlockMutex(audio_mutex); | |
61 } | |
62 | |
63 int system_sample_rate() | |
64 { | |
65 return sample_rate; | |
66 } | |
67 | |
68 int system_buffer_size() | |
69 { | |
70 return buffer_size; | |
71 } | |
72 | |
28
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
73 static int num_controllers; |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
74 static SDL_GameController **game_controllers; |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
75 |
24 | 76 int system_init(int width, int height, int desired_sample_rate) |
77 { | |
28
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
78 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMECONTROLLER) < 0) { |
15 | 79 fprintf(stderr, "Failed to init SDL: %s\n", SDL_GetError()); |
80 return 0; | |
81 } | |
82 atexit(SDL_Quit); | |
17 | 83 window = SDL_CreateWindow("simple16", 0, 0, width, height, 0); |
84 if (!window) { | |
85 fprintf(stderr, "Failed to create window: %s\n", SDL_GetError()); | |
15 | 86 return 0; |
87 } | |
17 | 88 |
89 renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); | |
90 if (!renderer) { | |
91 fprintf(stderr, "Failed to create renderer: %s\n", SDL_GetError()); | |
24 | 92 goto renderer_error; |
17 | 93 } |
94 | |
15 | 95 texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGB444, SDL_TEXTUREACCESS_STREAMING, 320, 240); |
96 if (!texture) { | |
97 fprintf(stderr, "Failed to create texture: %s\n", SDL_GetError()); | |
24 | 98 goto error; |
15 | 99 } |
24 | 100 |
101 audio_mutex = SDL_CreateMutex(); | |
102 source_ready = SDL_CreateCond(); | |
103 output_ready = SDL_CreateCond(); | |
104 | |
105 SDL_AudioSpec desired, actual; | |
106 desired.freq = desired_sample_rate; | |
107 desired.format = AUDIO_S16SYS; | |
108 desired.channels = 1; | |
109 desired.callback = audio_callback; | |
110 desired.userdata = NULL; | |
111 desired.samples = 512; | |
112 | |
113 if (SDL_OpenAudio(&desired, &actual) < 0) { | |
114 fprintf(stderr, "Failed to open audio: %s\n", SDL_GetError()); | |
115 goto error; | |
116 } | |
117 printf("Initialized audio at frequency %d with a %d sample buffer and %d channels\n", actual.freq, actual.samples, actual.channels); | |
118 sample_rate = actual.freq; | |
119 buffer_size = actual.samples; | |
120 atexit(close_audio); | |
121 SDL_PauseAudio(0); | |
122 | |
28
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
123 num_controllers = SDL_NumJoysticks(); |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
124 game_controllers = calloc(num_controllers, sizeof(*game_controllers)); |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
125 |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
126 for (int i = 0; i < num_controllers; i++) |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
127 { |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
128 if (!SDL_IsGameController(i)) { |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
129 printf("Joystick %d: %s is not recognized as a controller by SDL2\n", i, SDL_JoystickNameForIndex(i)); |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
130 continue; |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
131 } |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
132 game_controllers[i] = SDL_GameControllerOpen(i); |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
133 } |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
134 |
15 | 135 return 1; |
24 | 136 |
137 error: | |
138 SDL_DestroyRenderer(renderer); | |
139 renderer_error: | |
140 SDL_DestroyWindow(window); | |
141 return 0; | |
15 | 142 } |
143 | |
144 uint16_t *system_get_framebuffer(int *pitch) | |
145 { | |
146 void *pixels; | |
147 if (SDL_LockTexture(texture, NULL, &pixels, pitch) < 0) { | |
148 fprintf(stderr, "Failed to lock texture: %s\n", SDL_GetError()); | |
149 return NULL; | |
150 } | |
151 return pixels; | |
152 } | |
153 | |
154 void system_framebuffer_updated() | |
155 { | |
156 SDL_UnlockTexture(texture); | |
157 SDL_RenderCopy(renderer, texture, NULL, NULL); | |
158 SDL_RenderPresent(renderer); | |
159 } | |
160 | |
28
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
161 //SDL2 provides this, but only in 2.0.4+ |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
162 SDL_GameController *controller_by_id(SDL_JoystickID which) |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
163 { |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
164 for (int i = 0; i < num_controllers; i++) |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
165 { |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
166 if (!game_controllers[i]) { |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
167 continue; |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
168 } |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
169 if (SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(game_controllers[i])) == which) { |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
170 return game_controllers[i]; |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
171 } |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
172 } |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
173 return NULL; |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
174 } |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
175 |
38
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
176 static const uint16_t mapping[SDL_CONTROLLER_BUTTON_MAX] = { |
28
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
177 [SDL_CONTROLLER_BUTTON_LEFTSHOULDER] = 0x001, |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
178 [SDL_CONTROLLER_BUTTON_Y] = 0x002, |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
179 [SDL_CONTROLLER_BUTTON_X] = 0x004, |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
180 [SDL_CONTROLLER_BUTTON_RIGHTSHOULDER] = 0x008, |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
181 [SDL_CONTROLLER_BUTTON_B] = 0x010, |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
182 [SDL_CONTROLLER_BUTTON_A] = 0x020, |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
183 [SDL_CONTROLLER_BUTTON_BACK] = 0x040, |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
184 [SDL_CONTROLLER_BUTTON_START] = 0x080, |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
185 [SDL_CONTROLLER_BUTTON_DPAD_RIGHT] = 0x100, |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
186 [SDL_CONTROLLER_BUTTON_DPAD_LEFT] = 0x200, |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
187 [SDL_CONTROLLER_BUTTON_DPAD_DOWN] = 0x400, |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
188 [SDL_CONTROLLER_BUTTON_DPAD_UP] = 0x800, |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
189 }; |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
190 |
38
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
191 static uint16_t keycode_to_bit(SDL_Keycode keycode) |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
192 { |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
193 switch(keycode) |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
194 { |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
195 case SDLK_a: |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
196 return 0x020; |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
197 case SDLK_s: |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
198 return 0x010; |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
199 case SDLK_d: |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
200 return 0x008; |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
201 case SDLK_q: |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
202 return 0x004; |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
203 case SDLK_w: |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
204 return 0x002; |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
205 case SDLK_e: |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
206 return 0x001; |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
207 case SDLK_f: |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
208 return 0x040; |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
209 case SDLK_RETURN: |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
210 return 0x080; |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
211 case SDLK_UP: |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
212 return 0x800; |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
213 case SDLK_DOWN: |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
214 return 0x400; |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
215 case SDLK_LEFT: |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
216 return 0x200; |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
217 case SDLK_RIGHT: |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
218 return 0x100; |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
219 } |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
220 return 0; |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
221 } |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
222 |
16
ae58e7c3c328
Poll events regularly to avoid unresponsive app warnings. Handle quit event
Michael Pavone <pavone@retrodev.com>
parents:
15
diff
changeset
|
223 void system_poll_events() |
ae58e7c3c328
Poll events regularly to avoid unresponsive app warnings. Handle quit event
Michael Pavone <pavone@retrodev.com>
parents:
15
diff
changeset
|
224 { |
ae58e7c3c328
Poll events regularly to avoid unresponsive app warnings. Handle quit event
Michael Pavone <pavone@retrodev.com>
parents:
15
diff
changeset
|
225 SDL_Event event; |
ae58e7c3c328
Poll events regularly to avoid unresponsive app warnings. Handle quit event
Michael Pavone <pavone@retrodev.com>
parents:
15
diff
changeset
|
226 while(SDL_PollEvent(&event)) |
ae58e7c3c328
Poll events regularly to avoid unresponsive app warnings. Handle quit event
Michael Pavone <pavone@retrodev.com>
parents:
15
diff
changeset
|
227 { |
ae58e7c3c328
Poll events regularly to avoid unresponsive app warnings. Handle quit event
Michael Pavone <pavone@retrodev.com>
parents:
15
diff
changeset
|
228 switch (event.type) |
ae58e7c3c328
Poll events regularly to avoid unresponsive app warnings. Handle quit event
Michael Pavone <pavone@retrodev.com>
parents:
15
diff
changeset
|
229 { |
ae58e7c3c328
Poll events regularly to avoid unresponsive app warnings. Handle quit event
Michael Pavone <pavone@retrodev.com>
parents:
15
diff
changeset
|
230 case SDL_QUIT: |
ae58e7c3c328
Poll events regularly to avoid unresponsive app warnings. Handle quit event
Michael Pavone <pavone@retrodev.com>
parents:
15
diff
changeset
|
231 exit(0); |
ae58e7c3c328
Poll events regularly to avoid unresponsive app warnings. Handle quit event
Michael Pavone <pavone@retrodev.com>
parents:
15
diff
changeset
|
232 break; |
28
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
233 case SDL_CONTROLLERBUTTONDOWN: |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
234 controller_pressed(event.cbutton.which, mapping[event.cbutton.button]); |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
235 break; |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
236 case SDL_CONTROLLERBUTTONUP: |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
237 controller_released(event.cbutton.which, mapping[event.cbutton.button]); |
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
238 break; |
38
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
239 case SDL_KEYDOWN: |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
240 controller_pressed(0, keycode_to_bit(event.key.keysym.sym)); |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
241 break; |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
242 case SDL_KEYUP: |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
243 controller_released(0, keycode_to_bit(event.key.keysym.sym)); |
3b7910575a00
Implemented basic keyboard support
Michael Pavone <pavone@retrodev.com>
parents:
28
diff
changeset
|
244 break; |
28
c677507682e3
Untested controller implementation
Michael Pavone <pavone@retrodev.com>
parents:
24
diff
changeset
|
245 //TODO: Controller hotplug |
16
ae58e7c3c328
Poll events regularly to avoid unresponsive app warnings. Handle quit event
Michael Pavone <pavone@retrodev.com>
parents:
15
diff
changeset
|
246 } |
ae58e7c3c328
Poll events regularly to avoid unresponsive app warnings. Handle quit event
Michael Pavone <pavone@retrodev.com>
parents:
15
diff
changeset
|
247 } |
ae58e7c3c328
Poll events regularly to avoid unresponsive app warnings. Handle quit event
Michael Pavone <pavone@retrodev.com>
parents:
15
diff
changeset
|
248 } |
ae58e7c3c328
Poll events regularly to avoid unresponsive app warnings. Handle quit event
Michael Pavone <pavone@retrodev.com>
parents:
15
diff
changeset
|
249 |