picodrive/platform/s60/PicoDriveExe.Cpp
notaz cc68a136aa initial import
git-svn-id: file:///home/notaz/opt/svn/PicoDrive@2 be3aeb3a-fb24-0410-a615-afba39da0efa
2006-12-19 20:53:21 +00:00

2495 lines
57 KiB
C++

#include <stdlib.h>
#include <stdio.h>
#include <eikenv.h>
#include <e32keys.h>
#include <eikapp.h>
#include <zlib.h>
#ifdef S60V3
#include <picodrive.rsg>
#else
#include <picodriveS60.rsg>
#endif
#include <eikdoc.h>
#include <aknlistquerydialog.h>
#include <s32file.h>
#include <string.h>
#include <ctype.h>
#include <eikenv.h>
#include <sys\time.h>
#include "PicoDriveexe.h"
#include "pico.h"
#include "unzip.h"
#include "PicoInt.h"
#include "GGenie.h"
TInt KLineGap = 2;
static const char* KAboutText =
"This emulator uses code from\n"
"these people/projects:\n"
"\n"
"Dave\n"
"Cyclone 68000 core,\n"
"Pico emulation library\n"
"Homepage:http://www.finalburn.com\n"
"E-mail: david(at)finalburn.com\n"
"\n"
"notaz\n"
"UIQ port,Cyclone 68000 hacks,some\n"
"additional coding (see changelog).\n"
"Homepage:http://notaz.atspace.com/\n"
"E-mail: notasas(at)gmail.com\n"
"\n"
"Reesy\n"
"DrZ80, the Z80 emulator\n"
"written in ARM assembly.\n"
"Homepage: http://reesy.gp32x.de/\n"
"E-mail:drsms_reesy(at)yahoo.co.uk\n"
"\n"
"Tatsuyuki Satoh, Jarek Burczynski,\n"
"MultiArcadeMachineEmulator\n"
"development\n"
"software implementation of\n"
"Yamaha FM sound generator\n"
"\n"
"MultiArcadeMachineEmulator(MAME)\n"
"development\n"
"Texas Instruments SN76489/SN76496\n"
"programmable tone/noise generator\n"
"Homepage: http://www.mame.net/\n"
"\n"
"Additional thanks\n"
"-----------------\n"
"* Peter van Sebille for ECompXL\n"
" and his various open-source\n"
" Symbian project to learn from.\n"
"* Mark and Jean-loup for zlib\n"
" library.\n"
"* Reesy for also finding some\n"
" Cyclone bugs.\n"
"* Charles MacDonald\n"
" (http://cgfm2.emuviews.com/)\n"
" for old but still very useful\n"
" info about genesis hardware.\n"
"* Stúphane Dallongeville\n"
" for creating Gens\n"
" (http://www.gens.ws)\n"
"*The development team behind the\n"
" Symbian GCC Improvement Project\n"
" http://www.inf.u-szeged.hu\n"
" /symbian-gcc/) for their updated\n"
" compiler tools.\n"
"* Inder for the icons.\n";
// Picodrive prefrence uid
const TUid KPicoDrivePrefs={0x1234432E};
// Bittable corresponding to the bitvalues for the different control actions
TUint16 KBitValTable[EPicoNoKeys]={1,2,4,8 ,64,16,32,1024,512,256,2048,128,5,9,10,6,0,0,0};
extern"C" unsigned short *framebuff = 0; // temporary buffer in sega native BGR format
const int framebuffsize = ((8+320)*(224+16))*2; // actual framebuffer size (in bytes+to support new rendering mode)
// Colour lookuptable from BGR to RGB
unsigned short gColorMapTab[4096];
// Scaling line table
TUint8 gColumnStepTable[320];
TUint8 gNarrowColumnStepTable[256];
unsigned short gLineTable[240];
TUint32 gLineOffsets[416];
TUint32 gFullOffset;
extern int PsndLen;
#ifndef S60V3
GLDEF_C TInt E32Dll(TDllReason)
{
return KErrNone;
}
#ifdef __WINS__
_LIT(KLitResourceFileName, "z:\\system\\apps\\picodrives60\\PicoDriveS60.rsc");
#else
_LIT(KLitResourceFileName, "PicoDriveS60.rsc");
#endif
#endif
#ifdef __WINS__
RHeap* gChunk;
#endif
struct Target Targ;
#ifdef S60V3
#include "S60V3Video.inl"
#else
#include "NormalVideo.inl"
#include "InterpolateVideo.inl"
#endif
TInt CPicoDriveUi::AsyncUpdateL(TAny* aAppUi)
{
static_cast<CPicoDriveUi*>(aAppUi)->UpdateScreen();
return 0;
}
void CPicoDriveUi::StartAsynchUpdate()
{
TCallBack callback(AsyncUpdateL,iEikonEnv->EikAppUi());
iAsyncUpdate.Cancel();
iAsyncUpdate.Set(callback);
iAsyncUpdate.CallBack();
}
CPicoDriveUi::CPicoDriveUi():iIdleCallBack(CActive::EPriorityIdle),iStartUp(CActive::EPriorityIdle),
iAsyncUpdate(CActive::EPriorityStandard)
{
iCurrentScan=-1;
FramesPerSecond=60;
PicoOpt = 7;
iLastAboutPos = -1;
iFrameSkip = -1;
PsndRate = 8000;
iInterpolate = ETrue;
iSoundVolume = 6;
gFullOffset = 0;
}
CPicoDriveUi::~CPicoDriveUi()
{
delete iKeyNames;
delete iRegNames;
if(iView)
{
RemoveFromStack(iView);
delete iView;
}
delete iBackBuffer;
delete iSndStream;
#ifndef S60V3
iCoeEnv->DeleteResourceFile(iResourceFileId);
#endif
#ifdef __WINS__
if(gChunk != NULL)
{
gChunk->Close();
}
#endif
free(framebuff);
framebuff = 0;
CloseSTDLIB();
}
TKeyResponse CPicoDriveUi::HandleKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
{
if(iCheatEnter)
{
return iCheatDlg->OfferKeyEventL(aKeyEvent,aType);
}
if(aType==EEventKey && aKeyEvent.iScanCode==EStdKeyBackspace)
{
if(iPicoMenu ==ESelectSoundMenu)
{
if(iSndRateChanged)
{
if(!UpdatePSndRate()) // Not compatible.. reset to 8000
{
PsndRate = 8000;
UpdatePSndRate();
}
if(iRomLoaded)
{
sound_rerate();
}
}
iView->Clear();
iPicoMenu = EPicoMainMenu;
PutMainMenu();
return EKeyWasConsumed;
}
else if (iPicoMenu == ESelectControlsMenu)
{
iView->Clear();
iPicoMenu = EPicoMainMenu;
PutMainMenu();
return EKeyWasConsumed;
}
else if(iPicoMenu == ESelectScrMenu)
{
iScrMode = iLastScrMode;
iView->Clear();
iPicoMenu = EPicoMainMenu;
PutMainMenu();
return EKeyWasConsumed;
}
else if(iPicoMenu == ESelectCheatMenu)
{
if(iCheatSelection<2)
{
iView->Clear();
iPicoMenu = EPicoMainMenu;
PutMainMenu();
}
else
{
TInt index = (iListOffset+iCheatSelection)-2;
TInt noFound = 0;
for(TInt i = 0; i < 256;i++)
{
if (Liste_GG[i].code[0] != 0)
{
noFound++;
if(noFound-1 == index)
{
Liste_GG[i].code[0] = 0;
Liste_GG[i].active = 0;
iNoCheats--;
iListOffset = 0;
iCheatSelection = 0;
break;
}
}
}
iView->Clear();
PutCheatSelect();
}
return EKeyWasConsumed;
}
if(!iEmuRunning && (iPicoMenu!=EPicoMainMenu ||iCurrentScan!=-1) )
return EKeyWasNotConsumed;
if(iRomLoaded )
{
iEmuRunning=!iEmuRunning;
if(iEmuRunning && iRomLoaded)
{
iView->Clear();
TCallBack callback(StartEmulatorL,this);
iStartUp.Set(callback);
iStartUp.CallBack();
}
}
return EKeyWasConsumed;
}
if(!iEmuRunning)
{
if(iCurrentScan==-1)
{
if(aType==EEventKey)
{
switch(aKeyEvent.iScanCode) // first determine bit value to change
{
case EStdKeyUpArrow:
switch(iPicoMenu)
{
case ESelectControlsMenu:
{
iCtrlSelection=!iCtrlSelection;
PutControllerSelect();
}break;
case EPicoMainMenu:
if(iSelection>0)
iSelection--;
else iSelection=EExitPico;
PutMainMenu();
break;
case ESelectScrMenu:
if(iScrMode>0)
iScrMode--;
else iScrMode=10;
PutScreenSelect();
break;
case ESelectCheatMenu:
if(iCheatSelection>0)
iCheatSelection--;
else
iCheatSelection = ELastCheatItem-1;
PutCheatSelect();
break;
case EAboutPicoMenu:
{
iView->Clear();
PutAbout();
}break;
case ESelectSoundMenu:
{
if(iSndSelection>0)
iSndSelection--;
else
iSndSelection = ELastSoundItem-1;
PutSoundSelect();
}break;
}
break;
case EStdKeyDownArrow:
switch(iPicoMenu)
{
case ESelectControlsMenu:
{
iCtrlSelection=!iCtrlSelection;
PutControllerSelect();
}break;
case EPicoMainMenu:
iSelection++;
if(iSelection==ELastMenuItem)
iSelection=0;
PutMainMenu();
break;
case ESelectScrMenu:
iScrMode++;
if(iScrMode==11)
iScrMode=0;
PutScreenSelect();
break;
case ESelectCheatMenu:
if(iCheatSelection<(ELastCheatItem+iNoCheats-1) && iCheatSelection<6)
iCheatSelection++;
else if(iCheatSelection == ELastCheatItem+4 && iListOffset<iNoCheats-5)
{
iListOffset++;
}
else
{
iListOffset = 0;
iCheatSelection = 0;
}
PutCheatSelect();
break;
case EAboutPicoMenu:
{
iView->Clear();
PutAbout();
}break;
case ESelectSoundMenu:
{
iSndSelection++;
if(iSndSelection==ELastSoundItem)
iSndSelection=0;
PutSoundSelect();
}break;
}
break;
case EStdKeyDevice0:
case EStdKeyDevice3:
{
switch(iPicoMenu)
{
case ESelectControlsMenu:
{
if(iCtrlSelection == EConfigControls)
{
iPicoMenu = EPicoMainMenu;
iView->Clear();
iCurrentScan=0;
PutConfigKeys();
}
else
{
iEnableSixButtons = !iEnableSixButtons;
PicoOpt=PicoOpt^ 32;
PutControllerSelect();
}
}break;
case ESelectCheatMenu:
{
switch(iCheatSelection)
{
case EAddCheat:
{
TBuf8<16> cheatCode;
iCheatEnter = ETrue;
iCheatDlg = new (ELeave) CPicoAddCheatDlg(cheatCode);
iCheatDlg->SetMopParent(iEikonEnv->EikAppUi());
TInt result = iCheatDlg->ExecuteLD(R_PICO_ADD_CHEAT);
if(result == EEikBidOk)
{
for(TInt i = 0; i < 256;i++)
{
if (Liste_GG[i].code[0] == 0)
{
if(check_code((const char*) cheatCode.PtrZ(),i))
{
decode( Liste_GG[i].code, (patch *) (&(Liste_GG[i].addr)));
if ((Liste_GG[i].restore == 0xFFFFFFFF) && (Liste_GG[i].addr < Pico.romsize) && (iRomLoaded))
{
Liste_GG[i].restore = (unsigned int) (Pico.rom[Liste_GG[i].addr] & 0xFF);
Liste_GG[i].restore += (unsigned int) ((Pico.rom[Liste_GG[i].addr + 1] & 0xFF) << 8);
}
iNoCheats++;
Liste_GG[i].active = 1;
}
break; // Found position free
}
}
}
iCheatDlg = NULL;
iCheatEnter = EFalse;
}break;
case EClearCheats:
{
iNoCheats = 0;
for(TInt i = 0; i < 256;i++)
{
Liste_GG[i].code[0] = 0;
Liste_GG[i].active = 0;
}
}
break;
default:
{
TInt index = (iListOffset+iCheatSelection)-2;
TInt noFound = 0;
for(TInt i = 0; i < 256;i++)
{
if (Liste_GG[i].code[0] != 0)
{
noFound++;
if(noFound-1 == index)
{
Liste_GG[i].active=!Liste_GG[i].active;
break;
}
}
}
}
break;
}
PutCheatSelect();
}
break;
case EAboutPicoMenu:
{
iView->Clear();
PutAbout();
}break;
case ESelectScrMenu:
{
switch(iScrMode)
{
case 5:
iInterpolate = !iInterpolate;
iView->Clear();
PutScreenSelect();
break;
case 6:
iFrameSkip++;
if(iFrameSkip == 11)
{
iFrameSkip = -1;
}
iView->Clear();
PutScreenSelect();
break;
case 7:
PicoOpt = PicoOpt^0x40;
iView->Clear();
PutScreenSelect();
break;
case 8:
PicoOpt = PicoOpt^0x80;
iView->Clear();
PutScreenSelect();
break;
case 9:
PicoOpt = PicoOpt^0x10;
iView->Clear();
PutScreenSelect();
break;
case 10:
switch(PicoRegionOverride)
{
case 0:
default:
PicoRegionOverride = 1;
break;
case 1:
PicoRegionOverride = 2;
break;
case 2:
PicoRegionOverride = 4;
break;
case 4:
PicoRegionOverride = 8;
break;
case 8:
PicoRegionOverride = 0;
break;
}
iView->Clear();
PutScreenSelect();
break;
default:
{
TBitmapUtil util(iBackBuffer);
util.Begin(TPoint(0,0));
TSize sz=iBackBuffer->SizeInPixels();
TInt dataSize=sz.iWidth*sz.iHeight*2;
TPtr8 ptr(reinterpret_cast<unsigned char*>(iBackBuffer->DataAddress()),dataSize,dataSize);
ptr.Fill(0);
util.End();
iPicoMenu=EPicoMainMenu;
iView->Clear();
PutMainMenu();
TargetInit();
SaveSettingsL();
}break;
}
}break;
case ESelectSoundMenu:
{
switch(iSndSelection)
{
case EEnableZ80:
PicoOpt=PicoOpt^4;
break;
case EEnableYM2612:
PicoOpt=PicoOpt^1;
break;
case EEnableSN76496:
PicoOpt=PicoOpt^2;
break;
case ESoundVolume:
{
iSoundVolume++;
if(iSoundVolume==11)
{
iSoundVolume=0;
iEnableSound=EFalse;
}
else
{
iEnableSound=ETrue;
iSndStream->SetVolume((iSndStream->MaxVolume()*iSoundVolume)/10);
}
if(!iEnableSound)
{
iSndStream->Stop();
}
}break;
case ESoundRate:
{
iSndRateChanged = ETrue;
switch(PsndRate)
{
case 8000:
PsndRate = 11025;
break;
case 11025:
PsndRate = 16000;
break;
case 16000:
PsndRate = 22050;
break;
case 22050:
PsndRate = 8000;
break;
}
}break;
}
PutSoundSelect();
}break;
case EPicoMainMenu:
{
switch(iSelection)
{
case EResetHw:
{
if(!PicoReset(0))
{
iEmuRunning=ETrue;
TCallBack callback(StartEmulatorL,this);
iStartUp.Set(callback);
iStartUp.CallBack();
}
}
break;
case ELoadState:
{
if(iRomLoaded)
{
saveLoadGame(1,0);
iEmuRunning=ETrue;
iView->Clear();
TCallBack callback(StartEmulatorL,this);
iStartUp.Set(callback);
iStartUp.CallBack();
}
}
break;
case ESaveState:
{
if(iRomLoaded)
{
saveLoadGame(0,0);
iEmuRunning=ETrue;
iView->Clear();
TCallBack callback(StartEmulatorL,this);
iStartUp.Set(callback);
iStartUp.CallBack();
}
}
break;
case ELoadRom:
{
TParsePtr parse(iRomName);
iRomName=parse.DriveAndPath();
if(SelectFile(iRomName))
{
SaveSettingsL();
EmulateExit();
TPtr8 ptr((unsigned char*)RomName,256);
ptr.Fill(0,256);
ptr.Copy(iRomName);
User::CompressAllHeaps();
if(EmulateInit()==0)
{
if(Pico.m.pal)
{
FramesPerSecond=50;
}
else
{
FramesPerSecond=60;
}
SetKeyBlockMode(ENoKeyBlock);
iEmuRunning=ETrue;
iRomLoaded=ETrue;
iView->Clear();
TCallBack callback(StartEmulatorL,this);
iStartUp.Set(callback);
iStartUp.CallBack();
}
else
{
iRomName=KNullDesC();
iView->Clear();
PutMainMenu();
iRomLoaded=EFalse;
}
}
else
{
iView->Clear();
PutMainMenu();
}
}
break;//load rom
case ESetControls:
iPicoMenu = ESelectControlsMenu;
PutControllerSelect();
break;
case ESetScreen:
iView->Clear();
iLastScrMode = iScrMode; // In case of cancel
PutScreenSelect();
iPicoMenu=ESelectScrMenu;
break;
case ESelectSound:
{
iSndRateChanged = EFalse;
iPicoMenu=ESelectSoundMenu;
PutSoundSelect();
}break;
case ESelectCheat:
{
iPicoMenu=ESelectCheatMenu;
iListOffset = 0;
iNoCheats = 0;
for(TInt i = 0; i < 256;i++)
{
if (Liste_GG[i].code[0] != 0)
{
iNoCheats++;
if ((Liste_GG[i].restore != 0xFFFFFFFF) && (Liste_GG[i].addr < Pico.romsize) && (iRomLoaded))
{
Pico.rom[Liste_GG[i].addr] = (unsigned char)(Liste_GG[i].restore & 0xFF);
Pico.rom[Liste_GG[i].addr + 1] = (unsigned char)((Liste_GG[i].restore & 0xFF00) >> 8);
}
}
}
PutCheatSelect();
}
break;
case EAboutPico:
{
iView->Clear();
PutAbout();
iPicoMenu=EAboutPicoMenu;
}break;
case EExitPico:
{
SaveSettingsL();
EmulateExit();
Exit();
}
break;
}
}
}break;
}
break;
}
}
}
else
{
if(aType == EEventKeyDown)
{
if(aKeyEvent.iScanCode != EStdKeyBackspace)
{
iScanCodes[iCurrentScan]=aKeyEvent.iScanCode;
}
else
{
iScanCodes[iCurrentScan] = KErrNotFound;
}
iCurrentScan++;
if(iCurrentScan==iKeyNames->Count())
{
SaveSettingsL();
iCurrentScan=-1;
iView->DrawText(_L("Done!"),TPoint(0,iFontHeight*11));
User::After(1000000);
iView->Clear();
PutMainMenu();
}
else
{
iView->Clear();
PutConfigKeys();
}
}
}
}
else
{
if((aType == EEventKeyUp || aType == EEventKeyDown))
{
TUint16 bitVal=0;
for(TInt loop=0;loop<16;loop++)
{
if(aKeyEvent.iScanCode==iScanCodes[loop])
{
bitVal=KBitValTable[loop];
break;
}
}
if(aType == EEventKeyUp)
{
iPad1=iPad1&(65535-bitVal); // remove bit
}
else
{
iPad1=(iPad1|bitVal); // set bit
}
}
if(aType == EEventKey)
{
if(aKeyEvent.iScanCode == iScanCodes[EPicoResetKey])
{
PicoReset(0);
}
if(aKeyEvent.iScanCode == iScanCodes[EPicoPanLKey] && gFullOffset>0)
{
gFullOffset-=24;
}
else if(aKeyEvent.iScanCode == iScanCodes[EPicoPanRKey]&& gFullOffset<144)
{
gFullOffset+=24;
}
}
}
return EKeyWasConsumed;
}
TInt CPicoDriveUi::SelectFile(TFileName& aFileName)
{
TFileName filename=aFileName;
TInt selectedIndex=-1;
RArray<TEntry> romList;
TDriveList driveList;
TBool refresh=EFalse;
TInt lastLength=-1;
do
{
CAknListQueryDialog* dlg = new (ELeave) CAknListQueryDialog(&selectedIndex);
CDesCArrayFlat* list=new (ELeave) CDesCArrayFlat(5);
refresh=EFalse;
if(filename.Length()==0)
{
iEikonEnv->FsSession().DriveList(driveList);
for(TInt drive=0;drive<driveList.Length();drive++)
{
if(driveList[drive]!=0)
{
TBuf<16> form;
form.Format(_L("%c:\\"),drive+65);
list->AppendL(form);
}
}
}
else
{
CDir* romDir = NULL;;
romList.Reset();
iEikonEnv->FsSession().GetDir(filename,KEntryAttMatchMask,0,romDir);
if(romDir!=NULL)
list->AppendL(_L(".. <DIR>"));
if(romDir!=NULL && romDir->Count()>0)
{
for(TInt loop=0;loop<romDir->Count();loop++)
{
const TEntry& entry=(*romDir)[loop];
TFileName name=entry.iName;
if(entry.IsDir())
{
name.Append(_L(" <DIR>"));
list->AppendL(name);
romList.Append(entry);
}
else
{
TParsePtr parse(name);
if(parse.Ext().CompareF(_L(".bin"))==KErrNone ||
parse.Ext().CompareF(_L(".smd"))==KErrNone ||
parse.Ext().CompareF(_L(".zip"))==KErrNone)
{
romList.Append(entry);
list->AppendL(name);
}
}
}
delete romDir;
romDir=NULL;
}
else // no files found.. or path not found.. return to
{
if(filename.Length()>3) // more than a c:\ specified
{
refresh=ETrue;
filename=KNullDesC();
}
else return EFalse;
}
}
if(list->Count()>0)
{
dlg->PrepareLC(R_PICO_FILE_SELECT_DIALOG);
dlg->SetItemTextArray(list);
if(dlg->RunLD())
{
if(filename.Length()==0)
{
TFileName driveLetter;
TUint8 driveL;
TInt countedDrives=0;
for(TInt drive=0;drive<driveList.Length();drive++)
{
if(driveList[drive]!=0 && countedDrives==selectedIndex)
{
driveLetter.Format(_L("%c:\\"),drive+65);
driveL=drive+65;
break;
}
else if(driveList[drive]!=0) countedDrives++;
}
filename=driveLetter;
refresh=ETrue;
}
else
{
if(selectedIndex>0)
{
selectedIndex--;
const TEntry& entry=romList[selectedIndex];
TFileName name =entry.iName;
if(entry.IsDir())
{
lastLength=aFileName.Length();
filename.Append(name);
filename.Append(_L("\\"));
refresh=ETrue;
}
else
{
filename.Append(name);
aFileName=filename;
romList.Close();
return ETrue;
}
}
else
{
refresh=ETrue;
TInt pos=filename.Left(filename.Length()-1).LocateReverse('\\');
if(pos!=KErrNotFound)
filename=filename.Left(pos+1);// keep
else filename=KNullDesC();
// and changefilename..
//return 2;// go up one.
}
}
}
else
{
romList.Close();
return EFalse;
}
}
}while(refresh);
romList.Close();
return EFalse;
}
void CPicoDriveUi::SaveSettingsL()
{
#ifdef S60V3
CDictionaryStore* prefs = Application()->OpenIniFileLC(iEikonEnv->FsSession());
#else
CDictionaryFileStore* prefs=CDictionaryFileStore::OpenLC(iEikonEnv->FsSession(),iAppPath,TUid::Uid(0));
#endif
ExternalizeL(*prefs);
prefs->CommitL();
CleanupStack::PopAndDestroy();//close prefs
}
void CPicoDriveUi::ExternalizeL(CDictionaryStore& aStore)
{
RDictionaryWriteStream writeStream;
writeStream.AssignLC(aStore, KPicoDrivePrefs);
TInt loop=0;
for(loop=0;loop<EPicoNoKeys;loop++)
{
writeStream.WriteInt32L(iScanCodes[loop]);
}
writeStream.WriteInt32L(iScrMode);
writeStream.WriteInt32L(PicoOpt);
writeStream.WriteInt32L(iSoundVolume);
writeStream.WriteInt32L(iFrameSkip);
writeStream.WriteInt32L(PsndRate);
writeStream.WriteInt32L(iInterpolate);
writeStream.WriteInt32L(iEnableSixButtons);
writeStream.WriteInt32L(PicoRegionOverride);
TParsePtr parser(iRomName);
writeStream.WriteInt32L(parser.DriveAndPath().Length());
writeStream.WriteL(parser.DriveAndPath(),parser.DriveAndPath().Length());
writeStream.CommitL();
CleanupStack::PopAndDestroy();//writeStream
}
void CPicoDriveUi::InternalizeL(const CDictionaryStore& aStore)
{
if (!aStore.IsPresentL(KPicoDrivePrefs))
{
iFirstStart = ETrue;
return;
}
RDictionaryReadStream readStream;
readStream.OpenLC(aStore, KPicoDrivePrefs);
TInt loop=0;
for(loop=0;loop<EPicoNoKeys;loop++)
{
iScanCodes[loop] = readStream.ReadInt32L();
}
iScrMode=readStream.ReadInt32L();
PicoOpt=readStream.ReadInt32L();
iEnableSound = PicoOpt&3;
iSoundVolume=readStream.ReadInt32L();
iFrameSkip = readStream.ReadInt32L();
PsndRate = readStream.ReadInt32L();
iInterpolate = readStream.ReadInt32L();
iEnableSixButtons = readStream.ReadInt32L();
PicoRegionOverride = readStream.ReadInt32L();
TInt len=0;
TRAPD(err,len=readStream.ReadInt32L())
if(err==KErrNone)
{
readStream.ReadL(iRomName,len);
}
CleanupStack::PopAndDestroy();//readStream
}
void CPicoDriveUi::ConstructL()
{
#ifdef S60V3
CAknAppUi::BaseConstructL(CAknAppUi::EAknEnableSkin);
#else
BaseConstructL(ENoAppResourceFile);
#endif
framebuff = (unsigned short *) malloc(framebuffsize);
memset(framebuff,0,framebuffsize);
iFontHeight = iEikonEnv->NormalFont()->HeightInPixels()+KLineGap;
iScanCodes[0]= EStdKeyUpArrow;
iScanCodes[1]= EStdKeyDownArrow;
iScanCodes[2]=EStdKeyLeftArrow;
iScanCodes[3]= EStdKeyRightArrow;
iScanCodes[6]=EStdKeyDevice0;
iScanCodes[4]= EStdKeyDevice1;
iScanCodes[5]=EStdKeyDevice3;
iScanCodes[7]=0;//x
iScanCodes[8]=0; // y
iScanCodes[9]=0;//z
iScanCodes[10]=0;// mode
iScanCodes[11]= '0'; // start
#ifdef __WINS__
gChunk = UserHeap::ChunkHeap(&_L("ROMHEAP"),512000,16384000);
#endif
#ifndef S60V3
TFileName name;
iEikonEnv->RootWin().SetName(_L("PicoDrive"));
#ifndef __WINS__
RProcess process;
process.Rename(_L("PicoDrive"));
TFileName fname =process.FileName();
TParsePtr parser(fname);
name.Append(parser.DriveAndPath());
#endif
name.Append(KLitResourceFileName());
iAppPath=_L("C:");
iAppPath.Append(TParsePtr(name).Path());
iAppPath.Append(_L("PicoDriveS60.ini"));
iResourceFileId = iCoeEnv->AddResourceFileL(name); // eb205: needs to hunt around drives
#endif // S60V3
iKeyNames =iEikonEnv->ReadDesCArrayResourceL(R_PICODRIVE_KEYS);
iRegNames = iEikonEnv->ReadDesCArrayResourceL(R_PICODRIVE_REGIONS);
iEikonEnv->FsSession().MkDirAll(TParsePtr(iAppPath).DriveAndPath());
#ifdef S60V3
CDictionaryStore* prefs = Application()->OpenIniFileLC(iEikonEnv->FsSession());
InternalizeL(*prefs);
CleanupStack::PopAndDestroy();//close prefs
#else
TRAPD(err,{CDictionaryFileStore* prefs=CDictionaryFileStore::OpenLC(iEikonEnv->FsSession(),iAppPath,TUid::Uid(0));
InternalizeL(*prefs);
CleanupStack::PopAndDestroy();//close prefs
});
#endif
if(iFirstStart)
{
iPicoMenu = EAboutPicoMenu;
}
iView=new (ELeave)CQPicoDriveView;
iView->ConstructL();
AddToStackL(iView);
iDisplayMode =iEikonEnv->ScreenDevice()->DisplayMode();
if(iDisplayMode != EColor64K && iDisplayMode != EColor4K)
{
iDisplayMode=EColor64K;; // Also tried to switch to by the view.
}
CalculatePaletteTable();
iBackBuffer= new (ELeave)CFbsBitmap;
iBackBuffer->Create(iEikonEnv->ScreenDevice()->SizeInPixels(),iDisplayMode);
TBitmapUtil util(iBackBuffer);
util.Begin(TPoint(0,0));
TSize sz=iBackBuffer->SizeInPixels();
Targ.view = TRect(TPoint(0,0),sz);
TInt dataSize=sz.iWidth*sz.iHeight*2;
Targ.scanline_length = sz.iWidth*2;
Targ.screen_offset = Targ.scanline_length*(sz.iHeight-1);
TPtr8 ptr(reinterpret_cast<unsigned char*>(iBackBuffer->DataAddress()),dataSize,dataSize);
ptr.Fill(0);
util.End();
SetKeyBlockMode(ENoKeyBlock);
iSelection=0;
iSndStream = CMdaAudioOutputStream::NewL(*this);
iAudioSettings.Query();
iAudioSettings.iSampleRate = TMdaAudioDataSettings::ESampleRate8000Hz;
iAudioSettings.iChannels = TMdaAudioDataSettings::EChannelsMono;
iAudioSettings.iFlags = 0;
iAudioSettings.iVolume = iAudioSettings.iMaxVolume/2;
iSndStream->Open(&iAudioSettings);
CActiveScheduler::Start(); // wait for open
}
void CPicoDriveUi::PutAbout(TBool iOnlyRedraw)
{
TPtrC8 charPtr((unsigned char*)KAboutText,strlen(KAboutText));
HBufC* credits = HBufC::NewLC(charPtr.Length());
credits->Des().Copy(charPtr);
if(iLastAboutPos>=credits->Length())
{
iLastAboutPos = -1;
iView->Clear();
iPicoMenu = EPicoMainMenu;
PutMainMenu();
}
else
{
if(iLastAboutPos == -1)
iLastAboutPos = 0;
iView->DrawText(_L("PicoDrive S60 Credits"),TPoint(0,0));
if(iOnlyRedraw && iLastAboutPos == 0)
iView->DrawTextInRect(*credits,TRect(0,iFontHeight*2,Targ.view.iBr.iX,Targ.view.iBr.iY),iLastAboutPos);
else
iLastAboutPos = iView->DrawTextInRect(*credits,TRect(0,iFontHeight*2,Targ.view.iBr.iX,Targ.view.iBr.iY),iLastAboutPos);
}
CleanupStack::PopAndDestroy(credits);
}
void CPicoDriveUi::PutMainMenu()
{
iView->DrawText(_L("PicoDrive S60"),TPoint(0,0));
iView->DrawText(_L("by Dave et Co"),TPoint(0,iFontHeight*1));
iView->DrawText(_L("Load ROM"),TPoint(0,iFontHeight*3),iSelection==0);
iView->DrawText(_L("Load state"),TPoint(0,iFontHeight*4),iSelection==1);
iView->DrawText(_L("Save state"),TPoint(0,iFontHeight*5),iSelection==2);
iView->DrawText(_L("Configure controls"),TPoint(0,iFontHeight*6),iSelection==3);
iView->DrawText(_L("Configure screen"),TPoint(0,iFontHeight*7),iSelection==4);
iView->DrawText(_L("Configure sound"),TPoint(0,iFontHeight*8),iSelection==5);
iView->DrawText(_L("Game Genie/Cheats"),TPoint(0,iFontHeight*9),iSelection==6);
iView->DrawText(_L("Reset"),TPoint(0,iFontHeight*10),iSelection==7);
iView->DrawText(_L("Credits"),TPoint(0,iFontHeight*11),iSelection==8);
iView->DrawText(_L("Exit"),TPoint(0,iFontHeight*12),iSelection==9);
if(iRomName.Length()>0)
{
iView->DrawText(TParsePtr(iRomName).Name(),TPoint(0,iFontHeight*13));
}
else
{
iView->DrawText(_L("No rom loaded"),TPoint(0,iFontHeight*13));
}
}
void CPicoDriveUi::PutScreenSelect()
{
TInt regionIndex = 0;
switch(PicoRegionOverride)
{
default:
regionIndex = 0;
break;
case 1:
regionIndex = 1;
break;
case 2:
regionIndex = 2;
break;
case 4:
regionIndex = 3;
break;
case 8:
regionIndex = 4;
break;
}
iView->DrawText(_L("PicoDrive S60"),TPoint(0,0));
iView->DrawText(_L("Screen options"),TPoint(0,iFontHeight));
iView->DrawText(_L("Portrait"),TPoint(0,iFontHeight*3),iScrMode==0);
iView->DrawText(_L("Landscape Left"),TPoint(0,iFontHeight*4),iScrMode==1);
iView->DrawText(_L("Landscape Right"),TPoint(0,iFontHeight*5),iScrMode==2);
iView->DrawText(_L("Portrait stretched"),TPoint(0,iFontHeight*6),iScrMode==3);
iView->DrawText(_L("Portrait full"),TPoint(0,iFontHeight*7),iScrMode==4);
if(iInterpolate)
{
iView->DrawText(_L("Interpolate on"),TPoint(0,iFontHeight*8),iScrMode==5);
}
else
{
iView->DrawText(_L("Interpolate off"),TPoint(0,iFontHeight*8),iScrMode==5);
}
if(iFrameSkip == -1)
{
iView->DrawText(_L("Frameskip auto"),TPoint(0,iFontHeight*9),iScrMode==6);
}
else
{
TBuf<64> skip;
skip.Format(_L("Frameskip %d"),iFrameSkip);
iView->DrawText(skip,TPoint(0,iFontHeight*9),iScrMode==6);
}
if(PicoOpt & 0x40)
{
iView->DrawText(_L("Accurate timing on"),TPoint(0,iFontHeight*10),iScrMode==7);
}
else
{
iView->DrawText(_L("Accurate timing off"),TPoint(0,iFontHeight*10),iScrMode==7);
}
if(PicoOpt & 0x80)
{
iView->DrawText(_L("Accurate sprites on"),TPoint(0,iFontHeight*11),iScrMode==8);
}
else
{
iView->DrawText(_L("Accurate sprites off"),TPoint(0,iFontHeight*11),iScrMode==8);
}
if(PicoOpt & 0x10)
{
iView->DrawText(_L("Alt. renderer on"),TPoint(0,iFontHeight*12),iScrMode==9);
}
else
{
iView->DrawText(_L("Alt. renderer off"),TPoint(0,iFontHeight*12),iScrMode==9);
}
iView->DrawText(iRegNames->MdcaPoint(regionIndex),TPoint(0,iFontHeight*13),iScrMode==10);
}
void CPicoDriveUi::PutSoundSelect()
{
iView->Clear();
iView->DrawText(_L("PicoDrive S60"),TPoint(0,0));
iView->DrawText(_L("Sound options"),TPoint(0,iFontHeight));
if (PicoOpt&4)
iView->DrawText(_L("Z80 enabled"),TPoint(0,iFontHeight*3),iSndSelection==EEnableZ80);
else
iView->DrawText(_L("Z80 disabled"),TPoint(0,iFontHeight*3),iSndSelection==EEnableZ80);
if (PicoOpt&1)
iView->DrawText(_L("YM2612 enabled"),TPoint(0,iFontHeight*4),iSndSelection==EEnableYM2612);
else
iView->DrawText(_L("YM2612 disabled"),TPoint(0,iFontHeight*4),iSndSelection==EEnableYM2612);
if (PicoOpt&2)
iView->DrawText(_L("SN76496 enabled"),TPoint(0,iFontHeight*5),iSndSelection==EEnableSN76496);
else
iView->DrawText(_L("SN76496 disabled"),TPoint(0,iFontHeight*5),iSndSelection==EEnableSN76496);
TBuf<32> vol;
vol.Format(_L("Volume %d"),iSoundVolume*10);
iView->DrawText(vol,TPoint(0,iFontHeight*6),iSndSelection==ESoundVolume);
vol.Format(_L("Sample rate %dKhz"),PsndRate/1000);
iView->DrawText(vol,TPoint(0,iFontHeight*7),iSndSelection==ESoundRate);
}
void CPicoDriveUi::PutCheatSelect()
{
iView->Clear();
iView->DrawText(_L("PicoDrive S60"),TPoint(0,0));
iView->DrawText(_L("Cheat options"),TPoint(0,iFontHeight));
iView->DrawText(_L("Add cheat"),TPoint(0,iFontHeight*3),iCheatSelection==EAddCheat);
iView->DrawText(_L("Clear cheats"),TPoint(0,iFontHeight*4),iCheatSelection==EClearCheats);
TInt noCheats = 0;
TBuf<17>cheatCode;
for(TInt i = iListOffset; (i < 256)&&(noCheats<5); i++)
{
if (Liste_GG[i].code[0] != 0)
{
TRgb textColour = Liste_GG[i].active?KRgbGreen:KRgbDarkGreen;
if(iCheatSelection == 2+(i-iListOffset))
{
textColour = Liste_GG[i].active?KRgbRed:KRgbDarkRed;
}
TPtrC8 ptr((const unsigned char*)Liste_GG[i].code,strlen(Liste_GG[i].code));
cheatCode.Copy(ptr);
iView->DrawText(cheatCode,TPoint(0,iFontHeight*(5+noCheats)),EFalse,textColour);
noCheats++;
}
}
iView->DrawText(_L("Supports GG & Patch"),TPoint(0,iFontHeight*11));
iView->DrawText(_L("GG: XXXX-XXXX"),TPoint(0,iFontHeight*12));
iView->DrawText(_L("Patch: XXXXXX:YYYY"),TPoint(0,iFontHeight*13));
}
void CPicoDriveUi::PutControllerSelect()
{
iView->Clear();
iView->DrawText(_L("PicoDrive S60"),TPoint(0,0));
iView->DrawText(_L("Controller options"),TPoint(0,iFontHeight));
if (iEnableSixButtons)
iView->DrawText(_L("6 button pad"),TPoint(0,iFontHeight*3),iCtrlSelection==EControllerType);
else
iView->DrawText(_L("3 button pad"),TPoint(0,iFontHeight*3),iCtrlSelection==EControllerType);
iView->DrawText(_L("Configure keys"),TPoint(0,iFontHeight*4),iCtrlSelection==EConfigControls);
}
void CPicoDriveUi::PutConfigKeys()
{
iView->DrawText(_L("PicoDrive S60"),TPoint(0,0));
iView->DrawText(_L("Configure keys"),TPoint(0,iFontHeight));
iView->DrawText(_L("Please press:"),TPoint(0,iFontHeight*3));
iView->DrawText(iKeyNames->MdcaPoint(iCurrentScan),TPoint(0,iFontHeight*4));
iView->DrawText(_L("Press 'C' to skip this!"),TPoint(0,iFontHeight*6));
}
TInt CPicoDriveUi::IdleCallBackStop(TAny* /*aAppUi*/)
{
CActiveScheduler::Stop();
return 0;
}
TInt CPicoDriveUi::StartEmulatorL(TAny* aAppUi)
{
static_cast<CPicoDriveUi*>(aAppUi)->StartEmulatorL();
return 0;
}
void CPicoDriveUi::HandleForegroundEventL(TBool aForeground)
{
if(iView != NULL)
{
iView->iForeground=aForeground;
}
if(!aForeground)
{
if(iView != NULL)
{
iView->AbortNow(RDirectScreenAccess::ETerminateCancel);
}
}
else
{
if(iView != NULL)
{
iView->Restart(RDirectScreenAccess::ETerminateCancel);
UpdateScreen();
}
SetKeyBlockMode(ENoKeyBlock);
}
}
void CPicoDriveUi::UpdateScreen()
{
if(!iEmuRunning)
{
iView->Clear();
if(iCurrentScan>=0)
{
PutConfigKeys();
}
else if(iPicoMenu==ESelectScrMenu)
{
PutScreenSelect();
}
else if (iPicoMenu==EAboutPicoMenu)
{
PutAbout(ETrue);
}
else if (iPicoMenu==ESelectSoundMenu)
{
PutSoundSelect();
}
else if (iPicoMenu==ESelectControlsMenu)
{
PutControllerSelect();
}
else if (iPicoMenu==ESelectCheatMenu)
{
PutCheatSelect();
}
else
PutMainMenu();
}
}
void CPicoDriveUi::StartEmulatorL()
{
iView->Clear();
TTime time;
time.HomeTime();
#ifdef S60V3
LastSecond=(TInt)(time.Int64()/1000);//GetTickCount();
#else
LastSecond=(TInt)(time.Int64()/1000).GetTInt();//GetTickCount();
#endif
FramesDone=0;
iSndStream->SetVolume((iSndStream->MaxVolume()*iSoundVolume)/10);
UpdatePSndRate();
while(iEmuRunning)
{
EmulateFrame();
}
iSndStream->Stop();
iView->Clear();
PutMainMenu();
}
/**
* Calculates the palette table 0-4096
*/
void CPicoDriveUi::CalculatePaletteTable()
{
for(TInt cram =0;cram<4096;cram++)
{
if(iDisplayMode == EColor4K)
{
unsigned short high=0x111;
high|=(cram&0x00e)<<8; // Red
high|=(cram&0x0e0); // Green
high|=(cram&0xe00)>> 8; // Blue
gColorMapTab[cram] = high;
}
else // 64K color mode
{
unsigned short high=0x0841;
// Convert 0000bbbb ggggrrrr
// to rrrr1ggg g10bbbb1
high|=(cram&0x00f)<<12; // Red
high|=(cram&0x0f0)<< 3; // Green
high|=(cram&0xf00)>> 7; // Blue
gColorMapTab[cram] = high;
}
}
}
int CPicoDriveUi::TargetInit()
{
PicoCram=NULL;
TUint16 currentLine = 0;
TReal xFactor = 1;
TReal xNarrowFactor = 1;
TReal yFactor = 1;
TInt loop;
memset(framebuff,0,framebuffsize);
if(iScrMode==0)
{
#ifdef S60V3
xFactor = ((TReal)Targ.view.iBr.iX/(TReal)320);
xNarrowFactor = ((TReal)Targ.view.iBr.iX/(TReal)256);
if(xFactor>1)
xFactor = 1;
if(xNarrowFactor>1)
xNarrowFactor = 1;
yFactor = ((TReal)Targ.view.iBr.iY/(TReal)240);
if(yFactor>1)
yFactor = 1;
for(loop = 0;loop<256;loop++)
{
TInt line = (loop*xNarrowFactor);
TInt nextLine = ((loop+1)*xNarrowFactor);
if(line != nextLine)
{
gNarrowColumnStepTable[loop] = 1;
}
else
{
gNarrowColumnStepTable[loop] = 0;
}
}
for(loop = 0;loop<320;loop++)
{
TInt line = (loop*xFactor);
TInt nextLine = ((loop+1)*xFactor);
if( line != nextLine)
{
gColumnStepTable[loop] = 1;
}
else
{
gColumnStepTable[loop] = 0;
}
}
for(TInt loop = 0;loop<240;loop++)
{
gLineTable[loop] = currentLine;
if((loop*yFactor) != ((loop+1)*yFactor))
currentLine++;
}
myPicoScan=EmulateScan16;
#else
if(iInterpolate)
myPicoScan=EmulateScan16_176Interpolate;
else
myPicoScan=EmulateScan16_176;
for(TInt loop = 0;loop<240;loop++)
{
gLineTable[loop] = currentLine;
if(((loop*3)/4) != (((loop+1)*3)/4))
currentLine++;
}
#endif
KBitValTable[0] = 1;
KBitValTable[1] = 2;
KBitValTable[2] = 4;
KBitValTable[3] = 8;
}
#ifdef S60V3
else if (iScrMode == 1 || iScrMode == 2)
{
xFactor = ((TReal)Targ.view.iBr.iY/(TReal)320);
xNarrowFactor = ((TReal)Targ.view.iBr.iY/(TReal)256);
if(xFactor>2)
xFactor = 2;
if(xNarrowFactor>2)
xNarrowFactor = 2;
yFactor = ((TReal)Targ.view.iBr.iX/(TReal)240);
if(yFactor>2)
yFactor = 2;
for(loop = 0;loop<256;loop++)
{
TInt col = (loop*xNarrowFactor);
TInt nextCol= ((loop+1)*xNarrowFactor);
gNarrowColumnStepTable[loop] = nextCol-col;;
}
for(loop = 0;loop<320;loop++)
{
TInt col = (loop*xFactor);
TInt nextCol= ((loop+1)*xFactor);
gColumnStepTable[loop] = nextCol-col;;
}
for(TInt loop = 0;loop<240;loop++)
{
gLineTable[loop] = currentLine;
TInt line = (loop*yFactor);
TInt nextLine = ((loop+1)*yFactor);
currentLine+=(nextLine-line);
}
if(iScrMode == 2)
{
KBitValTable[0] = 4;
KBitValTable[1] = 8;
KBitValTable[2] = 2;
KBitValTable[3] = 1;
myPicoScan=EmulateScanFullRight16;
}
else
{
KBitValTable[0] = 8;
KBitValTable[1] = 4;
KBitValTable[2] = 1;
KBitValTable[3] = 2;
myPicoScan=EmulateScanFull16;
}
#else
else if (iScrMode == 1)
{
if(iInterpolate)
myPicoScan=EmulateScanFull16_176Interpolate;
else
myPicoScan=EmulateScanFull16_176;
for(TInt loop = 0;loop<240;loop++)
{
gLineTable[loop] = currentLine;
if(((loop*3)/4) != (((loop+1)*3)/4))
currentLine++;
}
KBitValTable[0] = 8;
KBitValTable[1] = 4;
KBitValTable[2] = 1;
KBitValTable[3] = 2;
#endif
}
#ifndef S60V3
else if(iScrMode==2)
{
if(iInterpolate)
myPicoScan=EmulateScanFullRight16_176Interpolate;
else
myPicoScan=EmulateScanFullRight16_176;
for(TInt loop = 0;loop<240;loop++)
{
gLineTable[loop] = currentLine;
if(((loop*3)/4) != (((loop+1)*3)/4))
currentLine++;
}
KBitValTable[0] = 4;
KBitValTable[1] = 8;
KBitValTable[2] = 2;
KBitValTable[3] = 1;
}
#endif
else
{
#ifdef S60V3
xFactor = ((TReal)Targ.view.iBr.iX/(TReal)320);
xNarrowFactor = ((TReal)Targ.view.iBr.iX/(TReal)256);
if(xFactor>2)
xFactor = 2;
if(xNarrowFactor>2)
xNarrowFactor = 2;
yFactor = ((TReal)Targ.view.iBr.iY/(TReal)240);
if(yFactor>2)
yFactor = 2;
for(loop = 0;loop<256;loop++)
{
TInt col = (loop*xNarrowFactor);
TInt nextCol= ((loop+1)*xNarrowFactor);
gNarrowColumnStepTable[loop] = nextCol-col;;
}
for(loop = 0;loop<320;loop++)
{
TInt col = (loop*xFactor);
TInt nextCol= ((loop+1)*xFactor);
gColumnStepTable[loop] = nextCol-col;;
}
for(TInt loop = 0;loop<240;loop++)
{
gLineTable[loop] = currentLine;
TInt line = (loop*yFactor);
TInt nextLine = ((loop+1)*yFactor);
currentLine+=(nextLine-line);
}
myPicoScan=EmulateStretchScan16;
#else
if(iScrMode == 4)
{
myPicoScan=EmulateStretchScan16_320;
iInterpolate = EFalse; // not needed
}
else
{
if(iInterpolate)
myPicoScan=EmulateStretchScan16_176Interpolate;
else
myPicoScan=EmulateStretchScan16_176;
}
for(TInt loop = 0;loop<240;loop++)
{
gLineTable[loop] = currentLine;
if(((loop*15)/16) != (((loop+1)*15)/16))
currentLine++;
}
#endif
KBitValTable[0] = 1;
KBitValTable[1] = 2;
KBitValTable[2] = 4;
KBitValTable[3] = 8;
}
if(iView)
iView->SetRect(TRect(TPoint(0,0),iEikonEnv->ScreenDevice()->SizeInPixels()));
#ifdef S60V3
switch(iScrMode)
{
case 0:
case 3:
case 4:
iPutRect=TRect(TPoint(0,0),TSize(xFactor*320,yFactor*240));
iPutPoint=TPoint(Targ.view.Size().iWidth/2-iPutRect.Size().iWidth/2,Targ.view.Size().iHeight/2-iPutRect.Size().iHeight/2);
break;
case 1:
case 2:
iPutRect=TRect(TPoint(0,0),TSize(yFactor*240,xFactor*320));
iPutPoint=TPoint(Targ.view.Size().iWidth/2-iPutRect.Size().iWidth/2,Targ.view.Size().iHeight/2-iPutRect.Size().iHeight/2);
break;
}
#else
switch(iScrMode)
{
case 0:
iPutPoint=TPoint(0,20);
iPutRect=TRect(TPoint(0,0),TSize(176,168));
break;
case 1:
case 2:
iPutPoint=TPoint(4,1);
iPutRect=TRect(TPoint(4,1),TSize(168,205));
break;
case 3:
case 4:
iPutPoint=TPoint(0,0);
iPutRect=TRect(TPoint(0,0),TSize(176,208));
break;
}
#endif
CalulateLineStarts();
return 0;
}
#ifdef S60V3
#define KCenterOffset 8
#else
#define KCenterOffset 0
#endif
void CPicoDriveUi::CalulateLineStarts()
{
switch(iScrMode)
{
case 0:
case 3:
case 4:
{
for(TInt loop = 0;loop<Targ.view.Size().iHeight;loop++)
{
gLineOffsets[loop] = loop*Targ.scanline_length;
}
}break;
case 1:
{
for(TInt loop = 0;loop<Targ.view.Size().iHeight;loop++)
{
gLineOffsets[loop] = loop*2+Targ.screen_offset+KCenterOffset;
}
}break;
case 2:
{
for(TInt loop = 0;loop<Targ.view.Size().iHeight;loop++)
{
gLineOffsets[loop] = Targ.scanline_length-loop*2-KCenterOffset;
}
}break;
}
}
bool IsZip(char *filename)
{
unsigned char buf[2];
FILE *fp;
if((fp=fopen(filename,"rb"))!=NULL)
{
fread(buf, 2, 1, fp);
fclose(fp);
return(memcmp(buf,"PK",2)==0);
}
if(fp)fclose(fp);
return false;
}
int CPicoDriveUi::EmulateInit()
{
FILE *f=NULL;
EmulateExit(); // Make sure exited
TargetInit(); // Find out where to put the screen
PicoInit();
// Load cartridge
if(IsZip(RomName))
{
if(CartLoadZip(RomName,&RomData,&RomSize))
{
return 1;
}
}
else
{
// Load cartridge
RFile file;
TInt error = file.Open(iEikonEnv->FsSession(),iRomName,0);
file.Close();
f=fopen(RomName,"rb");
if (f==NULL)
return 1;
TInt result =PicoCartLoad(f,&RomData,&RomSize);
fclose(f);
if(result)
return 1; // failed to load cart
}
TParsePtr parser(iRomName);
TPtr8 ptr(Pico.rom_name,511);
ptr.Copy(parser.DriveAndPath());
ptr.Append(parser.Name());
ptr.ZeroTerminate();
PicoCartInsert(RomData,RomSize);
Load_Patch_File();
saveLoadGame(1, 1); // load sram if any saved
if(!iEnableSixButtons)
PicoOpt=PicoOpt& 223;
else
PicoOpt=PicoOpt|32;
return 0;
}
void CPicoDriveUi::EmulateExit()
{
// Save sram if any
if(RomData != NULL)
{
if(SRam.changed)
{
saveLoadGame(0,1);
SRam.changed = 0;
}
Save_Patch_File();
// Remove cartridge
PicoCartInsert(NULL,0);
PicoUnloadCart(RomData);
RomData=NULL; RomSize=0;
}
PicoExit();
}
int CPicoDriveUi::InputFrame()
{
if(PicoOpt & 3)
{
PsndOut=(short*)(iMonoSound.Ptr()+2*iCurrentSeg*PsndLen);
}
else
{
PsndOut=NULL;
}
Patch_Codes();
PicoFrame();
if(PicoOpt & 3)
{
iCurrentSeg++;
if(iCurrentSeg==6)
{
iMonoSound.SetLength(PsndLen*2*6);
iSndStream->WriteL(iMonoSound);
iCurrentSeg=0;
}
}
TCallBack callback(IdleCallBackStop,this);
iIdleCallBack.Cancel();
iIdleCallBack.Set(callback);
iIdleCallBack.CallBack();
CActiveScheduler::Start();
PicoPad[0]=iPad1;
return 0;
}
int CPicoDriveUi::EmulateFrame()
{
int i=0,need=2;
if (!iRomLoaded)
return 1;
// Speed throttle:
if(iFrameSkip ==-1) // auto skipping
{
int time=0,frame=0;
TTime newtime;
newtime.HomeTime();
#ifdef S60V3
TInt64 tic=(newtime.Int64()/1000);
time=(tic-LastSecond); // This will be about 0-1000 ms
#else
TInt64 tic=(newtime.Int64()/1000).GetTInt();
time=(tic-LastSecond).GetTInt(); // This will be about 0-1000 ms
#endif
frame=time*FramesPerSecond/1000;
need=frame-FramesDone;
FramesDone=frame;
if (FramesPerSecond>0)
{
// Carry over any >60 frame count to one second
while (FramesDone>=FramesPerSecond) { FramesDone-=FramesPerSecond; LastSecond+=1000; }
}
if (need<=0) {
TTime nextTime;
do
{
nextTime.HomeTime();
}while((nextTime.Int64()-newtime.Int64())<15000);
}
if (need>10) need=10; // Limit frame skipping
}
else
{
need = iFrameSkip+1;
}
PicoSkipFrame=1;
for (i=0;i<need-1;i++) InputFrame(); // Frame skip if needed
PicoSkipFrame=0;
// Now final frame is drawn:
TBitmapUtil util(iBackBuffer);
util.Begin(TPoint(0,0));
Targ.screen=(unsigned char*)iBackBuffer->DataAddress();
if (Targ.screen == NULL)
{
util.End();
return 1;
}
PicoScan=myPicoScan; // Setup scanline callback
InputFrame();
if(PicoOpt & 0x10) // need to render separatly
{
unsigned short* framebuffptr = framebuff+2632;
if(!(Pico.video.reg[12]&1))
{
framebuffptr=framebuffptr-32;
}
TInt skipNext =0;
for(TInt loop = 0;loop<224;loop++)
{
if(skipNext == 0)
{
skipNext = PicoScan(loop,framebuffptr);
}
else
skipNext--;
framebuffptr+=328;
}
}
PicoScan=NULL;
util.End();
Targ.screen = NULL;
iView->PutBitmap(iBackBuffer,iPutPoint,iPutRect);;
return 0;
}
void CPicoDriveUi::MaoscOpenComplete(TInt aError)
{
if(aError == KErrNone)
{
iSndStream->SetPriority(EPriorityMuchMore, EMdaPriorityPreferenceNone);
iSndStream->SetVolume((iSndStream->MaxVolume()*iSoundVolume)/10);
if(!UpdatePSndRate())
{
PsndRate = 8000;
UpdatePSndRate();
}
}
CActiveScheduler::Stop();
}
void CPicoDriveUi::MaoscBufferCopied(TInt /*aError*/, const TDesC8& /*aBuffer*/)
{
}
void CPicoDriveUi::MaoscPlayComplete(TInt aError)
{
if(aError != KErrNone)
{
iSndStream->SetVolume((iSndStream->MaxVolume()*iSoundVolume)/10);
UpdatePSndRate();
}
}
TBool CPicoDriveUi::UpdatePSndRate()
{
TInt sampleRate = TMdaAudioDataSettings::ESampleRate8000Hz;
if(PsndRate == 11025)
sampleRate = TMdaAudioDataSettings::ESampleRate11025Hz;
else if (PsndRate == 16000)
sampleRate = TMdaAudioDataSettings::ESampleRate16000Hz;
else if (PsndRate == 22050)
sampleRate = TMdaAudioDataSettings::ESampleRate22050Hz;
TRAPD(err,iSndStream->SetAudioPropertiesL(sampleRate,TMdaAudioDataSettings::EChannelsMono));
return (err == KErrNone);
}
size_t gzRead2(void *p, size_t _size, size_t _n, void *file)
{
return gzread(file, p, _n);
}
size_t gzWrite2(void *p, size_t _size, size_t _n, void *file)
{
return gzwrite(file, p, _n);
}
// this function is shared between both threads
int CPicoDriveUi::saveLoadGame(int load, int sram)
{
int res = 0;
if(!(iRomName.Length()>0)) return -1;
// make save filename
strcpy(saveFname,RomName);
saveFname[KMaxFileName-5] = 0;
if(saveFname[strlen(saveFname)-4] == '.') saveFname[strlen(saveFname)-4] = 0;
strcat(saveFname, sram ? ".srm" : ".mds");
if(sram) {
int sram_size = SRam.end-SRam.start+1;
if(SRam.reg_back & 4) sram_size=0x2000;
if(!SRam.data) return 0; // SRam forcefully disabled for this game
if(load) {
PmovFile = fopen(saveFname, "rb");
if(!PmovFile) return -1;
fread(SRam.data, 1, sram_size, (FILE *) PmovFile);
fclose((FILE *) PmovFile);
} else {
// sram save needs some special processing
// see if we have anything to save
for(; sram_size > 0; sram_size--)
if(SRam.data[sram_size-1]) break;
if(sram_size) {
PmovFile = fopen(saveFname, "wb");
res = fwrite(SRam.data, 1, sram_size, (FILE *) PmovFile);
res = (res != sram_size) ? -1 : 0;
fclose((FILE *) PmovFile);
}
}
PmovFile = 0;
return res;
} else {
// try gzip first
//if(currentConfig.iFlags & 0x80) {
strcat(saveFname, ".gz");
if( (PmovFile = gzopen(saveFname, load ? "rb" : "wb")) ) {
areaRead = gzRead2;
areaWrite = gzWrite2;
if(!load) gzsetparams(PmovFile, 9, Z_DEFAULT_STRATEGY);
} else
saveFname[strlen(saveFname)-3] = 0;
// }
if(!PmovFile) { // gzip failed or was disabled
if( (PmovFile = fopen(saveFname, load ? "rb" : "wb")) ) {
areaRead = (arearw *) fread;
areaWrite = (arearw *) fwrite;
}
}
if(PmovFile) {
PmovAction = load ? 6 : 5; // load/save
PmovState();
if(areaRead == gzRead2)
gzclose(PmovFile);
else fclose ((FILE *) PmovFile);
PmovFile = 0;
} else {
res = -1;
}
return res;
}
}
CQPicoDriveView::~CQPicoDriveView()
{
iDsa->Cancel();
delete iDsa;
}
void CQPicoDriveView::Restart(RDirectScreenAccess::TTerminationReasons /*aReason*/)
{
if(iForeground)
{
iDsa->Cancel();
iDsa->StartL();
iDsa->Gc()->SetClippingRegion(iDsa->DrawingRegion());
iDrawingOn=ETrue;
}
}
void CQPicoDriveView::AbortNow(RDirectScreenAccess::TTerminationReasons /*aReason*/)
{
iDsa->Cancel();
iDrawingOn=EFalse;
}
void CQPicoDriveView::Draw(const TRect& aRect) const
{
CWindowGc& gc=SystemGc();
gc.SetBrushColor(KRgbBlack);
gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
gc.SetPenStyle(CGraphicsContext::ENullPen);
gc.DrawRect(aRect);
static_cast<CPicoDriveUi*>(iEikonEnv->EikAppUi())->StartAsynchUpdate();
}
void CQPicoDriveView::ConstructL()
{
CreateWindowL();
ActivateL();
SetFocus(ETrue);
SetRect(TRect(TPoint(0,0),iEikonEnv->ScreenDevice()->SizeInPixels())/*iEikonEnv->EikAppUi()->ClientRect()*/);
iDsa=CDirectScreenAccess::NewL(iEikonEnv->WsSession(),*iEikonEnv->ScreenDevice(),Window(),*this);
iDsa->StartL();
iDsa->Gc()->SetClippingRegion(iDsa->DrawingRegion());
iDrawingOn=ETrue;
if(Window().DisplayMode() != EColor4K && Window().DisplayMode() != EColor64K)
{
Window().SetRequiredDisplayMode(EColor64K); // Try to set 64K color mode
}
}
void CQPicoDriveView::Clear()
{
CBitmapContext* gc;
if(iDrawingOn)
{
gc=iDsa->Gc();
}
else
{
ActivateGc();
gc=&SystemGc();
}
gc->SetBrushColor(KRgbBlack);
gc->SetBrushStyle(CGraphicsContext::ESolidBrush);
gc->SetPenStyle(CGraphicsContext::ENullPen);
gc->DrawRect(Rect());
if(iDrawingOn)
{
iDsa->ScreenDevice()->Update();
iEikonEnv->WsSession().Flush();
}
else
{
DeactivateGc();
}
}
void CQPicoDriveView::DrawText(const TDesC& aText,TPoint aPoint,TBool aHighLight,TRgb aTextColour)
{
CBitmapContext* gc;
if(iDrawingOn)
{
gc=iDsa->Gc();
}
else
{
ActivateGc();
gc=&SystemGc();
}
gc->SetBrushColor(KRgbBlack);
gc->SetBrushStyle(CGraphicsContext::ESolidBrush);
if(!aHighLight)
{
gc->SetPenColor(aTextColour);
}
else
{
gc->SetPenColor(KRgbRed);
}
gc->SetPenStyle(CGraphicsContext::ESolidPen);
aPoint.iY+=iEikonEnv->NormalFont()->HeightInPixels()-2;
aPoint.iX=Size().iWidth/2-iEikonEnv->NormalFont()->TextWidthInPixels(aText)/2;
gc->UseFont(iEikonEnv->NormalFont());
gc->DrawText(aText,aPoint);
gc->DiscardFont();
if(iDrawingOn)
{
iDsa->ScreenDevice()->Update();
}
else
{
DeactivateGc();
}
}
TInt CQPicoDriveView::DrawTextInRect(const TDesC& aText,TRect aRect,TInt aStartPos)
{
CBitmapContext* gc;
TInt pos = aStartPos;
TInt len = aText.Length();
if(iDrawingOn)
{
gc=iDsa->Gc();
}
else
{
ActivateGc();
gc=&SystemGc();
}
gc->SetBrushColor(KRgbBlack);
gc->SetBrushStyle(CGraphicsContext::ESolidBrush);
gc->SetPenColor(KRgbWhite);
gc->SetPenStyle(CGraphicsContext::ESolidPen);
gc->UseFont(iEikonEnv->DenseFont());
while(pos<len && aRect.iTl.iY<aRect.iBr.iY-(iEikonEnv->DenseFont()->HeightInPixels()+3))
{
TInt newline = aText.Right(len-pos).Locate('\n');
if(newline == KErrNotFound)
newline=(len-1)-pos;
gc->DrawText(aText.Mid(pos,newline),aRect,iEikonEnv->DenseFont()->HeightInPixels());
pos=pos+newline+1; // skip new line
aRect.iTl+=TSize(0,iEikonEnv->DenseFont()->HeightInPixels()+3);
}
gc->DiscardFont();
if(iDrawingOn)
{
iDsa->ScreenDevice()->Update();
}
else
{
DeactivateGc();
}
return pos;
}
void CQPicoDriveView::PutBitmap(CFbsBitmap* aBitmap,TPoint aPoint,TRect aRect)
{
if(iDrawingOn)
{
//#ifdef __WINS__
iDsa->Gc()->BitBlt(aPoint,aBitmap,aRect);
iDsa->ScreenDevice()->Update();
//#endif
//iEikonEnv->WsSession().Flush();
}
else
{
ActivateGc();
CWindowGc& gc=SystemGc();
gc.BitBlt(aPoint,aBitmap,aRect);
DeactivateGc();
}
}
void Execute()
{
__UHEAP_MARK;
CTrapCleanup* cleanup = CTrapCleanup::New();
// Create a eikenv
CEikonEnv* eikenv = new CEikonEnv;
if (!eikenv)
{
return /*KErrNoMemory*/;
}
TRAPD(eikErr, eikenv->ConstructL());
if (eikErr != KErrNone)
{
delete eikenv;
return /*eikErr*/;
}
CPicoDriveUi* appUi = new (ELeave) CPicoDriveUi;
if (!appUi)
{
delete eikenv;
return /*KErrNoMemory*/;
}
TRAPD(constructErr,appUi->ConstructL());
eikenv->SetAppUi(appUi); // passing ownership of appUi to coe
TInt leaveValue = KErrNone;
if (leaveValue != KErrNone)
{
delete eikenv;
}
else
{
// now accept request from clients (start the scheduler)
eikenv->ExecuteD();
//delete eikenv; // ExecuteD kills eikenv
}
delete cleanup;
__UHEAP_MARKEND;
}
//ARM build
#ifdef S60V3
CPicoDriveApp::CPicoDriveApp()
{
}
CPicoDriveApp::~CPicoDriveApp()
{
}
CApaDocument* CPicoDriveApp::CreateDocumentL()
{
return new (ELeave) CPicoDriveDoc(*this);
}
TUid CPicoDriveApp::AppDllUid()const
{
return TUid::Uid(0xA00007BE);
}
/**
* From @c CApaApplication. Opens the .ini file associated with the
* application. By default, ini files are not supported by SERIES60
* applications. If you want to use an ini file, either override this
* function to base call @c CEikApplication::OpenIniFileLC, or call it
* directly.
* @param aFs File server session to use. Not used.
* @return Pointer to the dictionary store object representing the
* application's .ini file.
*/
CDictionaryStore* CPicoDriveApp::OpenIniFileLC(RFs& aFs) const
{
return CEikApplication::OpenIniFileLC(aFs);
}
CPicoDriveDoc::CPicoDriveDoc(CEikApplication& aApp):CAknDocument(aApp)
{
}
CPicoDriveDoc::~CPicoDriveDoc()
{
}
CEikAppUi* CPicoDriveDoc::CreateAppUiL()
{
return new (ELeave) CPicoDriveUi;
}
#ifdef S60V3
LOCAL_C
#endif
CApaApplication* NewApplication() {
// Return pointer to newly created Application
return new CPicoDriveApp;
}
#include <eikstart.h>
#endif
GLDEF_C TInt E32Main()
{
#ifdef S60V3
return EikStart::RunApplication(NewApplication);
#else
Execute();
#endif
return KErrNone;
}
#if defined(__WINS__)
#ifndef S60V3
EXPORT_C TInt WinsMain()
{
E32Main();
return KErrNone;
}
#endif
extern "C" void my_free(void* anAddress)
{
if(gChunk != NULL)
{
gChunk->Free(anAddress);
}
}
extern "C" void* my_malloc(int aSize)
{
if(gChunk != NULL)
{
return gChunk->Alloc(aSize);
}
return NULL;
}
#endif