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 }