You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4454 lines
128 KiB

/*
* ALT64 Menu v0.1.8.6 - 2013
* a menu for the Everdrive64
* based on libdragon, Neo64Menu, ED64IO, libn64-hkz, libmikmod
* by saturnu
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <math.h>
//libdragon n64 lib
#include <libdragon.h>
//everdrive system libs
#include "types.h"
#include "sys.h"
#include "everdrive.h"
#include "everdrive.h"
//filesystem
#include "disk.h"
#include "fat.h"
//utils
#include "utils.h"
//config file on sd
#include "ini.h"
#include "strlib.h"
//menu header
#include "menu.h"
//sound
#include <mikmod.h>
#include "mp3.h"
// YAML parser
#include <yaml.h>
#ifdef USE_TRUETYPE
#define STB_TRUETYPE_IMPLEMENTATION
#include "stb_truetype.h"
struct glyph {
int xoff;
int yoff;
int adv;
int lsb;
float scale;
unsigned int color;
unsigned char *alpha;
sprite_t sprite;
};
typedef struct glyph glyph_t;
glyph_t sans[96];
glyph_t serif[96];
#endif
typedef struct
{
uint32_t type;
uint32_t color;
char filename[MAX_FILENAME_LEN+1];
} direntry_t;
//ini file
typedef struct
{
int version;
const char* name;
char* background_image;
char* border_color_1;
char* border_color_2;
char* box_color;
char* selection_color;
char* list_font_color;
char* list_dir_font_color;
char* selection_font_color;
char* mempak_path;
char* save_path;
int sound_on;
int page_display;
int tv_mode;
int quick_boot;
int enable_colored_list;
int ext_type;
int cd_behaviour;
int scroll_behaviour;
int text_offset;
int hide_sysfolder;
int sd_speed;
} configuration;
volatile u32 *romaddr_ptr = (u32 *) ROM_ADDR;
unsigned int gBootCic=CIC_6102;
u8 debug=DBG_MODE;
static uint8_t mempak_data[128 * 256];
static void *bg_buffer;
void *__safe_bg_buffer;
#define __get_buffer( x ) __safe_buffer[(x)-1]
extern uint32_t __bitdepth;
extern uint32_t __width;
extern uint32_t __height;
extern void *__safe_buffer[];
char firmware_str[64];
int firm_found=0;
char rom_config[10];
display_context_t lockVideo(int wait);
int select_mode = 0;
int toplist_reload=1;
int toplist_cursor=0;
char toplist15[15][256];
int fat_initialized=0;
int exit_ok = 0;
int boot_cic=0;
int boot_save=0;
int cursor_line=0;
int cursor_lastline=0;
u16 cursor_history[32];
u16 cursor_history_pos=0;
u8 empty=0;
u8 playing=0;
u8 gb_load_y=0;
//start with filebrowser menu key settings
int input_mapping=1;
/* 1=filemanager
* 2=mempak-menu
* 3=charinput
* 4=rom loaded
* 5=format mpk
* 6=restore mpk
* 7=rom config box
* 8=toplist
* 9=mpk choice
* 10=mpk quick-backup
* 11=mp3
* 98= A/B abort screen
*/
//holds the string of the character input screen result
int text_input_on=0;
//char input vars
int x,y,position,set;
unsigned char input_text[32];
uint32_t chr_forecolor;
uint32_t chr_backcolor;
//save type still set - save todo after reboot
int save_reboot=0;
//cart id from rom header
unsigned char cartID[4];
char curr_dirname[64];
char pwd[64];
char rom_filename[128];
u32 rom_buff[128]; //rom buffer
u8 *rom_buff8; //rom buffer
u8 *firmware;
u8 gbload=0;
int cheats_on=0;
int checksum_fix_on=0;
short int gCheats = 0; /* 0 = off, 1 = select, 2 = all */
short int force_tv = 0;
short int boot_country=0;
static resolution_t res = RESOLUTION_320x240;
//background sprites
sprite_t *loadPng(u8 *png_filename);
sprite_t *background; //background
sprite_t *background0; //splash screen
//config file theme settings
u32 border_color_1=0xFFFFFFFF; //hex 0xRRGGBBAA AA=transparenxy
u32 border_color_2=0x3F3F3FFF;
u32 box_color=0x00000080;
u32 selection_color=0x6495ED60;
u32 selection_font_color=0xFFFFFFFF;
u32 list_font_color=0xFFFFFFFF;
u32 list_dir_font_color=0xFFFFFFFF;
char* border_color_1_s;
char* border_color_2_s;
char* box_color_s;
char* selection_color_s;
char* selection_font_color_s;
char* list_font_color_s;
char* list_dir_font_color_s;
char* mempak_path;
char* save_path;
u8 sound_on=0;
u8 page_display=0;
int text_offset=0;
u8 tv_mode=0; // 1=ntsc 2=pal 3=mpal 0=default automatic
u8 quick_boot=0;
u8 enable_colored_list=0;
u8 cd_behaviour=0; //0=first entry 1=last entry
u8 scroll_behaviour=0; //1=classic 0=new page-system
u8 ext_type=0; //0=classic 1=org os
u8 sd_speed=1; // 1=25Mhz 2=50Mhz
u8 hide_sysfolder=0;
char* background_image;
//toplist helper
int list_pos_backup[3];
char list_pwd_backup[256];
char dirz[512] = "rom://";
short int gCursorX;
short int gCursorY;
int count = 0;
int page = 0;
int cursor = 0;
direntry_t *list;
int filesize( FILE *pFile )
{
fseek( pFile, 0, SEEK_END );
int lSize = ftell( pFile );
rewind( pFile );
return lSize;
}
sprite_t *read_sprite( const char * const spritename ) {
FILE *fp = fopen( spritename, "r" );
if( fp ) {
sprite_t *sp = malloc( filesize( fp ) );
fread( sp, 1, filesize( fp ), fp );
fclose( fp );
return sp;
}
else {
return 0;
}
}
void drawSelection(display_context_t disp,int p){
int s_x=23+(text_offset*8);
if(scroll_behaviour){
if(select_mode){
if(cursor_lastline>cursor && cursor_line > 0) {
cursor_line--;
}
if(cursor_lastline<cursor && cursor_line < 19) {
cursor_line++;
}
p=cursor_line;
graphics_draw_box_trans(disp, s_x, (((p+3)*8)+24), 272, 8, selection_color); //(p+3) diff
cursor_lastline=cursor;
}
}
else { //new page-system
//accept p
graphics_draw_box_trans(disp, s_x, (((p+3)*8)+24), 272, 8, selection_color);
}
}
void drawConfigSelection(display_context_t disp,int l){
int s_x=62+(text_offset*8);
l=l+5;
graphics_draw_box_trans(disp, s_x, (((l+3)*8)+24), 193, 8, 0x00000080); //(p+3) diff
}
void drawToplistSelection(display_context_t disp,int l){
int s_x=30+(text_offset*8);
l=l+2;
graphics_draw_box_trans(disp, s_x, (((l+3)*8)+24), 256, 8, 0xFFFFFF70); //(p+3) diff
}
void chdir( const char * const dirent ) {
/* Ghetto implementation */
if( strcmp( dirent, ".." ) == 0 ) {
/* Go up one */
int len = strlen( dirz ) - 1;
/* Stop going past the min */
if( dirz[len] == '/' && dirz[len-1] == '/' && dirz[len-2] == ':' ) {
//return if ://
return;
}
if( dirz[len] == '/' ) {
dirz[len] = 0;
len--;
}
while( dirz[len] != '/') {
dirz[len] = 0;
len--;
}
}
else {
/* Add to end */
strcat( dirz, dirent );
strcat( dirz, "/" );
}
}
int compare(const void * a, const void * b) {
direntry_t *first = (direntry_t *)a;
direntry_t *second = (direntry_t *)b;
if(first->type == DT_DIR && second->type != DT_DIR) {
/* First should be first */
return -1;
}
if(first->type != DT_DIR && second->type == DT_DIR) {
/* First should be second */
return 1;
}
return strcmp(first->filename, second->filename);
}
int compare_int (const void *a, const void *b) {
const int *ia = (const int *)a; // casting pointer types
const int *ib = (const int *)b;
return *ia - *ib;
}
int compare_int_reverse (const void *a, const void *b) {
const int *ia = (const int *)a; // casting pointer types
const int *ib = (const int *)b;
return *ib - *ia;
}
void free_dir(direntry_t *dirz) {
if(dirz) { free(dirz); }
}
void new_scroll_pos(int *cursor, int *page, int max, int count) {
/* Make sure windows too small can be calculated right */
if(max > count) {
max = count;
}
/* Bounds checking */
if(*cursor >= count) {
*cursor = count-1;
}
if(*cursor < 0) {
*cursor = 0;
}
/* Scrolled up? */
if(*cursor < *page) {
*page = *cursor;
return;
}
/* Scrolled down/ */
if(*cursor >= (*page + max)) {
*page = (*cursor - max) + 1;
return;
}
/* Nothing here, should be good! */
}
void display_dir(direntry_t *list, int cursor, int page, int max, int count, display_context_t disp) {
//system color
uint32_t forecolor=0;
uint32_t forecolor_menu=0;
uint32_t backcolor;
backcolor = graphics_make_color(0x00, 0x00, 0x00, 0xFF); //bg
forecolor_menu = graphics_make_color(0xFF, 0xFF, 0xFF, 0xFF); //fg
graphics_set_color (list_font_color, backcolor);
u8 c_pos[MAX_LIST+1];
int c_pos_counter=0;
c_pos[c_pos_counter++]=0;
u8 c_dirname[64];
if(page_display){
u8 pi = page/20;
u8 ci=0;
if(count%20==0)
ci = (count-1)/20;
else
ci = count/20;
sprintf(c_dirname, "%i/%i SD:/%s", pi+1, ci+1, pwd);
}
else{
sprintf(c_dirname, "SD:/%s", pwd);
}
char sel_str[128];
printText(c_dirname, 3, 4, disp);
int firstrun=1;
/* Page bounds checking */
if(max > count) { //count = directories starting at 1
max = count;
}
/* Cursor bounds checking */
if(cursor >= (page + max)) {
cursor = (page + max) - 1;
}
if(cursor < page) {
cursor = page;
}
if( max == 0 ) {
printText("dir empty...", 3, 6, disp);
sprintf(sel_str, "dir empty...");
empty=1;
}
else {
empty=0;
}
//last page anti ghosting entries
if(page == (count/20)*20)
max=count%20;
for(int i = page; i < (page + max); i++) {//from page to page + max
if(list[i].type == DT_DIR) {
char tmpdir[(CONSOLE_WIDTH-5)+1];
strncpy(tmpdir, list[i].filename, CONSOLE_WIDTH-5);
tmpdir[CONSOLE_WIDTH-5] = 0;
char *dir_str;
dir_str = malloc(slen(tmpdir)+3);
if(i == cursor){
sprintf(dir_str, " [%s]", tmpdir);
sprintf(sel_str, " [%s]", tmpdir);
if(scroll_behaviour)
drawSelection(disp,i);
c_pos[c_pos_counter++]=1;
}
else{
sprintf(dir_str, "[%s]", tmpdir);
c_pos[c_pos_counter++]=0;
}
graphics_set_color (list_dir_font_color, backcolor);
if(firstrun){
printText(dir_str, 3, 6, disp);
firstrun=0;
}
else{
printText(dir_str, 3, -1, disp);
}
free(dir_str);
}
else { //if(list[i].type == DT_REG)
int fcolor=list[i].color;
if(fcolor!=0){
switch(fcolor){
case 1: forecolor = graphics_make_color(0xFF, 0xFF, 0xFF, 0xFF); //common (white)
break;
case 2: forecolor = graphics_make_color(0x00, 0xFF, 0x00, 0xCF); //uncommon (green)
break;
case 3: forecolor = graphics_make_color(0x1E, 0x90, 0xFF, 0xFF); //rare (blue)
break;
case 4: forecolor = graphics_make_color(0x9B, 0x30, 0xFF, 0xFF); //epic (purple)
break;
case 5: forecolor = graphics_make_color(0xFF, 0xA5, 0x00, 0xFF); //legendary (orange)
break;
default:
break;
}
}
else
forecolor = list_font_color;
char tmpdir[(CONSOLE_WIDTH-3)+1];
strncpy(tmpdir, list[i].filename, CONSOLE_WIDTH-3);
tmpdir[CONSOLE_WIDTH-3] = 0;
char *dir_str;
dir_str = malloc(slen(tmpdir)+1);
if(i == cursor){
sprintf(dir_str, " %s", tmpdir);
sprintf(sel_str, " %s", tmpdir);
if(scroll_behaviour)
drawSelection(disp,i);
c_pos[c_pos_counter++]=1;
}
else{
sprintf(dir_str, "%s", tmpdir);
c_pos[c_pos_counter++]=0;
}
graphics_set_color(list_font_color, backcolor);
if(firstrun){
if(enable_colored_list)
graphics_set_color(forecolor, backcolor);
printText(dir_str, 3, 6, disp); //3,6
firstrun=0;
}
else{
if(enable_colored_list)
graphics_set_color(forecolor, backcolor);
printText(dir_str, 3, -1, disp); //3,1
}
free(dir_str);
}
}
//for page-wise scrolling
if(scroll_behaviour==0){
int c=0;
for(c=0;c<max+1;c++){
if(c_pos[c]==1){
drawSelection(disp,c-1);
//todo: set selection color
graphics_set_color(selection_font_color, backcolor);
printText(sel_str, 3, 6+c-1, disp);
graphics_set_color(forecolor, backcolor);
}
}
}
graphics_set_color(forecolor_menu, backcolor);
}
void printText(char *msg, int x, int y, display_context_t dcon) {
x=x+text_offset;
if (x != -1)
gCursorX = x;
if (y != -1)
gCursorY = y;
if (dcon)
graphics_draw_text(dcon, gCursorX*8, gCursorY*8, msg);
gCursorY++;
if (gCursorY > 29) {
gCursorY = 0;
gCursorX ++;
}
}
void lprintText(char *msg, int x, int y, display_context_t dcon) {
x=x+text_offset;
if (x != -1)
gCursorX = x;
if (y != -1)
gCursorY = y;
if (dcon)
graphics_draw_text(dcon, gCursorX*8, gCursorY*8, msg);
if (gCursorY > 29) {
gCursorY = 0;
gCursorX ++;
}
}
//background sprite
void drawBg(display_context_t disp){
graphics_draw_sprite( disp, 0, 0, background );
}
void drawBox(short x, short y, short width, short height, display_context_t disp){
x=x+(text_offset*8);
/*
* |Y
* | x0/y0
* |
* |
* | x1/y1
* |_______________X
*
*/
// X0 Y0 X1 Y1
graphics_draw_line(disp, x, y, width+x, y, border_color_1); //A top left tp bottom right ok
graphics_draw_line(disp, width+x, y, width+x, height+y, border_color_1); //B top right to bottom right
graphics_draw_line(disp, x, y, x, height+y, border_color_2); //C //152-20
graphics_draw_line(disp, x, height+y, width+x, height+y, border_color_2); //D
graphics_draw_box_trans(disp, x+1, y+1, width-1, height-1, box_color); //red light transparent
}
void drawBoxNumber(display_context_t disp, int box){
int old_color = box_color;
//backup color
switch(box){
case 1: drawBox(20, 24, 277, 193, disp); break; //filebrowser
case 2: drawBox(60, 56, 200, 128, disp); break; //info screen
case 3:
box_color= graphics_make_color(0x00, 0x00, 0x60, 0xC9);
drawBox(79, 29, 161, 180, disp);
break; //cover
case 4:
box_color= graphics_make_color(0x30, 0x00, 0x00, 0xA3);
drawBox(79, 29, 161, 180, disp);
break; //mempak content
case 5:
box_color= graphics_make_color(0x60, 0x00, 0x00, 0xD3);
drawBox(60, 64, 197, 114, disp); //red confirm screen
break; //mempak content
case 6:
box_color= graphics_make_color(0x60, 0x60, 0x00, 0xC3);
drawBox(60, 64, 197, 125, disp); //yellow screen
break; //rom config box
case 7:
box_color= graphics_make_color(0x00, 0x00, 0x60, 0xC3);
drawBox(60, 105, 197, 20, disp); //blue info screen
break; //info screen
case 8:
box_color= graphics_make_color(0x60, 0x00, 0x00, 0xD3);
drawBox(60, 105, 197, 20, disp); //red error screen
break; //info screen
case 9:
box_color= graphics_make_color(0x00, 0x00, 0x00, 0xB6);
drawBox(28, 49, 260, 150, disp);
break; //yellow toplist
case 10:
box_color= graphics_make_color(0x00, 0x60, 0x00, 0xC3);
drawBox(60, 105, 197, 20, disp); //green info screen
break; //info screen
case 11:
box_color= graphics_make_color(0x00, 0x60, 0x00, 0xC3);
drawBox(28, 105, 260, 30, disp);
break; //green full filename
default:
break;
}
//restore color
box_color=old_color;
}
//is setting the config file vars into the pconfig-structure
static int configHandler(void* user, const char* section, const char* name, const char* value) {
configuration* pconfig = (configuration*)user;
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
if (MATCH("ed64", "border_color_1")) {
pconfig->border_color_1 = strdup(value);
}
else if (MATCH("ed64", "border_color_2")) {
pconfig->border_color_2 = strdup(value);
}
else if (MATCH("ed64", "box_color")) {
pconfig->box_color = strdup(value);
}
else if (MATCH("ed64", "selection_color")) {
pconfig->selection_color = strdup(value);
}
else if (MATCH("ed64", "list_font_color")) {
pconfig->list_font_color = strdup(value);
}
else if (MATCH("ed64", "list_dir_font_color")) {
pconfig->list_dir_font_color = strdup(value);
}
else if (MATCH("ed64", "selection_font_color")) {
pconfig->selection_font_color = strdup(value);
}
else if (MATCH("ed64", "mempak_path")) {
pconfig->mempak_path = strdup(value);
}
else if (MATCH("ed64", "save_path")) {
pconfig->save_path = strdup(value);
}
else if (MATCH("ed64", "sound_on")) {
pconfig->sound_on = atoi(value);
}
else if (MATCH("ed64", "page_display")) {
pconfig->page_display = atoi(value);
}
else if (MATCH("ed64", "tv_mode")) {
pconfig->tv_mode = atoi(value);
}
else if (MATCH("ed64", "quick_boot")) {
pconfig->quick_boot = atoi(value);
}
else if (MATCH("ed64", "enable_colored_list")) {
pconfig->enable_colored_list = atoi(value);
}
else if (MATCH("ed64", "ext_type")) {
pconfig->ext_type = atoi(value);
}
else if (MATCH("ed64", "cd_behaviour")) {
pconfig->cd_behaviour = atoi(value);
}
else if (MATCH("ed64", "scroll_behaviour")) {
pconfig->scroll_behaviour = atoi(value);
}
else if (MATCH("ed64", "text_offset")) {
pconfig->text_offset = atoi(value);
}
else if (MATCH("ed64", "sd_speed")) {
pconfig->sd_speed = atoi(value);
}
else if (MATCH("ed64", "hide_sysfolder")) {
pconfig->hide_sysfolder = atoi(value);
}
else if (MATCH("ed64", "background_image")) {
pconfig->background_image = strdup(value);
}
else if (MATCH("user", "name")) {
pconfig->name = strdup(value);
}
else {
return 0; /* unknown section/name, error */
}
return 1;
}
//everdrive init functions
void configure() {
u16 tv;
u16 msg = 0;
u16 sd_mode = 0;
u8 buff[16];
u16 firm;
evd_init();
//REG_MAX_MSG
evd_setCfgBit(ED_CFG_SDRAM_ON, 0);
dma_read_s(buff, ROM_ADDR + 0x20, 16);
asm_date = memRomRead32(0x38);
evd_setCfgBit(ED_CFG_SDRAM_ON, 1);
firm = evd_readReg(REG_VER);
if (streql("ED64 SD boot", buff, 12) && firm >= 0x0116) {
sd_mode = 1;
}
if (firm >= 0x0200) {
sleep(1);
evd_setCfgBit(ED_CFG_SDRAM_ON, 0);
sleep(1);
msg = evd_readReg(REG_MAX_MSG);
if (!(msg & (1 << 14))) {
msg |= 1 << 14;
evd_writeReg(REG_MAX_MSG, msg);
bi_load_firmware(firmware);
sleep(1);
evd_init();
}
sleep(1);
evd_setCfgBit(ED_CFG_SDRAM_ON, 1);
}
if (sd_mode) {
diskSetInterface(DISK_IFACE_SD);
} else {
diskSetInterface(DISK_IFACE_SPI);
}
memSpiSetDma(0);
}
//rewrites the background and the box to clear the screen
void clearScreen(display_context_t disp){
drawBg(disp); //background
drawBoxNumber(disp,1); //filebrowser box
}
void romInfoScreen(display_context_t disp, u8 *buff, int silent){
if(silent!=1)
sleep(10);
u8 tmp[32];
u8 filename[64];
u8 ok=0;
sprintf(filename, "%s",buff);
int swapped=0;
FatRecord rec_tmpf;
//not needed any longer :>
//file IS there, it's selected at this point
ok = fatFindRecord(filename, &rec_tmpf, 0);
u8 resp = 0;
resp = fatOpenFileByeName(filename, 0); //err if not found ^^
int mb = file.sec_available/2048;
int block_offset = 0;
u32 cart_buff_offset = 0;
u32 begin_sector = file.sector;
//filesize -> readfile / 512
int fsize=512; //rom-headersize 4096 but the bootcode is not needed
unsigned char headerdata[fsize]; //1*512
resp = fatReadFile(&headerdata, fsize / 512); //1 cluster
int sw_type=is_valid_rom(headerdata);
if(sw_type!=0){
swapped=1;
swap_header(headerdata, 512);
}
//char 32-51 name
unsigned char rom_name[32];
for(int u=0; u<19;u++){
if(u!=0)
sprintf(rom_name, "%s%c", rom_name, headerdata[32+u]);
else
sprintf(rom_name, "%c", headerdata[32+u]);
}
//trim right spaces
//romname=trimmed rom name for filename
sprintf(rom_name, "%s", trim(rom_name));
if(silent!=1)
printText(rom_name, 11, 19, disp);
sprintf(rom_name, "Size: %iMb", mb);
if(silent!=1)
printText(rom_name, 11, -1, disp);
//unique cart id for gametype
unsigned char cartID_str[12];
sprintf(cartID_str, "ID: %c%c%c%c", headerdata[0x3B], headerdata[0x3C], headerdata[0x3D], headerdata[0x3E]);
if(silent!=1)
printText(cartID_str, 11, -1, disp);
int cic, save;
cic = get_cic(&headerdata[0x40]);
unsigned char cartID_short[4];
sprintf(cartID_short, "%c%c\0", headerdata[0x3C], headerdata[0x3D]);
if (get_cic_save(cartID_short, &cic, &save)) {
if(silent!=1)
printText("found in db", 11, -1, disp);
unsigned char save_type_str[12];
sprintf(save_type_str, "Save: %s", saveTypeToExtension(save,ext_type));
if(silent!=1)
printText(save_type_str, 11, -1, disp);
unsigned char cic_type_str[12];
sprintf(cic_type_str, "CIC: CIC-610%i", cic);
if(silent!=1)
printText(cic_type_str, 11, -1, disp);
//thanks for the db :>
//cart was found, use CIC and SaveRAM type
}
if(silent!=1){
char box_path[32];
sprite_t *n64cover;
sprintf(box_path, "/ED64/boxart/lowres/%c%c.png", headerdata[0x3C], headerdata[0x3D]);
int found;