#include #include #include #include #include #include "main.h" #include "a7800utils.h" #include "emu/Bios.h" #include "emu/Database.h" #include "emu/ProSystem.h" #include "emu/Sound.h" #include "clickNoQuit_wav.h" #include "bgBottom.h" #include "bgTop.h" #include "bgFileSel.h" static unsigned int sound_idx __attribute__((section(".dtcm"))) = 0; static unsigned int myPokeyBufIdx __attribute__((section(".dtcm"))) = 0; static unsigned char lastPokeySample __attribute__((section(".dtcm"))) = 0; static unsigned char lastTiaSample __attribute__((section(".dtcm"))) = 0; static unsigned char lastSample __attribute__((section(".dtcm"))) = 0; unsigned char keyboard_data[20] __attribute__((section(".dtcm"))); FICA7800 proromlist[1024]; unsigned int countpro=0, countfiles=0, ucFicAct=0; int bg0; int bg1; int bg0b,bg1b; int bg2; int bg3; // BG pointers int bg0s, bg1s, bg2s, bg3s; // sub BG pointers int full_speed = 0; int etatEmu; int gTotalAtariFrames=0; int fpsDisplay=0; int atari_frames = 0; #define MAX_DEBUG 5 int debug[MAX_DEBUG]={0}; //#define DEBUG_DUMP //#define CART_INFO #define SOUND_FREQ (31440/2) // Be careful if you change this - this matches the frequency of the POKEY update and if we are TIA-only, we will double it. uint video_height; // Actual video height u16 *bufVideo; // Video flipping buffer gamecfg GameConf; // Game Config svg short cxBG, cyBG, xdxBG,ydyBG; unsigned char *filebuffer; bool bRefreshXY = false; #define WAITVBL swiWaitForVBlank(); swiWaitForVBlank(); swiWaitForVBlank(); swiWaitForVBlank(); swiWaitForVBlank(); static void DumpDebugData(void) { #ifdef DEBUG_DUMP char dbgbuf[32]; for (int i=0; ivalEnd;ucFade--) { if (ucScr & 0x01) REG_BLDY=ucFade; if (ucScr & 0x02) REG_BLDY_SUB=ucFade; for (ucBcl=0;ucBcl0 ? "<" : " ")); dsPrintValue(31,22,0,(char *) (NoDebGame+14" : " ")); sprintf(szName,"%s","A TO SELECT A GAME, B TO GO BACK"); dsPrintValue(16-strlen(szName)/2,23,0,szName); for (ucBcl=0;ucBcl<17; ucBcl++) { ucGame= ucBcl+NoDebGame; if (ucGame < countpro) { maxLen=strlen(proromlist[ucGame].filename); strcpy(szName,proromlist[ucGame].filename); if (maxLen>29) szName[29]='\0'; if (proromlist[ucGame].directory) { sprintf(szName2,"%-29s",szName); dsPrintValue(0,5+ucBcl,(ucSel == ucBcl ? 1 : 0),szName2); } else { sprintf(szName2,"%-29s",strupr(szName)); dsPrintValue(1,5+ucBcl,(ucSel == ucBcl ? 1 : 0),szName2); } } } } unsigned int dsWaitForRom(void) { bool bDone=false, bRet=false; u32 ucHaut=0x00, ucBas=0x00,ucSHaut=0x00, ucSBas=0x00,romSelected= 0, firstRomDisplay=0,nbRomPerPage, uNbRSPage, uLenFic=0,ucFlip=0, ucFlop=0; char szName[64]; decompress(bgFileSelTiles, bgGetGfxPtr(bg0b), LZ77Vram); decompress(bgFileSelMap, (void*) bgGetMapPtr(bg0b), LZ77Vram); dmaCopy((void *) bgFileSelPal,(u16*) BG_PALETTE_SUB,256*2); unsigned short dmaVal = *(bgGetMapPtr(bg1b) +31*32); dmaFillWords(dmaVal | (dmaVal<<16),(void*) bgGetMapPtr(bg1b),32*24*2); nbRomPerPage = (countpro>=17 ? 17 : countpro); uNbRSPage = (countpro>=5 ? 5 : countpro); if (ucFicAct>countpro-nbRomPerPage) { firstRomDisplay=countpro-nbRomPerPage; romSelected=ucFicAct-countpro+nbRomPerPage; } else { firstRomDisplay=ucFicAct; romSelected=0; } dsDisplayFiles(firstRomDisplay,romSelected); while (!bDone) { if (keysCurrent() & KEY_UP) { if (!ucHaut) { ucFicAct = (ucFicAct>0 ? ucFicAct-1 : countpro-1); if (romSelected>uNbRSPage) { romSelected -= 1; } else { if (firstRomDisplay>0) { firstRomDisplay -= 1; } else { if (romSelected>0) { romSelected -= 1; } else { firstRomDisplay=countpro-nbRomPerPage; romSelected=nbRomPerPage-1; } } } ucHaut=0x01; dsDisplayFiles(firstRomDisplay,romSelected); } else { ucHaut++; if (ucHaut>10) ucHaut=0; } } else { ucHaut = 0; } if (keysCurrent() & KEY_DOWN) { if (!ucBas) { ucFicAct = (ucFicAct< countpro-1 ? ucFicAct+1 : 0); if (romSelected10) ucBas=0; } } else { ucBas = 0; } if((keysCurrent() & KEY_R) || (keysCurrent() & KEY_RIGHT)) { if (!ucSBas) { ucFicAct = (ucFicAct< countpro-nbRomPerPage ? ucFicAct+nbRomPerPage : countpro-nbRomPerPage); if (firstRomDisplay10) ucSBas=0; } } else { ucSBas = 0; } if ((keysCurrent() & KEY_L) || (keysCurrent() & KEY_LEFT)) { if (!ucSHaut) { ucFicAct = (ucFicAct> nbRomPerPage ? ucFicAct-nbRomPerPage : 0); if (firstRomDisplay>nbRomPerPage) { firstRomDisplay -= nbRomPerPage; } else { firstRomDisplay = 0; } if (ucFicAct == 0) romSelected = 0; if (romSelected > ucFicAct) romSelected = ucFicAct; ucSHaut=0x01; dsDisplayFiles(firstRomDisplay,romSelected); } else { ucSHaut++; if (ucSHaut>10) ucSHaut=0; } } else { ucSHaut = 0; } if ( keysCurrent() & KEY_B ) { bDone=true; while (keysCurrent() & KEY_B); } if (keysCurrent() & KEY_A) { if (!proromlist[ucFicAct].directory) { bRet=true; bDone=true; } else { chdir(proromlist[ucFicAct].filename); proFindFiles(); ucFicAct = 0; nbRomPerPage = (countpro>=16 ? 16 : countpro); uNbRSPage = (countpro>=5 ? 5 : countpro); if (ucFicAct>countpro-nbRomPerPage) { firstRomDisplay=countpro-nbRomPerPage; romSelected=ucFicAct-countpro+nbRomPerPage; } else { firstRomDisplay=ucFicAct; romSelected=0; } dsDisplayFiles(firstRomDisplay,romSelected); while (keysCurrent() & KEY_A); } } // Scroll la selection courante if (strlen(proromlist[ucFicAct].filename) > 29) { ucFlip++; if (ucFlip >= 8) { ucFlip = 0; uLenFic++; if ((uLenFic+29)>strlen(proromlist[ucFicAct].filename)) { ucFlop++; if (ucFlop >= 8) { uLenFic=0; ucFlop = 0; } else uLenFic--; } strncpy(szName,proromlist[ucFicAct].filename+uLenFic,29); szName[29] = '\0'; dsPrintValue(1,5+romSelected,1,szName); } } swiWaitForVBlank(); } decompress(bgBottomTiles, bgGetGfxPtr(bg0b), LZ77Vram); decompress(bgBottomMap, (void*) bgGetMapPtr(bg0b), LZ77Vram); dmaCopy((void *) bgBottomPal,(u16*) BG_PALETTE_SUB,256*2); dmaVal = *(bgGetMapPtr(bg1b) +31*32); dmaFillWords(dmaVal | (dmaVal<<16),(void*) bgGetMapPtr(bg1b),32*24*2); return bRet; } unsigned int dsWaitOnMenu(unsigned int actState) { unsigned int uState=A7800_PLAYINIT; bool bDone=false, romSel; int iTx,iTy; while (bDone==false) { // wait for stylus scanKeys(); if(keysHeld() & KEY_TOUCH) { touchPosition touch; touchRead(&touch); iTx = touch.px; iTy = touch.py; if ((iTx>31) && (iTx<65) && (iTy>159) && (iTy<169)) { // 32,160 -> 64,168 quit soundPlaySample(clickNoQuit_wav, SoundFormat_16Bit, clickNoQuit_wav_size, 22050, 127, 64, false, 0); bDone=dsWaitOnQuit(); if (bDone) uState=A7800_QUITSTDS; } if ((iTx>79) && (iTx<180) && (iTy>10) && (iTy<65)) { // 80,32 -> 179,61 cartridge slot bDone=true; // Find files in current directory and show it proFindFiles(); romSel=dsWaitForRom(); if (romSel) { uState=A7800_PLAYINIT; dsLoadGame(proromlist[ucFicAct].filename); } else { uState=actState; } } } swiWaitForVBlank(); } return uState; } void dsPrintValue(int x, int y, unsigned int isSelect, char *pchStr) { u16 *pusEcran,*pusMap; u16 usCharac; char *pTrTxt=pchStr; char ch; pusEcran=(u16*) (bgGetMapPtr(bg1b))+x+(y<<5); pusMap=(u16*) (bgGetMapPtr(bg0b)+(2*isSelect+24)*32); while((*pTrTxt)!='\0' ) { ch = *pTrTxt; if (ch >= 'a' && ch <= 'z') ch -= 32; // Faster than strcpy/strtoupper usCharac=0x0000; if ((ch) == '|') usCharac=*(pusMap); else if (((ch)<' ') || ((ch)>'_')) usCharac=*(pusMap); else if((ch)<'@') usCharac=*(pusMap+(ch)-' '); else usCharac=*(pusMap+32+(ch)-'@'); *pusEcran++=usCharac; pTrTxt++; } } //--------------------------------------------------------------------------------- void dsInstallSoundEmuFIFO(void) { FifoMessage msg; msg.SoundPlay.data = &sound_buffer; msg.SoundPlay.freq = (cartridge_pokey ? SOUND_FREQ:SOUND_FREQ*2); msg.SoundPlay.volume = 127; msg.SoundPlay.pan = 64; msg.SoundPlay.loop = 1; msg.SoundPlay.format = ((1)<<4) | SoundFormat_8Bit; msg.SoundPlay.loopPoint = 0; msg.SoundPlay.dataSize = SNDLENGTH >> 2; msg.type = EMUARM7_PLAY_SND; fifoSendDatamsg(FIFO_USER_01, sizeof(msg), (u8*)&msg); } void dsMainLoop(void) { static int lcd_swap_counter=0; static int special_hsc_entry=0; static int last_keys_pressed = 999; char fpsbuf[32]; unsigned int keys_pressed,keys_touch=0, romSel; int iTx,iTy; static int dampen = 0; // Timers are fed with 33.513982 MHz clock. // With DIV_1024 the clock is 32,728.5 ticks per sec... TIMER0_DATA=0; TIMER0_CR=TIMER_ENABLE|TIMER_DIV_1024; TIMER1_DATA=0; TIMER1_CR=TIMER_ENABLE | TIMER_DIV_1024; while(etatEmu != A7800_QUITSTDS) { switch (etatEmu) { case A7800_MENUINIT: dsShowScreenMain(); etatEmu = A7800_MENUSHOW; break; case A7800_MENUSHOW: etatEmu = dsWaitOnMenu(A7800_MENUSHOW); break; case A7800_PLAYINIT: dsShowScreenEmu(); etatEmu = A7800_PLAYGAME; break; case A7800_PLAYGAME: // 32,728.5 ticks = 1 second // 1 frame = 1/50 or 1/60 (0.02 or 0.016) // 655 -> 50 fps and 546 -> 60 fps if (!full_speed) { while(TIMER0_DATA < (546*atari_frames)) ; } // Execute one frame prosystem_ExecuteFrame(keyboard_data); if (++atari_frames == 60) { TIMER0_CR=0; TIMER0_DATA=0; TIMER0_CR=TIMER_ENABLE|TIMER_DIV_1024; atari_frames=0; } // Read keys if (special_hsc_entry > 0) { special_hsc_entry--; tchepres(10); if (special_hsc_entry < 10) { tchepres(11); } continue; } memset(keyboard_data, 0x00, 15); // Not the difficulty switches which are the two bytes after this... scanKeys(); keys_pressed = keysCurrent(); if (dampen == 0) { // if touch screen pressed if (keys_pressed & KEY_TOUCH) { if (!keys_touch) { touchPosition touch; keys_touch=1; touchRead(&touch); iTx = touch.px; iTy = touch.py; if ((iTx>31) && (iTx<65) && (iTy>159) && (iTy<169)) { // 32,160 -> 64,168 quit irqDisable(IRQ_TIMER2); fifoSendValue32(FIFO_USER_01,(1<<16) | (0) | SOUND_SET_VOLUME); soundPlaySample(clickNoQuit_wav, SoundFormat_16Bit, clickNoQuit_wav_size, 22050, 127, 64, false, 0); if (dsWaitOnQuit()) etatEmu=A7800_QUITSTDS; else { irqEnable(IRQ_TIMER2); } fifoSendValue32(FIFO_USER_01,(1<<16) | (127) | SOUND_SET_VOLUME); } else if ((iTx>240) && (iTx<256) && (iTy>0) && (iTy<20)) { // Full Speed Toggle ... upper corner... full_speed = 1-full_speed; if (full_speed) dsPrintValue(30,0,0,"FS"); else dsPrintValue(30,0,0," "); dampen=60; } else if ((iTx>71) && (iTx<106) && (iTy>159) && (iTy<169)) { // 72,160 -> 105,168 pause soundPlaySample(clickNoQuit_wav, SoundFormat_16Bit, clickNoQuit_wav_size, 22050, 127, 64, false, 0); tchepres(10); } else if ((iTx>190) && (iTx<225) && (iTy>159) && (iTy<169)) { // 191,160 -> 224,168 reset soundPlaySample(clickNoQuit_wav, SoundFormat_16Bit, clickNoQuit_wav_size, 22050, 127, 64, false, 0); tchepres(6); } else if ((iTx>141) && (iTx<176) && (iTy>159) && (iTy<169)) { // 142,160 -> 175,168 select soundPlaySample(clickNoQuit_wav, SoundFormat_16Bit, clickNoQuit_wav_size, 22050, 127, 64, false, 0); tchepres(11); } else if ((iTx>90) && (iTx<110) && (iTy>90) && (iTy<110)) { // Atari Logo - Activate HSC Maintenence Mode (only on High Score screen) special_hsc_entry=70; } else if ((iTx>115) && (iTx<138) && (iTy>159) && (iTy<169)) { // Snap HSC Sram dsPrintValue(13,0,0, "SAVING"); soundPlaySample(clickNoQuit_wav, SoundFormat_16Bit, clickNoQuit_wav_size, 22050, 127, 64, false, 0); WAITVBL cartridge_SaveHighScoreSram(); dsPrintValue(13,0,0, " "); dampen=60; continue; } else if ((iTx>79) && (iTx<180) && (iTy>31) && (iTy<62)) { // 80,32 -> 179,61 cartridge slot irqDisable(IRQ_TIMER2); fifoSendValue32(FIFO_USER_01,(1<<16) | (0) | SOUND_SET_VOLUME); // Find files in current directory and show it proFindFiles(); romSel=dsWaitForRom(); if (romSel) { etatEmu=A7800_PLAYINIT; dsLoadGame(proromlist[ucFicAct].filename); if (full_speed) dsPrintValue(30,0,0,"FS"); else dsPrintValue(30,0,0," ");} else { irqEnable(IRQ_TIMER2); } fifoSendValue32(FIFO_USER_01,(1<<16) | (127) | SOUND_SET_VOLUME); } } else keys_touch=0; } if (keys_pressed != last_keys_pressed) { last_keys_pressed = keys_pressed; if ( (keys_pressed & KEY_SELECT) ) { tchepres(11); } // BUTTON SELECT if (cartridge_controller[0] != TWIN) { if ( (keys_pressed & KEY_START) ) {tchepres(10);} // BUTTON PAUSE if ( (keys_pressed & KEY_X) ) { fpsDisplay = 1-fpsDisplay; gTotalAtariFrames=0; if (!fpsDisplay) dsPrintValue(0,0,0," ");} } if (cartridge_controller[0] == SOTA) { if ( (keys_pressed & KEY_R) ) { cartridge_xOffset +=28; bRefreshXY = true; } if ( (keys_pressed & KEY_L) ) { cartridge_xOffset -=28; bRefreshXY = true; } } } dampen = 6; } else dampen--; // manage a7800 pad if ( (keys_pressed & KEY_UP) ) { tchepres(0); } // UP if ( (keys_pressed & KEY_DOWN) ) { tchepres(1); } // DOWN if ( (keys_pressed & KEY_RIGHT) ) { tchepres(3); } // RIGHT if ( (keys_pressed & KEY_LEFT) ) { tchepres(2); } // LEFT if (cartridge_controller[0] == TWIN) { if ( (keys_pressed & KEY_A) ) { tchepres(12); } // Left Joystick Right if ( (keys_pressed & KEY_B) ) { tchepres(13); } // Left Joystick Down if ( (keys_pressed & KEY_X) ) { tchepres(15); } // Left Joystick Up if ( (keys_pressed & KEY_Y) ) { tchepres(14); } // Left Joystick Left if ( (keys_pressed & KEY_START) ) { tchepres(4); } // Fire Button (mainly to enter high scores and start game) } else { if ( (keys_pressed & KEY_A) ) { tchepres(4); } // BUTTON #1 if ( (keys_pressed & KEY_B) ) { tchepres(5); } // BUTTON #2 if ( (keys_pressed & KEY_Y) ) { tchepres(4); } // BUTTON #1 } if ((keys_pressed & KEY_R) || (keys_pressed & KEY_L)) { if ((keys_pressed & KEY_R) && (keys_pressed & KEY_L)) { if (++lcd_swap_counter == 30) { if (keys_pressed & KEY_A) lcdSwap(); } } if ((keys_pressed & KEY_R) && (keys_pressed & KEY_UP)) { cartridge_yOffset++; bRefreshXY = true; } if ((keys_pressed & KEY_R) && (keys_pressed & KEY_DOWN)) { cartridge_yOffset--; bRefreshXY = true; } if ((keys_pressed & KEY_R) && (keys_pressed & KEY_LEFT)) { cartridge_xOffset++; bRefreshXY = true; } if ((keys_pressed & KEY_R) && (keys_pressed & KEY_RIGHT)) { cartridge_xOffset--; bRefreshXY = true; } if ((keys_pressed & KEY_L) && (keys_pressed & KEY_UP)) if (cartridge_yScale <= 256) { cartridge_yScale++; bRefreshXY = true; } if ((keys_pressed & KEY_L) && (keys_pressed & KEY_DOWN)) if (cartridge_yScale >= 192) { cartridge_yScale--; bRefreshXY = true; } if ((keys_pressed & KEY_L) && (keys_pressed & KEY_RIGHT)) if (cartridge_xScale < 320) { cartridge_xScale++; bRefreshXY = true; } if ((keys_pressed & KEY_L) && (keys_pressed & KEY_LEFT)) if (cartridge_xScale >= 192) { cartridge_xScale--; bRefreshXY = true; } } else lcd_swap_counter=0; // ------------------------------------------------------------- // Stuff to do once/second such as FPS display and Debug Data // ------------------------------------------------------------- if (TIMER1_DATA >= 32728) // 1000MS (1 sec) { TIMER1_CR = 0; TIMER1_DATA = 0; TIMER1_CR=TIMER_ENABLE | TIMER_DIV_1024; if (fpsDisplay) { int fps = gTotalAtariFrames; gTotalAtariFrames = 0; fpsbuf[0] = '0' + (int)fps/100; fps = fps % 100; fpsbuf[1] = '0' + (int)fps/10; fpsbuf[2] = '0' + (int)fps%10; fpsbuf[3] = 0; dsPrintValue(0,0,0, fpsbuf); } DumpDebugData(); } break; } } prosystem_Close(); } //---------------------------------------------------------------------------------- // Find files (a78 / bin) available int a78Filescmp (const void *c1, const void *c2) { FICA7800 *p1 = (FICA7800 *) c1; FICA7800 *p2 = (FICA7800 *) c2; if (p1->filename[0] == '.' && p2->filename[0] != '.') return -1; if (p2->filename[0] == '.' && p1->filename[0] != '.') return 1; if (p1->directory && !(p2->directory)) return -1; if (p2->directory && !(p1->directory)) return 1; return strcasecmp (p1->filename, p2->filename); } void proFindFiles(void) { DIR *pdir; struct dirent *pent; char filenametmp[255]; countpro = countfiles = 0; pdir = opendir("."); if (pdir) { while (((pent=readdir(pdir))!=NULL)) { strcpy(filenametmp,pent->d_name); if (pent->d_type == DT_DIR) { if (!( (filenametmp[0] == '.') && (strlen(filenametmp) == 1))) { proromlist[countpro].directory = true; strcpy(proromlist[countpro].filename,filenametmp); countpro++; } } else { if (strlen(filenametmp)>4) { if ( (strcasecmp(strrchr(filenametmp, '.'), ".a78") == 0) ) { proromlist[countpro].directory = false; strcpy(proromlist[countpro].filename,filenametmp); countpro++;countfiles++; } if ( (strcasecmp(strrchr(filenametmp, '.'), ".bin") == 0) ) { proromlist[countpro].directory = false; strcpy(proromlist[countpro].filename,filenametmp); countpro++;countfiles++; } } } } closedir(pdir); } if (countpro) { qsort (proromlist, countpro, sizeof (FICA7800), a78Filescmp); } else // Failsafe... always provide a back directory... { proromlist[countpro].directory = true; strcpy(proromlist[countpro].filename,".."); countpro = 1; } }