libretro.c 11 KB
Newer Older
's avatar
committed
1
#include "libretro.h"
jdgleaver's avatar
jdgleaver committed
2
#include "libretro_core_options.h"
frangarcj's avatar
frangarcj committed
3
#include "log.h"
4
#include <stdio.h>
's avatar
committed
5
6
#include <string.h>

Libretro-Admin's avatar
Libretro-Admin committed
7
#include "../types.h"
's avatar
committed
8
9
#include "../state.h"
#include "../neopopsound.h"
negativeExponent's avatar
negativeExponent committed
10
#include "../sound.h"
's avatar
committed
11
12
13
#include "../input.h"
#include "../flash.h"
#include "../tlcs900h.h"
14
#include "../race-memory.h"
's avatar
committed
15
#include "../graphics.h"
negativeExponent's avatar
negativeExponent committed
16
#include "../state.h"
's avatar
committed
17
18
19
20
21
22
23
24
25

static retro_log_printf_t log_cb;
static retro_video_refresh_t video_cb;
static retro_audio_sample_batch_t audio_batch_cb;
static retro_environment_t environ_cb;
static retro_input_poll_t input_poll_cb;
static retro_input_state_t input_state_cb;

#define RACE_NAME_MODULE "race"
26
#define RACE_NAME "RACE"
27
#define RACE_VERSION "v2.16"
's avatar
committed
28
29
#define RACE_EXTENSIONS "ngp|ngc|ngpc|npc"
#define RACE_TIMING_FPS 60.25
30
#define RACE_GEOMETRY_BASE_W 160
's avatar
committed
31
32
33
#define RACE_GEOMETRY_BASE_H 152
#define RACE_GEOMETRY_MAX_W 160
#define RACE_GEOMETRY_MAX_H 152
frangarcj's avatar
frangarcj committed
34
#define RACE_GEOMETRY_ASPECT_RATIO 1.05
's avatar
committed
35
36
37
38

#define FB_WIDTH 160
#define FB_HEIGHT 152

39
/* core options */
's avatar
committed
40
41
static int RETRO_SAMPLE_RATE = 44100;

Libretro-Admin's avatar
Libretro-Admin committed
42
struct ngp_screen* screen;
43
int setting_ngp_language; /* 0x6F87 - language */
's avatar
committed
44
int gfx_hacks;
45
int tipo_consola; /* 0x6F91 - OS version */
negativeExponent's avatar
negativeExponent committed
46
static bool libretro_supports_input_bitmasks;
's avatar
committed
47

48
49
char retro_save_directory[2048];

Libretro-Admin's avatar
Libretro-Admin committed
50
51
52
53
54
struct map
{
   unsigned retro;
   unsigned ngp;
};
's avatar
committed
55

Libretro-Admin's avatar
Libretro-Admin committed
56
static struct map btn_map[] = {
frangarcj's avatar
frangarcj committed
57
58
   { RETRO_DEVICE_ID_JOYPAD_A, 0x20 },
   { RETRO_DEVICE_ID_JOYPAD_B, 0x10 },
's avatar
committed
59
60
61
62
   { RETRO_DEVICE_ID_JOYPAD_RIGHT, 0x08 },
   { RETRO_DEVICE_ID_JOYPAD_LEFT, 0x04 },
   { RETRO_DEVICE_ID_JOYPAD_UP, 0x01 },
   { RETRO_DEVICE_ID_JOYPAD_DOWN, 0x02 },
jdgleaver's avatar
jdgleaver committed
63
   { RETRO_DEVICE_ID_JOYPAD_START, 0x40 },
's avatar
committed
64
65
66
67
68
69
70
};

unsigned retro_api_version(void)
{
   return RETRO_API_VERSION;
}

Libretro-Admin's avatar
Libretro-Admin committed
71
void graphics_paint(void)
's avatar
committed
72
{
negativeExponent's avatar
negativeExponent committed
73
   video_cb(screen->pixels, screen->w, screen->h, FB_WIDTH << 1);
's avatar
committed
74
75
76
77
}

