emu.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071
  1. // (c) Copyright 2006-2007 notaz, All rights reserved.
  2. // Free for non-commercial use.
  3. // For commercial use, separate licencing terms must be obtained.
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <ctype.h> // tolower
  7. #ifndef NO_SYNC
  8. #include <unistd.h>
  9. #endif
  10. #include "emu.h"
  11. #include "menu.h"
  12. #include "fonts.h"
  13. #include "lprintf.h"
  14. #include "config.h"
  15. #include "common.h"
  16. #include <Pico/PicoInt.h>
  17. #include <Pico/Patch.h>
  18. #include <Pico/cd/cue.h>
  19. #include <zlib/zlib.h>
  20. char *PicoConfigFile = "config.cfg";
  21. currentConfig_t currentConfig, defaultConfig;
  22. int rom_loaded = 0;
  23. char noticeMsg[64] = { 0, };
  24. int state_slot = 0;
  25. int config_slot = 0, config_slot_current = 0;
  26. char loadedRomFName[512] = { 0, };
  27. int kb_combo_keys = 0, kb_combo_acts = 0; // keys and actions which need button combos
  28. int pico_inp_mode = 0;
  29. unsigned char *movie_data = NULL;
  30. static int movie_size = 0;
  31. // provided by platform code:
  32. extern void emu_noticeMsgUpdated(void);
  33. extern int emu_getMainDir(char *dst, int len);
  34. extern void menu_romload_prepare(const char *rom_name);
  35. extern void menu_romload_end(void);
  36. // utilities
  37. static void strlwr_(char* string)
  38. {
  39. while ( (*string++ = (char)tolower(*string)) );
  40. }
  41. static int try_rfn_cut(char *fname)
  42. {
  43. FILE *tmp;
  44. char *p;
  45. p = fname + strlen(fname) - 1;
  46. for (; p > fname; p--)
  47. if (*p == '.') break;
  48. *p = 0;
  49. if((tmp = fopen(fname, "rb"))) {
  50. fclose(tmp);
  51. return 1;
  52. }
  53. return 0;
  54. }
  55. static void get_ext(char *file, char *ext)
  56. {
  57. char *p;
  58. p = file + strlen(file) - 4;
  59. if (p < file) p = file;
  60. strncpy(ext, p, 4);
  61. ext[4] = 0;
  62. strlwr_(ext);
  63. }
  64. char *biosfiles_us[] = { "us_scd1_9210", "us_scd2_9306", "SegaCDBIOS9303" };
  65. char *biosfiles_eu[] = { "eu_mcd1_9210", "eu_mcd2_9306", "eu_mcd2_9303" };
  66. char *biosfiles_jp[] = { "jp_mcd1_9112", "jp_mcd1_9111" };
  67. int emu_findBios(int region, char **bios_file)
  68. {
  69. static char bios_path[1024];
  70. int i, count;
  71. char **files;
  72. FILE *f = NULL;
  73. if (region == 4) { // US
  74. files = biosfiles_us;
  75. count = sizeof(biosfiles_us) / sizeof(char *);
  76. } else if (region == 8) { // EU
  77. files = biosfiles_eu;
  78. count = sizeof(biosfiles_eu) / sizeof(char *);
  79. } else if (region == 1 || region == 2) {
  80. files = biosfiles_jp;
  81. count = sizeof(biosfiles_jp) / sizeof(char *);
  82. } else {
  83. return 0;
  84. }
  85. for (i = 0; i < count; i++)
  86. {
  87. emu_getMainDir(bios_path, sizeof(bios_path));
  88. strcat(bios_path, files[i]);
  89. strcat(bios_path, ".bin");
  90. f = fopen(bios_path, "rb");
  91. if (f) break;
  92. bios_path[strlen(bios_path) - 4] = 0;
  93. strcat(bios_path, ".zip");
  94. f = fopen(bios_path, "rb");
  95. if (f) break;
  96. }
  97. if (f) {
  98. lprintf("using bios: %s\n", bios_path);
  99. fclose(f);
  100. if (bios_file) *bios_file = bios_path;
  101. return 1;
  102. } else {
  103. sprintf(menuErrorMsg, "no %s BIOS files found, read docs",
  104. region != 4 ? (region == 8 ? "EU" : "JAP") : "USA");
  105. lprintf("%s\n", menuErrorMsg);
  106. return 0;
  107. }
  108. }
  109. /* check if the name begins with BIOS name */
  110. /*
  111. static int emu_isBios(const char *name)
  112. {
  113. int i;
  114. for (i = 0; i < sizeof(biosfiles_us)/sizeof(biosfiles_us[0]); i++)
  115. if (strstr(name, biosfiles_us[i]) != NULL) return 1;
  116. for (i = 0; i < sizeof(biosfiles_eu)/sizeof(biosfiles_eu[0]); i++)
  117. if (strstr(name, biosfiles_eu[i]) != NULL) return 1;
  118. for (i = 0; i < sizeof(biosfiles_jp)/sizeof(biosfiles_jp[0]); i++)
  119. if (strstr(name, biosfiles_jp[i]) != NULL) return 1;
  120. return 0;
  121. }
  122. */
  123. static unsigned char id_header[0x100];
  124. /* checks if fname points to valid MegaCD image
  125. * if so, checks for suitable BIOS */
  126. int emu_cdCheck(int *pregion, char *fname_in)
  127. {
  128. unsigned char buf[32];
  129. pm_file *cd_f;
  130. int region = 4; // 1: Japan, 4: US, 8: Europe
  131. char ext[5], *fname = fname_in;
  132. cue_track_type type = CT_UNKNOWN;
  133. cue_data_t *cue_data = NULL;
  134. get_ext(fname_in, ext);
  135. if (strcasecmp(ext, ".cue") == 0) {
  136. cue_data = cue_parse(fname_in);
  137. if (cue_data != NULL) {
  138. fname = cue_data->tracks[1].fname;
  139. type = cue_data->tracks[1].type;
  140. }
  141. else
  142. return -1;
  143. }
  144. cd_f = pm_open(fname);
  145. if (cue_data != NULL)
  146. cue_destroy(cue_data);
  147. if (cd_f == NULL) return 0; // let the upper level handle this
  148. if (pm_read(buf, 32, cd_f) != 32) {
  149. pm_close(cd_f);
  150. return -1;
  151. }
  152. if (!strncasecmp("SEGADISCSYSTEM", (char *)buf+0x00, 14)) {
  153. if (type && type != CT_ISO)
  154. elprintf(EL_STATUS, ".cue has wrong type: %i", type);
  155. type = CT_ISO; // Sega CD (ISO)
  156. }
  157. if (!strncasecmp("SEGADISCSYSTEM", (char *)buf+0x10, 14)) {
  158. if (type && type != CT_BIN)
  159. elprintf(EL_STATUS, ".cue has wrong type: %i", type);
  160. type = CT_BIN; // Sega CD (BIN)
  161. }
  162. if (type == CT_UNKNOWN) {
  163. pm_close(cd_f);
  164. return 0;
  165. }
  166. pm_seek(cd_f, (type == CT_ISO) ? 0x100 : 0x110, SEEK_SET);
  167. pm_read(id_header, sizeof(id_header), cd_f);
  168. /* it seems we have a CD image here. Try to detect region now.. */
  169. pm_seek(cd_f, (type == CT_ISO) ? 0x100+0x10B : 0x110+0x10B, SEEK_SET);
  170. pm_read(buf, 1, cd_f);
  171. pm_close(cd_f);
  172. if (buf[0] == 0x64) region = 8; // EU
  173. if (buf[0] == 0xa1) region = 1; // JAP
  174. lprintf("detected %s Sega/Mega CD image with %s region\n",
  175. type == CT_BIN ? "BIN" : "ISO", region != 4 ? (region == 8 ? "EU" : "JAP") : "USA");
  176. if (pregion != NULL) *pregion = region;
  177. return type;
  178. }
  179. static int extract_text(char *dest, const unsigned char *src, int len, int swab)
  180. {
  181. char *p = dest;
  182. int i;
  183. if (swab) swab = 1;
  184. for (i = len - 1; i >= 0; i--)
  185. {
  186. if (src[i^swab] != ' ') break;
  187. }
  188. len = i + 1;
  189. for (i = 0; i < len; i++)
  190. {
  191. unsigned char s = src[i^swab];
  192. if (s >= 0x20 && s < 0x7f && s != '#' && s != '|' &&
  193. s != '[' && s != ']' && s != '\\')
  194. {
  195. *p++ = s;
  196. }
  197. else
  198. {
  199. sprintf(p, "\\%02x", s);
  200. p += 3;
  201. }
  202. }
  203. return p - dest;
  204. }
  205. char *emu_makeRomId(void)
  206. {
  207. static char id_string[3+0xe*3+0x3*3+0x30*3+3];
  208. int pos, swab = 1;
  209. if (PicoAHW & PAHW_MCD) {
  210. strcpy(id_string, "CD|");
  211. swab = 0;
  212. }
  213. else strcpy(id_string, "MD|");
  214. pos = 3;
  215. pos += extract_text(id_string + pos, id_header + 0x80, 0x0e, swab); // serial
  216. id_string[pos] = '|'; pos++;
  217. pos += extract_text(id_string + pos, id_header + 0xf0, 0x03, swab); // region
  218. id_string[pos] = '|'; pos++;
  219. pos += extract_text(id_string + pos, id_header + 0x50, 0x30, swab); // overseas name
  220. id_string[pos] = 0;
  221. return id_string;
  222. }
  223. // buffer must be at least 150 byte long
  224. void emu_getGameName(char *str150)
  225. {
  226. int ret, swab = (PicoAHW & PAHW_MCD) ? 0 : 1;
  227. char *s, *d;
  228. ret = extract_text(str150, id_header + 0x50, 0x30, swab); // overseas name
  229. for (s = d = str150 + 1; s < str150+ret; s++)
  230. {
  231. if (*s == 0) break;
  232. if (*s != ' ' || d[-1] != ' ')
  233. *d++ = *s;
  234. }
  235. *d = 0;
  236. }
  237. // note: this function might mangle rom_fname
  238. int emu_ReloadRom(char *rom_fname)
  239. {
  240. unsigned int rom_size = 0;
  241. char *used_rom_name = rom_fname;
  242. unsigned char *rom_data = NULL;
  243. char ext[5];
  244. pm_file *rom = NULL;
  245. int ret, cd_state, cd_region, cfg_loaded = 0;
  246. lprintf("emu_ReloadRom(%s)\n", rom_fname);
  247. get_ext(rom_fname, ext);
  248. // detect wrong extensions
  249. if (!strcmp(ext, ".srm") || !strcmp(ext, "s.gz") || !strcmp(ext, ".mds")) { // s.gz ~ .mds.gz
  250. sprintf(menuErrorMsg, "Not a ROM/CD selected.");
  251. return 0;
  252. }
  253. PicoPatchUnload();
  254. // check for movie file
  255. if (movie_data) {
  256. free(movie_data);
  257. movie_data = 0;
  258. }
  259. if (!strcmp(ext, ".gmv"))
  260. {
  261. // check for both gmv and rom
  262. int dummy;
  263. FILE *movie_file = fopen(rom_fname, "rb");
  264. if(!movie_file) {
  265. sprintf(menuErrorMsg, "Failed to open movie.");
  266. return 0;
  267. }
  268. fseek(movie_file, 0, SEEK_END);
  269. movie_size = ftell(movie_file);
  270. fseek(movie_file, 0, SEEK_SET);
  271. if(movie_size < 64+3) {
  272. sprintf(menuErrorMsg, "Invalid GMV file.");
  273. fclose(movie_file);
  274. return 0;
  275. }
  276. movie_data = malloc(movie_size);
  277. if(movie_data == NULL) {
  278. sprintf(menuErrorMsg, "low memory.");
  279. fclose(movie_file);
  280. return 0;
  281. }
  282. fread(movie_data, 1, movie_size, movie_file);
  283. fclose(movie_file);
  284. if (strncmp((char *)movie_data, "Gens Movie TEST", 15) != 0) {
  285. sprintf(menuErrorMsg, "Invalid GMV file.");
  286. return 0;
  287. }
  288. dummy = try_rfn_cut(rom_fname) || try_rfn_cut(rom_fname);
  289. if (!dummy) {
  290. sprintf(menuErrorMsg, "Could't find a ROM for movie.");
  291. return 0;
  292. }
  293. get_ext(rom_fname, ext);
  294. }
  295. else if (!strcmp(ext, ".pat"))
  296. {
  297. int dummy;
  298. PicoPatchLoad(rom_fname);
  299. dummy = try_rfn_cut(rom_fname) || try_rfn_cut(rom_fname);
  300. if (!dummy) {
  301. sprintf(menuErrorMsg, "Could't find a ROM to patch.");
  302. return 0;
  303. }
  304. get_ext(rom_fname, ext);
  305. }
  306. emu_shutdownMCD();
  307. // check for MegaCD image
  308. cd_state = emu_cdCheck(&cd_region, rom_fname);
  309. if (cd_state >= 0 && cd_state != CIT_NOT_CD)
  310. {
  311. PicoAHW |= PAHW_MCD;
  312. // valid CD image, check for BIOS..
  313. // we need to have config loaded at this point
  314. ret = emu_ReadConfig(1, 1);
  315. if (!ret) emu_ReadConfig(0, 1);
  316. cfg_loaded = 1;
  317. if (PicoRegionOverride) {
  318. cd_region = PicoRegionOverride;
  319. lprintf("overrided region to %s\n", cd_region != 4 ? (cd_region == 8 ? "EU" : "JAP") : "USA");
  320. }
  321. if (!emu_findBios(cd_region, &used_rom_name)) {
  322. // bios_help() ?
  323. PicoAHW &= ~PAHW_MCD;
  324. return 0;
  325. }
  326. get_ext(used_rom_name, ext);
  327. }
  328. else
  329. {
  330. if (PicoAHW & PAHW_MCD) Stop_CD();
  331. PicoAHW &= ~PAHW_MCD;
  332. }
  333. rom = pm_open(used_rom_name);
  334. if (!rom) {
  335. sprintf(menuErrorMsg, "Failed to open ROM/CD image");
  336. goto fail;
  337. }
  338. if (cd_state < 0) {
  339. sprintf(menuErrorMsg, "Invalid CD image");
  340. goto fail;
  341. }
  342. menu_romload_prepare(used_rom_name); // also CD load
  343. PicoCartUnload();
  344. rom_loaded = 0;
  345. if ( (ret = PicoCartLoad(rom, &rom_data, &rom_size)) ) {
  346. sprintf(menuErrorMsg, "PicoCartLoad() failed.");
  347. lprintf("%s\n", menuErrorMsg);
  348. goto fail2;
  349. }
  350. pm_close(rom);
  351. rom = NULL;
  352. // detect wrong files (Pico crashes on very small files), also see if ROM EP is good
  353. if (rom_size <= 0x200 || strncmp((char *)rom_data, "Pico", 4) == 0 ||
  354. ((*(unsigned char *)(rom_data+4)<<16)|(*(unsigned short *)(rom_data+6))) >= (int)rom_size) {
  355. if (rom_data) free(rom_data);
  356. sprintf(menuErrorMsg, "Not a ROM selected.");
  357. goto fail2;
  358. }
  359. // load config for this ROM (do this before insert to get correct region)
  360. if (!(PicoAHW & PAHW_MCD))
  361. memcpy(id_header, rom_data + 0x100, sizeof(id_header));
  362. if (!cfg_loaded) {
  363. ret = emu_ReadConfig(1, 1);
  364. if (!ret) emu_ReadConfig(0, 1);
  365. }
  366. lprintf("PicoCartInsert(%p, %d);\n", rom_data, rom_size);
  367. if (PicoCartInsert(rom_data, rom_size)) {
  368. sprintf(menuErrorMsg, "Failed to load ROM.");
  369. goto fail2;
  370. }
  371. // insert CD if it was detected
  372. if (cd_state != CIT_NOT_CD) {
  373. ret = Insert_CD(rom_fname, cd_state);
  374. if (ret != 0) {
  375. sprintf(menuErrorMsg, "Insert_CD() failed, invalid CD image?");
  376. lprintf("%s\n", menuErrorMsg);
  377. goto fail2;
  378. }
  379. }
  380. menu_romload_end();
  381. if (PicoPatches) {
  382. PicoPatchPrepare();
  383. PicoPatchApply();
  384. }
  385. // additional movie stuff
  386. if (movie_data)
  387. {
  388. if (movie_data[0x14] == '6')
  389. PicoOpt |= POPT_6BTN_PAD; // 6 button pad
  390. else PicoOpt &= ~POPT_6BTN_PAD;
  391. PicoOpt |= POPT_DIS_VDP_FIFO; // no VDP fifo timing
  392. if (movie_data[0xF] >= 'A') {
  393. if (movie_data[0x16] & 0x80) {
  394. PicoRegionOverride = 8;
  395. } else {
  396. PicoRegionOverride = 4;
  397. }
  398. PicoReset();
  399. // TODO: bits 6 & 5
  400. }
  401. movie_data[0x18+30] = 0;
  402. sprintf(noticeMsg, "MOVIE: %s", (char *) &movie_data[0x18]);
  403. }
  404. else
  405. {
  406. PicoOpt &= ~POPT_DIS_VDP_FIFO;
  407. if (Pico.m.pal) {
  408. strcpy(noticeMsg, "PAL SYSTEM / 50 FPS");
  409. } else {
  410. strcpy(noticeMsg, "NTSC SYSTEM / 60 FPS");
  411. }
  412. }
  413. emu_noticeMsgUpdated();
  414. // load SRAM for this ROM
  415. if (currentConfig.EmuOpt & EOPT_USE_SRAM)
  416. emu_SaveLoadGame(1, 1);
  417. strncpy(loadedRomFName, rom_fname, sizeof(loadedRomFName)-1);
  418. loadedRomFName[sizeof(loadedRomFName)-1] = 0;
  419. rom_loaded = 1;
  420. return 1;
  421. fail2:
  422. menu_romload_end();
  423. fail:
  424. if (rom != NULL) pm_close(rom);
  425. return 0;
  426. }
  427. void emu_shutdownMCD(void)
  428. {
  429. if ((PicoAHW & PAHW_MCD) && Pico_mcd != NULL)
  430. Stop_CD();
  431. PicoAHW &= ~PAHW_MCD;
  432. }
  433. static void romfname_ext(char *dst, const char *prefix, const char *ext)
  434. {
  435. char *p;
  436. int prefix_len = 0;
  437. // make save filename
  438. p = loadedRomFName+strlen(loadedRomFName)-1;
  439. for (; p >= loadedRomFName && *p != PATH_SEP_C; p--); p++;
  440. *dst = 0;
  441. if (prefix) {
  442. int len = emu_getMainDir(dst, 512);
  443. strcpy(dst + len, prefix);
  444. prefix_len = len + strlen(prefix);
  445. }
  446. #ifdef UIQ3
  447. else p = loadedRomFName; // backward compatibility
  448. #endif
  449. strncpy(dst + prefix_len, p, 511-prefix_len);
  450. dst[511-8] = 0;
  451. if (dst[strlen(dst)-4] == '.') dst[strlen(dst)-4] = 0;
  452. if (ext) strcat(dst, ext);
  453. }
  454. static void make_config_cfg(char *cfg)
  455. {
  456. int len;
  457. len = emu_getMainDir(cfg, 512);
  458. strncpy(cfg + len, PicoConfigFile, 512-6-1-len);
  459. if (config_slot != 0)
  460. {
  461. char *p = strrchr(cfg, '.');
  462. if (p == NULL) p = cfg + strlen(cfg);
  463. sprintf(p, ".%i.cfg", config_slot);
  464. }
  465. cfg[511] = 0;
  466. }
  467. void emu_packConfig(void)
  468. {
  469. currentConfig.s_PicoOpt = PicoOpt;
  470. currentConfig.s_PsndRate = PsndRate;
  471. currentConfig.s_PicoRegion = PicoRegionOverride;
  472. currentConfig.s_PicoAutoRgnOrder = PicoAutoRgnOrder;
  473. currentConfig.s_PicoCDBuffers = PicoCDBuffers;
  474. }
  475. void emu_unpackConfig(void)
  476. {
  477. PicoOpt = currentConfig.s_PicoOpt;
  478. PsndRate = currentConfig.s_PsndRate;
  479. PicoRegionOverride = currentConfig.s_PicoRegion;
  480. PicoAutoRgnOrder = currentConfig.s_PicoAutoRgnOrder;
  481. PicoCDBuffers = currentConfig.s_PicoCDBuffers;
  482. }
  483. static void emu_setDefaultConfig(void)
  484. {
  485. memcpy(&currentConfig, &defaultConfig, sizeof(currentConfig));
  486. emu_unpackConfig();
  487. }
  488. int emu_ReadConfig(int game, int no_defaults)
  489. {
  490. char cfg[512];
  491. int ret;
  492. if (!game)
  493. {
  494. if (!no_defaults)
  495. emu_setDefaultConfig();
  496. make_config_cfg(cfg);
  497. ret = config_readsect(cfg, NULL);
  498. }
  499. else
  500. {
  501. char *sect = emu_makeRomId();
  502. // try new .cfg way
  503. if (config_slot != 0)
  504. sprintf(cfg, "game.%i.cfg", config_slot);
  505. else strcpy(cfg, "game.cfg");
  506. ret = -1;
  507. if (config_havesect(cfg, sect))
  508. {
  509. // read user's config
  510. int vol = currentConfig.volume;
  511. emu_setDefaultConfig();
  512. ret = config_readsect(cfg, sect);
  513. currentConfig.volume = vol; // make vol global (bah)
  514. }
  515. else
  516. {
  517. // read global config, and apply game_def.cfg on top
  518. make_config_cfg(cfg);
  519. config_readsect(cfg, NULL);
  520. ret = config_readsect("game_def.cfg", sect);
  521. }
  522. if (ret == 0)
  523. {
  524. lprintf("loaded cfg from sect \"%s\"\n", sect);
  525. }
  526. }
  527. // some sanity checks
  528. if (currentConfig.CPUclock < 10 || currentConfig.CPUclock > 4096) currentConfig.CPUclock = 200;
  529. #ifdef PSP
  530. if (currentConfig.gamma < -4 || currentConfig.gamma > 16) currentConfig.gamma = 0;
  531. if (currentConfig.gamma2 < 0 || currentConfig.gamma2 > 2) currentConfig.gamma2 = 0;
  532. #else
  533. if (currentConfig.gamma < 10 || currentConfig.gamma > 300) currentConfig.gamma = 100;
  534. #endif
  535. if (currentConfig.volume < 0 || currentConfig.volume > 99) currentConfig.volume = 50;
  536. #ifdef __GP2X__
  537. // if volume keys are unbound, bind them to volume control
  538. if (!currentConfig.KeyBinds[23] && !currentConfig.KeyBinds[22]) {
  539. currentConfig.KeyBinds[23] = 1<<29; // vol up
  540. currentConfig.KeyBinds[22] = 1<<30; // vol down
  541. }
  542. #endif
  543. if (ret == 0) config_slot_current = config_slot;
  544. return (ret == 0);
  545. }
  546. int emu_WriteConfig(int is_game)
  547. {
  548. char cfg[512], *game_sect = NULL;
  549. int ret, write_lrom = 0;
  550. if (!is_game)
  551. {
  552. make_config_cfg(cfg);
  553. write_lrom = 1;
  554. } else {
  555. if (config_slot != 0)
  556. sprintf(cfg, "game.%i.cfg", config_slot);
  557. else strcpy(cfg, "game.cfg");
  558. game_sect = emu_makeRomId();
  559. lprintf("emu_WriteConfig: sect \"%s\"\n", game_sect);
  560. }
  561. lprintf("emu_WriteConfig: %s ", cfg);
  562. ret = config_writesect(cfg, game_sect);
  563. if (write_lrom) config_writelrom(cfg);
  564. #ifndef NO_SYNC
  565. sync();
  566. #endif
  567. lprintf((ret == 0) ? "(ok)\n" : "(failed)\n");
  568. if (ret == 0) config_slot_current = config_slot;
  569. return ret == 0;
  570. }
  571. #ifndef UIQ3
  572. void emu_textOut8(int x, int y, const char *text)
  573. {
  574. int i,l,len=strlen(text);
  575. unsigned char *screen = (unsigned char *)SCREEN_BUFFER + x + y*SCREEN_WIDTH;
  576. /* always using built-in font */
  577. for (i = 0; i < len; i++)
  578. {
  579. for (l=0;l<8;l++)
  580. {
  581. unsigned char fd = fontdata8x8[((text[i])*8)+l];
  582. if (fd&0x80) screen[l*SCREEN_WIDTH+0]=0xf0;
  583. if (fd&0x40) screen[l*SCREEN_WIDTH+1]=0xf0;
  584. if (fd&0x20) screen[l*SCREEN_WIDTH+2]=0xf0;
  585. if (fd&0x10) screen[l*SCREEN_WIDTH+3]=0xf0;
  586. if (fd&0x08) screen[l*SCREEN_WIDTH+4]=0xf0;
  587. if (fd&0x04) screen[l*SCREEN_WIDTH+5]=0xf0;
  588. if (fd&0x02) screen[l*SCREEN_WIDTH+6]=0xf0;
  589. if (fd&0x01) screen[l*SCREEN_WIDTH+7]=0xf0;
  590. }
  591. screen += 8;
  592. }
  593. }
  594. void emu_textOut16(int x, int y, const char *text)
  595. {
  596. int i,l,len=strlen(text);
  597. unsigned short *screen = (unsigned short *)SCREEN_BUFFER + x + y*SCREEN_WIDTH;
  598. for (i = 0; i < len; i++)
  599. {
  600. for (l=0;l<8;l++)
  601. {
  602. unsigned char fd = fontdata8x8[((text[i])*8)+l];
  603. if(fd&0x80) screen[l*SCREEN_WIDTH+0]=0xffff;
  604. if(fd&0x40) screen[l*SCREEN_WIDTH+1]=0xffff;
  605. if(fd&0x20) screen[l*SCREEN_WIDTH+2]=0xffff;
  606. if(fd&0x10) screen[l*SCREEN_WIDTH+3]=0xffff;
  607. if(fd&0x08) screen[l*SCREEN_WIDTH+4]=0xffff;
  608. if(fd&0x04) screen[l*SCREEN_WIDTH+5]=0xffff;
  609. if(fd&0x02) screen[l*SCREEN_WIDTH+6]=0xffff;
  610. if(fd&0x01) screen[l*SCREEN_WIDTH+7]=0xffff;
  611. }
  612. screen += 8;
  613. }
  614. }
  615. #endif
  616. #ifdef PSP
  617. #define MAX_COMBO_KEY 23
  618. #else
  619. #define MAX_COMBO_KEY 31
  620. #endif
  621. void emu_findKeyBindCombos(void)
  622. {
  623. int act, u;
  624. // find out which keys and actions are combos
  625. kb_combo_keys = kb_combo_acts = 0;
  626. for (act = 0; act < 32; act++)
  627. {
  628. int keyc = 0, keyc2 = 0;
  629. if (act == 16 || act == 17) continue; // player2 flag
  630. if (act > 17)
  631. {
  632. for (u = 0; u <= MAX_COMBO_KEY; u++)
  633. if (currentConfig.KeyBinds[u] & (1 << act)) keyc++;
  634. }
  635. else
  636. {
  637. for (u = 0; u <= MAX_COMBO_KEY; u++)
  638. if ((currentConfig.KeyBinds[u] & 0x30000) == 0 && // pl. 1
  639. (currentConfig.KeyBinds[u] & (1 << act))) keyc++;
  640. for (u = 0; u <= MAX_COMBO_KEY; u++)
  641. if ((currentConfig.KeyBinds[u] & 0x30000) == 1 && // pl. 2
  642. (currentConfig.KeyBinds[u] & (1 << act))) keyc2++;
  643. if (keyc2 > keyc) keyc = keyc2;
  644. }
  645. if (keyc > 1)
  646. {
  647. // loop again and mark those keys and actions as combo
  648. for (u = 0; u <= MAX_COMBO_KEY; u++)
  649. {
  650. if (currentConfig.KeyBinds[u] & (1 << act)) {
  651. kb_combo_keys |= 1 << u;
  652. kb_combo_acts |= 1 << act;
  653. }
  654. }
  655. }
  656. }
  657. // printf("combo keys/acts: %08x %08x\n", kb_combo_keys, kb_combo_acts);
  658. }
  659. void emu_updateMovie(void)
  660. {
  661. int offs = Pico.m.frame_count*3 + 0x40;
  662. if (offs+3 > movie_size) {
  663. free(movie_data);
  664. movie_data = 0;
  665. strcpy(noticeMsg, "END OF MOVIE.");
  666. lprintf("END OF MOVIE.\n");
  667. emu_noticeMsgUpdated();
  668. } else {
  669. // MXYZ SACB RLDU
  670. PicoPad[0] = ~movie_data[offs] & 0x8f; // ! SCBA RLDU
  671. if(!(movie_data[offs] & 0x10)) PicoPad[0] |= 0x40; // A
  672. if(!(movie_data[offs] & 0x20)) PicoPad[0] |= 0x10; // B
  673. if(!(movie_data[offs] & 0x40)) PicoPad[0] |= 0x20; // A
  674. PicoPad[1] = ~movie_data[offs+1] & 0x8f; // ! SCBA RLDU
  675. if(!(movie_data[offs+1] & 0x10)) PicoPad[1] |= 0x40; // A
  676. if(!(movie_data[offs+1] & 0x20)) PicoPad[1] |= 0x10; // B
  677. if(!(movie_data[offs+1] & 0x40)) PicoPad[1] |= 0x20; // A
  678. PicoPad[0] |= (~movie_data[offs+2] & 0x0A) << 8; // ! MZYX
  679. if(!(movie_data[offs+2] & 0x01)) PicoPad[0] |= 0x0400; // X
  680. if(!(movie_data[offs+2] & 0x04)) PicoPad[0] |= 0x0100; // Z
  681. PicoPad[1] |= (~movie_data[offs+2] & 0xA0) << 4; // ! MZYX
  682. if(!(movie_data[offs+2] & 0x10)) PicoPad[1] |= 0x0400; // X
  683. if(!(movie_data[offs+2] & 0x40)) PicoPad[1] |= 0x0100; // Z
  684. }
  685. }
  686. static size_t gzRead2(void *p, size_t _size, size_t _n, void *file)
  687. {
  688. return gzread(file, p, _n);
  689. }
  690. static size_t gzWrite2(void *p, size_t _size, size_t _n, void *file)
  691. {
  692. return gzwrite(file, p, _n);
  693. }
  694. static int try_ropen_file(const char *fname)
  695. {
  696. FILE *f;
  697. f = fopen(fname, "rb");
  698. if (f) {
  699. fclose(f);
  700. return 1;
  701. }
  702. return 0;
  703. }
  704. char *emu_GetSaveFName(int load, int is_sram, int slot)
  705. {
  706. static char saveFname[512];
  707. char ext[16];
  708. if (is_sram)
  709. {
  710. romfname_ext(saveFname, (PicoAHW&1) ? "brm"PATH_SEP : "srm"PATH_SEP, (PicoAHW&1) ? ".brm" : ".srm");
  711. if (load) {
  712. if (try_ropen_file(saveFname)) return saveFname;
  713. // try in current dir..
  714. romfname_ext(saveFname, NULL, (PicoAHW & PAHW_MCD) ? ".brm" : ".srm");
  715. if (try_ropen_file(saveFname)) return saveFname;
  716. return NULL; // give up
  717. }
  718. }
  719. else
  720. {
  721. ext[0] = 0;
  722. if(slot > 0 && slot < 10) sprintf(ext, ".%i", slot);
  723. strcat(ext, (currentConfig.EmuOpt & EOPT_GZIP_SAVES) ? ".mds.gz" : ".mds");
  724. romfname_ext(saveFname, "mds" PATH_SEP, ext);
  725. if (load) {
  726. if (try_ropen_file(saveFname)) return saveFname;
  727. romfname_ext(saveFname, NULL, ext);
  728. if (try_ropen_file(saveFname)) return saveFname;
  729. // no gzipped states, search for non-gzipped
  730. if (currentConfig.EmuOpt & EOPT_GZIP_SAVES)
  731. {
  732. ext[0] = 0;
  733. if(slot > 0 && slot < 10) sprintf(ext, ".%i", slot);
  734. strcat(ext, ".mds");
  735. romfname_ext(saveFname, "mds"PATH_SEP, ext);
  736. if (try_ropen_file(saveFname)) return saveFname;
  737. romfname_ext(saveFname, NULL, ext);
  738. if (try_ropen_file(saveFname)) return saveFname;
  739. }
  740. return NULL;
  741. }
  742. }
  743. return saveFname;
  744. }
  745. int emu_checkSaveFile(int slot)
  746. {
  747. return emu_GetSaveFName(1, 0, slot) ? 1 : 0;
  748. }
  749. void emu_setSaveStateCbs(int gz)
  750. {
  751. if (gz) {
  752. areaRead = gzRead2;
  753. areaWrite = gzWrite2;
  754. areaEof = (areaeof *) gzeof;
  755. areaSeek = (areaseek *) gzseek;
  756. areaClose = (areaclose *) gzclose;
  757. } else {
  758. areaRead = (arearw *) fread;
  759. areaWrite = (arearw *) fwrite;
  760. areaEof = (areaeof *) feof;
  761. areaSeek = (areaseek *) fseek;
  762. areaClose = (areaclose *) fclose;
  763. }
  764. }
  765. int emu_SaveLoadGame(int load, int sram)
  766. {
  767. int ret = 0;
  768. char *saveFname;
  769. // make save filename
  770. saveFname = emu_GetSaveFName(load, sram, state_slot);
  771. if (saveFname == NULL) {
  772. if (!sram) {
  773. strcpy(noticeMsg, load ? "LOAD FAILED (missing file)" : "SAVE FAILED ");
  774. emu_noticeMsgUpdated();
  775. }
  776. return -1;
  777. }
  778. lprintf("saveLoad (%i, %i): %s\n", load, sram, saveFname);
  779. if (sram)
  780. {
  781. FILE *sramFile;
  782. int sram_size;
  783. unsigned char *sram_data;
  784. int truncate = 1;
  785. if (PicoAHW & PAHW_MCD)
  786. {
  787. if (PicoOpt&POPT_EN_MCD_RAMCART) {
  788. sram_size = 0x12000;
  789. sram_data = SRam.data;
  790. if (sram_data)
  791. memcpy32((int *)sram_data, (int *)Pico_mcd->bram, 0x2000/4);
  792. } else {
  793. sram_size = 0x2000;
  794. sram_data = Pico_mcd->bram;
  795. truncate = 0; // the .brm may contain RAM cart data after normal brm
  796. }
  797. } else {
  798. sram_size = SRam.end-SRam.start+1;
  799. if(Pico.m.sram_reg & 4) sram_size=0x2000;
  800. sram_data = SRam.data;
  801. }
  802. if (!sram_data) return 0; // SRam forcefully disabled for this game
  803. if (load)
  804. {
  805. sramFile = fopen(saveFname, "rb");
  806. if(!sramFile) return -1;
  807. fread(sram_data, 1, sram_size, sramFile);
  808. fclose(sramFile);
  809. if ((PicoAHW & PAHW_MCD) && (PicoOpt&POPT_EN_MCD_RAMCART))
  810. memcpy32((int *)Pico_mcd->bram, (int *)sram_data, 0x2000/4);
  811. } else {
  812. // sram save needs some special processing
  813. // see if we have anything to save
  814. for (; sram_size > 0; sram_size--)
  815. if (sram_data[sram_size-1]) break;
  816. if (sram_size) {
  817. sramFile = fopen(saveFname, truncate ? "wb" : "r+b");
  818. if (!sramFile) sramFile = fopen(saveFname, "wb"); // retry
  819. if (!sramFile) return -1;
  820. ret = fwrite(sram_data, 1, sram_size, sramFile);
  821. ret = (ret != sram_size) ? -1 : 0;
  822. fclose(sramFile);
  823. #ifndef NO_SYNC
  824. sync();
  825. #endif
  826. }
  827. }
  828. return ret;
  829. }
  830. else
  831. {
  832. void *PmovFile = NULL;
  833. if (strcmp(saveFname + strlen(saveFname) - 3, ".gz") == 0)
  834. {
  835. if( (PmovFile = gzopen(saveFname, load ? "rb" : "wb")) ) {
  836. emu_setSaveStateCbs(1);
  837. if (!load) gzsetparams(PmovFile, 9, Z_DEFAULT_STRATEGY);
  838. }
  839. }
  840. else
  841. {
  842. if( (PmovFile = fopen(saveFname, load ? "rb" : "wb")) ) {
  843. emu_setSaveStateCbs(0);
  844. }
  845. }
  846. if(PmovFile) {
  847. ret = PmovState(load ? 6 : 5, PmovFile);
  848. areaClose(PmovFile);
  849. PmovFile = 0;
  850. if (load) Pico.m.dirtyPal=1;
  851. #ifndef NO_SYNC
  852. else sync();
  853. #endif
  854. }
  855. else ret = -1;
  856. if (!ret)
  857. strcpy(noticeMsg, load ? "GAME LOADED " : "GAME SAVED ");
  858. else
  859. {
  860. strcpy(noticeMsg, load ? "LOAD FAILED " : "SAVE FAILED ");
  861. ret = -1;
  862. }
  863. emu_noticeMsgUpdated();
  864. return ret;
  865. }
  866. }
  867. void emu_changeFastForward(int set_on)
  868. {
  869. static void *set_PsndOut = NULL;
  870. static int set_Frameskip, set_EmuOpt, is_on = 0;
  871. if (set_on && !is_on) {
  872. set_PsndOut = PsndOut;
  873. set_Frameskip = currentConfig.Frameskip;
  874. set_EmuOpt = currentConfig.EmuOpt;
  875. PsndOut = NULL;
  876. currentConfig.Frameskip = 8;
  877. currentConfig.EmuOpt &= ~4;
  878. currentConfig.EmuOpt |= 0x40000;
  879. is_on = 1;
  880. strcpy(noticeMsg, "FAST FORWARD ");
  881. emu_noticeMsgUpdated();
  882. }
  883. else if (!set_on && is_on) {
  884. PsndOut = set_PsndOut;
  885. currentConfig.Frameskip = set_Frameskip;
  886. currentConfig.EmuOpt = set_EmuOpt;
  887. PsndRerate(1);
  888. is_on = 0;
  889. }
  890. }
  891. void emu_RunEventsPico(unsigned int events)
  892. {
  893. if (events & (1 << 3)) {
  894. pico_inp_mode++;
  895. if (pico_inp_mode > 2) pico_inp_mode = 0;
  896. switch (pico_inp_mode) {
  897. case 2: strcpy(noticeMsg, "Input: Pen on Pad "); break;
  898. case 1: strcpy(noticeMsg, "Input: Pen on Storyware"); break;
  899. case 0: strcpy(noticeMsg, "Input: Joytick ");
  900. PicoPicohw.pen_pos[0] = PicoPicohw.pen_pos[1] = 0x8000;
  901. break;
  902. }
  903. emu_noticeMsgUpdated();
  904. }
  905. if (events & (1 << 4)) {
  906. PicoPicohw.page--;
  907. if (PicoPicohw.page < 0) PicoPicohw.page = 0;
  908. sprintf(noticeMsg, "Page %i ", PicoPicohw.page);
  909. emu_noticeMsgUpdated();
  910. }
  911. if (events & (1 << 5)) {
  912. PicoPicohw.page++;
  913. if (PicoPicohw.page > 6) PicoPicohw.page = 6;
  914. sprintf(noticeMsg, "Page %i ", PicoPicohw.page);
  915. emu_noticeMsgUpdated();
  916. }
  917. }
  918. void emu_DoTurbo(int *pad, int acts)
  919. {
  920. static int turbo_pad = 0;
  921. static unsigned char turbo_cnt[3] = { 0, 0, 0 };
  922. int inc = currentConfig.turbo_rate * 2;
  923. if (acts & 0x1000) {
  924. turbo_cnt[0] += inc;
  925. if (turbo_cnt[0] >= 60)
  926. turbo_pad ^= 0x10, turbo_cnt[0] = 0;
  927. }
  928. if (acts & 0x2000) {
  929. turbo_cnt[1] += inc;
  930. if (turbo_cnt[1] >= 60)
  931. turbo_pad ^= 0x20, turbo_cnt[1] = 0;
  932. }
  933. if (acts & 0x4000) {
  934. turbo_cnt[2] += inc;
  935. if (turbo_cnt[2] >= 60)
  936. turbo_pad ^= 0x40, turbo_cnt[2] = 0;
  937. }
  938. *pad |= turbo_pad & (acts >> 8);
  939. }