1 #include <stdio.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <stdarg.h>
6 #include <ctype.h>
7 
8 #include <libretro.h>
9 #include <streams/memory_stream.h>
10 #include <libretro_dipswitch.h>
11 #include <libretro_core_options.h>
12 
13 #include "../../fceu.h"
14 #include "../../fceu-endian.h"
15 #include "../../input.h"
16 #include "../../state.h"
17 #include "../../ppu.h"
18 #include "../../cart.h"
19 #include "../../x6502.h"
20 #include "../../git.h"
21 #include "../../palette.h"
22 #include "../../sound.h"
23 #include "../../file.h"
24 #include "../../cheat.h"
25 #include "../../ines.h"
26 #include "../../unif.h"
27 #include "../../fds.h"
28 #include "../../vsuni.h"
29 #include "../../video.h"
30 
31 #ifdef PSP
32 #include "pspgu.h"
33 #endif
34 
35 #if defined(RENDER_GSKIT_PS2)
36 #include "libretro-common/include/libretro_gskit_ps2.h"
37 #endif
38 
39 #define MAX_PLAYERS 4 /* max supported players */
40 #define MAX_PORTS 2   /* max controller ports,
41                        * port 0 for player 1/3, port 1 for player 2/4 */
42 
43 #define RETRO_DEVICE_AUTO        RETRO_DEVICE_JOYPAD
44 #define RETRO_DEVICE_GAMEPAD     RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 1)
45 #define RETRO_DEVICE_ZAPPER      RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_MOUSE,  0)
46 #define RETRO_DEVICE_ARKANOID    RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_MOUSE,  1)
47 
48 #define RETRO_DEVICE_FC_ARKANOID RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_MOUSE,  2)
49 #define RETRO_DEVICE_FC_OEKAKIDS RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_MOUSE,  3)
50 #define RETRO_DEVICE_FC_SHADOW   RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_MOUSE,  4)
51 #define RETRO_DEVICE_FC_4PLAYERS RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 2)
52 #define RETRO_DEVICE_FC_AUTO     RETRO_DEVICE_JOYPAD
53 
54 #define NES_WIDTH   256
55 #define NES_HEIGHT  240
56 #define NES_8_7_PAR  ((width * (8.0 / 7.0)) / height)
57 #define NES_4_3      ((width / (height * (256.0 / 240.0))) * 4.0 / 3.0)
58 
59 #if defined(_3DS)
60 void* linearMemAlign(size_t size, size_t alignment);
61 void linearFree(void* mem);
62 #endif
63 
64 #if defined(RENDER_GSKIT_PS2)
65 RETRO_HW_RENDER_INTEFACE_GSKIT_PS2 *ps2 = NULL;
66 #endif
67 
68 extern void FCEU_ZapperSetTolerance(int t);
69 
70 static retro_video_refresh_t video_cb = NULL;
71 static retro_input_poll_t poll_cb = NULL;
72 static retro_input_state_t input_cb = NULL;
73 static retro_audio_sample_batch_t audio_batch_cb = NULL;
74 retro_environment_t environ_cb = NULL;
75 #ifdef PSP
76 static bool crop_overscan;
77 #else
78 static bool crop_overscan_h;
79 static bool crop_overscan_v;
80 #endif
81 
82 static bool use_raw_palette;
83 static bool use_par;
84 
85 /*
86  * Flags to keep track of whether turbo
87  * buttons toggled on or off.
88  *
89  * There are two values in array
90  * for Turbo A and Turbo B for
91  * each player
92  */
93 
94 #define MAX_BUTTONS 8
95 #define TURBO_BUTTONS 2
96 unsigned char turbo_button_toggle[MAX_PLAYERS][TURBO_BUTTONS] = { {0} };
97 
98 typedef struct
99 {
100    unsigned retro;
101    unsigned nes;
102 } keymap;
103 
104 static const keymap turbomap[] = {
105    { RETRO_DEVICE_ID_JOYPAD_X, JOY_A },
106    { RETRO_DEVICE_ID_JOYPAD_Y, JOY_B },
107 };
108 
109 static const keymap bindmap[] = {
110    { RETRO_DEVICE_ID_JOYPAD_A, JOY_A },
111    { RETRO_DEVICE_ID_JOYPAD_B, JOY_B },
112    { RETRO_DEVICE_ID_JOYPAD_SELECT, JOY_SELECT },
113    { RETRO_DEVICE_ID_JOYPAD_START, JOY_START },
114    { RETRO_DEVICE_ID_JOYPAD_UP, JOY_UP },
115    { RETRO_DEVICE_ID_JOYPAD_DOWN, JOY_DOWN },
116    { RETRO_DEVICE_ID_JOYPAD_LEFT, JOY_LEFT },
117    { RETRO_DEVICE_ID_JOYPAD_RIGHT, JOY_RIGHT },
118 };
119 
120 typedef struct {
121    bool enable_4player;                /* four-score / 4-player adapter used */
122    bool up_down_allowed;               /* disabled simultaneous up+down and left+right dpad combinations */
123 
124    /* turbo related */
125    uint32_t turbo_enabler[MAX_PLAYERS];
126    uint32_t turbo_delay;
127 
128    uint32_t type[MAX_PLAYERS + 1];     /* 4-players + famicom expansion */
129 
130    /* input data */
131    uint32_t JSReturn;                  /* player input data, 1 byte per player (1-4) */
132    uint32_t MouseData[MAX_PORTS][3];   /* nes mouse data */
133    uint32_t FamicomData[3];            /* Famicom expansion port data */
134 } NES_INPUT_T;
135 
136 static NES_INPUT_T nes_input = { 0 };
137 enum RetroZapperInputModes{RetroLightgun, RetroMouse, RetroPointer};
138 static enum RetroZapperInputModes zappermode = RetroLightgun;
139 
140 static bool libretro_supports_bitmasks = false;
141 
142 /* emulator-specific variables */
143 
144 const size_t PPU_BIT = 1ULL << 31ULL;
145 
146 extern uint8 NTARAM[0x800], PALRAM[0x20], SPRAM[0x100], PPU[4];
147 
148 /* overclock the console by adding dummy scanlines to PPU loop
149  * disables DMC DMA and WaveHi filling for these dummies
150  * doesn't work with new PPU */
151 unsigned overclock_enabled = -1;
152 unsigned overclocked = 0;
153 unsigned skip_7bit_overclocking = 1; /* 7-bit samples have priority over overclocking */
154 unsigned totalscanlines = 0;
155 unsigned normal_scanlines = 240;
156 unsigned extrascanlines = 0;
157 unsigned vblankscanlines = 0;
158 unsigned dendy = 0;
159 
160 static unsigned systemRegion = 0;
161 static unsigned opt_region = 0;
162 static unsigned opt_showAdvSoundOptions = 0;
163 static unsigned opt_showAdvSystemOptions = 0;
164 
165 int FCEUnetplay;
166 
167 #if defined(PSP) || defined(PS2)
168 static __attribute__((aligned(16))) uint16_t retro_palette[256];
169 #else
170 static uint16_t retro_palette[256];
171 #endif
172 #if defined(RENDER_GSKIT_PS2)
173 static uint8_t* fceu_video_out;
174 #else
175 static uint16_t* fceu_video_out;
176 #endif
177 
178 /* Some timing-related variables. */
179 static unsigned sndsamplerate;
180 static unsigned sndquality;
181 static unsigned sndvolume;
182 unsigned swapDuty;
183 
184 static int32_t *sound = 0;
185 static uint32_t Dummy = 0;
186 static uint32_t current_palette = 0;
187 static unsigned serialize_size;
188 
189 int PPUViewScanline=0;
190 int PPUViewer=0;
191 
192 /* extern forward decls.*/
193 extern FCEUGI *GameInfo;
194 extern uint8 *XBuf;
195 extern CartInfo iNESCart;
196 extern CartInfo UNIFCart;
197 extern int show_crosshair;
198 extern int option_ramstate;
199 
200 /* emulator-specific callback functions */
201 
UpdatePPUView(int refreshchr)202 void UpdatePPUView(int refreshchr) { }
203 
GetKeyboard(void)204 const char * GetKeyboard(void)
205 {
206    return "";
207 }
208 
209 #define BUILD_PIXEL_RGB565(R,G,B) (((int) ((R)&0x1f) << RED_SHIFT) | ((int) ((G)&0x3f) << GREEN_SHIFT) | ((int) ((B)&0x1f) << BLUE_SHIFT))
210 
211 #if defined (PSP)
212 #define RED_SHIFT 0
213 #define GREEN_SHIFT 5
214 #define BLUE_SHIFT 11
215 #define RED_EXPAND 3
216 #define GREEN_EXPAND 2
217 #define BLUE_EXPAND 3
218 #elif defined (FRONTEND_SUPPORTS_ABGR1555)
219 #define RED_SHIFT 0
220 #define GREEN_SHIFT 5
221 #define BLUE_SHIFT 10
222 #define RED_EXPAND 3
223 #define GREEN_EXPAND 3
224 #define BLUE_EXPAND 3
225 #define RED_MASK 0x1F
226 #define GREEN_MASK 0x3E0
227 #define BLUE_MASK 0x7C00
228 #elif defined (FRONTEND_SUPPORTS_RGB565)
229 #define RED_SHIFT 11
230 #define GREEN_SHIFT 5
231 #define BLUE_SHIFT 0
232 #define RED_EXPAND 3
233 #define GREEN_EXPAND 2
234 #define BLUE_EXPAND 3
235 #define RED_MASK 0xF800
236 #define GREEN_MASK 0x7e0
237 #define BLUE_MASK 0x1f
238 #else
239 #define RED_SHIFT 10
240 #define GREEN_SHIFT 5
241 #define BLUE_SHIFT 0
242 #define RED_EXPAND 3
243 #define GREEN_EXPAND 3
244 #define BLUE_EXPAND 3
245 #endif
246 
FCEUD_SetPalette(uint8_t index,uint8_t r,uint8_t g,uint8_t b)247 void FCEUD_SetPalette(uint8_t index, uint8_t r, uint8_t g, uint8_t b)
248 {
249    unsigned char index_to_write = index;
250 #if defined(RENDER_GSKIT_PS2)
251    /* Index correction for PS2 GS */
252    int modi = index & 63;
253    if ((modi >= 8 && modi < 16) || (modi >= 40 && modi < 48)) {
254       index_to_write += 8;
255    } else if ((modi >= 16 && modi < 24) || (modi >= 48 && modi < 56)) {
256          index_to_write -= 8;
257    }
258 #endif
259 
260 #ifdef FRONTEND_SUPPORTS_RGB565
261    retro_palette[index_to_write] = BUILD_PIXEL_RGB565(r >> RED_EXPAND, g >> GREEN_EXPAND, b >> BLUE_EXPAND);
262 #else
263    retro_palette[index_to_write] =
264       ((r >> RED_EXPAND) << RED_SHIFT) | ((g >> GREEN_EXPAND) << GREEN_SHIFT) | ((b >> BLUE_EXPAND) << BLUE_SHIFT);
265 #endif
266 }
267 
268 static struct retro_log_callback log_cb;
269 
default_logger(enum retro_log_level level,const char * fmt,...)270 static void default_logger(enum retro_log_level level, const char *fmt, ...) {}
271 
FCEUD_PrintError(char * c)272 void FCEUD_PrintError(char *c)
273 {
274    log_cb.log(RETRO_LOG_WARN, "%s", c);
275 }
276 
FCEUD_Message(char * s)277 void FCEUD_Message(char *s)
278 {
279    log_cb.log(RETRO_LOG_INFO, "%s", s);
280 }
281 
FCEUD_DispMessage(char * m)282 void FCEUD_DispMessage(char *m)
283 {  struct retro_message msg;
284    msg.msg = m;
285    msg.frames = 180;
286    environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE, &msg);
287 }
288 
FCEUD_NetworkClose(void)289 void FCEUD_NetworkClose(void)
290 { }
291 
FCEUD_SoundToggle(void)292 void FCEUD_SoundToggle (void)
293 {
294    FCEUI_SetSoundVolume(sndvolume);
295 }
296 
FCEUD_UTF8fopen(const char * n,const char * m)297 FILE *FCEUD_UTF8fopen(const char *n, const char *m)
298 {
299    if (n)
300       return fopen(n, m);
301    else
302       return NULL;
303 }
304 
305 /*palette for FCEU*/
306 #define PAL_TOTAL   16 /* total no. of palettes in palettes[] */
307 #define PAL_DEFAULT (PAL_TOTAL + 1)
308 #define PAL_RAW     (PAL_TOTAL + 2)
309 #define PAL_CUSTOM  (PAL_TOTAL + 3)
310 
311 static int external_palette_exist = 0;
312 extern int ipalette;
313 
314 /* table for currently loaded palette */
315 static uint8_t base_palette[192];
316 
317 struct st_palettes {
318    char name[32];
319    char desc[32];
320    unsigned int data[64];
321 };
322 
323 struct st_palettes palettes[] = {
324    { "asqrealc", "AspiringSquire's Real palette",
325       { 0x6c6c6c, 0x00268e, 0x0000a8, 0x400094,
326          0x700070, 0x780040, 0x700000, 0x621600,
327          0x442400, 0x343400, 0x005000, 0x004444,
328          0x004060, 0x000000, 0x101010, 0x101010,
329          0xbababa, 0x205cdc, 0x3838ff, 0x8020f0,
330          0xc000c0, 0xd01474, 0xd02020, 0xac4014,
331          0x7c5400, 0x586400, 0x008800, 0x007468,
332          0x00749c, 0x202020, 0x101010, 0x101010,
333          0xffffff, 0x4ca0ff, 0x8888ff, 0xc06cff,
334          0xff50ff, 0xff64b8, 0xff7878, 0xff9638,
335          0xdbab00, 0xa2ca20, 0x4adc4a, 0x2ccca4,
336          0x1cc2ea, 0x585858, 0x101010, 0x101010,
337          0xffffff, 0xb0d4ff, 0xc4c4ff, 0xe8b8ff,
338          0xffb0ff, 0xffb8e8, 0xffc4c4, 0xffd4a8,
339          0xffe890, 0xf0f4a4, 0xc0ffc0, 0xacf4f0,
340          0xa0e8ff, 0xc2c2c2, 0x202020, 0x101010 }
341    },
342    { "nintendo-vc", "Virtual Console palette",
343       { 0x494949, 0x00006a, 0x090063, 0x290059,
344          0x42004a, 0x490000, 0x420000, 0x291100,
345          0x182700, 0x003010, 0x003000, 0x002910,
346          0x012043, 0x000000, 0x000000, 0x000000,
347          0x747174, 0x003084, 0x3101ac, 0x4b0194,
348          0x64007b, 0x6b0039, 0x6b2101, 0x5a2f00,
349          0x424900, 0x185901, 0x105901, 0x015932,
350          0x01495a, 0x101010, 0x000000, 0x000000,
351          0xadadad, 0x4a71b6, 0x6458d5, 0x8450e6,
352          0xa451ad, 0xad4984, 0xb5624a, 0x947132,
353          0x7b722a, 0x5a8601, 0x388e31, 0x318e5a,
354          0x398e8d, 0x383838, 0x000000, 0x000000,
355          0xb6b6b6, 0x8c9db5, 0x8d8eae, 0x9c8ebc,
356          0xa687bc, 0xad8d9d, 0xae968c, 0x9c8f7c,
357          0x9c9e72, 0x94a67c, 0x84a77b, 0x7c9d84,
358          0x73968d, 0xdedede, 0x000000, 0x000000 }
359    },
360    { "rgb", "Nintendo RGB PPU palette",
361       { 0x6D6D6D, 0x002492, 0x0000DB, 0x6D49DB,
362          0x92006D, 0xB6006D, 0xB62400, 0x924900,
363          0x6D4900, 0x244900, 0x006D24, 0x009200,
364          0x004949, 0x000000, 0x000000, 0x000000,
365          0xB6B6B6, 0x006DDB, 0x0049FF, 0x9200FF,
366          0xB600FF, 0xFF0092, 0xFF0000, 0xDB6D00,
367          0x926D00, 0x249200, 0x009200, 0x00B66D,
368          0x009292, 0x242424, 0x000000, 0x000000,
369          0xFFFFFF, 0x6DB6FF, 0x9292FF, 0xDB6DFF,
370          0xFF00FF, 0xFF6DFF, 0xFF9200, 0xFFB600,
371          0xDBDB00, 0x6DDB00, 0x00FF00, 0x49FFDB,
372          0x00FFFF, 0x494949, 0x000000, 0x000000,
373          0xFFFFFF, 0xB6DBFF, 0xDBB6FF, 0xFFB6FF,
374          0xFF92FF, 0xFFB6B6, 0xFFDB92, 0xFFFF49,
375          0xFFFF6D, 0xB6FF49, 0x92FF6D, 0x49FFDB,
376          0x92DBFF, 0x929292, 0x000000, 0x000000 }
377    },
378    { "yuv-v3", "FBX's YUV-V3 palette",
379       { 0x666666, 0x002A88, 0x1412A7, 0x3B00A4,
380          0x5C007E, 0x6E0040, 0x6C0700, 0x561D00,
381          0x333500, 0x0C4800, 0x005200, 0x004C18,
382          0x003E5B, 0x000000, 0x000000, 0x000000,
383          0xADADAD, 0x155FD9, 0x4240FF, 0x7527FE,
384          0xA01ACC, 0xB71E7B, 0xB53120, 0x994E00,
385          0x6B6D00, 0x388700, 0x0D9300, 0x008C47,
386          0x007AA0, 0x000000, 0x000000, 0x000000,
387          0xFFFFFF, 0x64B0FF, 0x9290FF, 0xC676FF,
388          0xF26AFF, 0xFF6ECC, 0xFF8170, 0xEA9E22,
389          0xBCBE00, 0x88D800, 0x5CE430, 0x45E082,
390          0x48CDDE, 0x4F4F4F, 0x000000, 0x000000,
391          0xFFFFFF, 0xC0DFFF, 0xD3D2FF, 0xE8C8FF,
392          0xFAC2FF, 0xFFC4EA, 0xFFCCC5, 0xF7D8A5,
393          0xE4E594, 0xCFEF96, 0xBDF4AB, 0xB3F3CC,
394          0xB5EBF2, 0xB8B8B8, 0x000000, 0x000000 }
395    },
396    { "unsaturated-final", "FBX's Unsaturated-Final palette",
397       { 0x676767, 0x001F8E, 0x23069E, 0x40008E,
398          0x600067, 0x67001C, 0x5B1000, 0x432500,
399          0x313400, 0x074800, 0x004F00, 0x004622,
400          0x003A61, 0x000000, 0x000000, 0x000000,
401          0xB3B3B3, 0x205ADF, 0x5138FB, 0x7A27EE,
402          0xA520C2, 0xB0226B, 0xAD3702, 0x8D5600,
403          0x6E7000, 0x2E8A00, 0x069200, 0x008A47,
404          0x037B9B, 0x101010, 0x000000, 0x000000,
405          0xFFFFFF, 0x62AEFF, 0x918BFF, 0xBC78FF,
406          0xE96EFF, 0xFC6CCD, 0xFA8267, 0xE29B26,
407          0xC0B901, 0x84D200, 0x58DE38, 0x46D97D,
408          0x49CED2, 0x494949, 0x000000, 0x000000,
409          0xFFFFFF, 0xC1E3FF, 0xD5D4FF, 0xE7CCFF,
410          0xFBC9FF, 0xFFC7F0, 0xFFD0C5, 0xF8DAAA,
411          0xEBE69A, 0xD1F19A, 0xBEF7AF, 0xB6F4CD,
412          0xB7F0EF, 0xB2B2B2, 0x000000, 0x000000 }
413    },
414    { "sony-cxa2025as-us", "Sony CXA2025AS US palette",
415       { 0x585858, 0x00238C, 0x00139B, 0x2D0585,
416          0x5D0052, 0x7A0017, 0x7A0800, 0x5F1800,
417          0x352A00, 0x093900, 0x003F00, 0x003C22,
418          0x00325D, 0x000000, 0x000000, 0x000000,
419          0xA1A1A1, 0x0053EE, 0x153CFE, 0x6028E4,
420          0xA91D98, 0xD41E41, 0xD22C00, 0xAA4400,
421          0x6C5E00, 0x2D7300, 0x007D06, 0x007852,
422          0x0069A9, 0x000000, 0x000000, 0x000000,
423          0xFFFFFF, 0x1FA5FE, 0x5E89FE, 0xB572FE,
424          0xFE65F6, 0xFE6790, 0xFE773C, 0xFE9308,
425          0xC4B200, 0x79CA10, 0x3AD54A, 0x11D1A4,
426          0x06BFFE, 0x424242, 0x000000, 0x000000,
427          0xFFFFFF, 0xA0D9FE, 0xBDCCFE, 0xE1C2FE,
428          0xFEBCFB, 0xFEBDD0, 0xFEC5A9, 0xFED18E,
429          0xE9DE86, 0xC7E992, 0xA8EEB0, 0x95ECD9,
430          0x91E4FE, 0xACACAC, 0x000000, 0x000000 }
431    },
432    { "pal", "PAL palette",
433       { 0x808080, 0x0000BA, 0x3700BF, 0x8400A6,
434          0xBB006A, 0xB7001E, 0xB30000, 0x912600,
435          0x7B2B00, 0x003E00, 0x00480D, 0x003C22,
436          0x002F66, 0x000000, 0x050505, 0x050505,
437          0xC8C8C8, 0x0059FF, 0x443CFF, 0xB733CC,
438          0xFE33AA, 0xFE375E, 0xFE371A, 0xD54B00,
439          0xC46200, 0x3C7B00, 0x1D8415, 0x009566,
440          0x0084C4, 0x111111, 0x090909, 0x090909,
441          0xFEFEFE, 0x0095FF, 0x6F84FF, 0xD56FFF,
442          0xFE77CC, 0xFE6F99, 0xFE7B59, 0xFE915F,
443          0xFEA233, 0xA6BF00, 0x51D96A, 0x4DD5AE,
444          0x00D9FF, 0x666666, 0x0D0D0D, 0x0D0D0D,
445          0xFEFEFE, 0x84BFFF, 0xBBBBFF, 0xD0BBFF,
446          0xFEBFEA, 0xFEBFCC, 0xFEC4B7, 0xFECCAE,
447          0xFED9A2, 0xCCE199, 0xAEEEB7, 0xAAF8EE,
448          0xB3EEFF, 0xDDDDDD, 0x111111, 0x111111 }
449    },
450    { "bmf-final2", "BMF's Final 2 palette",
451       { 0x525252, 0x000080, 0x08008A, 0x2C007E,
452          0x4A004E, 0x500006, 0x440000, 0x260800,
453          0x0A2000, 0x002E00, 0x003200, 0x00260A,
454          0x001C48, 0x000000, 0x000000, 0x000000,
455          0xA4A4A4, 0x0038CE, 0x3416EC, 0x5E04DC,
456          0x8C00B0, 0x9A004C, 0x901800, 0x703600,
457          0x4C5400, 0x0E6C00, 0x007400, 0x006C2C,
458          0x005E84, 0x000000, 0x000000, 0x000000,
459          0xFFFFFF, 0x4C9CFF, 0x7C78FF, 0xA664FF,
460          0xDA5AFF, 0xF054C0, 0xF06A56, 0xD68610,
461          0xBAA400, 0x76C000, 0x46CC1A, 0x2EC866,
462          0x34C2BE, 0x3A3A3A, 0x000000, 0x000000,
463          0xFFFFFF, 0xB6DAFF, 0xC8CAFF, 0xDAC2FF,
464          0xF0BEFF, 0xFCBCEE, 0xFAC2C0, 0xF2CCA2,
465          0xE6DA92, 0xCCE68E, 0xB8EEA2, 0xAEEABE,
466          0xAEE8E2, 0xB0B0B0, 0x000000, 0x000000 }
467    },
468    { "bmf-final3", "BMF's Final 3 palette",
469       { 0x686868, 0x001299, 0x1A08AA, 0x51029A,
470          0x7E0069, 0x8E001C, 0x7E0301, 0x511800,
471          0x1F3700, 0x014E00, 0x005A00, 0x00501C,
472          0x004061, 0x000000, 0x000000, 0x000000,
473          0xB9B9B9, 0x0C5CD7, 0x5035F0, 0x8919E0,
474          0xBB0CB3, 0xCE0C61, 0xC02B0E, 0x954D01,
475          0x616F00, 0x1F8B00, 0x01980C, 0x00934B,
476          0x00819B, 0x000000, 0x000000, 0x000000,
477          0xFFFFFF, 0x63B4FF, 0x9B91FF, 0xD377FF,
478          0xEF6AFF, 0xF968C0, 0xF97D6C, 0xED9B2D,
479          0xBDBD16, 0x7CDA1C, 0x4BE847, 0x35E591,
480          0x3FD9DD, 0x606060, 0x000000, 0x000000,
481          0xFFFFFF, 0xACE7FF, 0xD5CDFF, 0xEDBAFF,
482          0xF8B0FF, 0xFEB0EC, 0xFDBDB5, 0xF9D28E,
483          0xE8EB7C, 0xBBF382, 0x99F7A2, 0x8AF5D0,
484          0x92F4F1, 0xBEBEBE, 0x000000, 0x000000 }
485    },
486    { "smooth-fbx", "FBX's Smooth palette",
487       { 0x6A6D6A, 0x001380, 0x1E008A, 0x39007A,
488          0x550056, 0x5A0018, 0x4F1000, 0x3D1C00,
489          0x253200, 0x003D00, 0x004000, 0x003924,
490          0x002E55, 0x000000, 0x000000, 0x000000,
491          0xB9BCB9, 0x1850C7, 0x4B30E3, 0x7322D6,
492          0x951FA9, 0x9D285C, 0x983700, 0x7F4C00,
493          0x5E6400, 0x227700, 0x027E02, 0x007645,
494          0x006E8A, 0x000000, 0x000000, 0x000000,
495          0xFFFFFF, 0x68A6FF, 0x8C9CFF, 0xB586FF,
496          0xD975FD, 0xE377B9, 0xE58D68, 0xD49D29,
497          0xB3AF0C, 0x7BC211, 0x55CA47, 0x46CB81,
498          0x47C1C5, 0x4A4D4A, 0x000000, 0x000000,
499          0xFFFFFF, 0xCCEAFF, 0xDDDEFF, 0xECDAFF,
500          0xF8D7FE, 0xFCD6F5, 0xFDDBCF, 0xF9E7B5,
501          0xF1F0AA, 0xDAFAA9, 0xC9FFBC, 0xC3FBD7,
502          0xC4F6F6, 0xBEC1BE, 0x000000, 0x000000 }
503    },
504    { "composite-direct-fbx", "FBX's Composite Direct palette",
505       { 0x656565, 0x00127D, 0x18008E, 0x360082,
506          0x56005D, 0x5A0018, 0x4F0500, 0x381900,
507          0x1D3100, 0x003D00, 0x004100, 0x003B17,
508          0x002E55, 0x000000, 0x000000, 0x000000,
509          0xAFAFAF, 0x194EC8, 0x472FE3, 0x6B1FD7,
510          0x931BAE, 0x9E1A5E, 0x993200, 0x7B4B00,
511          0x5B6700, 0x267A00, 0x008200, 0x007A3E,
512          0x006E8A, 0x000000, 0x000000, 0x000000,
513          0xFFFFFF, 0x64A9FF, 0x8E89FF, 0xB676FF,
514          0xE06FFF, 0xEF6CC4, 0xF0806A, 0xD8982C,
515          0xB9B40A, 0x83CB0C, 0x5BD63F, 0x4AD17E,
516          0x4DC7CB, 0x4C4C4C, 0x000000, 0x000000,
517          0xFFFFFF, 0xC7E5FF, 0xD9D9FF, 0xE9D1FF,
518          0xF9CEFF, 0xFFCCF1, 0xFFD4CB, 0xF8DFB1,
519          0xEDEAA4, 0xD6F4A4, 0xC5F8B8, 0xBEF6D3,
520          0xBFF1F1, 0xB9B9B9, 0x000000, 0x000000 }
521    },
522    { "pvm-style-d93-fbx", "FBX's PVM Style D93 palette",
523       { 0x696B63, 0x001774, 0x1E0087, 0x340073,
524          0x560057, 0x5E0013, 0x531A00, 0x3B2400,
525          0x243000, 0x063A00, 0x003F00, 0x003B1E,
526          0x00334E, 0x000000, 0x000000, 0x000000,
527          0xB9BBB3, 0x1453B9, 0x4D2CDA, 0x671EDE,
528          0x98189C, 0x9D2344, 0xA03E00, 0x8D5500,
529          0x656D00, 0x2C7900, 0x008100, 0x007D42,
530          0x00788A, 0x000000, 0x000000, 0x000000,
531          0xFFFFFF, 0x69A8FF, 0x9691FF, 0xB28AFA,
532          0xEA7DFA, 0xF37BC7, 0xF28E59, 0xE6AD27,
533          0xD7C805, 0x90DF07, 0x64E53C, 0x45E27D,
534          0x48D5D9, 0x4E5048, 0x000000, 0x000000,
535          0xFFFFFF, 0xD2EAFF, 0xE2E2FF, 0xE9D8FF,
536          0xF5D2FF, 0xF8D9EA, 0xFADEB9, 0xF9E89B,
537          0xF3F28C, 0xD3FA91, 0xB8FCA8, 0xAEFACA,
538          0xCAF3F3, 0xBEC0B8, 0x000000, 0x000000 }
539    },
540    { "ntsc-hardware-fbx", "FBX's NTSC Hardware palette",
541       { 0x6A6D6A, 0x001380, 0x1E008A, 0x39007A,
542          0x550056, 0x5A0018, 0x4F1000, 0x382100,
543          0x213300, 0x003D00, 0x004000, 0x003924,
544          0x002E55, 0x000000, 0x000000, 0x000000,
545          0xB9BCB9, 0x1850C7, 0x4B30E3, 0x7322D6,
546          0x951FA9, 0x9D285C, 0x963C00, 0x7A5100,
547          0x5B6700, 0x227700, 0x027E02, 0x007645,
548          0x006E8A, 0x000000, 0x000000, 0x000000,
549          0xFFFFFF, 0x68A6FF, 0x9299FF, 0xB085FF,
550          0xD975FD, 0xE377B9, 0xE58D68, 0xCFA22C,
551          0xB3AF0C, 0x7BC211, 0x55CA47, 0x46CB81,
552          0x47C1C5, 0x4A4D4A, 0x000000, 0x000000,
553          0xFFFFFF, 0xCCEAFF, 0xDDDEFF, 0xECDAFF,
554          0xF8D7FE, 0xFCD6F5, 0xFDDBCF, 0xF9E7B5,
555          0xF1F0AA, 0xDAFAA9, 0xC9FFBC, 0xC3FBD7,
556          0xC4F6F6, 0xBEC1BE, 0x000000, 0x000000 }
557    },
558    { "nes-classic-fbx-fs", "FBX's NES-Classic FS palette",
559       { 0x60615F, 0x000083, 0x1D0195, 0x340875,
560          0x51055E, 0x56000F, 0x4C0700, 0x372308,
561          0x203A0B, 0x0F4B0E, 0x194C16, 0x02421E,
562          0x023154, 0x000000, 0x000000, 0x000000,
563          0xA9AAA8, 0x104BBF, 0x4712D8, 0x6300CA,
564          0x8800A9, 0x930B46, 0x8A2D04, 0x6F5206,
565          0x5C7114, 0x1B8D12, 0x199509, 0x178448,
566          0x206B8E, 0x000000, 0x000000, 0x000000,
567          0xFBFBFB, 0x6699F8, 0x8974F9, 0xAB58F8,
568          0xD557EF, 0xDE5FA9, 0xDC7F59, 0xC7A224,
569          0xA7BE03, 0x75D703, 0x60E34F, 0x3CD68D,
570          0x56C9CC, 0x414240, 0x000000, 0x000000,
571          0xFBFBFB, 0xBED4FA, 0xC9C7F9, 0xD7BEFA,
572          0xE8B8F9, 0xF5BAE5, 0xF3CAC2, 0xDFCDA7,
573          0xD9E09C, 0xC9EB9E, 0xC0EDB8, 0xB5F4C7,
574          0xB9EAE9, 0xABABAB, 0x000000, 0x000000 }
575    },
576    { "nescap", "RGBSource's NESCAP palette",
577       { 0x646365, 0x001580, 0x1D0090, 0x380082,
578          0x56005D, 0x5A001A, 0x4F0900, 0x381B00,
579          0x1E3100, 0x003D00, 0x004100, 0x003A1B,
580          0x002F55, 0x000000, 0x000000, 0x000000,
581          0xAFADAF, 0x164BCA, 0x472AE7, 0x6B1BDB,
582          0x9617B0, 0x9F185B, 0x963001, 0x7B4800,
583          0x5A6600, 0x237800, 0x017F00, 0x00783D,
584          0x006C8C, 0x000000, 0x000000, 0x000000,
585          0xFFFFFF, 0x60A6FF, 0x8F84FF, 0xB473FF,
586          0xE26CFF, 0xF268C3, 0xEF7E61, 0xD89527,
587          0xBAB307, 0x81C807, 0x57D43D, 0x47CF7E,
588          0x4BC5CD, 0x4C4B4D, 0x000000, 0x000000,
589          0xFFFFFF, 0xC2E0FF, 0xD5D2FF, 0xE3CBFF,
590          0xF7C8FF, 0xFEC6EE, 0xFECEC6, 0xF6D7AE,
591          0xE9E49F, 0xD3ED9D, 0xC0F2B2, 0xB9F1CC,
592          0xBAEDED, 0xBAB9BB, 0x000000, 0x000000 }
593    },
594    { "wavebeam", "nakedarthur's Wavebeam palette",
595       { 0X6B6B6B, 0X001B88, 0X21009A, 0X40008C,
596          0X600067, 0X64001E, 0X590800, 0X481600,
597          0X283600, 0X004500, 0X004908, 0X00421D,
598          0X003659, 0X000000, 0X000000, 0X000000,
599          0XB4B4B4, 0X1555D3, 0X4337EF, 0X7425DF,
600          0X9C19B9, 0XAC0F64, 0XAA2C00, 0X8A4B00,
601          0X666B00, 0X218300, 0X008A00, 0X008144,
602          0X007691, 0X000000, 0X000000, 0X000000,
603          0XFFFFFF, 0X63B2FF, 0X7C9CFF, 0XC07DFE,
604          0XE977FF, 0XF572CD, 0XF4886B, 0XDDA029,
605          0XBDBD0A, 0X89D20E, 0X5CDE3E, 0X4BD886,
606          0X4DCFD2, 0X525252, 0X000000, 0X000000,
607          0XFFFFFF, 0XBCDFFF, 0XD2D2FF, 0XE1C8FF,
608          0XEFC7FF, 0XFFC3E1, 0XFFCAC6, 0XF2DAAD,
609          0XEBE3A0, 0XD2EDA2, 0XBCF4B4, 0XB5F1CE,
610          0XB6ECF1, 0XBFBFBF, 0X000000, 0X000000 }
611    }
612 };
613 
614 #ifdef HAVE_NTSC_FILTER
615 /* ntsc */
616 #include "nes_ntsc.h"
617 #define NTSC_NONE       0
618 #define NTSC_COMPOSITE  1
619 #define NTSC_SVIDEO     2
620 #define NTSC_RGB        3
621 #define NTSC_MONOCHROME 4
622 
623 #define NES_NTSC_WIDTH  (((NES_NTSC_OUT_WIDTH(256) + 3) >> 2) << 2)
624 
625 static unsigned use_ntsc = 0;
626 static unsigned burst_phase;
627 static nes_ntsc_t nes_ntsc;
628 static nes_ntsc_setup_t ntsc_setup;
629 static uint16_t *ntsc_video_out = NULL; /* for ntsc blit buffer */
630 
NTSCFilter_Cleanup(void)631 static void NTSCFilter_Cleanup(void)
632 {
633    if (ntsc_video_out)
634       free(ntsc_video_out);
635    ntsc_video_out = NULL;
636 }
637 
NTSCFilter_Init(void)638 static void NTSCFilter_Init(void)
639 {
640    memset(&nes_ntsc, 0, sizeof(nes_ntsc));
641    memset(&ntsc_setup, 0, sizeof(ntsc_setup));
642    ntsc_video_out = (uint16_t *)malloc(NES_NTSC_WIDTH * NES_HEIGHT * sizeof(uint16_t));
643 }
644 
NTSCFilter_Setup(void)645 static void NTSCFilter_Setup(void)
646 {
647    if (ntsc_video_out == NULL)
648       NTSCFilter_Init();
649 
650    switch (use_ntsc) {
651    case NTSC_COMPOSITE:
652       ntsc_setup = nes_ntsc_composite;
653       break;
654    case NTSC_SVIDEO:
655       ntsc_setup = nes_ntsc_svideo;
656       break;
657    case NTSC_RGB:
658       ntsc_setup = nes_ntsc_rgb;
659       break;
660    case NTSC_MONOCHROME:
661       ntsc_setup = nes_ntsc_monochrome;
662       break;
663    default:
664       break;
665    }
666 
667    ntsc_setup.merge_fields = 0;
668    if ((GameInfo->type != GIT_VSUNI) && (current_palette == PAL_DEFAULT || current_palette == PAL_RAW))
669       /* use ntsc default palette instead of internal default palette for that "identity" effect */
670       ntsc_setup.base_palette = NULL;
671    else
672       /* use internal palette, this includes palette presets, external palette and custom palettes
673           * for VS. System games */
674       ntsc_setup.base_palette = (unsigned char const *)palo;
675 
676    nes_ntsc_init(&nes_ntsc, &ntsc_setup);
677 }
678 #endif /* HAVE_NTSC_FILTER */
679 
680 static void ResetPalette(void);
681 static void retro_set_custom_palette(void);
682 
ResetPalette(void)683 static void ResetPalette(void)
684 {
685    retro_set_custom_palette();
686 #ifdef HAVE_NTSC_FILTER
687    NTSCFilter_Setup();
688 #endif
689 }
690 
retro_api_version(void)691 unsigned retro_api_version(void)
692 {
693    return RETRO_API_VERSION;
694 }
695 
retro_set_video_refresh(retro_video_refresh_t cb)696 void retro_set_video_refresh(retro_video_refresh_t cb)
697 {
698    video_cb = cb;
699 }
700 
retro_set_audio_sample(retro_audio_sample_t cb)701 void retro_set_audio_sample(retro_audio_sample_t cb)
702 { }
703 
retro_set_audio_sample_batch(retro_audio_sample_batch_t cb)704 void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb)
705 {
706    audio_batch_cb = cb;
707 }
708 
retro_set_input_poll(retro_input_poll_t cb)709 void retro_set_input_poll(retro_input_poll_t cb)
710 {
711    poll_cb = cb;
712 }
713 
retro_set_input_state(retro_input_state_t cb)714 void retro_set_input_state(retro_input_state_t cb)
715 {
716    input_cb = cb;
717 }
718 
update_nes_controllers(unsigned port,unsigned device)719 static void update_nes_controllers(unsigned port, unsigned device)
720 {
721    nes_input.type[port] = device;
722 
723    if (port < 4)
724    {
725       switch (device)
726       {
727       case RETRO_DEVICE_NONE:
728          FCEUI_SetInput(port, SI_NONE, &Dummy, 0);
729          FCEU_printf(" Player %u: None Connected\n", port + 1);
730          break;
731       case RETRO_DEVICE_ZAPPER:
732          FCEUI_SetInput(port, SI_ZAPPER, nes_input.MouseData[port], 1);
733          FCEU_printf(" Player %u: Zapper\n", port + 1);
734          break;
735       case RETRO_DEVICE_ARKANOID:
736          FCEUI_SetInput(port, SI_ARKANOID, nes_input.MouseData[port], 0);
737          FCEU_printf(" Player %u: Arkanoid\n", port + 1);
738          break;
739       case RETRO_DEVICE_GAMEPAD:
740       default:
741          nes_input.type[port] = RETRO_DEVICE_GAMEPAD;
742          FCEUI_SetInput(port, SI_GAMEPAD, &nes_input.JSReturn, 0);
743          FCEU_printf(" Player %u: Gamepad\n", port + 1);
744          break;
745       }
746    }
747 
748    if (port == 4)
749    {
750       switch (device)
751       {
752       case RETRO_DEVICE_FC_ARKANOID:
753          FCEUI_SetInputFC(SIFC_ARKANOID, nes_input.FamicomData, 0);
754          FCEU_printf(" Famicom Expansion: Arkanoid\n");
755          break;
756       case RETRO_DEVICE_FC_SHADOW:
757          FCEUI_SetInputFC(SIFC_SHADOW, nes_input.FamicomData, 1);
758          FCEU_printf(" Famicom Expansion: (Bandai) Hyper Shot\n");
759          break;
760       case RETRO_DEVICE_FC_OEKAKIDS:
761          FCEUI_SetInputFC(SIFC_OEKAKIDS, nes_input.FamicomData, 1);
762          FCEU_printf(" Famicom Expansion: Oeka Kids Tablet\n");
763          break;
764       case RETRO_DEVICE_FC_4PLAYERS:
765          FCEUI_SetInputFC(SIFC_4PLAYER, &nes_input.JSReturn, 0);
766          FCEU_printf(" Famicom Expansion: Famicom 4-Player Adapter\n");
767          break;
768       case RETRO_DEVICE_NONE:
769       default:
770          FCEUI_SetInputFC(SIFC_NONE, &Dummy, 0);
771          FCEU_printf(" Famicom Expansion: None Connected\n");
772          break;
773       }
774    }
775 }
776 
nes_to_libretro(int d)777 static unsigned nes_to_libretro(int d)
778 {
779    switch(d)
780    {
781    case SI_UNSET:
782    case SI_GAMEPAD:
783       return RETRO_DEVICE_GAMEPAD;
784    case SI_NONE:
785       return RETRO_DEVICE_NONE;
786    case SI_ZAPPER:
787       return RETRO_DEVICE_ZAPPER;
788    case SI_ARKANOID:
789       return RETRO_DEVICE_ARKANOID;
790    }
791 
792    return (RETRO_DEVICE_GAMEPAD);
793 }
794 
fc_to_libretro(int d)795 static unsigned fc_to_libretro(int d)
796 {
797    switch(d)
798    {
799    case SIFC_UNSET:
800    case SIFC_NONE:
801       return RETRO_DEVICE_NONE;
802    case SIFC_ARKANOID:
803       return RETRO_DEVICE_FC_ARKANOID;
804    case SIFC_SHADOW:
805       return RETRO_DEVICE_FC_SHADOW;
806    case SIFC_OEKAKIDS:
807       return RETRO_DEVICE_FC_OEKAKIDS;
808    case SIFC_4PLAYER:
809       return RETRO_DEVICE_FC_4PLAYERS;
810    }
811 
812    return (RETRO_DEVICE_NONE);
813 }
814 
retro_set_controller_port_device(unsigned port,unsigned device)815 void retro_set_controller_port_device(unsigned port, unsigned device)
816 {
817    if (port < 5)
818    {
819       if (port < 2) /* player 1-2 */
820       {
821          if (device != RETRO_DEVICE_AUTO)
822             update_nes_controllers(port, device);
823          else
824             update_nes_controllers(port, nes_to_libretro(GameInfo->input[port]));
825       }
826       else
827       {
828          if (port < 4) /* player 3-4 */
829          {
830             /* This section automatically enables 4players support
831              * when player 3 or 4 used */
832 
833             nes_input.type[port] = RETRO_DEVICE_NONE;
834 
835             if (device == RETRO_DEVICE_AUTO)
836             {
837                if (nes_input.enable_4player)
838                   nes_input.type[port] = RETRO_DEVICE_GAMEPAD;
839             }
840             else if (device == RETRO_DEVICE_GAMEPAD)
841                nes_input.type[port] = RETRO_DEVICE_GAMEPAD;
842 
843             FCEU_printf(" Player %u: %s\n", port + 1,
844                (nes_input.type[port] == RETRO_DEVICE_NONE) ? "None Connected" : "Gamepad");
845          }
846          else /* do famicom controllers here */
847          {
848             if (device != RETRO_DEVICE_FC_AUTO)
849                update_nes_controllers(4, device);
850             else
851                update_nes_controllers(4, fc_to_libretro(GameInfo->inputfc));
852          }
853 
854          if (nes_input.type[2] == RETRO_DEVICE_GAMEPAD
855          || nes_input.type[3] == RETRO_DEVICE_GAMEPAD)
856             FCEUI_DisableFourScore(0);
857          else
858             FCEUI_DisableFourScore(1);
859 
860          /* check if famicom 4player adapter is used */
861          if (nes_input.type[4] == RETRO_DEVICE_FC_4PLAYERS)
862             FCEUI_DisableFourScore(1);
863       }
864    }
865 }
866 
set_variables(void)867 static void set_variables(void)
868 {
869    unsigned i = 0, index = 0;
870 
871    /* Initialize main core option struct */
872    for (i = 0; i < MAX_CORE_OPTIONS; i++)
873       option_defs_us[i] = option_defs_empty;
874 
875    /* Write common core options to main struct */
876    while (option_defs_common[index].key) {
877       option_defs_us[index] = option_defs_common[index];
878       index++;
879    }
880 
881    /* Append dipswitch settings to core options if available */
882    index += set_dipswitch_variables(index, option_defs_us);
883    option_defs_us[index] = option_defs_empty;
884 
885    libretro_set_core_options(environ_cb);
886 }
887 
retro_set_environment(retro_environment_t cb)888 void retro_set_environment(retro_environment_t cb)
889 {
890    static const struct retro_controller_description pads1[] = {
891       { "Auto",    RETRO_DEVICE_AUTO },
892       { "Gamepad", RETRO_DEVICE_GAMEPAD },
893       { "Zapper",  RETRO_DEVICE_ZAPPER },
894       { 0, 0 },
895    };
896 
897    static const struct retro_controller_description pads2[] = {
898       { "Auto",     RETRO_DEVICE_AUTO },
899       { "Gamepad",  RETRO_DEVICE_GAMEPAD },
900       { "Arkanoid", RETRO_DEVICE_ARKANOID },
901       { "Zapper",   RETRO_DEVICE_ZAPPER },
902       { 0, 0 },
903    };
904 
905    static const struct retro_controller_description pads3[] = {
906       { "Auto",     RETRO_DEVICE_AUTO },
907       { "Gamepad",  RETRO_DEVICE_GAMEPAD },
908       { 0, 0 },
909    };
910 
911    static const struct retro_controller_description pads4[] = {
912       { "Auto",     RETRO_DEVICE_AUTO },
913       { "Gamepad",  RETRO_DEVICE_GAMEPAD },
914       { 0, 0 },
915    };
916 
917    static const struct retro_controller_description pads5[] = {
918       { "Auto",                  RETRO_DEVICE_FC_AUTO },
919       { "Arkanoid",              RETRO_DEVICE_FC_ARKANOID },
920       { "(Bandai) Hyper Shot",   RETRO_DEVICE_FC_SHADOW },
921       { "Oeka Kids Tablet",      RETRO_DEVICE_FC_OEKAKIDS },
922       { "4-Player Adapter",      RETRO_DEVICE_FC_4PLAYERS },
923       { 0, 0 },
924    };
925 
926    static const struct retro_controller_info ports[] = {
927       { pads1, 3 },
928       { pads2, 4 },
929       { pads3, 2 },
930       { pads4, 2 },
931       { pads5, 5 },
932       { 0, 0 },
933    };
934 
935    environ_cb = cb;
936    environ_cb(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports);
937 }
938 
retro_get_system_info(struct retro_system_info * info)939 void retro_get_system_info(struct retro_system_info *info)
940 {
941    info->need_fullpath    = false;
942    info->valid_extensions = "fds|nes|unf|unif";
943 #ifdef GIT_VERSION
944    info->library_version  = "(SVN)" GIT_VERSION;
945 #else
946    info->library_version  = "(SVN)";
947 #endif
948    info->library_name     = "FCEUmm";
949    info->block_extract    = false;
950 }
951 
retro_get_system_av_info(struct retro_system_av_info * info)952 void retro_get_system_av_info(struct retro_system_av_info *info)
953 {
954 #ifdef PSP
955    unsigned width  = NES_WIDTH  - (crop_overscan ? 16 : 0);
956    unsigned height = NES_HEIGHT - (crop_overscan ? 16 : 0);
957 #else
958    unsigned width  = NES_WIDTH  - (crop_overscan_h ? 16 : 0);
959    unsigned height = NES_HEIGHT - (crop_overscan_v ? 16 : 0);
960 #endif
961 #ifdef HAVE_NTSC_FILTER
962    info->geometry.base_width = (use_ntsc ? NES_NTSC_OUT_WIDTH(width) : width);
963    info->geometry.max_width = (use_ntsc ? NES_NTSC_WIDTH : NES_WIDTH);
964 #else
965    info->geometry.base_width = width;
966    info->geometry.max_width = NES_WIDTH;
967 #endif
968    info->geometry.base_height = height;
969    info->geometry.max_height = NES_HEIGHT;
970    info->geometry.aspect_ratio = (float)(use_par ? NES_8_7_PAR : NES_4_3);
971    info->timing.sample_rate = (float)sndsamplerate;
972    if (FSettings.PAL || dendy)
973       info->timing.fps = 838977920.0/16777215.0;
974    else
975       info->timing.fps = 1008307711.0/16777215.0;
976 }
977 
check_system_specs(void)978 static void check_system_specs(void)
979 {
980    /* TODO - when we get it running at fullspeed on PSP, set to 4 */
981    unsigned level = 5;
982    environ_cb(RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL, &level);
983 }
984 
retro_init(void)985 void retro_init(void)
986 {
987    bool achievements = true;
988    log_cb.log=default_logger;
989    environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log_cb);
990 
991    environ_cb(RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS, &achievements);
992 
993    if (environ_cb(RETRO_ENVIRONMENT_GET_INPUT_BITMASKS, NULL))
994       libretro_supports_bitmasks = true;
995 }
996 
retro_set_custom_palette(void)997 static void retro_set_custom_palette(void)
998 {
999    unsigned i;
1000 
1001    ipalette = 0;
1002    use_raw_palette = false;
1003 
1004    /* VS UNISystem uses internal palette presets regardless of options */
1005    if (GameInfo->type == GIT_VSUNI)
1006       FCEU_ResetPalette();
1007 
1008    /* Reset and choose between default internal or external custom palette */
1009    else if (current_palette == PAL_DEFAULT || current_palette == PAL_CUSTOM)
1010    {
1011       ipalette = external_palette_exist && (current_palette == PAL_CUSTOM);
1012 
1013       /* if ipalette is set to 1, external palette
1014        * is loaded, else it will load default NES palette.
1015        * FCEUI_SetPaletteArray() both resets the palette array to
1016        * internal default palette and then chooses which one to use. */
1017       FCEUI_SetPaletteArray( NULL );
1018    }
1019 
1020    /* setup raw palette */
1021    else if (current_palette == PAL_RAW)
1022    {
1023       pal color;
1024       use_raw_palette = true;
1025       for (i = 0; i < 64; i++)
1026       {
1027          color.r = (((i >> 0) & 0xF) * 255) / 15;
1028          color.g = (((i >> 4) & 0x3) * 255) / 3;
1029          color.b = 0;
1030          FCEUD_SetPalette( i, color.r, color.g, color.b);
1031       }
1032    }
1033 
1034    /* setup palette presets */
1035    else
1036    {
1037       unsigned *palette_data = palettes[current_palette].data;
1038       for ( i = 0; i < 64; i++ )
1039       {
1040          unsigned data = palette_data[i];
1041          base_palette[ i * 3 + 0 ] = ( data >> 16 ) & 0xff; /* red */
1042          base_palette[ i * 3 + 1 ] = ( data >>  8 ) & 0xff; /* green */
1043          base_palette[ i * 3 + 2 ] = ( data >>  0 ) & 0xff; /* blue */
1044       }
1045       FCEUI_SetPaletteArray( base_palette );
1046    }
1047 }
1048 
1049 /* Set variables for NTSC(1) / PAL(2) / Dendy(3)
1050  * Dendy has PAL framerate and resolution, but ~NTSC timings,
1051  * and has 50 dummy scanlines to force 50 fps.
1052  */
FCEUD_RegionOverride(unsigned region)1053 static void FCEUD_RegionOverride(unsigned region)
1054 {
1055    unsigned pal = 0;
1056    unsigned d = 0;
1057 
1058    switch (region)
1059    {
1060       case 0: /* auto */
1061          d = (systemRegion >> 1) & 1;
1062          pal = systemRegion & 1;
1063          break;
1064       case 1: /* ntsc */
1065          FCEU_DispMessage("System: NTSC");
1066          break;
1067       case 2: /* pal */
1068          pal = 1;
1069          FCEU_DispMessage("System: PAL");
1070          break;
1071       case 3: /* dendy */
1072          d = 1;
1073          FCEU_DispMessage("System: Dendy");
1074          break;
1075    }
1076 
1077    dendy = d;
1078    FCEUI_SetVidSystem(pal);
1079    ResetPalette();
1080 }
1081 
retro_deinit(void)1082 void retro_deinit (void)
1083 {
1084    FCEUI_CloseGame();
1085    FCEUI_Sound(0);
1086    FCEUI_Kill();
1087 #if defined(_3DS)
1088    linearFree(fceu_video_out);
1089 #else
1090    if (fceu_video_out)
1091       free(fceu_video_out);
1092    fceu_video_out = NULL;
1093 #endif
1094 #if defined(RENDER_GSKIT_PS2)
1095    ps2 = NULL;
1096 #endif
1097    libretro_supports_bitmasks = false;
1098    DPSW_Cleanup();
1099 #ifdef HAVE_NTSC_FILTER
1100    NTSCFilter_Cleanup();
1101 #endif
1102 }
1103 
retro_reset(void)1104 void retro_reset(void)
1105 {
1106    ResetNES();
1107 }
1108 
set_apu_channels(int chan)1109 static void set_apu_channels(int chan)
1110 {
1111    FSettings.SquareVolume[1] = (chan & 1) ? 256 : 0;
1112    FSettings.SquareVolume[0] = (chan & 2) ? 256 : 0;
1113    FSettings.TriangleVolume  = (chan & 3) ? 256 : 0;
1114    FSettings.NoiseVolume     = (chan & 4) ? 256 : 0;
1115    FSettings.PCMVolume       = (chan & 5) ? 256 : 0;
1116 }
1117 
check_variables(bool startup)1118 static void check_variables(bool startup)
1119 {
1120    struct retro_variable var = {0};
1121    char key[256];
1122    int i, enable_apu;
1123 
1124    /* 1 = Performs only geometry update: e.g. overscans */
1125    /* 2 = Performs video/geometry update when needed and timing changes: e.g. region and filter change */
1126    int audio_video_updated = 0;
1127 
1128    var.key = "fceumm_ramstate";
1129 
1130    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
1131    {
1132       if (!strcmp(var.value, "random"))
1133          option_ramstate = 2;
1134       else if (!strcmp(var.value, "fill $00"))
1135          option_ramstate = 1;
1136       else
1137          option_ramstate = 0;
1138    }
1139 
1140 #ifdef HAVE_NTSC_FILTER
1141    var.key = "fceumm_ntsc_filter";
1142 
1143    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
1144    {
1145       unsigned orig_value = use_ntsc;
1146       if (strcmp(var.value, "disabled") == 0)
1147          use_ntsc = NTSC_NONE;
1148       else if (strcmp(var.value, "composite") == 0)
1149          use_ntsc = NTSC_COMPOSITE;
1150       else if (strcmp(var.value, "svideo") == 0)
1151          use_ntsc = NTSC_SVIDEO;
1152       else if (strcmp(var.value, "rgb") == 0)
1153          use_ntsc = NTSC_RGB;
1154       else if (strcmp(var.value, "monochrome") == 0)
1155          use_ntsc = NTSC_MONOCHROME;
1156       if (use_ntsc != orig_value)
1157       {
1158          ResetPalette();
1159          audio_video_updated = 2;
1160       }
1161    }
1162 #endif /* HAVE_NTSC_FILTER */
1163 
1164    var.key = "fceumm_palette";
1165 
1166    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
1167    {
1168       unsigned orig_value = current_palette;
1169 
1170       if (!strcmp(var.value, "default"))
1171          current_palette = PAL_DEFAULT;
1172       else if (!strcmp(var.value, "raw"))
1173          current_palette = PAL_RAW;
1174       else if (!strcmp(var.value, "custom"))
1175          current_palette = PAL_CUSTOM;
1176       else if (!strcmp(var.value, "asqrealc"))
1177          current_palette = 0;
1178       else if (!strcmp(var.value, "nintendo-vc"))
1179          current_palette = 1;
1180       else if (!strcmp(var.value, "rgb"))
1181          current_palette = 2;
1182       else if (!strcmp(var.value, "yuv-v3"))
1183          current_palette = 3;
1184       else if (!strcmp(var.value, "unsaturated-final"))
1185          current_palette = 4;
1186       else if (!strcmp(var.value, "sony-cxa2025as-us"))
1187          current_palette = 5;
1188       else if (!strcmp(var.value, "pal"))
1189          current_palette = 6;
1190       else if (!strcmp(var.value, "bmf-final2"))
1191          current_palette = 7;
1192       else if (!strcmp(var.value, "bmf-final3"))
1193          current_palette = 8;
1194       else if (!strcmp(var.value, "smooth-fbx"))
1195          current_palette = 9;
1196       else if (!strcmp(var.value, "composite-direct-fbx"))
1197          current_palette = 10;
1198       else if (!strcmp(var.value, "pvm-style-d93-fbx"))
1199          current_palette = 11;
1200       else if (!strcmp(var.value, "ntsc-hardware-fbx"))
1201          current_palette = 12;
1202       else if (!strcmp(var.value, "nes-classic-fbx-fs"))
1203          current_palette = 13;
1204       else if (!strcmp(var.value, "nescap"))
1205          current_palette = 14;
1206       else if (!strcmp(var.value, "wavebeam"))
1207          current_palette = 15;
1208 
1209       if (current_palette != orig_value)
1210       {
1211          audio_video_updated = 1;
1212          ResetPalette();
1213       }
1214    }
1215 
1216    var.key = "fceumm_up_down_allowed";
1217 
1218    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
1219       nes_input.up_down_allowed = (!strcmp(var.value, "enabled")) ? true : false;
1220    else
1221       nes_input.up_down_allowed = false;
1222 
1223    var.key = "fceumm_nospritelimit";
1224 
1225    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
1226    {
1227       int no_sprite_limit = (!strcmp(var.value, "enabled")) ? 1 : 0;
1228       FCEUI_DisableSpriteLimitation(no_sprite_limit);
1229    }
1230 
1231    var.key = "fceumm_overclocking";
1232 
1233    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
1234    {
1235       bool do_reinit = false;
1236 
1237       if (!strcmp(var.value, "disabled")
1238             && overclock_enabled != 0)
1239       {
1240          skip_7bit_overclocking = 1;
1241          extrascanlines         = 0;
1242          vblankscanlines        = 0;
1243          overclock_enabled      = 0;
1244          do_reinit              = true;
1245       }
1246       else if (!strcmp(var.value, "2x-Postrender"))
1247       {
1248          skip_7bit_overclocking = 1;
1249          extrascanlines         = 266;
1250          vblankscanlines        = 0;
1251          overclock_enabled      = 1;
1252          do_reinit              = true;
1253       }
1254       else if (!strcmp(var.value, "2x-VBlank"))
1255       {
1256          skip_7bit_overclocking = 1;
1257          extrascanlines         = 0;
1258          vblankscanlines        = 266;
1259          overclock_enabled      = 1;
1260          do_reinit              = true;
1261       }
1262 
1263       normal_scanlines = dendy ? 290 : 240;
1264       totalscanlines = normal_scanlines + (overclock_enabled ? extrascanlines : 0);
1265 
1266       if (do_reinit && startup)
1267       {
1268          FCEU_KillVirtualVideo();
1269          FCEU_InitVirtualVideo();
1270       }
1271    }
1272 
1273    var.key = "fceumm_zapper_mode";
1274 
1275    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
1276    {
1277       if (!strcmp(var.value, "mouse")) zappermode = RetroMouse;
1278       else if (!strcmp(var.value, "touchscreen")) zappermode = RetroPointer;
1279       else zappermode = RetroLightgun; /*default setting*/
1280    }
1281 
1282    var.key = "fceumm_zapper_tolerance";
1283 
1284    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
1285    {
1286       FCEU_ZapperSetTolerance(atoi(var.value));
1287    }
1288 
1289    var.key = "fceumm_region";
1290    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
1291 
1292    var.key = "fceumm_show_crosshair";
1293 
1294    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
1295    {
1296       if (!strcmp(var.value, "enabled")) show_crosshair = 1;
1297       else if (!strcmp(var.value, "disabled")) show_crosshair = 0;
1298    }
1299 
1300 #ifdef PSP
1301    var.key = "fceumm_overscan";
1302 
1303    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
1304    {
1305       bool newval = (!strcmp(var.value, "enabled"));
1306       if (newval != crop_overscan)
1307       {
1308          crop_overscan = newval;
1309          audio_video_updated = 1;
1310       }
1311    }
1312 
1313 #else
1314    var.key = "fceumm_overscan_h";
1315 
1316    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
1317    {
1318       bool newval = (!strcmp(var.value, "enabled"));
1319       if (newval != crop_overscan_h)
1320       {
1321          crop_overscan_h = newval;
1322          audio_video_updated = 1;
1323       }
1324    }
1325 
1326    var.key = "fceumm_overscan_v";
1327 
1328    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
1329    {
1330       bool newval = (!strcmp(var.value, "enabled"));
1331       if (newval != crop_overscan_v)
1332       {
1333          crop_overscan_v = newval;
1334          audio_video_updated = 1;
1335       }
1336    }
1337 #endif
1338    var.key = "fceumm_aspect";
1339 
1340    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
1341    {
1342       bool newval = (!strcmp(var.value, "8:7 PAR"));
1343       if (newval != use_par)
1344       {
1345          use_par = newval;
1346          audio_video_updated = 1;
1347       }
1348    }
1349 
1350    var.key = "fceumm_turbo_enable";
1351 
1352    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
1353    {
1354       nes_input.turbo_enabler[0] = 0;
1355       nes_input.turbo_enabler[1] = 0;
1356 
1357       if (!strcmp(var.value, "Player 1"))
1358          nes_input.turbo_enabler[0] = 1;
1359       else if (!strcmp(var.value, "Player 2"))
1360          nes_input.turbo_enabler[1] = 1;
1361       else if (!strcmp(var.value, "Both"))
1362       {
1363          nes_input.turbo_enabler[0] = 1;
1364          nes_input.turbo_enabler[1] = 1;
1365       }
1366    }
1367 
1368    var.key = "fceumm_turbo_delay";
1369 
1370    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
1371       nes_input.turbo_delay = atoi(var.value);
1372 
1373    var.key = "fceumm_region";
1374    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
1375    {
1376       unsigned oldval = opt_region;
1377       if (!strcmp(var.value, "Auto"))
1378          opt_region = 0;
1379       else if (!strcmp(var.value, "NTSC"))
1380          opt_region = 1;
1381       else if (!strcmp(var.value, "PAL"))
1382          opt_region = 2;
1383       else if (!strcmp(var.value, "Dendy"))
1384          opt_region = 3;
1385       if (opt_region != oldval)
1386       {
1387          FCEUD_RegionOverride(opt_region);
1388          audio_video_updated = 2;
1389       }
1390    }
1391 
1392    var.key = "fceumm_sndquality";
1393 
1394    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
1395    {
1396       unsigned oldval = sndquality;
1397       if (!strcmp(var.value, "Low"))
1398          sndquality = 0;
1399       else if (!strcmp(var.value, "High"))
1400          sndquality = 1;
1401       else if (!strcmp(var.value, "Very High"))
1402          sndquality = 2;
1403       if (sndquality != oldval)
1404          FCEUI_SetSoundQuality(sndquality);
1405    }
1406 
1407    var.key = "fceumm_sndvolume";
1408 
1409    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
1410    {
1411       int val = (int)(atof(var.value) * 25.6);
1412       sndvolume = val;
1413       FCEUD_SoundToggle();
1414    }
1415 
1416    if (audio_video_updated && !startup)
1417    {
1418       struct retro_system_av_info av_info;
1419       retro_get_system_av_info(&av_info);
1420       if (audio_video_updated == 2)
1421          environ_cb(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &av_info);
1422       else
1423          environ_cb(RETRO_ENVIRONMENT_SET_GEOMETRY, &av_info);
1424    }
1425 
1426    var.key = "fceumm_swapduty";
1427 
1428    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
1429    {
1430       bool newval = (!strcmp(var.value, "enabled"));
1431       if (newval != swapDuty)
1432          swapDuty = newval;
1433    }
1434 
1435    var.key = key;
1436 
1437    enable_apu = 0xff;
1438 
1439    strcpy(key, "fceumm_apu_x");
1440    for (i = 0; i < 5; i++)
1441    {
1442       key[strlen("fceumm_apu_")] = '1' + i;
1443       var.value = NULL;
1444       if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && !strcmp(var.value, "disabled"))
1445          enable_apu &= ~(1 << i);
1446    }
1447    set_apu_channels(enable_apu);
1448 
1449    update_dipswitch();
1450 
1451    var.key = "fceumm_show_adv_system_options";
1452    var.value = NULL;
1453 
1454    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
1455    {
1456       unsigned newval = (!strcmp(var.value, "enabled")) ? 1 : 0;
1457       if ((opt_showAdvSystemOptions != newval) || startup)
1458       {
1459          struct retro_core_option_display option_display;
1460          unsigned i;
1461          unsigned size;
1462          char options_list[][25] = {
1463             "fceumm_overclocking",
1464             "fceumm_ramstate",
1465             "fceumm_nospritelimit",
1466             "fceumm_up_down_allowed",
1467             "fceumm_show_crosshair"
1468          };
1469 
1470          opt_showAdvSystemOptions = newval;
1471          option_display.visible = opt_showAdvSystemOptions;
1472          size = sizeof(options_list) / sizeof(options_list[0]);
1473          for (i = 0; i < size; i++)
1474          {
1475             option_display.key = options_list[i];
1476             environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, &option_display);
1477          }
1478       }
1479    }
1480 
1481    var.key = "fceumm_show_adv_sound_options";
1482    var.value = NULL;
1483 
1484    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
1485    {
1486       unsigned newval = (!strcmp(var.value, "enabled")) ? 1 : 0;
1487       if ((opt_showAdvSoundOptions != newval) || startup)
1488       {
1489          struct retro_core_option_display option_display;
1490          unsigned i;
1491          unsigned size;
1492          char options_list[][25] = {
1493             "fceumm_sndvolume",
1494             "fceumm_sndquality",
1495             "fceumm_swapduty",
1496             "fceumm_apu_1",
1497             "fceumm_apu_2",
1498             "fceumm_apu_3",
1499             "fceumm_apu_4",
1500             "fceumm_apu_5"
1501          };
1502 
1503          opt_showAdvSoundOptions = newval;
1504          option_display.visible  = opt_showAdvSoundOptions;
1505          size = sizeof(options_list) / sizeof(options_list[0]);
1506          for (i = 0; i < size; i++)
1507          {
1508             option_display.key = options_list[i];
1509             environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, &option_display);
1510          }
1511       }
1512    }
1513 }
1514 
1515 static int mzx = 0, mzy = 0;
1516 
get_mouse_input(unsigned port,uint32_t * zapdata)1517 void get_mouse_input(unsigned port, uint32_t *zapdata)
1518 {
1519    bool adjx = false;
1520    bool adjy = false;
1521    int min_width, min_height, max_width, max_height;
1522 
1523 #ifdef PSP
1524    adjx = adjy = crop_overscan ? 1 : 0;
1525 #else
1526    adjx        = crop_overscan_h ? 1 : 0;
1527    adjy        = crop_overscan_v ? 1 : 0;
1528 #endif
1529    max_width   = 256;
1530    max_height  = 240;
1531    zapdata[2]  = 0; /* reset click state */
1532 
1533    if (zappermode == RetroMouse) /* mouse device */
1534    {
1535       min_width   = (adjx ? 8 : 0) + 1;
1536       min_height  = (adjy ? 8 : 0) + 1;
1537       max_width  -= (adjx ? 8 : 0);
1538       max_height -= (adjy ? 8 : 0);
1539 
1540       /* TODO: Add some sort of mouse sensitivity */
1541       mzx += input_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_X);
1542       mzy += input_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_Y);
1543 
1544       /* Set crosshair within the limits of current screen resolution */
1545       if (mzx < min_width) mzx = min_width;
1546       else if (mzx > max_width) mzx = max_width;
1547 
1548       if (mzy < min_height) mzy = min_height;
1549       else if (mzy > max_height) mzy = max_height;
1550 
1551       zapdata[0] = mzx;
1552       zapdata[1] = mzy;
1553 
1554       if (input_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT))
1555          zapdata[2] |= 0x1;
1556       if (input_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_RIGHT))
1557          zapdata[2] |= 0x2;
1558    }
1559    else if (zappermode == RetroPointer) {
1560       int offset_x = (adjx ? 0X8FF : 0);
1561       int offset_y = (adjy ? 0X999 : 0);
1562 
1563       int _x = input_cb(port, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X);
1564       int _y = input_cb(port, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y);
1565 
1566       if (_x == 0 && _y == 0)
1567       {
1568          zapdata[0] = 0;
1569          zapdata[1] = 0;
1570       }
1571       else
1572       {
1573          zapdata[0] = (_x + (0x7FFF + offset_x)) * max_width  / ((0x7FFF + offset_x) * 2);
1574          zapdata[1] = (_y + (0x7FFF + offset_y)) * max_height  / ((0x7FFF + offset_y) * 2);
1575       }
1576 
1577       if (input_cb(port, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_PRESSED))
1578          zapdata[2] |= 0x1;
1579    }
1580    else /* lightgun device */
1581    {
1582       int offset_x = (adjx ? 0X8FF : 0);
1583       int offset_y = (adjy ? 0X999 : 0);
1584       int offscreen;
1585       int offscreen_shot;
1586       int trigger;
1587 
1588       offscreen = input_cb( port, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN );
1589       offscreen_shot = input_cb( port, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_RELOAD );
1590       trigger = input_cb( port, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_TRIGGER );
1591 
1592       if ( offscreen || offscreen_shot )
1593       {
1594          zapdata[0] = 0;
1595          zapdata[1] = 0;
1596       }
1597       else
1598       {
1599          int _x = input_cb(port, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X);
1600          int _y = input_cb(port, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y);
1601 
1602          zapdata[0] = (_x + (0x7FFF + offset_x)) * max_width  / ((0x7FFF + offset_x) * 2);
1603          zapdata[1] = (_y + (0x7FFF + offset_y)) * max_height  / ((0x7FFF + offset_y) * 2);
1604       }
1605 
1606       if ( trigger || offscreen_shot )
1607          zapdata[2] |= 0x1;
1608    }
1609 }
1610 
FCEUD_UpdateInput(void)1611 static void FCEUD_UpdateInput(void)
1612 {
1613    unsigned player, port;
1614 
1615    poll_cb();
1616 
1617    /* Reset input states */
1618    nes_input.JSReturn = 0;
1619 
1620    /* nes gamepad */
1621    for (player = 0; player < MAX_PLAYERS; player++)
1622    {
1623       int i              = 0;
1624       uint8_t input_buf  = 0;
1625       int player_enabled = (nes_input.type[player] == RETRO_DEVICE_GAMEPAD) || (nes_input.type[player] == RETRO_DEVICE_JOYPAD);
1626 
1627       if (player_enabled)
1628       {
1629          int16_t ret;
1630 
1631          if (libretro_supports_bitmasks)
1632          {
1633             ret = input_cb(player, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_MASK);
1634 
1635             if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_A))
1636                input_buf |= JOY_A;
1637             if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_B))
1638                input_buf |= JOY_B;
1639             if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_SELECT))
1640                input_buf |= JOY_SELECT;
1641             if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_START))
1642                input_buf |= JOY_START;
1643             if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_UP))
1644                input_buf |= JOY_UP;
1645             if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_DOWN))
1646                input_buf |= JOY_DOWN;
1647             if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_LEFT))
1648                input_buf |= JOY_LEFT;
1649             if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_RIGHT))
1650                input_buf |= JOY_RIGHT;
1651          }
1652          else
1653          {
1654             for (i = 0; i < MAX_BUTTONS; i++)
1655                input_buf |= input_cb(player, RETRO_DEVICE_JOYPAD, 0,
1656                      bindmap[i].retro) ? bindmap[i].nes : 0;
1657          }
1658 
1659          /* Turbo A and Turbo B buttons are
1660           * mapped to Joypad X and Joypad Y
1661           * in RetroArch joypad.
1662           *
1663           * We achieve this by keeping track of
1664           * the number of times it increments
1665           * the toggle counter and fire or not fire
1666           * depending on whether the delay value has
1667           * been reached.
1668           */
1669 
1670          if (nes_input.turbo_enabler[player])
1671          {
1672             /* Handle Turbo A & B buttons */
1673             for (i = 0; i < TURBO_BUTTONS; i++)
1674             {
1675                if (input_cb(player, RETRO_DEVICE_JOYPAD, 0, turbomap[i].retro))
1676                {
1677                   if (!turbo_button_toggle[player][i])
1678                      input_buf |= turbomap[i].nes;
1679                   turbo_button_toggle[player][i]++;
1680                   turbo_button_toggle[player][i] %= nes_input.turbo_delay + 1;
1681                }
1682                else
1683                   /* If the button is not pressed, just reset the toggle */
1684                   turbo_button_toggle[player][i] = 0;
1685             }
1686          }
1687       }
1688 
1689       if (!nes_input.up_down_allowed)
1690       {
1691          if (input_buf & (JOY_UP))
1692             if (input_buf & (JOY_DOWN))
1693                input_buf &= ~((JOY_UP ) | (JOY_DOWN));
1694          if (input_buf & (JOY_LEFT))
1695             if (input_buf & (JOY_RIGHT))
1696                input_buf &= ~((JOY_LEFT ) | (JOY_RIGHT));
1697       }
1698 
1699       nes_input.JSReturn |= (input_buf & 0xff) << (player << 3);
1700    }
1701 
1702    /* other inputs*/
1703    for (port = 0; port < MAX_PORTS; port++)
1704    {
1705       switch (nes_input.type[port])
1706       {
1707          case RETRO_DEVICE_ARKANOID:
1708          case RETRO_DEVICE_ZAPPER:
1709             get_mouse_input(port, nes_input.MouseData[port]);
1710             break;
1711       }
1712    }
1713 
1714    /* famicom inputs */
1715    switch (nes_input.type[4])
1716    {
1717       case RETRO_DEVICE_FC_ARKANOID:
1718       case RETRO_DEVICE_FC_OEKAKIDS:
1719       case RETRO_DEVICE_FC_SHADOW:
1720          get_mouse_input(0, nes_input.FamicomData);
1721          break;
1722    }
1723 
1724    if (input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2))
1725       FCEU_VSUniCoin();             /* Insert Coin VS System */
1726 
1727    if (GameInfo->type == GIT_FDS)   /* Famicom Disk System */
1728    {
1729       bool curL = input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L);
1730       bool curR = input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R);
1731       static bool prevL = false, prevR = false;
1732 
1733       if (curL && !prevL)
1734          FCEU_FDSSelect();          /* Swap FDisk side */
1735       prevL = curL;
1736 
1737       if (curR && !prevR)
1738          FCEU_FDSInsert(-1);        /* Insert or eject the disk */
1739       prevR = curR;
1740    }
1741 }
1742 
FCEUD_Update(uint8 * XBuf,int32 * Buffer,int Count)1743 void FCEUD_Update(uint8 *XBuf, int32 *Buffer, int Count)
1744 {
1745 }
1746 
retro_run_blit(uint8_t * gfx)1747 static void retro_run_blit(uint8_t *gfx)
1748 {
1749    unsigned x, y;
1750 #ifdef PSP
1751    static unsigned int __attribute__((aligned(16))) d_list[32];
1752    void* texture_vram_p = NULL;
1753 #endif
1754    unsigned incr   = 0;
1755    unsigned width  = 256;
1756    unsigned height = 240;
1757    unsigned pitch  = 512;
1758 
1759 #ifdef PSP
1760    if (crop_overscan)
1761    {
1762       width  -= 16;
1763       height -= 16;
1764    }
1765    texture_vram_p = (void*) (0x44200000 - (256 * 256)); /* max VRAM address - frame size */
1766 
1767    sceKernelDcacheWritebackRange(retro_palette,256 * 2);
1768    sceKernelDcacheWritebackRange(XBuf, 256*240 );
1769 
1770    sceGuStart(GU_DIRECT, d_list);
1771 
1772    /* sceGuCopyImage doesnt seem to work correctly with GU_PSM_T8
1773     * so we use GU_PSM_4444 ( 2 Bytes per pixel ) instead
1774     * with half the values for pitch / width / x offset
1775     */
1776    if (crop_overscan)
1777       sceGuCopyImage(GU_PSM_4444, 4, 4, 120, 224, 128, XBuf, 0, 0, 128, texture_vram_p);
1778    else
1779       sceGuCopyImage(GU_PSM_4444, 0, 0, 128, 240, 128, XBuf, 0, 0, 128, texture_vram_p);
1780 
1781    sceGuTexSync();
1782    sceGuTexImage(0, 256, 256, 256, texture_vram_p);
1783    sceGuTexMode(GU_PSM_T8, 0, 0, GU_FALSE);
1784    sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGB);
1785    sceGuDisable(GU_BLEND);
1786    sceGuClutMode(GU_PSM_5650, 0, 0xFF, 0);
1787    sceGuClutLoad(32, retro_palette);
1788 
1789    sceGuFinish();
1790 
1791    video_cb(texture_vram_p, width, height, 256);
1792 #elif defined(RENDER_GSKIT_PS2)
1793    uint32_t *buf = (uint32_t *)RETRO_HW_FRAME_BUFFER_VALID;
1794 
1795    if (!ps2) {
1796       if (!environ_cb(RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE, (void **)&ps2) || !ps2) {
1797          printf("Failed to get HW rendering interface!\n");
1798          return;
1799       }
1800 
1801       if (ps2->interface_version != RETRO_HW_RENDER_INTERFACE_GSKIT_PS2_VERSION) {
1802          printf("HW render interface mismatch, expected %u, got %u!\n",
1803                   RETRO_HW_RENDER_INTERFACE_GSKIT_PS2_VERSION, ps2->interface_version);
1804          return;
1805       }
1806 
1807       ps2->coreTexture->Width = width;
1808       ps2->coreTexture->Height = height;
1809       ps2->coreTexture->PSM = GS_PSM_T8;
1810       ps2->coreTexture->ClutPSM = GS_PSM_CT16;
1811       ps2->coreTexture->Filter = GS_FILTER_LINEAR;
1812       ps2->padding = (struct retro_hw_ps2_insets){ crop_overscan_v ? 8.0f : 0.0f,
1813                                                    crop_overscan_h ? 8.0f : 0.0f,
1814                                                    crop_overscan_v ? 8.0f : 0.0f,
1815                                                    crop_overscan_h ? 8.0f : 0.0f};
1816    }
1817 
1818    ps2->coreTexture->Clut = (u32*)retro_palette;
1819    ps2->coreTexture->Mem = (u32*)gfx;
1820 
1821    video_cb(buf, width, height, pitch);
1822 #else
1823 #ifdef HAVE_NTSC_FILTER
1824    if (use_ntsc)
1825    {
1826       burst_phase ^= 1;
1827       if (ntsc_setup.merge_fields)
1828          burst_phase = 0;
1829 
1830       nes_ntsc_blit(&nes_ntsc, (NES_NTSC_IN_T const*)gfx, (NES_NTSC_IN_T *)XDBuf,
1831           NES_WIDTH, burst_phase, NES_WIDTH, NES_HEIGHT,
1832           ntsc_video_out, NES_NTSC_WIDTH * sizeof(uint16));
1833 
1834       width    = NES_WIDTH - (crop_overscan_h ? 16 : 0);
1835       width    = NES_NTSC_OUT_WIDTH(width);
1836       height   = NES_HEIGHT - (crop_overscan_v ? 16 : 0);
1837       pitch    = width * sizeof(uint16_t);
1838 
1839       {
1840          int32_t h_offset   = crop_overscan_h ?  NES_NTSC_OUT_WIDTH(8) : 0;
1841          int32_t v_offset   = crop_overscan_v ? 8 : 0;
1842          const uint16_t *in = ntsc_video_out + h_offset + NES_NTSC_WIDTH * v_offset;
1843          uint16_t *out      = fceu_video_out;
1844 
1845          for (y = 0; y < height; y++)
1846          {
1847             memcpy(out, in, pitch);
1848             in += NES_NTSC_WIDTH;
1849             out += width;
1850          }
1851       }
1852       video_cb(fceu_video_out, width, height, pitch);
1853    }
1854    else
1855 #endif /* HAVE_NTSC_FILTER */
1856    {
1857       incr   += (crop_overscan_h ? 16 : 0);
1858       width  -= (crop_overscan_h ? 16 : 0);
1859       height -= (crop_overscan_v ? 16 : 0);
1860       pitch  -= (crop_overscan_h ? 32 : 0);
1861       gfx    += (crop_overscan_v ? ((crop_overscan_h ? 8 : 0) + 256 * 8) : (crop_overscan_h ? 8 : 0));
1862 
1863       if (use_raw_palette)
1864       {
1865          uint8_t *deemp = XDBuf + (gfx - XBuf);
1866          for (y = 0; y < height; y++, gfx += incr, deemp += incr)
1867             for (x = 0; x < width; x++, gfx++, deemp++)
1868                fceu_video_out[y * width + x] = retro_palette[*gfx & 0x3F] | (*deemp << 2);
1869       }
1870       else
1871       {
1872          for (y = 0; y < height; y++, gfx += incr)
1873             for (x = 0; x < width; x++, gfx++)
1874                fceu_video_out[y * width + x] = retro_palette[*gfx];
1875       }
1876       video_cb(fceu_video_out, width, height, pitch);
1877    }
1878 #endif
1879 }
1880 
retro_run(void)1881 void retro_run(void)
1882 {
1883    uint8_t *gfx;
1884    int32_t i, ssize = 0;
1885    bool updated = false;
1886 
1887    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
1888       check_variables(false);
1889 
1890    FCEUD_UpdateInput();
1891    FCEUI_Emulate(&gfx, &sound, &ssize, 0);
1892 
1893    for (i = 0; i < ssize; i++)
1894       sound[i] = (sound[i] << 16) | (sound[i] & 0xffff);
1895 
1896    audio_batch_cb((const int16_t*)sound, ssize);
1897 
1898    retro_run_blit(gfx);
1899 }
1900 
retro_serialize_size(void)1901 size_t retro_serialize_size(void)
1902 {
1903    if (serialize_size == 0)
1904    {
1905       /* Something arbitrarily big.*/
1906       uint8_t *buffer = (uint8_t*)malloc(1000000);
1907       memstream_set_buffer(buffer, 1000000);
1908 
1909       FCEUSS_Save_Mem();
1910       serialize_size = memstream_get_last_size();
1911       free(buffer);
1912    }
1913 
1914    return serialize_size;
1915 }
1916 
retro_serialize(void * data,size_t size)1917 bool retro_serialize(void *data, size_t size)
1918 {
1919    if (size != retro_serialize_size())
1920       return false;
1921 
1922    memstream_set_buffer((uint8_t*)data, size);
1923    FCEUSS_Save_Mem();
1924    return true;
1925 }
1926 
retro_unserialize(const void * data,size_t size)1927 bool retro_unserialize(const void * data, size_t size)
1928 {
1929    if (size != retro_serialize_size())
1930       return false;
1931 
1932    memstream_set_buffer((uint8_t*)data, size);
1933    FCEUSS_Load_Mem();
1934    return true;
1935 }
1936 
checkGG(char c)1937 static int checkGG(char c)
1938 {
1939    static const char lets[16] = { 'A', 'P', 'Z', 'L', 'G', 'I', 'T', 'Y', 'E', 'O', 'X', 'U', 'K', 'S', 'V', 'N' };
1940    int x;
1941 
1942    for (x = 0; x < 16; x++)
1943       if (lets[x] == toupper(c))
1944          return 1;
1945    return 0;
1946 }
1947 
GGisvalid(const char * code)1948 static int GGisvalid(const char *code)
1949 {
1950    size_t len = strlen(code);
1951    uint32 i;
1952 
1953    if (len != 6 && len != 8)
1954       return 0;
1955 
1956    for (i = 0; i < len; i++)
1957       if (!checkGG(code[i]))
1958          return 0;
1959    return 1;
1960 }
1961 
retro_cheat_reset(void)1962 void retro_cheat_reset(void)
1963 {
1964    FCEU_ResetCheats();
1965 }
1966 
retro_cheat_set(unsigned index,bool enabled,const char * code)1967 void retro_cheat_set(unsigned index, bool enabled, const char *code)
1968 {
1969    char name[256];
1970    char temp[256];
1971    char *codepart;
1972    uint16 a;
1973    uint8  v;
1974    int    c;
1975    int    type = 1;
1976 
1977    if (code == NULL)
1978       return;
1979 
1980    sprintf(name, "N/A");
1981    strcpy(temp, code);
1982    codepart = strtok(temp, "+,;._ ");
1983 
1984    while (codepart)
1985    {
1986       if ((strlen(codepart) == 7) && (codepart[4]==':'))
1987       {
1988          /* raw code in xxxx:xx format */
1989          log_cb.log(RETRO_LOG_DEBUG, "Cheat code added: '%s' (Raw)\n", codepart);
1990          codepart[4] = '\0';
1991          a = strtoul(codepart, NULL, 16);
1992          v = strtoul(codepart + 5, NULL, 16);
1993          c = -1;
1994          /* Zero-page addressing modes don't go through the normal read/write handlers in FCEU, so
1995           * we must do the old hacky method of RAM cheats. */
1996          if (a < 0x0100) type = 0;
1997          FCEUI_AddCheat(name, a, v, c, type);
1998       }
1999       else if ((strlen(codepart) == 10) && (codepart[4] == '?') && (codepart[7] == ':'))
2000       {
2001          /* raw code in xxxx?xx:xx */
2002          log_cb.log(RETRO_LOG_DEBUG, "Cheat code added: '%s' (Raw)\n", codepart);
2003          codepart[4] = '\0';
2004          codepart[7] = '\0';
2005          a = strtoul(codepart, NULL, 16);
2006          v = strtoul(codepart + 8, NULL, 16);
2007          c = strtoul(codepart + 5, NULL, 16);
2008          /* Zero-page addressing modes don't go through the normal read/write handlers in FCEU, so
2009           * we must do the old hacky method of RAM cheats. */
2010          if (a < 0x0100) type = 0;
2011          FCEUI_AddCheat(name, a, v, c, type);
2012       }
2013       else if (GGisvalid(codepart) && FCEUI_DecodeGG(codepart, &a, &v, &c))
2014       {
2015          FCEUI_AddCheat(name, a, v, c, type);
2016          log_cb.log(RETRO_LOG_DEBUG, "Cheat code added: '%s' (GG)\n", codepart);
2017       }
2018       else if (FCEUI_DecodePAR(codepart, &a, &v, &c, &type))
2019       {
2020          FCEUI_AddCheat(name, a, v, c, type);
2021          log_cb.log(RETRO_LOG_DEBUG, "Cheat code added: '%s' (PAR)\n", codepart);
2022       }
2023       else
2024          log_cb.log(RETRO_LOG_DEBUG, "Invalid or unknown code: '%s'\n", codepart);
2025       codepart = strtok(NULL,"+,;._ ");
2026    }
2027 }
2028 
2029 typedef struct cartridge_db
2030 {
2031    char title[256];
2032    uint32_t crc;
2033 } cartridge_db_t;
2034 
2035 static const struct cartridge_db fourscore_db_list[] =
2036 {
2037    {
2038       "Bomberman II (USA)",
2039       0x1ebb5b42
2040    },
2041 #if 0
2042    {
2043       "Championship Bowling (USA)",
2044       0xeac38105
2045    },
2046 #endif
2047    {
2048       "Chris Evert & Ivan Lendl in Top Players' Tennis (USA)",
2049       0xf99e37eb
2050    },
2051 #if 0
2052    {
2053       "Crash 'n' the Boys - Street Challenge (USA)",
2054       0xc7f0c457
2055    },
2056 #endif
2057    {
2058       "Four Players' Tennis (Europe)",
2059       0x48b8ee58
2060    },
2061    {
2062       "Danny Sullivan's Indy Heat (Europe)",
2063       0x27ca0679,
2064    },
2065    {
2066       "Gauntlet II (Europe)",
2067       0x79f688bc
2068    },
2069    {
2070       "Gauntlet II (USA)",
2071       0x1b71ccdb
2072    },
2073    {
2074       "Greg Norman's Golf Power (USA)",
2075       0x1352f1b9
2076    },
2077    {
2078       "Harlem Globetrotters (USA)",
2079       0x2e6ee98d
2080    },
2081    {
2082       "Ivan 'Ironman' Stewart's Super Off Road (Europe)",
2083       0x05104517
2084    },
2085    {
2086       "Ivan 'Ironman' Stewart's Super Off Road (USA)",
2087       0x4b041b6b
2088    },
2089    {
2090       "Kings of the Beach - Professional Beach Volleyball (USA)",
2091       0xf54b34bd
2092    },
2093    {
2094       "Magic Johnson's Fast Break (USA)",
2095       0xc6c2edb5
2096    },
2097    {
2098       "M.U.L.E. (USA)",
2099       0x0939852f
2100    },
2101    {
2102       "Micro Mages",
2103       0x4e6b9078
2104    },
2105    {
2106       "Monster Truck Rally (USA)",
2107       0x2f698c4d
2108    },
2109    {
2110       "NES Play Action Football (USA)",
2111       0xb9b4d9e0
2112    },
2113    {
2114       "Nightmare on Elm Street, A (USA)",
2115       0xda2cb59a
2116    },
2117    {
2118       "Nintendo World Cup (Europe)",
2119       0x8da6667d
2120    },
2121    {
2122       "Nintendo World Cup (Europe) (Rev A)",
2123       0x7c16f819
2124    },
2125    {
2126       "Nintendo World Cup (Europe) (Rev B)",
2127       0x7f08d0d9
2128    },
2129    {
2130       "Nintendo World Cup (USA)",
2131       0xa22657fa
2132    },
2133    {
2134       "R.C. Pro-Am II (Europe)",
2135       0x308da987
2136    },
2137    {
2138       "R.C. Pro-Am II (USA)",
2139       0x9edd2159
2140    },
2141    {
2142       "Rackets & Rivals (Europe)",
2143       0x8fa6e92c
2144    },
2145    {
2146       "Roundball - 2-on-2 Challenge (Europe)",
2147       0xad0394f0
2148    },
2149    {
2150       "Roundball - 2-on-2 Challenge (USA)",
2151       0x6e4dcfd2
2152    },
2153    {
2154       "Spot - The Video Game (Japan)",
2155       0x0abdd5ca
2156    },
2157    {
2158       "Spot - The Video Game (USA)",
2159       0xcfae9dfa
2160    },
2161    {
2162       "Smash T.V. (Europe)",
2163       0x0b8f8128
2164    },
2165    {
2166       "Smash T.V. (USA)",
2167       0x6ee94d32
2168    },
2169    {
2170       "Super Jeopardy! (USA)",
2171       0xcf4487a2
2172    },
2173    {
2174       "Super Spike V'Ball (Europe)",
2175       0xc05a63b2
2176    },
2177    {
2178       "Super Spike V'Ball (USA)",
2179       0xe840fd21
2180    },
2181    {
2182       "Super Spike V'Ball + Nintendo World Cup (USA)",
2183       0x407d6ffd
2184    },
2185    {
2186       "Swords and Serpents (Europe)",
2187       0xd153caf6
2188    },
2189    {
2190       "Swords and Serpents (France)",
2191       0x46135141
2192    },
2193    {
2194       "Swords and Serpents (USA)",
2195       0x3417ec46
2196    },
2197    {
2198       "Battle City (Japan) (4 Players Hack) http://www.romhacking.net/hacks/2142/",
2199       0x69977c9e
2200    },
2201    {
2202       "Bomberman 3 (Homebrew) http://tempect.de/senil/games.html",
2203       0x2da5ece0
2204    },
2205    {
2206       "K.Y.F.F. (Homebrew) http://slydogstudios.org/index.php/k-y-f-f/",
2207       0x90d2e9f0
2208    },
2209    {
2210       "Super PakPak (Homebrew) http://wiki.nesdev.com/w/index.php/Super_PakPak",
2211       0x1394ded0
2212    },
2213    {
2214       "Super Mario Bros. + Tetris + Nintendo World Cup (Europe)",
2215       0x73298c87
2216    },
2217    {
2218       "Super Mario Bros. + Tetris + Nintendo World Cup (Europe) (Rev A)",
2219       0xf46ef39a
2220    }
2221 };
2222 
2223 static const struct cartridge_db famicom_4p_db_list[] =
2224 {
2225    {
2226       "Bakutoushi Patton-Kun (Japan) (FDS)",
2227       0xc39b3bb2
2228    },
2229    {
2230       "Bomber Man II (Japan)",
2231       0x0c401790
2232    },
2233    {
2234       "Championship Bowling (Japan)",
2235       0x9992f445
2236    },
2237    {
2238       "Downtown - Nekketsu Koushinkyoku - Soreyuke Daiundoukai (Japan)",
2239       0x3e470fe0
2240    },
2241    {
2242       "Ike Ike! Nekketsu Hockey-bu - Subette Koronde Dairantou (Japan)",
2243       0x4f032933
2244    },
2245    {
2246       "Kunio-kun no Nekketsu Soccer League (Japan)",
2247       0x4b5177e9
2248    },
2249    {
2250       "Moero TwinBee - Cinnamon Hakase o Sukue! (Japan)",
2251       0x9f03b11f
2252    },
2253    {
2254       "Moero TwinBee - Cinnamon Hakase wo Sukue! (Japan) (FDS)",
2255       0x13205221
2256    },
2257    {
2258       "Nekketsu Kakutou Densetsu (Japan)",
2259       0x37e24797
2260    },
2261    {
2262       "Nekketsu Koukou Dodgeball-bu (Japan)",
2263       0x62c67984
2264    },
2265    {
2266       "Nekketsu! Street Basket - Ganbare Dunk Heroes (Japan)",
2267       0x88062d9a
2268    },
2269    {
2270       "Super Dodge Ball (USA) (3-4p with Game Genie code GEUOLZZA)",
2271       0x689971f9
2272    },
2273    {
2274       "Super Dodge Ball (USA) (patched) http://www.romhacking.net/hacks/71/",
2275       0x4ff17864
2276    },
2277    {
2278       "U.S. Championship V'Ball (Japan)",
2279       0x213cb3fb
2280    },
2281    {
2282       "U.S. Championship V'Ball (Japan) (Beta)",
2283       0xd7077d96
2284    },
2285    {
2286       "Wit's (Japan)",
2287       0xb1b16b8a
2288    }
2289 };
2290 
2291 #ifdef _WIN32
2292 static char slash = '\\';
2293 #else
2294 static char slash = '/';
2295 #endif
2296 
retro_load_game(const struct retro_game_info * game)2297 bool retro_load_game(const struct retro_game_info *game)
2298 {
2299    unsigned i, j;
2300    char* dir=NULL;
2301    char* sav_dir=NULL;
2302    size_t fourscore_len = sizeof(fourscore_db_list)   / sizeof(fourscore_db_list[0]);
2303    size_t famicom_4p_len = sizeof(famicom_4p_db_list) / sizeof(famicom_4p_db_list[0]);
2304    enum retro_pixel_format rgb565;
2305 
2306    struct retro_input_descriptor desc[] = {
2307       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,  "D-Pad Left" },
2308       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,    "D-Pad Up" },
2309       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,  "D-Pad Down" },
2310       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
2311       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,     "B" },
2312       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A,     "A" },
2313       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT,   "Select" },
2314       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START,    "Start" },
2315       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2,     "(VSSystem) Insert Coin" },
2316       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L,     "(FDS) Disk Side Change" },
2317       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R,     "(FDS) Insert/Eject Disk" },
2318       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X,     "Turbo A" },
2319       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y,     "Turbo B" },
2320 
2321       { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,  "D-Pad Left" },
2322       { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,    "D-Pad Up" },
2323       { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,  "D-Pad Down" },
2324       { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
2325       { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,     "B" },
2326       { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A,     "A" },
2327       { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT,   "Select" },
2328       { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START,    "Start" },
2329       { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X,     "Turbo A" },
2330       { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y,     "Turbo B" },
2331 
2332       { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,  "D-Pad Left" },
2333       { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,    "D-Pad Up" },
2334       { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,  "D-Pad Down" },
2335       { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
2336       { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,     "B" },
2337       { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A,     "A" },
2338       { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT,   "Select" },
2339       { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START,    "Start" },
2340       { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X,     "Turbo A" },
2341       { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y,     "Turbo B" },
2342 
2343       { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,  "D-Pad Left" },
2344       { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,    "D-Pad Up" },
2345       { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,  "D-Pad Down" },
2346       { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
2347       { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,     "B" },
2348       { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A,     "A" },
2349       { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT,   "Select" },
2350       { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START,    "Start" },
2351       { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X,     "Turbo A" },
2352       { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y,     "Turbo B" },
2353 
2354       { 0 },
2355    };
2356    size_t desc_base = 64;
2357    struct retro_memory_descriptor descs[64 + 4];
2358    struct retro_memory_map        mmaps;
2359 
2360    if (!game)
2361       return false;
2362 
2363 #ifdef FRONTEND_SUPPORTS_RGB565
2364    rgb565 = RETRO_PIXEL_FORMAT_RGB565;
2365    if(environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &rgb565))
2366       log_cb.log(RETRO_LOG_INFO, "Frontend supports RGB565 - will use that instead of XRGB1555.\n");
2367 #endif
2368 
2369    /* initialize some of the default variables */
2370 #ifdef GEKKO
2371    sndsamplerate = 32000;
2372 #else
2373    sndsamplerate = 48000;
2374 #endif
2375    sndquality = 0;
2376    sndvolume = 150;
2377    swapDuty = 0;
2378    dendy = 0;
2379 
2380    /* Wii: initialize this or else last variable is passed through
2381     * when loading another rom causing save state size change. */
2382    serialize_size = 0;
2383 
2384    PowerNES();
2385    check_system_specs();
2386 #if defined(_3DS)
2387    fceu_video_out = (uint16_t*)linearMemAlign(256 * 240 * sizeof(uint16_t), 128);
2388 #elif !defined(PSP)
2389 #ifdef HAVE_NTSC_FILTER
2390 #define FB_WIDTH NES_NTSC_WIDTH
2391 #define FB_HEIGHT NES_HEIGHT
2392 #else /* !HAVE_NTSC_FILTER */
2393 #define FB_WIDTH NES_WIDTH
2394 #define FB_HEIGHT NES_HEIGHT
2395 #endif
2396    fceu_video_out = (uint16_t*)malloc(FB_WIDTH * FB_HEIGHT * sizeof(uint16_t));
2397 #endif
2398 
2399    environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc);
2400 
2401    if (environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &dir) && dir)
2402       FCEUI_SetBaseDirectory(dir);
2403    if (environ_cb(RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY, &sav_dir) && sav_dir)
2404       FCEUI_SetSaveDirectory(sav_dir);
2405 
2406    memset(base_palette, 0, sizeof(base_palette));
2407 
2408    FCEUI_Initialize();
2409 
2410    FCEUI_SetSoundVolume(sndvolume);
2411    FCEUI_Sound(sndsamplerate);
2412 
2413    GameInfo = (FCEUGI*)FCEUI_LoadGame(game->path, (uint8_t*)game->data, game->size);
2414    if (!GameInfo)
2415    {
2416       struct retro_message msg;
2417       char msg_local[256];
2418 
2419       sprintf(msg_local, "ROM loading failed...");
2420       msg.msg    = msg_local;
2421       msg.frames = 360;
2422       if (environ_cb)
2423          environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE, (void*)&msg);
2424       return false;
2425    }
2426 
2427    for (i = 0; i < MAX_PORTS; i++) {
2428       FCEUI_SetInput(i, SI_GAMEPAD, &nes_input.JSReturn, 0);
2429       nes_input.type[i] = RETRO_DEVICE_JOYPAD;
2430    }
2431 
2432    external_palette_exist = ipalette;
2433    if (external_palette_exist)
2434       FCEU_printf(" Loading custom palette: %s%cnes.pal\n", dir, slash);
2435 
2436    /* Save region and dendy mode for region-auto detect */
2437    systemRegion = (dendy << 1) | (retro_get_region() & 1);
2438 
2439    current_palette = 0;
2440 
2441    ResetPalette();
2442    FCEUD_SoundToggle();
2443    set_variables();
2444    check_variables(true);
2445    PowerNES();
2446 
2447    FCEUI_DisableFourScore(1);
2448 
2449    for (i = 0; i < fourscore_len; i++)
2450    {
2451       if (fourscore_db_list[i].crc == iNESCart.CRC32)
2452       {
2453          FCEUI_DisableFourScore(0);
2454          nes_input.enable_4player = true;
2455          break;
2456       }
2457    }
2458 
2459    for (i = 0; i < famicom_4p_len; i++)
2460    {
2461       if (famicom_4p_db_list[i].crc == iNESCart.CRC32)
2462       {
2463          GameInfo->inputfc = SIFC_4PLAYER;
2464          FCEUI_SetInputFC(SIFC_4PLAYER, &nes_input.JSReturn, 0);
2465          nes_input.enable_4player = true;
2466          break;
2467       }
2468    }
2469 
2470    memset(descs, 0, sizeof(descs));
2471    i = 0;
2472 
2473    for (j = 0; j < desc_base; j++)
2474    {
2475        if (MMapPtrs[j] != NULL)
2476        {
2477          descs[i].ptr    = MMapPtrs[j];
2478          descs[i].start  = j * 1024;
2479          descs[i].len    = 1024;
2480          descs[i].select = 0;
2481          i++;
2482        }
2483    }
2484    /* This doesn't map in 2004--2007 but those aren't really
2485     * worthwhile to read from on a vblank anyway
2486     */
2487    descs[i].flags = 0;
2488    descs[i].ptr = PPU;
2489    descs[i].offset = 0;
2490    descs[i].start = 0x2000;
2491    descs[i].select = 0;
2492    descs[i].disconnect = 0;
2493    descs[i].len = 4;
2494    descs[i].addrspace="PPUREG";
2495    i++;
2496    /* In the future, it would be good to map pattern tables 1 and 2,
2497     * but these must be remapped often
2498     */
2499    /* descs[i] = (struct retro_memory_descriptor){0, ????, 0, 0x0000 | PPU_BIT, PPU_BIT, PPU_BIT, 0x1000, "PAT0"}; */
2500    /* i++; */
2501    /* descs[i] = (struct retro_memory_descriptor){0, ????, 0, 0x1000 | PPU_BIT, PPU_BIT, PPU_BIT, 0x1000, "PAT1"}; */
2502    /* i++; */
2503    /* Likewise it would be better to use "vnapage" for this but
2504     * RetroArch API is inconvenient for handles like that, so we'll
2505     * just blithely assume the client will handle mapping and that
2506     * we'll ignore those carts that have extra NTARAM.
2507     */
2508    descs[i].flags = 0;
2509    descs[i].ptr = NTARAM;
2510    descs[i].offset = 0;
2511    descs[i].start = PPU_BIT | 0x2000;
2512    descs[i].select = PPU_BIT;
2513    descs[i].disconnect = PPU_BIT;
2514    descs[i].len = 0x0800;
2515    descs[i].addrspace="NTARAM";
2516    i++;
2517    descs[i].flags = 0;
2518    descs[i].ptr = PALRAM;
2519    descs[i].offset = 0;
2520    descs[i].start = PPU_BIT | 0x3000;
2521    descs[i].select = PPU_BIT;
2522    descs[i].disconnect = PPU_BIT;
2523    descs[i].len = 0x020;
2524    descs[i].addrspace="PALRAM";
2525    i++;
2526    /* OAM doesn't really live anywhere in address space so I'll put it at 0x4000. */
2527    descs[i].flags = 0;
2528    descs[i].ptr = SPRAM;
2529    descs[i].offset = 0;
2530    descs[i].start = PPU_BIT | 0x4000;
2531    descs[i].select = PPU_BIT;
2532    descs[i].disconnect = PPU_BIT;
2533    descs[i].len = 0x100;
2534    descs[i].addrspace="OAM";
2535    i++;
2536    mmaps.descriptors = descs;
2537    mmaps.num_descriptors = i;
2538    environ_cb(RETRO_ENVIRONMENT_SET_MEMORY_MAPS, &mmaps);
2539 
2540    return true;
2541 }
2542 
retro_load_game_special(unsigned game_type,const struct retro_game_info * info,size_t num_info)2543 bool retro_load_game_special(
2544   unsigned game_type,
2545   const struct retro_game_info *info, size_t num_info
2546 )
2547 {
2548    return false;
2549 }
2550 
retro_unload_game(void)2551 void retro_unload_game(void)
2552 {
2553    FCEUI_CloseGame();
2554 #if defined(_3DS)
2555    if (fceu_video_out)
2556       linearFree(fceu_video_out);
2557 #else
2558    if (fceu_video_out)
2559       free(fceu_video_out);
2560    fceu_video_out = NULL;
2561 #endif
2562 #if defined(RENDER_GSKIT_PS2)
2563    ps2 = NULL;
2564 #endif
2565 #ifdef HAVE_NTSC_FILTER
2566    NTSCFilter_Cleanup();
2567 #endif
2568 }
2569 
retro_get_region(void)2570 unsigned retro_get_region(void)
2571 {
2572    return FSettings.PAL ? RETRO_REGION_PAL : RETRO_REGION_NTSC;
2573 }
2574 
retro_get_memory_data(unsigned type)2575 void *retro_get_memory_data(unsigned type)
2576 {
2577    uint8_t* data;
2578 
2579    switch(type)
2580    {
2581       case RETRO_MEMORY_SAVE_RAM:
2582          if (iNESCart.battery && iNESCart.SaveGame[0] && iNESCart.SaveGameLen[0])
2583             return iNESCart.SaveGame[0];
2584          else if (UNIFCart.battery && UNIFCart.SaveGame[0] && UNIFCart.SaveGameLen[0])
2585             return UNIFCart.SaveGame[0];
2586          else if (GameInfo->type == GIT_FDS)
2587             return FDSROM_ptr();
2588          else
2589             data = NULL;
2590          break;
2591       case RETRO_MEMORY_SYSTEM_RAM:
2592          data = RAM;
2593          break;
2594       default:
2595          data = NULL;
2596          break;
2597    }
2598 
2599    return data;
2600 }
2601 
retro_get_memory_size(unsigned type)2602 size_t retro_get_memory_size(unsigned type)
2603 {
2604    unsigned size;
2605 
2606    switch(type)
2607    {
2608       case RETRO_MEMORY_SAVE_RAM:
2609          if (iNESCart.battery && iNESCart.SaveGame[0] && iNESCart.SaveGameLen[0])
2610             size = iNESCart.SaveGameLen[0];
2611          else if (UNIFCart.battery && UNIFCart.SaveGame[0] && UNIFCart.SaveGameLen[0])
2612             size = UNIFCart.SaveGameLen[0];
2613          else if (GameInfo->type == GIT_FDS)
2614             size = FDSROM_size();
2615          else
2616             size = 0;
2617          break;
2618       case RETRO_MEMORY_SYSTEM_RAM:
2619          size = 0x800;
2620          break;
2621       default:
2622          size = 0;
2623          break;
2624    }
2625 
2626    return size;
2627 }
2628