static void check_variables(void)
{
jdgleaver's avatar
jdgleaver committed
78
79
   struct retro_variable var  = {0};
   unsigned dark_filter_level = 0;
's avatar
committed
80

81
   var.key = "race_language";
's avatar
committed
82
83
84
85
   var.value = NULL;

   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
   {
86
87
88
89
      /* user must manually restart core for change to happen
       * > 0: English
       * > 1: Japanese
       */
's avatar
committed
90
91
      if (!strcmp(var.value, "japanese"))
         setting_ngp_language = 1;
jdgleaver's avatar
jdgleaver committed
92
93
      else if (!strcmp(var.value, "english"))
         setting_ngp_language = 0;
's avatar
committed
94
   }
jdgleaver's avatar
jdgleaver committed
95
96
97
98
99

   var.key   = "race_dark_filter_level";
   var.value = NULL;

   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
Libretro-Admin's avatar
Libretro-Admin committed
100
      dark_filter_level = (unsigned)(atoi(var.value));
jdgleaver's avatar
jdgleaver committed
101
   graphicsSetDarkFilterLevel(dark_filter_level);
's avatar
committed
102
103
104
}
void retro_init(void)
{
Libretro-Admin's avatar
Libretro-Admin committed
105
106
107
   char *dir = NULL;
   enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_RGB565;

frangarcj's avatar
frangarcj committed
108
109
   /* set up some logging */
   init_log(environ_cb);
's avatar
committed
110

111
112
113
   if (environ_cb(RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY, &dir) && dir)
      sprintf(retro_save_directory, "%s%c", dir, path_default_slash_c());

jdgleaver's avatar
jdgleaver committed
114
115
   if (log_cb)
      log_cb(RETRO_LOG_INFO, "[RACE]: Save directory: %s.\n", retro_save_directory);
116

's avatar
committed
117
118
   check_variables();

negativeExponent's avatar
negativeExponent committed
119
120
   if(!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt) && log_cb)
      log_cb(RETRO_LOG_ERROR, "[could not set RGB565]\n");
Libretro-Admin's avatar
Libretro-Admin committed
121

negativeExponent's avatar
negativeExponent committed
122
123
   if (environ_cb(RETRO_ENVIRONMENT_GET_INPUT_BITMASKS, NULL))
      libretro_supports_input_bitmasks = true;
's avatar
committed
124
125
126
127
128
129
130
131
132
133
134
135
}

void retro_reset(void)
{
   flashShutdown();
   system_sound_chipreset();
   mainemuinit();
}

void retro_deinit(void)
{
    flashShutdown();
negativeExponent's avatar
negativeExponent committed
136
    libretro_supports_input_bitmasks = false;
's avatar
committed
137
138
139
140
}

void retro_set_environment(retro_environment_t cb)
{
141
142
143
   static const struct retro_system_content_info_override content_overrides[] = {
      {
         RACE_EXTENSIONS, /* extensions */
144
145
146
#if defined(LOW_MEMORY)
         true,            /* need_fullpath */
#else
147
         false,           /* need_fullpath */
148
#endif
149
150
151
152
153
         false            /* persistent_data */
      },
      { NULL, false, false }
   };

's avatar
committed
154
   environ_cb = cb;
jdgleaver's avatar
jdgleaver committed
155
156

   libretro_set_core_options(environ_cb);
157
158
   environ_cb(RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE,
         (void*)content_overrides);
's avatar
committed
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
}

void retro_set_audio_sample(retro_audio_sample_t cb)
{
}

void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb)
{
   audio_batch_cb = cb;
}

void retro_set_input_poll(retro_input_poll_t cb)
{
   input_poll_cb = cb;
}

void retro_set_input_state(retro_input_state_t cb)
{
   input_state_cb = cb;
}

void retro_set_video_refresh(retro_video_refresh_t cb)
{
   video_cb = cb;
}

negativeExponent's avatar
negativeExponent committed
185
186
187
188
189
static unsigned get_race_input_bitmasks(void)
{
   unsigned i = 0;
   unsigned res = 0;
   unsigned ret = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_MASK);
Libretro-Admin's avatar
Libretro-Admin committed
190
   for (i = 0; i < sizeof(btn_map) / sizeof(struct map); i++)
negativeExponent's avatar
negativeExponent committed
191
192
193
194
      res |= (ret & (1 << btn_map[i].retro)) ? btn_map[i].ngp : 0;
   return res;
}

's avatar
committed
195
196
static unsigned get_race_input(void)
{
negativeExponent's avatar
negativeExponent committed
197
198
   unsigned i = 0;
   unsigned res = 0;
Libretro-Admin's avatar
Libretro-Admin committed
199
   for (i = 0; i < sizeof(btn_map) / sizeof(struct map); i++)
's avatar
committed
200
201
202
203
204
205
206
207
      res |= input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, btn_map[i].retro) ? btn_map[i].ngp : 0;
   return res;
}

static void race_input(void)
{
   ngpInputState = 0;
   input_poll_cb();
negativeExponent's avatar
negativeExponent committed
208
209
210
211
   if (libretro_supports_input_bitmasks)
      ngpInputState = get_race_input_bitmasks();
   else
      ngpInputState = get_race_input();
's avatar
committed
212
213
214
215
216
217
218
219
}

