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