Mercurial > repos > blastem
comparison libblastem.c @ 1687:6c54bb5fe3b3
Hacky WIP libertro implementation
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 20 Jan 2019 01:03:21 -0800 |
parents | |
children | 395f684c5379 |
comparison
equal
deleted
inserted
replaced
1686:475e84bfccbb | 1687:6c54bb5fe3b3 |
---|---|
1 #include "libretro.h" | |
2 #include "system.h" | |
3 #include "util.h" | |
4 #include "vdp.h" | |
5 #include "render.h" | |
6 #include "io.h" | |
7 | |
8 static retro_environment_t retro_environment; | |
9 RETRO_API void retro_set_environment(retro_environment_t re) | |
10 { | |
11 retro_environment = re; | |
12 } | |
13 | |
14 static retro_video_refresh_t retro_video_refresh; | |
15 RETRO_API void retro_set_video_refresh(retro_video_refresh_t rvf) | |
16 { | |
17 retro_video_refresh = rvf; | |
18 } | |
19 | |
20 static retro_audio_sample_t retro_audio_sample; | |
21 RETRO_API void retro_set_audio_sample(retro_audio_sample_t ras) | |
22 { | |
23 retro_audio_sample = ras; | |
24 } | |
25 | |
26 RETRO_API void retro_set_audio_sample_batch(retro_audio_sample_batch_t rasb) | |
27 { | |
28 } | |
29 | |
30 static retro_input_poll_t retro_input_poll; | |
31 RETRO_API void retro_set_input_poll(retro_input_poll_t rip) | |
32 { | |
33 retro_input_poll = rip; | |
34 } | |
35 | |
36 static retro_input_state_t retro_input_state; | |
37 RETRO_API void retro_set_input_state(retro_input_state_t ris) | |
38 { | |
39 retro_input_state = ris; | |
40 } | |
41 | |
42 int headless = 0; | |
43 int exit_after = 0; | |
44 int z80_enabled = 1; | |
45 char *save_filename; | |
46 tern_node *config; | |
47 uint8_t use_native_states = 1; | |
48 system_header *current_system; | |
49 system_media media; | |
50 | |
51 RETRO_API void retro_init(void) | |
52 { | |
53 } | |
54 | |
55 RETRO_API void retro_deinit(void) | |
56 { | |
57 } | |
58 | |
59 RETRO_API unsigned retro_api_version(void) | |
60 { | |
61 return RETRO_API_VERSION; | |
62 } | |
63 | |
64 RETRO_API void retro_get_system_info(struct retro_system_info *info) | |
65 { | |
66 info->library_name = "BlastEm"; | |
67 info->library_version = "0.6.2-pre"; //TODO: share this with blastem.c | |
68 info->valid_extensions = "md|gen|sms|bin|rom"; | |
69 info->need_fullpath = 0; | |
70 info->block_extract = 0; | |
71 } | |
72 | |
73 static vid_std video_standard; | |
74 RETRO_API void retro_get_system_av_info(struct retro_system_av_info *info) | |
75 { | |
76 info->geometry.base_width = info->geometry.max_width = LINEBUF_SIZE; | |
77 info->geometry.base_height = info->geometry.max_height = video_standard == VID_NTSC ? 243 : 294; | |
78 info->geometry.aspect_ratio = 0; | |
79 info->timing.fps = video_standard == VID_NTSC ? 60 : 50; | |
80 info->timing.sample_rate = 53267; //approximate sample rate of YM2612 | |
81 } | |
82 | |
83 RETRO_API void retro_set_controller_port_device(unsigned port, unsigned device) | |
84 { | |
85 } | |
86 | |
87 /* Resets the current game. */ | |
88 RETRO_API void retro_reset(void) | |
89 { | |
90 current_system->soft_reset(current_system); | |
91 } | |
92 | |
93 /* Runs the game for one video frame. | |
94 * During retro_run(), input_poll callback must be called at least once. | |
95 * | |
96 * If a frame is not rendered for reasons where a game "dropped" a frame, | |
97 * this still counts as a frame, and retro_run() should explicitly dupe | |
98 * a frame if GET_CAN_DUPE returns true. | |
99 * In this case, the video callback can take a NULL argument for data. | |
100 */ | |
101 static uint8_t started; | |
102 RETRO_API void retro_run(void) | |
103 { | |
104 if (started) { | |
105 current_system->resume_context(current_system); | |
106 } else { | |
107 current_system->start_context(current_system, NULL); | |
108 started = 1; | |
109 } | |
110 } | |
111 | |
112 /* Returns the amount of data the implementation requires to serialize | |
113 * internal state (save states). | |
114 * Between calls to retro_load_game() and retro_unload_game(), the | |
115 * returned size is never allowed to be larger than a previous returned | |
116 * value, to ensure that the frontend can allocate a save state buffer once. | |
117 */ | |
118 RETRO_API size_t retro_serialize_size(void) | |
119 { | |
120 return 0; | |
121 } | |
122 | |
123 /* Serializes internal state. If failed, or size is lower than | |
124 * retro_serialize_size(), it should return false, true otherwise. */ | |
125 RETRO_API bool retro_serialize(void *data, size_t size) | |
126 { | |
127 return 0; | |
128 } | |
129 | |
130 RETRO_API bool retro_unserialize(const void *data, size_t size) | |
131 { | |
132 return 0; | |
133 } | |
134 | |
135 RETRO_API void retro_cheat_reset(void) | |
136 { | |
137 } | |
138 | |
139 RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *code) | |
140 { | |
141 } | |
142 | |
143 /* Loads a game. */ | |
144 RETRO_API bool retro_load_game(const struct retro_game_info *game) | |
145 { | |
146 if (game->path) { | |
147 media.dir = path_dirname(game->path); | |
148 media.name = basename_no_extension(game->path); | |
149 media.extension = path_extension(game->path); | |
150 } | |
151 media.buffer = malloc(nearest_pow2(game->size)); | |
152 memcpy(media.buffer, game->data, game->size); | |
153 media.size = game->size; | |
154 current_system = alloc_config_system(detect_system_type(&media), &media, 0, 0); | |
155 | |
156 unsigned format = RETRO_PIXEL_FORMAT_XRGB8888; | |
157 retro_environment(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &format); | |
158 return current_system != NULL; | |
159 } | |
160 | |
161 /* Loads a "special" kind of game. Should not be used, | |
162 * except in extreme cases. */ | |
163 RETRO_API bool retro_load_game_special(unsigned game_type, const struct retro_game_info *info, size_t num_info) | |
164 { | |
165 return retro_load_game(info); | |
166 } | |
167 | |
168 /* Unloads a currently loaded game. */ | |
169 RETRO_API void retro_unload_game(void) | |
170 { | |
171 | |
172 free(media.dir); | |
173 free(media.name); | |
174 free(media.extension); | |
175 | |
176 } | |
177 | |
178 /* Gets region of game. */ | |
179 RETRO_API unsigned retro_get_region(void) | |
180 { | |
181 return video_standard == VID_NTSC ? RETRO_REGION_NTSC : RETRO_REGION_PAL; | |
182 } | |
183 | |
184 /* Gets region of memory. */ | |
185 RETRO_API void *retro_get_memory_data(unsigned id) | |
186 { | |
187 return NULL; | |
188 } | |
189 | |
190 RETRO_API size_t retro_get_memory_size(unsigned id) | |
191 { | |
192 return 0; | |
193 } | |
194 | |
195 //blastem render backend API implementation | |
196 uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b) | |
197 { | |
198 return r << 16 | g << 8 | b; | |
199 } | |
200 | |
201 uint8_t render_create_window(char *caption, uint32_t width, uint32_t height, window_close_handler close_handler) | |
202 { | |
203 //not supported in lib build | |
204 return 0; | |
205 } | |
206 | |
207 void render_destroy_window(uint8_t which) | |
208 { | |
209 //not supported in lib build | |
210 } | |
211 | |
212 static uint32_t fb[LINEBUF_SIZE * 294 * 2]; | |
213 uint32_t *render_get_framebuffer(uint8_t which, int *pitch) | |
214 { | |
215 *pitch = LINEBUF_SIZE * sizeof(uint32_t); | |
216 //TODO: deal with interlace | |
217 return fb; | |
218 } | |
219 | |
220 void render_framebuffer_updated(uint8_t which, int width) | |
221 { | |
222 //TODO: Deal with 256 px wide modes | |
223 //TODO: deal with interlace | |
224 retro_video_refresh(fb, LINEBUF_SIZE, video_standard == VID_NTSC ? 243 : 294, LINEBUF_SIZE * sizeof(uint32_t)); | |
225 current_system->request_exit(current_system); | |
226 } | |
227 | |
228 uint8_t render_get_active_framebuffer(void) | |
229 { | |
230 return 0; | |
231 } | |
232 | |
233 void render_set_video_standard(vid_std std) | |
234 { | |
235 video_standard = std; | |
236 } | |
237 | |
238 void process_events() | |
239 { | |
240 static int16_t prev_state[2][RETRO_DEVICE_ID_JOYPAD_L2]; | |
241 static const uint8_t map[] = { | |
242 BUTTON_A, BUTTON_X, BUTTON_MODE, BUTTON_START, DPAD_UP, DPAD_DOWN, | |
243 DPAD_LEFT, DPAD_RIGHT, BUTTON_B, BUTTON_Y, BUTTON_Z, BUTTON_C | |
244 }; | |
245 //TODO: handle other input device types | |
246 //TODO: handle more than 2 ports when appropriate | |
247 retro_input_poll(); | |
248 for (int port = 0; port < 2; port++) | |
249 { | |
250 for (int id = RETRO_DEVICE_ID_JOYPAD_B; id < RETRO_DEVICE_ID_JOYPAD_L2; id++) | |
251 { | |
252 int16_t new_state = retro_input_state(port, RETRO_DEVICE_JOYPAD, 0, id); | |
253 if (new_state != prev_state[port][id]) { | |
254 if (new_state) { | |
255 current_system->gamepad_down(current_system, port, map[id]); | |
256 } else { | |
257 current_system->gamepad_up(current_system, port, map[id]); | |
258 } | |
259 prev_state[port][id] = new_state; | |
260 } | |
261 } | |
262 } | |
263 } | |
264 | |
265 void render_errorbox(char *title, char *message) | |
266 { | |
267 } | |
268 void render_warnbox(char *title, char *message) | |
269 { | |
270 } | |
271 void render_infobox(char *title, char *message) | |
272 { | |
273 } | |
274 | |
275 struct audio_source { | |
276 int32_t freq; | |
277 int32_t left_accum; | |
278 int32_t right_accum; | |
279 int32_t num_samples; | |
280 }; | |
281 | |
282 static audio_source *audio_sources[8]; | |
283 static uint8_t num_audio_sources; | |
284 audio_source *render_audio_source(uint64_t master_clock, uint64_t sample_divider, uint8_t channels) | |
285 { | |
286 audio_sources[num_audio_sources] = calloc(1, sizeof(audio_source)); | |
287 return audio_sources[num_audio_sources++]; | |
288 } | |
289 | |
290 void render_audio_adjust_clock(audio_source *src, uint64_t master_clock, uint64_t sample_divider) | |
291 { | |
292 } | |
293 | |
294 static void check_put_sample(void) | |
295 { | |
296 for (int i = 0; i < num_audio_sources; i++) | |
297 { | |
298 if (!audio_sources[i]->num_samples) { | |
299 return; | |
300 } | |
301 int32_t effective_freq = audio_sources[i]->freq / audio_sources[i]->num_samples; | |
302 if (abs(effective_freq - 53267) > 53267) { | |
303 return; | |
304 } | |
305 } | |
306 int16_t left = 0, right = 0; | |
307 for (int i = 0; i < num_audio_sources; i++) | |
308 { | |
309 left += audio_sources[i]->left_accum / audio_sources[i]->num_samples; | |
310 right += audio_sources[i]->right_accum / audio_sources[i]->num_samples; | |
311 audio_sources[i]->left_accum = audio_sources[i]->right_accum = audio_sources[i]->num_samples = 0; | |
312 } | |
313 retro_audio_sample(left, right); | |
314 } | |
315 | |
316 void render_put_mono_sample(audio_source *src, int16_t value) | |
317 { | |
318 src->left_accum += value; | |
319 src->right_accum += value; | |
320 src->num_samples++; | |
321 check_put_sample(); | |
322 } | |
323 void render_put_stereo_sample(audio_source *src, int16_t left, int16_t right) | |
324 { | |
325 src->left_accum += left; | |
326 src->right_accum += right; | |
327 src->num_samples++; | |
328 check_put_sample(); | |
329 } | |
330 void render_pause_source(audio_source *src) | |
331 { | |
332 } | |
333 void render_resume_source(audio_source *src) | |
334 { | |
335 } | |
336 void render_free_source(audio_source *src) | |
337 { | |
338 int index; | |
339 for (index = 0; index < num_audio_sources; index++) | |
340 { | |
341 if (audio_sources[index] == src) { | |
342 break; | |
343 } | |
344 } | |
345 num_audio_sources--; | |
346 audio_sources[index] = audio_sources[num_audio_sources]; | |
347 free(src); | |
348 } | |
349 | |
350 void bindings_set_mouse_mode(uint8_t mode) | |
351 { | |
352 } | |
353 void bindings_release_capture(void) | |
354 { | |
355 } | |
356 void bindings_reacquire_capture(void) | |
357 { | |
358 } |