static bool race_initialize_sound(void)
{
    system_sound_chipreset();
    return true;
}

220
221
static bool race_initialize_system(const char *gamepath,
      const unsigned char *gamedata, size_t gamesize)
's avatar
committed
222
223
224
{
   mainemuinit();

225
226
   if (!handleInputFile(gamepath, gamedata, (int)gamesize))
   {
frangarcj's avatar
frangarcj committed
227
228
229
      handle_error("ERROR handleInputFile");
      return false;
   }
's avatar
committed
230
231
232
233

   return true;
}

Libretro-Admin's avatar
Libretro-Admin committed
234
void retro_set_controller_port_device(unsigned a, unsigned b) { }
's avatar
committed
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260

void retro_get_system_info(struct retro_system_info *info)
{
   memset(info, 0, sizeof(*info));
   info->library_name     = RACE_NAME;
#ifndef GIT_VERSION
#define GIT_VERSION ""
#endif

   info->need_fullpath    = true;
   info->library_version  = RACE_VERSION GIT_VERSION;
   info->valid_extensions = RACE_EXTENSIONS;
   info->block_extract    = false;
}
void retro_get_system_av_info(struct retro_system_av_info *info)
{
   memset(info, 0, sizeof(*info));
   info->timing.fps            = RACE_TIMING_FPS;
   info->timing.sample_rate    = RETRO_SAMPLE_RATE;
   info->geometry.base_width   = RACE_GEOMETRY_BASE_W;
   info->geometry.base_height  = RACE_GEOMETRY_BASE_H;
   info->geometry.max_width    = RACE_GEOMETRY_MAX_W;
   info->geometry.max_height   = RACE_GEOMETRY_MAX_H;
   info->geometry.aspect_ratio = RACE_GEOMETRY_ASPECT_RATIO;
}

negativeExponent's avatar
negativeExponent committed
261
#define CPU_FREQ 6144000
negativeExponent's avatar
negativeExponent committed
262

's avatar
committed
263
264
void retro_run(void)
{
Libretro-Admin's avatar
Libretro-Admin committed
265
266
267
268
269
270
271
   unsigned i;
   bool updated = false;
   static int16_t sampleBuffer[2048];
   static int16_t stereoBuffer[2048];
   int16_t *p = NULL;
   uint16_t samplesPerFrame;

's avatar
committed
272
273
   race_input();

negativeExponent's avatar
negativeExponent committed
274
   tlcs_execute(CPU_FREQ / HOST_FPS);
's avatar
committed
275

frangarcj's avatar
frangarcj committed
276
   /* Get the number of samples in a frame */
Libretro-Admin's avatar
Libretro-Admin committed
277
   samplesPerFrame = RETRO_SAMPLE_RATE / HOST_FPS;
frangarcj's avatar
frangarcj committed
278
279
280

   memset(sampleBuffer, 0, samplesPerFrame * sizeof(int16_t));

281
   sound_update((uint16_t*)sampleBuffer, samplesPerFrame * sizeof(int16_t)); /* Get sound data */
negativeExponent's avatar
negativeExponent committed
282
   dac_update((uint16_t*)sampleBuffer, samplesPerFrame * sizeof(int16_t));
frangarcj's avatar
frangarcj committed
283

Libretro-Admin's avatar
Libretro-Admin committed
284
   p = stereoBuffer;
negativeExponent's avatar
negativeExponent committed
285
   
Libretro-Admin's avatar
Libretro-Admin committed
286
   for (i = 0; i < samplesPerFrame; i++)
frangarcj's avatar
frangarcj committed
287
288
289
290
291
   {
      p[0] = sampleBuffer[i];
      p[1] = sampleBuffer[i];
      p += 2;
   }
292

frangarcj's avatar
frangarcj committed
293
294
   audio_batch_cb(stereoBuffer, samplesPerFrame);

Libretro-Admin's avatar
Libretro-Admin committed
295
   /* TODO/FIXME - shouldn't we check this at the top of this function? */
's avatar
committed
296
297
298
299
300
301
   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
      check_variables();
}

size_t retro_serialize_size(void)
{
302
   return state_get_size();
's avatar
committed
303
304
305
306
}

bool retro_serialize(void *data, size_t size)
{
307
   return state_store_mem(data);
's avatar
committed
308
309
310
311
}

bool retro_unserialize(const void *data, size_t size)
{
Libretro-Admin's avatar
Libretro-Admin committed
312
313
   int ret = state_restore_mem((void*)data);
   return (ret == 1);
's avatar
committed
314
315
316
317
}

bool retro_load_game(const struct retro_game_info *info)
{
318
319
320
321
   const struct retro_game_info_ext *info_ext = NULL;
   const unsigned char *content_data          = NULL;
   size_t content_size                        = 0;
   char content_path[_MAX_PATH];
's avatar
committed
322
323
324
325
326
327
328
329
330
331
332
333
334

   struct retro_input_descriptor desc[] = {
      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,  "D-Pad Left" },
      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,    "D-Pad Up" },
      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,  "D-Pad Down" },
      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,     "A" },
      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A,     "B" },
      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Option" },

      { 0 },
   };

335
336
337
338
339
   content_path[0] = '\0';

   /* Attempt to fetch extended game info */
   if (environ_cb(RETRO_ENVIRONMENT_GET_GAME_INFO_EXT, &info_ext))
   {
340
#if !defined(LOW_MEMORY)
341
342
      content_data = (const unsigned char *)info_ext->data;
      content_size = info_ext->size;
343
#endif
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
      if (info_ext->file_in_archive)
      {
         /* We don't have a 'physical' file in this
          * case, but the core still needs a filename
          * in order to build the save file path.
          * We therefore fake it, using the content
          * directory, canonical content name, and
          * content file extension */
         snprintf(content_path, sizeof(content_path), "%s%c%s.%s",
               info_ext->dir, path_default_slash_c(),
               info_ext->name, info_ext->ext);
      }
      else
      {
         strncpy(content_path, info_ext->full_path, sizeof(content_path));
         content_path[sizeof(content_path) - 1] = '\0';
      }
   }
   else
   {
      if (!info || !info->path)
         return false;

      strncpy(content_path, info->path, sizeof(content_path));
      content_path[sizeof(content_path) - 1] = '\0';
   }

's avatar
committed
371
372
   environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc);

Libretro-Admin's avatar
Libretro-Admin committed
373
   screen         = (struct ngp_screen*)calloc(1, sizeof(*screen));
374

's avatar
committed
375
376
   if (!screen)
      return false;
377

Libretro-Admin's avatar
Libretro-Admin committed
378
379
   screen->w      = FB_WIDTH;
   screen->h      = FB_HEIGHT;
's avatar
committed
380

negativeExponent's avatar
negativeExponent committed
381
   screen->pixels = calloc(1, FB_WIDTH * FB_HEIGHT * 2);
382

's avatar
committed
383
384
385
386
387
388
   if (!screen->pixels)
   {
      free(screen);
      return false;
   }

389
390
   if (!race_initialize_system(content_path,
         content_data, content_size))
Fco Jose Garcia Garcia's avatar
Fco Jose Garcia Garcia committed
391
392
393
394
395
396
397
      return false;

   if (!race_initialize_sound())
      return false;

   check_variables();

Libretro-Admin's avatar
Libretro-Admin committed
398
399
400
401
402
403
404
405
406
407
408
   {
      /* TODO: Mappings might need updating
       * Size is based on what is exposed in Mednafen NGP */
      struct retro_memory_descriptor descs = {
         RETRO_MEMDESC_SYSTEM_RAM, mainram, 0, 0, 0, 0, 16384, "RAM"
      };
      struct retro_memory_map retro_map = {
         &descs, 1
      };
      environ_cb(RETRO_ENVIRONMENT_SET_MEMORY_MAPS, &retro_map);
   }
409

's avatar
committed
410
411
412
   return true;
}

Libretro-Admin's avatar
Libretro-Admin committed
413
bool retro_load_game_special(unsigned a, const struct retro_game_info *b, size_t c)
's avatar
committed
414
415
416
417
418
419
{
   return false;
}

void retro_unload_game(void)
{
negativeExponent's avatar
negativeExponent committed
420
421
422
423
424
   if (screen)
   {
      if (screen->pixels)
         free(screen->pixels);
      free(screen);
negativeExponent's avatar
negativeExponent committed
425
      screen = NULL;
negativeExponent's avatar
negativeExponent committed
426
   }
's avatar
committed
427
428
429
430
431
432
433
434
435
436
}

void retro_cheat_reset(void)
{
}

void retro_cheat_set(unsigned index, bool enabled, const char *code)
{
}

437
unsigned retro_get_region(void)
's avatar
committed
438
439
440
441
442
443
444
445
446
447
448
449
{
   return RETRO_REGION_NTSC;
}

void *retro_get_memory_data(unsigned type)
{
   return NULL;
}

size_t retro_get_memory_size(unsigned type)
{
   return 0;
450
}