initial import

git-svn-id: file:///home/notaz/opt/svn/PicoDrive@2 be3aeb3a-fb24-0410-a615-afba39da0efa
This commit is contained in:
notaz 2006-12-19 20:53:21 +00:00
parent 2cadbd5e56
commit cc68a136aa
341 changed files with 180839 additions and 0 deletions

485
platform/uiq3/App.cpp Normal file
View file

@ -0,0 +1,485 @@
/*******************************************************************
*
* File: App.cpp
*
* Author: Peter van Sebille (peter@yipton.net)
*
* Modified/adapted for picodriveN by notaz, 2006
*
* (c) Copyright 2006, notaz
* (c) Copyright 2002, Peter van Sebille
* All Rights Reserved
*
*******************************************************************/
#include "app.h"
// #include "picodriven.mbg" // bitmap identifiers
#include <PicoDrive.RSG> // resource include
#include <eikenv.h>
#include <qbtselectdlg.h>
//#include <gulutil.h>
//#include <bautils.h>
//#include <eikmenub.h> // CEikMenuBar
#include <apgtask.h> // TApaSystemEvent
#include <eikstart.h>
#include <eikedwin.h>
#include <s32strm.h>
#include <QikAppUi.h>
#include <QikEditCategoryObserver.h>
#include <QikSelectFileDlg.h>
#include <QikCommand.h>
#include "Dialogs.h"
#include "engine/debug.h"
////////////////////////////////////////////////////////////////
//
// class CPicolAppView
//
////////////////////////////////////////////////////////////////
// Creates and constructs the view.
CPicolAppView* CPicolAppView::NewLC(CQikAppUi& aAppUi, TPicoConfig& aCurrentConfig)
{
CPicolAppView* self = new (ELeave) CPicolAppView(aAppUi, aCurrentConfig);
CleanupStack::PushL(self);
return self;
}
/**
Constructor for the view.
Passes the application UI reference to the construction of the super class.
KNullViewId should normally be passed as parent view for the applications
default view. The parent view is the logical view that is normally activated
when a go back command is issued. KNullViewId will activate the system
default view.
@param aAppUi Reference to the application UI
*/
CPicolAppView::CPicolAppView(CQikAppUi& aAppUi, TPicoConfig& aCurrentConfig)
: CQikViewBase(aAppUi, KNullViewId), iCurrentConfig(aCurrentConfig)
{
}
void CPicolAppView::ConstructL()
{
BaseConstructL();
}
CPicolAppView::~CPicolAppView()
{
}
/**
Inherited from CQikViewBase and called upon by the UI Framework.
It creates the view from resource.
*/
void CPicolAppView::ViewConstructL()
{
// Loads information about the UI configurations this view supports
// together with definition of each view.
ViewConstructFromResourceL(R_APP_UI_CONFIGURATIONS);
UpdateCommandList();
}
/**
Returns the view Id
@return Returns the Uid of the view
*/
TVwsViewId CPicolAppView::ViewId()const
{
return TVwsViewId(KUidPicolApp, KUidPicolMainView);
}
/**
Handles all commands in the view.
Called by the UI framework when a command has been issued.
The command Ids are defined in the .hrh file.
@param aCommand The command to be executed
@see CQikViewBase::HandleCommandL
*/
void CPicolAppView::HandleCommandL(CQikCommand& aCommand)
{
TInt res;
switch(aCommand.Id())
{
case EEikCmdPicoLoadState:
if(iROMLoaded) {
CEikonEnv::Static()->BusyMsgL(_L("Loading State"));
res = CPicoGameSession::Do(PicoMsgLoadState);
CEikonEnv::Static()->BusyMsgCancel();
// emu doesn't start to run if load fails, so we can display this
if(res) CEikonEnv::Static()->InfoMsg(_L("Load Failed"));
}
break;
case EEikCmdPicoSaveState:
if(iROMLoaded) {
CEikonEnv::Static()->BusyMsgL(_L("Saving State"));
res = CPicoGameSession::Do(PicoMsgSaveState);
CEikonEnv::Static()->BusyMsgCancel();
if(res) CEikonEnv::Static()->InfoMsg(_L("Save Failed"));
}
break;
case EEikCmdPicoLoadROM:
DisplayOpenROMDialogL();
DEBUGPRINT(_L("after DisplayOpenROMDialogL()"));
break;
case EEikCmdPicoResume:
CPicoGameSession::Do(PicoMsgResume);
break;
case EEikCmdPicoReset:
CPicoGameSession::Do(PicoMsgReset);
break;
case EEikCmdPicoSettings:
DisplayConfigDialogL();
break;
case EEikCmdHelpAbout:
DisplayAboutDialogL();
break;
case EEikCmdPicoDebugInfo:
DisplayDebugDialogL();
break;
case EEikCmdPicoKeys:
CPicoGameSession::Do(PicoMsgConfigChange, &iCurrentConfig);
CPicoGameSession::Do(PicoMsgKeys);
break;
case EEikCmdPicoFrameskipAuto:
iCurrentConfig.iFrameskip = TPicoConfig::PFSkipAuto;
iQikAppUi.Document()->SaveL();
break;
case EEikCmdPicoFrameskip0:
iCurrentConfig.iFrameskip = 0;
iQikAppUi.Document()->SaveL();
break;
case EEikCmdPicoFrameskip1:
iCurrentConfig.iFrameskip = 1;
iQikAppUi.Document()->SaveL();
break;
case EEikCmdPicoFrameskip2:
iCurrentConfig.iFrameskip = 2;
iQikAppUi.Document()->SaveL();
break;
case EEikCmdPicoFrameskip4:
iCurrentConfig.iFrameskip = 4;
iQikAppUi.Document()->SaveL();
break;
case EEikCmdPicoFrameskip8:
iCurrentConfig.iFrameskip = 8;
iQikAppUi.Document()->SaveL();
break;
case EEikCmdExit:
iQikAppUi.Document()->SaveL();
CPicoGameSession::freeResources();
//break; // this is intentional
default:
// Go back and exit command will be passed to the CQikViewBase to handle.
CQikViewBase::HandleCommandL(aCommand);
break;
}
}
void CPicolAppView::DisplayOpenROMDialogL()
{
// Array of mimetypes that the dialog shall filter on, if empty all
// mimetypes will be visible.
CDesCArray* mimeArray = new (ELeave) CDesCArrayFlat(1);
CleanupStack::PushL(mimeArray);
// Array that will be filled with the file paths that are choosen
// from the dialog.
CDesCArray* fileArray = new (ELeave) CDesCArraySeg(3);
CleanupStack::PushL(fileArray);
_LIT16(KDlgTitle, "Select a ROM file");
if( CQikSelectFileDlg::RunDlgLD( *mimeArray, *fileArray, &KDlgTitle, &iCurrentConfig.iLastROMFile) )
{
CEikonEnv::Static()->BusyMsgL(_L("Loading ROM"));
TPtrC16 file = (*fileArray)[0];
iCurrentConfig.iLastROMFile.Copy(file);
// push the config first
CPicoGameSession::Do(PicoMsgSetAppView, this);
CPicoGameSession::Do(PicoMsgConfigChange, &iCurrentConfig);
TInt res = CPicoGameSession::Do(PicoMsgLoadROM, &file);
CEikonEnv::Static()->BusyMsgCancel();
iROMLoaded = EFalse;
switch (res)
{
case PicoErrRomOpenFailed:
CEikonEnv::Static()->InfoWinL(_L("Error"), _L("Failed to open file."));
break;
case PicoErrOutOfMem:
CEikonEnv::Static()->InfoWinL(_L("Error"), _L("Failed to allocate memory."));
break;
case PicoErrNotRom:
CEikonEnv::Static()->InfoWinL(_L("Error"), _L("The file you selected is not a game ROM."));
break;
case PicoErrNoRomsInArchive:
CEikonEnv::Static()->InfoWinL(_L("Error"), _L("No game ROMs found in zipfile."));
break;
case PicoErrUncomp:
CEikonEnv::Static()->InfoWinL(_L("Error"), _L("Failed while unzipping ROM."));
break;
case PicoErrEmuThread:
CEikonEnv::Static()->InfoWinL(_L("Error"), _L("Failed to create emulation thread. Try to restart this application."));
break;
default:
iROMLoaded = ETrue;
break;
}
// errors which leave ROM loaded
switch (res)
{
case PicoErrOutOfMemSnd:
CEikonEnv::Static()->InfoWinL(_L("Error"), _L("Failed to allocate sound buffer, disabled sound."));
break;
case PicoErrGenSnd:
CEikonEnv::Static()->InfoWinL(_L("Error"), _L("Failed to start soundsystem, disabled sound."));
break;
}
if(res == 6 || res == 7) iCurrentConfig.iFlags &= ~4;
if(iROMLoaded) {
if(iTitleAdded)
ViewContext()->ChangeTextL(EEikCidTitleBarLabel, CPicoGameSession::iRomInternalName);
else ViewContext()->AddTextL (EEikCidTitleBarLabel, CPicoGameSession::iRomInternalName);
iTitleAdded = ETrue;
UpdateCommandList();
}
}
CleanupStack::PopAndDestroy(2, mimeArray);
}
void CPicolAppView::DisplayConfigDialogL()
{
CPicoConfigDialog* configDialog = new(ELeave)CPicoConfigDialog(iCurrentConfig);
configDialog->ExecuteLD(R_PICO_CONFIG);
CPicoGameSession::Do(PicoMsgConfigChange, &iCurrentConfig);
iQikAppUi.Document()->SaveL();
}
void CPicolAppView::DisplayAboutDialogL()
{
TInt iButtonRes;
CAboutDialog* dialog = new (ELeave) CAboutDialog;
dialog->PrepareLC(R_PICO_ABOUT);
iButtonRes = dialog->RunLD();
if(iButtonRes == EEikCmdPicoAboutCreditsCmd) {
CCreditsDialog *creditsDialog = new (ELeave) CCreditsDialog();
creditsDialog->PrepareLC(R_PICO_CREDITS);
creditsDialog->RunLD();
}
}
#ifdef __DEBUG_PRINT
extern "C" char *debugString();
#endif
void CPicolAppView::DisplayDebugDialogL()
{
#ifdef __DEBUG_PRINT
CDebugDialog* dialog = new (ELeave) CDebugDialog(debugString());
dialog->PrepareLC(R_PICO_DEBUG);
dialog->RunLD();
#endif
}
void CPicolAppView::UpdateCommandList()
{
CQikCommandManager& commandManager = CQikCommandManager::Static(*iCoeEnv);
CQikCommand *cmd_fs[10];
Mem::FillZ(cmd_fs, sizeof(CQikCommand*)*10);
CQikCommand* cmd_reset = commandManager.Command(*this, EEikCmdPicoReset);
CQikCommand* cmd_savest = commandManager.Command(*this, EEikCmdPicoSaveState);
CQikCommand* cmd_loadst = commandManager.Command(*this, EEikCmdPicoLoadState);
CQikCommand* cmd_resume = commandManager.Command(*this, EEikCmdPicoResume);
cmd_fs[0] = commandManager.Command(*this, EEikCmdPicoFrameskipAuto);
cmd_fs[1] = commandManager.Command(*this, EEikCmdPicoFrameskip0);
cmd_fs[2] = commandManager.Command(*this, EEikCmdPicoFrameskip1);
cmd_fs[3] = commandManager.Command(*this, EEikCmdPicoFrameskip2);
cmd_fs[5] = commandManager.Command(*this, EEikCmdPicoFrameskip4);
cmd_fs[9] = commandManager.Command(*this, EEikCmdPicoFrameskip8);
TBool dimmed = !CPicoGameSession::iEmuRunning || !iROMLoaded;
cmd_reset ->SetDimmed(dimmed);
cmd_savest->SetDimmed(dimmed);
cmd_loadst->SetDimmed(dimmed);
cmd_resume->SetDimmed(dimmed);
// frameskip
TInt fs_index = iCurrentConfig.iFrameskip + 1;
if (fs_index >= 0 && fs_index < 10 && cmd_fs[fs_index])
{
cmd_fs[fs_index]->SetChecked(ETrue);
}
}
////////////////////////////////////////////////////////////////
//
// class CPicolAppUi
//
////////////////////////////////////////////////////////////////
void CPicolAppUi::ConstructL()
{
BaseConstructL();
// Create the view and add it to the framework
iAppView = CPicolAppView::NewLC(*this, ((CPicolDocument *)Document())->iCurrentConfig);
AddViewL(*iAppView);
CleanupStack::Pop(iAppView);
}
////////////////////////////////////////////////////////////////
//
// CPicolDocument
//
////////////////////////////////////////////////////////////////
CPicolDocument::CPicolDocument(CQikApplication& aApp)
: CQikDocument(aApp)
{
iCurrentConfig.SetDefaults();
}
CQikAppUi* CPicolDocument::CreateAppUiL()
{
return new(ELeave) CPicolAppUi;
}
/**
Called by the framework when ::SaveL has been called.
*/
void CPicolDocument::StoreL(CStreamStore& aStore, CStreamDictionary& aStreamDic) const
{
RStoreWriteStream stream;
TStreamId preferenceId = stream.CreateLC(aStore);
aStreamDic.AssignL(KUidPicolStore, preferenceId);
// Externalize preference
stream << iCurrentConfig;
// Ensures that any buffered data is written to aStore
stream.CommitL();
CleanupStack::PopAndDestroy(); // stream
/*
// tmp
TInt res;
RFile logFile;
res = logFile.Replace(CEikonEnv::Static()->FsSession(), _L("C:\\Shared\\pico.cfg"), EFileWrite|EFileShareAny);
if(!res) {
logFile.Write(TPtr8((TUint8 *)&iCurrentConfig, sizeof(iCurrentConfig), sizeof(iCurrentConfig)));
logFile.Close();
}
*/
}
/**
Called by the framework on application start.
Loads the application data from disk, i.e. domain data and preferences.
*/
void CPicolDocument::RestoreL(const CStreamStore& aStore, const CStreamDictionary& aStreamDic)
{
// Find the stream ID of the model data from the stream dictionary:
TStreamId preferenceId(aStreamDic.At(KUidPicolStore));
RStoreReadStream stream;
stream.OpenLC(aStore, preferenceId);
if(preferenceId != KNullStreamId)
{
// Interalize preference and model
stream >> iCurrentConfig;
}
CleanupStack::PopAndDestroy(); // stream
// tmp
/* TInt res;
RFile logFile;
res = logFile.Open(CEikonEnv::Static()->FsSession(), _L("C:\\Shared\\pico.cfg"), EFileRead|EFileShareAny);
if(!res) {
TPtr8 ptr((TUint8 *)&iCurrentConfig, sizeof(iCurrentConfig), sizeof(iCurrentConfig));
logFile.Read(ptr);
logFile.Close();
}*/
}
////////////////////////////////////////////////////////////////
//
// framework
//
////////////////////////////////////////////////////////////////
CApaDocument* CPicolApplication::CreateDocumentL()
{
return new (ELeave) CPicolDocument(*this);
}
EXPORT_C CApaApplication* NewApplication()
{
return new CPicolApplication;
}
TUid CPicolApplication::AppDllUid() const
{
return KUidPicolApp;
}
GLDEF_C TInt E32Main()
{
User::SetExceptionHandler(ExceptionHandler, (TUint32) -1);
return EikStart::RunApplication(NewApplication);
}

112
platform/uiq3/App.h Normal file
View file

@ -0,0 +1,112 @@
/*******************************************************************
*
* File: App.h
*
* Author: Peter van Sebille (peter@yipton.net)
*
* Modified/adapted for picodriveN by notaz, 2006
*
* (c) Copyright 2006, notaz
* (c) Copyright 2001, Peter van Sebille
* All Rights Reserved
*
*******************************************************************/
#ifndef __APP_H
#define __APP_H
#include <coecntrl.h>
#include <coeccntx.h>
#include <coemain.h>
#include <qikappui.h>
#include <QikApplication.h>
#include <QikViewBase.h>
//#include <eikapp.h>
#include <QikDocument.h>
#include "Engine.h"
#include "picodrive.hrh"
const TUid KUidPicolApp = { 0xA00010F3 };
const TUid KUidPicolMainView = { 0x00000001 };
//const TUid KUidPicolFOView = { 0x1000C194 };
//const TUid KUidPicolFCView = { 0x1000C195 };
const TUid KUidPicolStore = { 0x00000011 }; // store stream UID
//enum
//{
// EScreenModeFlipOpen = 0,
// EScreenModeFlipClosed
//};
class CPicolAppView : public CQikViewBase
{
public:
static CPicolAppView* NewLC(CQikAppUi& aAppUi, TPicoConfig& aCurrentConfig);
~CPicolAppView();
// from CQikViewBase
TVwsViewId ViewId()const;
void HandleCommandL(CQikCommand& aCommand);
void UpdateCommandList();
protected:
// from CQikViewBase
void ViewConstructL();
private:
CPicolAppView(CQikAppUi& aAppUi, TPicoConfig& aCurrentConfig);
void ConstructL();
protected: // new stuf
void DisplayAboutDialogL();
void DisplayOpenROMDialogL();
void DisplayConfigDialogL();
void DisplayDebugDialogL();
/* void StopGame();
void RunGameL();*/
private:
TPicoConfig& iCurrentConfig;
TBool iROMLoaded;
TBool iTitleAdded;
};
class CPicolAppUi : public CQikAppUi
{
public:
// CPicolAppUi();
void ConstructL();
CPicolAppView* iAppView;
};
class CPicolDocument : public CQikDocument
{
public:
CPicolDocument(CQikApplication& aApp);
void StoreL(CStreamStore& aStore, CStreamDictionary& aStreamDic) const;
void RestoreL(const CStreamStore& aStore, const CStreamDictionary& aStreamDic);
TPicoConfig iCurrentConfig;
private: // from CQikDocument
CQikAppUi* CreateAppUiL();
};
class CPicolApplication : public CQikApplication
{
private: // from CApaApplication
CApaDocument* CreateDocumentL();
TUid AppDllUid() const;
};
#endif

View file

@ -0,0 +1,477 @@
/*******************************************************************
*
* File: CSimpleTextParser.cpp
*
* Author: Peter van Sebille (peter@yipton.net)
*
* (c) Copyright 2002, Peter van Sebille
* All Rights Reserved
*
*******************************************************************/
#include "CSimpleTextParser.h"
enum
{
EBadTag,
EBadZeroLengthTag,
EBadIntegerParam,
EBadAlignmentParam,
EBadRgbColorParam
};
void Panic(TInt aPanic)
{
User::Panic(_L("STP"), aPanic);
}
CSimpleTextFormatParser* CSimpleTextFormatParser::NewLC()
{
CSimpleTextFormatParser* self = new(ELeave)CSimpleTextFormatParser;
CleanupStack::PushL(self);
self->ConstructL();
return self;
}
CSimpleTextFormatParser::~CSimpleTextFormatParser()
{
delete iParaFormat;
}
void CSimpleTextFormatParser::ConstructL()
{
iParaFormat = CParaFormat::NewL();
}
void CSimpleTextFormatParser::SetBold(TBool aEnable)
{
iCharFormat.iFontSpec.iFontStyle.SetStrokeWeight(aEnable ? EStrokeWeightBold : EStrokeWeightNormal);
iCharMask.ClearAll();
iCharMask.SetAttrib(EAttFontStrokeWeight);
iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0);
}
void CSimpleTextFormatParser::SetItalic(TBool aEnable)
{
iCharFormat.iFontSpec.iFontStyle.SetPosture(aEnable ? EPostureItalic : EPostureUpright);
iCharMask.ClearAll();
iCharMask.SetAttrib(EAttFontPosture);
iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0);
}
void CSimpleTextFormatParser::SetUnderLine(TBool aEnable)
{
iCharFormat.iFontPresentation.iUnderline = aEnable ? EUnderlineOn : EUnderlineOff;
iCharMask.ClearAll();
iCharMask.SetAttrib(EAttFontUnderline);
iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0);
}
void CSimpleTextFormatParser::SetHiddenText(TBool aEnable)
{
iCharFormat.iFontPresentation.iHiddenText = aEnable;
iCharMask.ClearAll();
iCharMask.SetAttrib(EAttFontHiddenText);
iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0);
}
TRgb CSimpleTextFormatParser::ForegroundColor()
{
iCharMask.ClearAll();
iCharMask.SetAttrib(EAttColor);
iRichText->GetCharFormat(iCharFormat, iCharMask, TextPos(), 0);
return iCharFormat.iFontPresentation.iTextColor;
}
void CSimpleTextFormatParser::SetForegroundColor(const TRgb& aColor)
{
iCharFormat.iFontPresentation.iTextColor = aColor;
iCharMask.ClearAll();
iCharMask.SetAttrib(EAttColor);
iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0);
}
void CSimpleTextFormatParser::SetBackgroundColor(const TRgb& aColor)
{
iParaFormat->iFillColor = aColor;
iParaMask.ClearAll();
iParaMask.SetAttrib(EAttFillColor);
iRichText->ApplyParaFormatL(iParaFormat, iParaMask, ParaPos(), 0);
}
void CSimpleTextFormatParser::NewParagraph()
{
iCurrentPara++;
iRichText->AppendParagraphL();
AppendTextL(_L(""));
}
void CSimpleTextFormatParser::SetAlignment(CParaFormat::TAlignment aAlignment)
{
iParaFormat->iHorizontalAlignment = aAlignment;
iParaMask.ClearAll();
iParaMask.SetAttrib(EAttAlignment);
iRichText->ApplyParaFormatL(iParaFormat, iParaMask, ParaPos(), 0);
}
void CSimpleTextFormatParser::SetFontHeight(TInt aHeight)
{
iCharFormat.iFontSpec.iHeight = (aHeight * KTwipsPerInch)/KPointsPerInch;
iCharMask.ClearAll();
iCharMask.SetAttrib(EAttFontHeight);
iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0);
}
void CSimpleTextFormatParser::SetFontName(const TDesC& aName)
{
iCharFormat.iFontSpec.iTypeface.iName = aName;
iCharFormat.iFontSpec.iTypeface.SetAttributes(0);
iCharFormat.iFontSpec.iTypeface.SetIsProportional(ETrue);
iCharMask.ClearAll();
iCharMask.SetAttrib(EAttFontTypeface);
iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0);
}
/*
* Character formatting:
* <b> Bold on
* </b> Bold of
* <i> Italic on
* </i> Italic off
* <u> Underline on
* </u> Underline off
* <h> Hidden text on **doesn't work**
* </h> Hidden text off **doesn't work**
* <f=name> Fontname: name (type: string)
* <s=size> Fontsize: size (type: integer)
* <fg=color> Foreground color: color (type: color)
* </fg> Restore foreground color
*
* Paragraph formatting:
* <p> New paragraph - will reset both character & paragraph formatting to defaults
* <a=align> Alignment: aling (type: alignement)
* <bg=color> Background color: color (type: color) **doesn't work**
*
* Special characters:
* </<> The character: <
*
* Types:
* - string:
* - integer: Either decimal or hexidecimal value
* - color: Either integer specifing rgb value, or (r,g,b) in which r, g and b are of type integer
* - align: element of enumeration {center, left, right}
*
* Comments:
* The syntax/parser is fairly simplistic. The parser is not trying to match a tag like
* <tag> </tag> as XML/HTML do. Basically, when it encounters a tag (e.g., <b>) it will
* simply instruct the the editor to apply the formatting from the current position as
* specified by the tag (e.g., enable bold). For example, <b><b>Hello</b>World</b> results
* in Hello displayed in a Bold font and World in a normal font.
*
* The only case where state is maintained is when using <fg=color> and </fg>. The current
* fg color is stored when parsing <fg=color> and restored when doing </fg>. Again, <fg> and
* </fg> don't have the XML/HTML <tag> </tag> behavior. For example:
* <fg=red>Peter<fg=blue>was</fg></fg>here
* results in "Peter" displayed in red, "was" displayed in blue and "here" displayed in red.
* It literally goes like this:
* 1) <fg=red> --> apply editor text color red, previous color = whatever the editor's text color is now
* 2) <fg=blue> --> apply editor text color blue, previous color = whatever the editor's text color
* is now --> red
* 3) </fg> --> apply editor text to previous color --> red
* 4) </fg> --> apply editor text to previous color --> red
*
* What you probably wanted was:
* <fg=red>Peter</fg><fg=blue>was</fg>here
* Now "Peter" is displayed in red, "was" in blue and "here" in the default editor's color
*/
static TUint32 ParseInteger(const TDesC& aString)
{
TUint32 val = 0;
TBool parsed = EFalse;
if (aString.Length() > 2)
{
if ((aString[0] == '0') && ((aString[0] == 'x') || (aString[0] == 'X')))
{
TLex lex(aString.Right(aString.Length()-2));
if (lex.Val(val, EHex) != KErrNone)
{
__ASSERT_DEBUG(ETrue, Panic(EBadIntegerParam));
}
parsed = ETrue;
}
}
if (!parsed)
{
TLex lex(aString);
if (lex.Val(val, EDecimal) != KErrNone)
{
__ASSERT_DEBUG(ETrue, Panic(EBadIntegerParam));
}
}
return val;
}
static TRgb ParseColor(const TDesC& aString)
{
if (aString.Length() > 0)
{
if (aString[0] == 'R')
{
if (aString.Compare(_L("RgbBlack")) == 0)
return KRgbBlack;
else if (aString.Compare(_L("RgbDarkGray")) == 0)
return KRgbDarkGray;
else if (aString.Compare(_L("RgbDarkRed")) == 0)
return KRgbDarkRed;
else if (aString.Compare(_L("RgbDarkGreen")) == 0)
return KRgbDarkGreen;
else if (aString.Compare(_L("RgbDarkYellow")) == 0)
return KRgbDarkYellow;
else if (aString.Compare(_L("RgbDarkBlue")) == 0)
return KRgbDarkBlue;
else if (aString.Compare(_L("RgbDarkMagenta")) == 0)
return KRgbDarkMagenta;
else if (aString.Compare(_L("RgbDarkCyan")) == 0)
return KRgbDarkCyan;
else if (aString.Compare(_L("RgbRed")) == 0)
return KRgbRed;
else if (aString.Compare(_L("RgbGreen")) == 0)
return KRgbGreen;
else if (aString.Compare(_L("RgbYellow")) == 0)
return KRgbYellow;
else if (aString.Compare(_L("RgbBlue")) == 0)
return KRgbBlue;
else if (aString.Compare(_L("RgbMagenta")) == 0)
return KRgbMagenta;
else if (aString.Compare(_L("RgbCyan")) == 0)
return KRgbCyan;
else if (aString.Compare(_L("RgbGray")) == 0)
return KRgbGray;
else if (aString.Compare(_L("RgbWhite")) == 0)
return KRgbWhite;
else
{
__ASSERT_DEBUG(ETrue, Panic(EBadRgbColorParam));
}
}
return ParseInteger(aString);
}
__ASSERT_DEBUG(ETrue, Panic(EBadRgbColorParam));
return KRgbBlack;
}
static CParaFormat::TAlignment ParseAlignment(const TDesC& aString)
{
if (aString.Compare(_L("center")) == 0)
{
return CParaFormat::ECenterAlign;
}
else if (aString.Compare(_L("left")) == 0)
{
return CParaFormat::ELeftAlign;
}
else if (aString.Compare(_L("right")) == 0)
{
return CParaFormat::ERightAlign;
}
__ASSERT_DEBUG(ETrue, Panic(EBadAlignmentParam));
return CParaFormat::ECenterAlign;
}
void CSimpleTextFormatParser::ParseTagL(const TDesC& aTag)
{
TInt tagLength = aTag.Length();
if (tagLength == 0)
{
__ASSERT_DEBUG(ETrue, Panic(EBadZeroLengthTag));
return;
}
TPtrC param(_L(""));
TInt pos = aTag.Find(_L("="));
if (pos>0)
{
param.Set(aTag.Right(aTag.Length()-pos-1));
tagLength = pos;
}
TPtrC tag = aTag.Left(tagLength);
// RDebug::Print(_L("tag=%S, param=%S"), &tag, &param);
switch (tagLength)
{
case 1:
{
if (tag.Compare(_L("a")) == 0)
SetAlignment(ParseAlignment(param));
else if (tag.Compare(_L("b")) == 0)
SetBold();
else if (tag.Compare(_L("f")) == 0)
SetFontName(param);
else if (tag.Compare(_L("h")) == 0)
SetHiddenText();
else if (tag.Compare(_L("i")) == 0)
SetItalic();
else if (tag.Compare(_L("p")) == 0)
NewParagraph();
else if (tag.Compare(_L("s")) == 0)
SetFontHeight(ParseInteger(param));
else if (tag.Compare(_L("u")) == 0)
SetUnderLine();
else
{
__ASSERT_DEBUG(ETrue, Panic(EBadTag));
}
break;
}
case 2:
{
if (tag.Compare(_L("/b")) == 0)
SetBold(EFalse);
if (tag.Compare(_L("bg")) == 0)
SetBackgroundColor(ParseColor(param));
if (tag.Compare(_L("fg")) == 0)
{
iPrevFgColor = ForegroundColor();
SetForegroundColor(ParseColor(param));
}
else if (tag.Compare(_L("/h")) == 0)
SetHiddenText(EFalse);
else if (tag.Compare(_L("/i")) == 0)
SetItalic(EFalse);
else if (tag.Compare(_L("/u")) == 0)
SetUnderLine(EFalse);
else if (tag.Compare(_L("/<")) == 0)
AppendTextL(_L("<"));
break;
}
case 3:
{
if (tag.Compare(_L("/fg")) == 0)
SetForegroundColor(iPrevFgColor);
break;
}
default:
;
}
}
void CSimpleTextFormatParser::ParseL(const TDesC& aSimpleText, CRichText& aRichText)
{
iRichText = &aRichText;
iCurrentPara = 0;
TBool done = EFalse;
TPtrC simpleText(aSimpleText);
do
{
TInt pos = simpleText.Locate('<');
if (pos > 0)
{
AppendTextL(simpleText.Left(pos));
simpleText.Set(simpleText.Right(simpleText.Length() - pos));
}
else if (pos == 0)
{
pos = simpleText.Locate('>');
if (pos<=0)
User::Leave(KErrArgument);
ParseTagL(simpleText.Mid(1, pos-1));
simpleText.Set(simpleText.Right(simpleText.Length() - pos - 1));
}
else
{
AppendTextL(simpleText);
done = ETrue;
}
} while (!done);
}
TInt CSimpleTextFormatParser::TextPos()
{
return iRichText->DocumentLength();
#if 0
TInt pos, length;
pos = iRichText->CharPosOfParagraph(length, iCurrentPara);
return pos+length-1;
#endif
}
TInt CSimpleTextFormatParser::ParaPos()
{
return TextPos();
#if 0
TInt pos, length;
pos = iRichText->CharPosOfParagraph(length, iCurrentPara);
return pos+length-1;
#endif
}
void CSimpleTextFormatParser::AppendTextL(const TDesC& aText)
{
// RDebug::Print(_L("text=%S"), &aText);
iRichText->InsertL(TextPos(), aText);
}
#if 0
void CTestDialog::ShowTextL(CRichText& aRichText)
{
aRichText.Reset();
TCharFormat charFormat;
TCharFormatMask charMask;
aRichText.GetCharFormat(charFormat, charMask, 0, 0);
TInt para = 0;
AppendTextL(_L("http://www.yipton.net"), aRichText);
para++;
aRichText.AppendParagraphL();
CParaFormat* paraFormat = CParaFormat::NewLC();
TParaFormatMask paraMask;
aRichText.GetParaFormatL(paraFormat, paraMask, ParaPos(aRichText, para), 0);
paraFormat->iHorizontalAlignment = CParaFormat::ECenterAlign;
paraMask.ClearAll();
paraMask.SetAttrib(EAttAlignment);
aRichText.ApplyParaFormatL(paraFormat, paraMask, ParaPos(aRichText, para), 0);
charFormat.iFontPresentation.iUnderline = EUnderlineOn;
charFormat.iFontSpec.iFontStyle.SetPosture(EPostureItalic);
charMask.ClearAll();
charMask.SetAttrib(EAttFontPosture);
charMask.SetAttrib(EAttFontUnderline);
aRichText.ApplyCharFormatL(charFormat, charMask, TextPos(aRichText, para));
AppendTextL(_L("mailto:Peter is here"), aRichText, para);
para++;
aRichText.AppendParagraphL();
TFontSpec fontSpec(_L("edmunds"), 20 * KPointsPerInch);
// CFont* font = NULL;
// iCoeEnv->ScreenDevice()->GetNearestFontInTwips(font, fontSpec);
charFormat.iFontSpec = fontSpec;
charMask.ClearAll();
charMask.SetAttrib(EAttFontHeight);
charMask.SetAttrib(EAttFontTypeface);
aRichText.ApplyCharFormatL(charFormat, charMask, TextPos(aRichText, para));
AppendTextL(_L("mailto:Peter is here"), aRichText, para);
CleanupStack::PopAndDestroy();
}
#endif

View file

@ -0,0 +1,59 @@
/*******************************************************************
*
* File: CSimpleTextParser.h
*
* Author: Peter van Sebille (peter@yipton.net)
*
* (c) Copyright 2002, Peter van Sebille
* All Rights Reserved
*
*******************************************************************/
#ifndef __CSIMPLE_TEXT_PARSER_H
#define __CSIMPLE_TEXT_PARSER_H
#include <e32def.h>
#include <txtrich.h> // CRichText
#include <eikrted.h> // CEikRichTextEditor
class CSimpleTextFormatParser : public CBase
{
public:
static CSimpleTextFormatParser* NewLC();
void ParseL(const TDesC& aPSTText, CRichText& aRichText);
protected:
CSimpleTextFormatParser(){}
~CSimpleTextFormatParser();
void ConstructL();
void ParseTagL(const TDesC& aTag);
TRgb ForegroundColor();
void SetBold(TBool aEnable=ETrue);
void SetItalic(TBool aEnable=ETrue);
void SetUnderLine(TBool aEnable=ETrue);
void SetFontHeight(TInt aHeight);
void SetFontName(const TDesC& aName);
void SetHiddenText(TBool aEnable=ETrue);
void SetForegroundColor(const TRgb& aColor);
void NewParagraph();
void SetAlignment(CParaFormat::TAlignment aAlignment);
void SetBackgroundColor(const TRgb& aColor);
void AppendTextL(const TDesC& aText);
TInt TextPos();
TInt ParaPos();
CRichText* iRichText;
TCharFormat iCharFormat;
TCharFormatMask iCharMask;
CParaFormat* iParaFormat;
TParaFormatMask iParaMask;
TInt iCurrentPara;
TRgb iPrevFgColor;
};
#endif /* __CSIMPLE_TEXT_PARSER_H */

324
platform/uiq3/Dialogs.cpp Normal file
View file

@ -0,0 +1,324 @@
/*******************************************************************
*
* File: Dialogs.cpp
*
* Author: Peter van Sebille (peter@yipton.net)
*
* Modified/adapted for picodriveN by notaz, 2006
*
* (c) Copyright 2006, notaz
* (c) Copyright 2002, Peter van Sebille
* All Rights Reserved
*
*******************************************************************/
#include "Dialogs.h"
#include "Engine.h"
#include "picodrive.hrh"
#include <picodrive.rsg>
#include "version.h"
#include "CSimpleTextParser.h"
#include <txtrich.h> // CRichText
#include <eikrted.h> // CEikRichTextEditor
#include <qikvertoptionbuttonlist.h> // CEikHorOptionButtonList
#include <eikopbut.h> // CEikOptionButton
#include <eikedwin.h> // CEikEdwin
#include <QuartzKeys.h> // EQuartzKeyTwoWayDown
#include <QikCommand.h>
/************************************************
*
* config Dialog
*
************************************************/
CPicoConfigDialog::CPicoConfigDialog(TPicoConfig &cfg) : config(cfg)
{
}
void CPicoConfigDialog::PostLayoutDynInitL()
{
CEikHorOptionButtonList *buttons_rot = (CEikHorOptionButtonList*) Control( ECtlOptRotation );
CEikHorOptionButtonList *buttons_disp = (CEikHorOptionButtonList*) Control( ECtlOptScreenMode );
CEikCheckBox *chkbox_altrend= (CEikCheckBox*) Control( ECtlOptUseAltRend );
CEikCheckBox *chkbox_acctmng= (CEikCheckBox*) Control( ECtlOptUseAccTiming );
CEikCheckBox *chkbox_sram = (CEikCheckBox*) Control( ECtlOptUseSRAM );
CEikCheckBox *chkbox_fps = (CEikCheckBox*) Control( ECtlOptShowFPS );
CEikCheckBox *chkbox_sound = (CEikCheckBox*) Control( ECtlOptEnableSound );
CEikCheckBox *chkbox_z80 = (CEikCheckBox*) Control( ECtlOptEmulateZ80 );
CEikCheckBox *chkbox_ym2612 = (CEikCheckBox*) Control( ECtlOptEmulateYM2612 );
CEikCheckBox *chkbox_sn76496= (CEikCheckBox*) Control( ECtlOptEmulateSN76496 );
CEikChoiceListBase *combo_sndq = (CEikChoiceListBase*) Control( ECtlOptSndQuality );
CEikCheckBox *chkbox_6bpad = (CEikCheckBox*) Control( ECtlOpt6ButtonPad );
CEikCheckBox *chkbox_gzipst = (CEikCheckBox*) Control( ECtlOptGzipStates );
CEikCheckBox *chkbox_accsprt= (CEikCheckBox*) Control( ECtlOptUseAccSprites );
CEikChoiceListBase *combo_region = (CEikChoiceListBase*) Control( ECtlOptRegion );
CEikOptionButton *opt_fit2 = (CEikOptionButton*) buttons_disp->ComponentControl( TPicoConfig::PMFit2 );
buttons_rot ->SetButtonById(ECtlOptRotation0 + config.iScreenRotation);
buttons_disp->SetButtonById(ECtlOptScreenModeCenter + config.iScreenMode);
chkbox_sram ->SetState(config.iFlags & 1 ? CEikButtonBase::ESet : CEikButtonBase::EClear);
chkbox_fps ->SetState(config.iFlags & 2 ? CEikButtonBase::ESet : CEikButtonBase::EClear);
chkbox_sound ->SetState(config.iFlags & 4 ? CEikButtonBase::ESet : CEikButtonBase::EClear);
chkbox_gzipst ->SetState(config.iFlags & 0x80 ? CEikButtonBase::ESet : CEikButtonBase::EClear);
chkbox_z80 ->SetState(config.iPicoOpt & 4 ? CEikButtonBase::ESet : CEikButtonBase::EClear);
chkbox_ym2612 ->SetState(config.iPicoOpt & 1 ? CEikButtonBase::ESet : CEikButtonBase::EClear);
chkbox_sn76496->SetState(config.iPicoOpt & 2 ? CEikButtonBase::ESet : CEikButtonBase::EClear);
chkbox_altrend->SetState(config.iPicoOpt & 0x10? CEikButtonBase::ESet : CEikButtonBase::EClear);
chkbox_6bpad ->SetState(config.iPicoOpt & 0x20? CEikButtonBase::ESet : CEikButtonBase::EClear);
chkbox_acctmng->SetState(config.iPicoOpt & 0x40? CEikButtonBase::ESet : CEikButtonBase::EClear);
chkbox_accsprt->SetState(config.iPicoOpt & 0x80? CEikButtonBase::ESet : CEikButtonBase::EClear);
// dim "fit2" if we are not in 0 or 180 mode
if(config.iScreenRotation != TPicoConfig::PRot0 && config.iScreenRotation != TPicoConfig::PRot180) opt_fit2->SetDimmed(ETrue);
// dim some stuff for alternative renderer
if(config.iPicoOpt & 0x10) {
// dim accurate sprites
chkbox_accsprt->SetState(CEikButtonBase::EClear);
chkbox_accsprt->SetDimmed(ETrue);
// dim fit
if(buttons_rot->LabeledButtonId() == ECtlOptRotation0 || buttons_rot->LabeledButtonId() == ECtlOptRotation180)
((CEikOptionButton*)(buttons_disp->ComponentControl(TPicoConfig::PMFit)))->SetDimmed(ETrue);
}
TInt sel = (config.iPicoOpt&8) ? 5 : 0;
sel+= (config.iFlags>>3)&7;
if (sel >= 10) sel = 0;
combo_sndq->SetCurrentItem(sel);
switch(config.PicoRegion) {
case 1: sel = 4; break;
case 2: sel = 3; break;
case 4: sel = 2; break;
case 8: sel = 1; break;
default:sel = 0; // auto
}
combo_region->SetCurrentItem(sel);
}
TBool CPicoConfigDialog::OkToExitL(TInt aButtonId)
{
if(aButtonId != EEikBidOk) return ETrue;
CEikHorOptionButtonList *buttons_rot = (CEikHorOptionButtonList*) Control( ECtlOptRotation );
CEikHorOptionButtonList *buttons_disp = (CEikHorOptionButtonList*) Control( ECtlOptScreenMode );
CEikCheckBox *chkbox_altrend= (CEikCheckBox*) Control( ECtlOptUseAltRend );
CEikCheckBox *chkbox_acctmng= (CEikCheckBox*) Control( ECtlOptUseAccTiming );
CEikCheckBox *chkbox_sram = (CEikCheckBox*) Control( ECtlOptUseSRAM );
CEikCheckBox *chkbox_fps = (CEikCheckBox*) Control( ECtlOptShowFPS );
CEikCheckBox *chkbox_sound = (CEikCheckBox*) Control( ECtlOptEnableSound );
CEikCheckBox *chkbox_z80 = (CEikCheckBox*) Control( ECtlOptEmulateZ80 );
CEikCheckBox *chkbox_ym2612 = (CEikCheckBox*) Control( ECtlOptEmulateYM2612 );
CEikCheckBox *chkbox_sn76496= (CEikCheckBox*) Control( ECtlOptEmulateSN76496 );
CEikChoiceListBase *combo_sndq = (CEikChoiceListBase*) Control( ECtlOptSndQuality );
CEikCheckBox *chkbox_6bpad = (CEikCheckBox*) Control( ECtlOpt6ButtonPad );
CEikCheckBox *chkbox_gzipst = (CEikCheckBox*) Control( ECtlOptGzipStates );
CEikCheckBox *chkbox_accsprt= (CEikCheckBox*) Control( ECtlOptUseAccSprites );
CEikChoiceListBase *combo_region = (CEikChoiceListBase*) Control( ECtlOptRegion );
config.iScreenRotation = (TPicoConfig::TPicoScreenRotation) (buttons_rot->LabeledButtonId() - ECtlOptRotation0);
config.iScreenMode = (TPicoConfig::TPicoScreenMode) (buttons_disp->LabeledButtonId() - ECtlOptScreenModeCenter);
if(chkbox_sram ->State() == CEikButtonBase::ESet) config.iFlags |= 1; else config.iFlags &= ~1;
if(chkbox_fps ->State() == CEikButtonBase::ESet) config.iFlags |= 2; else config.iFlags &= ~2;
if(chkbox_sound ->State() == CEikButtonBase::ESet) config.iFlags |= 4; else config.iFlags &= ~4;
if(chkbox_gzipst ->State() == CEikButtonBase::ESet) config.iFlags |= 0x80; else config.iFlags &= ~0x80;
if(chkbox_z80 ->State() == CEikButtonBase::ESet) config.iPicoOpt |= 4; else config.iPicoOpt &= ~4;
if(chkbox_ym2612 ->State() == CEikButtonBase::ESet) config.iPicoOpt |= 1; else config.iPicoOpt &= ~1;
if(chkbox_sn76496->State() == CEikButtonBase::ESet) config.iPicoOpt |= 2; else config.iPicoOpt &= ~2;
if(chkbox_altrend->State() == CEikButtonBase::ESet) config.iPicoOpt |= 0x10;else config.iPicoOpt &= ~0x10;
if(chkbox_6bpad ->State() == CEikButtonBase::ESet) config.iPicoOpt |= 0x20;else config.iPicoOpt &= ~0x20;
if(chkbox_acctmng->State() == CEikButtonBase::ESet) config.iPicoOpt |= 0x40;else config.iPicoOpt &= ~0x40;
if(chkbox_accsprt->State() == CEikButtonBase::ESet) config.iPicoOpt |= 0x80;else config.iPicoOpt &= ~0x80;
TInt sel = combo_sndq->CurrentItem();
if(sel >= 5) { config.iPicoOpt |= 8; sel-=5; } else config.iPicoOpt &= ~8;
config.iFlags &= ~0x38;
config.iFlags |= (sel<<3)&0x38;
switch(combo_region->CurrentItem()) {
case 4: config.PicoRegion = 1; break;
case 3: config.PicoRegion = 2; break;
case 2: config.PicoRegion = 4; break;
case 1: config.PicoRegion = 8; break;
default:config.PicoRegion = 0; // auto
}
return ETrue;
}
// simple GUI stuff needs lots of code
void CPicoConfigDialog::HandleControlStateChangeL(TInt aControlId)
{
if(aControlId == ECtlOptEnableSound) {
CEikCheckBox *chkbox_sound = (CEikCheckBox*) Control( ECtlOptEnableSound );
CEikCheckBox *chkbox_z80 = (CEikCheckBox*) Control( ECtlOptEmulateZ80 );
CEikCheckBox *chkbox_ym2612 = (CEikCheckBox*) Control( ECtlOptEmulateYM2612 );
CEikCheckBox *chkbox_sn76496= (CEikCheckBox*) Control( ECtlOptEmulateSN76496 );
if(chkbox_sound->State() == CEikButtonBase::ESet) {
// check all sound chips too, but only if they all are not set
if((chkbox_z80->State() | chkbox_ym2612->State() | chkbox_sn76496->State()) == CEikButtonBase::EClear) { // (==0)
chkbox_z80 ->SetState(CEikButtonBase::ESet);
chkbox_ym2612 ->SetState(CEikButtonBase::ESet);
chkbox_sn76496->SetState(CEikButtonBase::ESet);
chkbox_z80 ->DrawDeferred();
chkbox_ym2612 ->DrawDeferred();
chkbox_sn76496->DrawDeferred();
}
} else {
// clear everything, but only if everything is set
if((chkbox_z80->State() & chkbox_ym2612->State() & chkbox_sn76496->State()) == CEikButtonBase::ESet) { // (==1)
chkbox_z80 ->SetState(CEikButtonBase::EClear);
chkbox_ym2612 ->SetState(CEikButtonBase::EClear);
chkbox_sn76496->SetState(CEikButtonBase::EClear);
chkbox_z80 ->DrawDeferred();
chkbox_ym2612 ->DrawDeferred();
chkbox_sn76496->DrawDeferred();
}
}
} else if(aControlId == ECtlOptUseAltRend || aControlId == ECtlOptRotation) {
CEikCheckBox *chkbox_altrend= (CEikCheckBox*) Control( ECtlOptUseAltRend );
CEikCheckBox *chkbox_accsprt= (CEikCheckBox*) Control( ECtlOptUseAccSprites );
CEikHorOptionButtonList *buttons_rot = (CEikHorOptionButtonList*) Control( ECtlOptRotation );
CEikHorOptionButtonList *buttons_disp = (CEikHorOptionButtonList*) Control( ECtlOptScreenMode );
CEikOptionButton *opt_fit = (CEikOptionButton*) buttons_disp->ComponentControl( TPicoConfig::PMFit );
CEikOptionButton *opt_fit2 = (CEikOptionButton*) buttons_disp->ComponentControl( TPicoConfig::PMFit2 );
TBool dimmed = chkbox_altrend->State() == CEikButtonBase::ESet;
// show/hide more stuff for alternative renderer
chkbox_accsprt->SetDimmed(dimmed);
if(buttons_rot->LabeledButtonId() == ECtlOptRotation0 || buttons_rot->LabeledButtonId() == ECtlOptRotation180) {
opt_fit->SetDimmed(dimmed);
if(dimmed && buttons_disp->LabeledButtonId() == ECtlOptScreenModeFit)
buttons_disp->SetButtonById(ECtlOptScreenModeFit2);
}
else opt_fit->SetDimmed(EFalse);
chkbox_accsprt->DrawDeferred();
buttons_disp->DrawDeferred();
if(buttons_rot->LabeledButtonId() == ECtlOptRotation0 || buttons_rot->LabeledButtonId() == ECtlOptRotation180) {
opt_fit2->SetDimmed(EFalse);
} else {
if(opt_fit2->State() == CEikButtonBase::ESet) {
buttons_disp->SetButtonById(ECtlOptScreenModeFit);
buttons_disp->DrawDeferred();
}
opt_fit2->SetDimmed(ETrue);
}
opt_fit2->DrawDeferred();
}
}
/************************************************
*
* About Dialog
*
************************************************/
void CAboutDialog::PostLayoutDynInitL()
{
TBuf<16> versionText;
TBuf<512> text;
#if (KPicoBuildNumber != 0)
versionText.Format(_L("%d.%d%d"), KPicoMajorVersionNumber, KPicoMinorVersionNumber, KPicoBuildNumber);
#else
versionText.Format(_L("%d.%d"), KPicoMajorVersionNumber, KPicoMinorVersionNumber);
#endif
CEikRichTextEditor* richTextEd = LocateControlByUniqueHandle<CEikRichTextEditor>(ECtlPicoAboutText);
User::LeaveIfNull(richTextEd);
HBufC *aboutFormat = CEikonEnv::Static()->AllocReadResourceLC(R_PICO_TEXT_ABOUT);
CSimpleTextFormatParser *parser = CSimpleTextFormatParser::NewLC();
text.Format(*aboutFormat, &versionText);
parser->ParseL(text, *richTextEd->RichText());
richTextEd->UpdateAllFieldsL(); // Updates all the fields in the document
CleanupStack::PopAndDestroy(parser);
CleanupStack::PopAndDestroy(aboutFormat);
}
/*************************************************************
*
* Credits dialog
*
**************************************************************/
void CCreditsDialog::PreLayoutDynInitL()
{
CEikEdwin *edwin = LocateControlByUniqueHandle<CEikEdwin>(ECtlPicoCreditsText);
User::LeaveIfNull(edwin);
CDesCArrayFlat* desArray = CEikonEnv::Static()->ReadDesCArrayResourceL(R_PICO_TBUF_CREDITS);
CleanupStack::PushL(desArray);
edwin->SetTextLimit(2048); // to prevent stupid "too big" warning
TInt count = desArray->Count();
for (TInt i = 0; i < count; i++)
{
edwin->Text()->InsertL(edwin->TextLength(), desArray->operator[](i));
edwin->Text()->InsertL(edwin->TextLength(), CEditableText::ELineBreak);
}
CleanupStack::PopAndDestroy(desArray);
}
TKeyResponse CCreditsDialog::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
{
if (aType == EEventKey)
{
CEikEdwin *edwin = LocateControlByUniqueHandle<CEikEdwin>(ECtlPicoCreditsText);
User::LeaveIfNull(edwin);
if (aKeyEvent.iCode == EQuartzKeyTwoWayDown)
{
edwin->MoveDisplayL(TCursorPosition::EFLineDown);
edwin->UpdateScrollBarsL();
return EKeyWasConsumed;
}
else if (aKeyEvent.iCode == EQuartzKeyTwoWayUp)
{
edwin->MoveDisplayL(TCursorPosition::EFLineUp);
edwin->UpdateScrollBarsL();
return EKeyWasConsumed;
}
}
return CQikSimpleDialog::OfferKeyEventL(aKeyEvent, aType);
}
/*************************************************************
*
* Debug dialog
*
**************************************************************/
CDebugDialog::CDebugDialog(char *t)
{
Mem::Copy(iText, t, 1024);
iText[1023] = 0;
}
void CDebugDialog::PreLayoutDynInitL()
{
char *p = iText, *line = iText;
TBool end=0;
TBuf<128> tbuf;
CEikEdwin *editor = LocateControlByUniqueHandle<CEikEdwin>(ECtlPicoCreditsText);
while(!end) {
while(*p && *p != '\r' && *p != '\n') p++;
if(!*p) end=1;
*p = 0;
TPtrC8 ptr((TUint8*) line);
tbuf.Copy(ptr);
editor->Text()->InsertL(editor->TextLength(), tbuf);
editor->Text()->InsertL(editor->TextLength(), CEditableText::ELineBreak);
line = ++p;
}
}

94
platform/uiq3/Dialogs.h Normal file
View file

@ -0,0 +1,94 @@
/*******************************************************************
*
* File: Dialogs.h
*
* Author: Peter van Sebille (peter@yipton.net)
*
* Modified/adapted for picodriveN by notaz, 2006
*
* (c) Copyright 2006, notaz
* (c) Copyright 2002, Peter van Sebille
* All Rights Reserved
*
*******************************************************************/
#ifndef __DIALOGS_H
#define __DIALOGS_H
#include <eikenv.h>
#include <eikdialg.h>
#include <eiktxlbx.h>
#include <eiktxlbm.h>
#include <eikdlgtb.h>
#include <eiklabel.h>
#include <eikchlst.h>
#include <eikchkbx.h>
#include <eikedwob.h>
#include <QikSimpleDialog.h>
/************************************************
*
* config Dialog
*
************************************************/
class TPicoConfig;
class CPicoConfigDialog : public CEikDialog
{
public:
CPicoConfigDialog(TPicoConfig &cfg);
protected: // framework
void PostLayoutDynInitL();
void HandleControlStateChangeL(TInt aControlId);
TBool OkToExitL(TInt aButtonId);
TPicoConfig &config;
};
/************************************************
*
* About Dialog
*
************************************************/
class CAboutDialog : public CQikSimpleDialog
{
protected: // from CQikSimpleDialog
void PostLayoutDynInitL();
};
/*************************************************************
*
* Credits dialog
*
**************************************************************/
class CCreditsDialog : public CQikSimpleDialog
{
protected: // from CQikSimpleDialog
void PreLayoutDynInitL();
TKeyResponse OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType);
};
/*************************************************************
*
* Debug dialog
*
**************************************************************/
class CDebugDialog : public CCreditsDialog
{
public:
CDebugDialog(char *t);
protected:
char iText[1024];
void PreLayoutDynInitL();
};
#endif // __DIALOGS_H

484
platform/uiq3/Engine.cpp Normal file
View file

@ -0,0 +1,484 @@
/*******************************************************************
*
* File: Engine.cpp
*
* Author: Peter van Sebille (peter@yipton.net)
*
* Modified/adapted for picodriveN by notaz, 2006
*
* (c) Copyright 2006, notaz
* (c) Copyright 2002, Peter van Sebille
* All Rights Reserved
*
*******************************************************************/
#include "Engine.h"
#include <w32std.h>
#include <eikenv.h>
#include <e32svr.h>
#include <e32math.h>
#include <e32uid.h>
#include <string.h>
#include "version.h"
#include "../../pico/picoInt.h"
#include "engine/debug.h"
#include "app.h"
// this is where we start to break a bunch of symbian rules
extern TInt machineUid;
extern int gamestate, gamestate_next;
extern TPicoConfig *currentConfig;
extern const char *actionNames[];
RSemaphore pauseSemaphore;
RSemaphore initSemaphore;
const char *RomFileName = 0;
int pico_was_reset = 0;
unsigned char *rom_data = 0;
static CPicolAppView *appView = 0;
TInt CPicoGameSession::Do(const TPicoServRqst what, TAny *param)
{
switch (what) {
case PicoMsgLoadState:
if(!rom_data) return -1; // no ROM
return saveLoadGame(1);
case PicoMsgSaveState:
if(!rom_data) return -1;
return saveLoadGame(0);
case PicoMsgLoadROM:
return loadROM((TPtrC16 *)param);
case PicoMsgResume:
DEBUGPRINT(_L("resume with rom %08x"), rom_data);
if(rom_data) {
return ChangeRunState(PGS_Running);
}
return 1;
case PicoMsgReset:
if(rom_data) {
PicoReset(0);
pico_was_reset = 1;
return ChangeRunState(PGS_Running);
}
return 1;
case PicoMsgKeys:
return ChangeRunState(PGS_KeyConfig);
case PicoMsgPause:
return ChangeRunState(PGS_Paused);
case PicoMsgQuit:
DEBUGPRINT(_L("got quit msg."));
return ChangeRunState(PGS_Quit);
// config change
case PicoMsgConfigChange:
return changeConfig((TPicoConfig *)param);
case PicoMsgSetAppView:
appView = (CPicolAppView *)param;
return 1;
default:
return 1;
}
}
TInt EmuThreadFunction(TAny* anArg);
TInt CPicoGameSession::StartEmuThread()
{
TInt res=KErrNone;
iEmuRunning = EFalse;
if (initSemaphore.Handle() > 0)
initSemaphore.Close();
initSemaphore.CreateLocal(0);
if (pauseSemaphore.Handle() <= 0)
pauseSemaphore.CreateLocal(0);
RThread thread;
if(iThreadWatcher && (res = thread.Open(iThreadWatcher->iTid)) == KErrNone) {
// should be a dead thread in some strange state.
DEBUGPRINT(_L("found thread with the same id (id=%i, RequestCount=%i), killing.."),
(TInt32)thread.Id(), thread.RequestCount());
// what can we do in this situation? Nothing seems to help, it just stays in this state.
delete iThreadWatcher;
iThreadWatcher = 0;
thread.Kill(1);
thread.Terminate(1);
thread.Close();
}
//semaphore.CreateLocal(0); // create a semaphore so we know when thread init is finished
res=thread.Create(_L("PicoEmuThread"), // create new server thread
EmuThreadFunction, // thread's main function
KDefaultStackSize,
KMinHeapSize,
KPicoMaxHeapSize,
0 // &semaphore // passed as TAny* argument to thread function
);
if(res == KErrNone) { // thread created ok - now start it going
thread.SetPriority(EPriorityMore);
iEmuRunning = ETrue;
if (iThreadWatcher) delete iThreadWatcher;
iThreadWatcher = CThreadWatcher::NewL(thread.Id());
thread.Resume(); // start it going
DEBUGPRINT(_L("initSemaphore.Wait()"));
res = initSemaphore.Wait(1000*1000); // wait until it's initialized
DEBUGPRINT(_L("initSemaphore resume, ExitReason() == %i"), thread.ExitReason());
res |= thread.ExitReason();
thread.Close(); // we're no longer interested in the other thread
if(res != KErrNone) iEmuRunning = EFalse;
return res;
}
return res;
}
TInt CPicoGameSession::ChangeRunState(TPicoGameState newstate, TPicoGameState newstate_next)
{
if (!iEmuRunning) {
gamestate = PGS_Paused;
TInt res = StartEmuThread();
if(res != KErrNone) DEBUGPRINT(_L("StartEmuThread() returned %i"), res);
if (!iEmuRunning) return PicoErrEmuThread;
}
int oldstate = gamestate;
gamestate = newstate;
gamestate_next = newstate_next ? newstate_next : PGS_Paused;
if (oldstate == PGS_Paused) pauseSemaphore.Signal();
return 0;
}
TInt CPicoGameSession::loadROM(TPtrC16 *pptr)
{
TInt res, i;
char buff[0x31];
if(rom_data) {
// save SRAM for previous ROM
if(currentConfig->iFlags & 1)
saveLoadGame(0, 1);
}
RomFileName = 0;
if(rom_data) {
free(rom_data);
rom_data = 0;
}
// read the contents of the client pointer into a TPtr.
static TBuf8<KMaxFileName> writeBuf;
writeBuf.Copy(*pptr);
// detect wrong extensions (.srm and .mds)
TBuf8<5> ext;
ext.Copy(writeBuf.Right(4));
ext.LowerCase();
if(!strcmp((char *)ext.PtrZ(), ".srm") || !strcmp((char *)ext.PtrZ(), "s.gz") || // .mds.gz
!strcmp((char *)ext.PtrZ(), ".mds")) {
return PicoErrNotRom;
}
FILE *rom = fopen((char *) writeBuf.PtrZ(), "rb");
if(!rom) {
DEBUGPRINT(_L("failed to open rom."));
return PicoErrRomOpenFailed;
}
// make sure emu thread is ok
res = ChangeRunState(PGS_Paused);
if(res) {
fclose(rom);
return res;
}
unsigned int rom_size = 0;
// zipfile support
if(!strcmp((char *)ext.PtrZ(), ".zip")) {
fclose(rom);
res = CartLoadZip((const char *) writeBuf.PtrZ(), &rom_data, &rom_size);
if(res) {
DEBUGPRINT(_L("CartLoadZip() failed (%i)"), res);
return res;
}
} else {
if( (res = PicoCartLoad(rom, &rom_data, &rom_size)) ) {
DEBUGPRINT(_L("PicoCartLoad() failed (%i)"), res);
fclose(rom);
return PicoErrOutOfMem;
}
fclose(rom);
}
// detect wrong files (Pico crashes on very small files), also see if ROM EP is good
if(rom_size <= 0x200 || strncmp((char *)rom_data, "Pico", 4) == 0 ||
((*(TUint16 *)(rom_data+4)<<16)|(*(TUint16 *)(rom_data+6))) >= (int)rom_size) {
free(rom_data);
rom_data = 0;
return PicoErrNotRom;
}
DEBUGPRINT(_L("PicoCartInsert(0x%08X, %d);"), rom_data, rom_size);
if(PicoCartInsert(rom_data, rom_size)) {
return PicoErrOutOfMem;
}
pico_was_reset = 1;
// global ROM file name for later use
RomFileName = (const char *) writeBuf.PtrZ();
// name from the ROM itself
for(i = 0; i < 0x30; i++)
buff[i] = rom_data[0x150 + (i^1)]; // unbyteswap
for(buff[i] = 0, i--; i >= 0; i--) {
if(buff[i] != ' ') break;
buff[i] = 0;
}
TPtrC8 buff8((TUint8*) buff);
iRomInternalName.Copy(buff8);
// load SRAM for this ROM
if(currentConfig->iFlags & 1)
saveLoadGame(1, 1);
// debug
#ifdef __DEBUG_PRINT
TInt cells = User::CountAllocCells();
TInt mem;
User::AllocSize(mem);
DEBUGPRINT(_L("comm: cels=%d, size=%d KB"), cells, mem/1024);
ChangeRunState(PGS_DebugHeap, PGS_Running);
#else
ChangeRunState(PGS_Running);
#endif
return 0;
}
TInt CPicoGameSession::changeConfig(TPicoConfig *aConfig)
{
DEBUGPRINT(_L("got new config."));
currentConfig = aConfig;
// set PicoOpt and rate
PicoRegionOverride = currentConfig->PicoRegion;
PicoOpt = currentConfig->iPicoOpt;
switch((currentConfig->iFlags>>3)&7) {
case 1: PsndRate=11025; break;
case 2: PsndRate=16000; break;
case 3: PsndRate=22050; break;
case 4: PsndRate=44100; break;
default: PsndRate= 8000; break;
}
// 6 button pad, enable XYZM config if needed
if(PicoOpt & 0x20) {
actionNames[8] = "Z";
actionNames[9] = "Y";
actionNames[10] = "X";
actionNames[11] = "MODE";
} else {
actionNames[8] = actionNames[9] = actionNames[10] = actionNames[11] = 0;
}
// if we are in center 90||270 modes, we can bind renderer switcher
if(currentConfig->iScreenMode == TPicoConfig::PMFit &&
(currentConfig->iScreenRotation == TPicoConfig::PRot0 || currentConfig->iScreenRotation == TPicoConfig::PRot180))
actionNames[25] = 0;
else actionNames[25] = "RENDERER";
return 0;
}
void MainOldCleanup(); // from main.cpp
#ifdef __DEBUG_PRINT_FILE
extern RMutex logMutex;
#endif
void CPicoGameSession::freeResources()
{
RThread thread;
TInt i;
DEBUGPRINT(_L("CPicoGameSession::freeResources()"));
if(iThreadWatcher && thread.Open(iThreadWatcher->iTid) == KErrNone)
{
// try to stop our emu thread
gamestate = PGS_Quit;
if(pauseSemaphore.Handle() > 0)
pauseSemaphore.Signal();
if(thread.Handle() > 0)
{
// tried reopening thread handle here over time intervals to detect if thread is alive,
// but would run into handle panics.
for(i = 0; i < 8; i++) {
User::After(100 * 1000);
if(thread.ExitReason() != 0) break;
}
if(thread.ExitReason() == 0) {
// too late, time to die
DEBUGPRINT(_L("thread %i not responding, killing.."), (TInt32) thread.Id());
thread.Terminate(1);
}
thread.Close();
}
}
if(iThreadWatcher != NULL)
{
DEBUGPRINT(_L("delete iThreadWatcher"));
delete iThreadWatcher;
DEBUGPRINT(_L("after delete iThreadWatcher"));
iThreadWatcher = NULL;
}
MainOldCleanup();
if (initSemaphore.Handle() > 0)
initSemaphore.Close();
if (pauseSemaphore.Handle() > 0)
pauseSemaphore.Close();
#ifdef __DEBUG_PRINT_FILE
if (logMutex.Handle() > 0)
logMutex.Close();
#endif
}
TBool CPicoGameSession::iEmuRunning = EFalse;
CThreadWatcher *CPicoGameSession::iThreadWatcher = 0;
TBuf<0x30> CPicoGameSession::iRomInternalName;
void TPicoConfig::SetDefaults()
{
iLastROMFile.SetLength(0);
iScreenRotation = PRot270;
iScreenMode = PMCenter;
iFlags = 1; // use_sram
iPicoOpt = 0; // all off
iFrameskip = PFSkipAuto;
Mem::FillZ(iKeyBinds, sizeof(iKeyBinds));
Mem::FillZ(iAreaBinds, sizeof(iAreaBinds));
iKeyBinds[0xd5] = 1<<26; // bind back
}
// load config
void TPicoConfig::InternalizeL(RReadStream &aStream)
{
TInt32 version, fname_len;
version = aStream.ReadInt32L();
fname_len = aStream.ReadInt32L();
// not sure if this is safe
iLastROMFile.SetMax();
aStream.ReadL((TUint8 *) iLastROMFile.Ptr(), KMaxFileName*2);
iLastROMFile.SetLength(fname_len);
iScreenRotation = aStream.ReadInt32L();
iScreenMode = aStream.ReadInt32L();
iFlags = aStream.ReadUint32L();
iPicoOpt = aStream.ReadInt32L();
iFrameskip = aStream.ReadInt32L();
aStream.ReadL((TUint8 *)iKeyBinds, sizeof(iKeyBinds));
aStream.ReadL((TUint8 *)iAreaBinds, sizeof(iAreaBinds));
PicoRegion = aStream.ReadInt32L();
}
// save config
void TPicoConfig::ExternalizeL(RWriteStream &aStream) const
{
TInt version = (KPicoMajorVersionNumber<<24)+(KPicoMinorVersionNumber<<16);
aStream.WriteInt32L(version);
aStream.WriteInt32L(iLastROMFile.Length());
aStream.WriteL((const TUint8 *)iLastROMFile.Ptr(), KMaxFileName*2);
aStream.WriteInt32L(iScreenRotation);
aStream.WriteInt32L(iScreenMode);
aStream.WriteUint32L(iFlags);
aStream.WriteInt32L(iPicoOpt);
aStream.WriteInt32L(iFrameskip);
aStream.WriteL((const TUint8 *)iKeyBinds, sizeof(iKeyBinds));
aStream.WriteL((const TUint8 *)iAreaBinds, sizeof(iAreaBinds));
aStream.WriteInt32L(PicoRegion);
}
// CThreadWatcher
CThreadWatcher::~CThreadWatcher()
{
Cancel();
DEBUGPRINT(_L("after CThreadWatcher::Cancel();"));
}
CThreadWatcher::CThreadWatcher(const TThreadId& aTid)
: CActive(CActive::EPriorityStandard), iTid(aTid)
{
}
CThreadWatcher* CThreadWatcher::NewL(const TThreadId& aTid)
{
CThreadWatcher* self = new(ELeave) CThreadWatcher(aTid);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(); // self
return self;
}
void CThreadWatcher::ConstructL()
{
CActiveScheduler::Add(this);
RThread thread;
if(thread.Open(iTid) == KErrNone) {
thread.Logon(iStatus);
thread.Close();
SetActive();
}
}
void CThreadWatcher::RunL()
{
DEBUGPRINT(_L("CThreadWatcher::RunL()"));
CPicoGameSession::iEmuRunning = EFalse;
if(appView) appView->UpdateCommandList();
//initSemaphore.Signal(); // no point to do that here, AS can't get here if it is waiting
}
void CThreadWatcher::DoCancel()
{
RThread thread;
DEBUGPRINT(_L("CThreadWatcher::DoCancel()"));
if(thread.Open(iTid) == KErrNone) {
DEBUGPRINT(_L("thread.LogonCancel(iStatus);"));
thread.LogonCancel(iStatus);
thread.Close();
}
}

159
platform/uiq3/Engine.h Normal file
View file

@ -0,0 +1,159 @@
/*******************************************************************
*
* File: Engine.h
*
* Author: Peter van Sebille (peter@yipton.net)
*
* Modified/adapted for picodriveN by notaz, 2006
*
* (c) Copyright 2006, notaz
* (c) Copyright 2002, Peter van Sebille
* All Rights Reserved
*
*******************************************************************/
#ifndef __ENGINE_H
#define __ENGINE_H
#include <e32base.h>
class RReadStream;
class RWriteStream;
// engine states
enum TPicoGameState {
PGS_Running = 1,
PGS_Paused,
PGS_Quit,
PGS_KeyConfig,
PGS_DebugHeap,
};
enum TPicoServRqst {
PicoMsgLoadState,
PicoMsgSaveState,
PicoMsgLoadROM,
PicoMsgResume,
PicoMsgReset,
PicoMsgKeys,
PicoMsgPause,
PicoMsgQuit,
PicoMsgConfigChange,
PicoMsgSetAppView,
kDefaultMessageSlots // this is how many messages we need :)
};
enum TPicoGenErrors { // generic errors
PicoErrNoErr = 0, // OK
PicoErrRomOpenFailed,
PicoErrOutOfMem,
PicoErrNotRom,
PicoErrNoRomsInArchive,
PicoErrUncomp, // 5
PicoErrOutOfMemSnd,
PicoErrGenSnd, // 7 generic sound system error
PicoErrEmuThread
};
// needed for creating server thread.
const TUint KPicoMaxHeapSize=0x00800000;
// key config entry (touchpad areas)
struct TPicoAreaConfigEntry {
TRect rect;
//unsigned long actions;
};
struct TPicoKeyConfigEntry
{
unsigned short keyCode;
unsigned char scanCode;
unsigned char flags; // lsb->msb: key_down, pulse_only, ?, ?, ?, ?, not_configurable, disabled
TInt32 handle1; // for CancelCaptureKeyUpAndDowns()
TInt32 handle2; // for CancelCaptureKey()
char *name;
};
// configuration data
class TPicoConfig
{
public:
void SetDefaults();
void InternalizeL(RReadStream &aStream);
void ExternalizeL(RWriteStream &aStream) const;
enum TPicoScreenRotation {
PRot0,
PRot90,
PRot180,
PRot270
};
enum TPicoScreenMode {
PMCenter,
PMFit,
PMFit2
};
enum TPicoFrameSkip {
PFSkipAuto = -1,
PFSkip0
};
public:
TFileName iLastROMFile;
TInt32 iScreenRotation;
TInt32 iScreenMode;
TUint32 iFlags; // LSb->MSb: use_sram, show_fps, enable_sound, sound_rate(3bits), gzip_saves{=0x40}, dont_use_mot_vol
// enable_ym2612&dac, enable_sn76496, enable_z80, stereo_sound;
// alt_renderer, 6button_gamepad, accurate_timing
TInt32 iPicoOpt;
TInt32 iFrameskip;
TUint32 iKeyBinds[256]; // a binding for every keycode
TUint32 iAreaBinds[19];
TInt32 PicoRegion;
};
class CThreadWatcher : public CActive
{
public:
static CThreadWatcher* NewL(const TThreadId& aTid);
~CThreadWatcher();
TThreadId iTid; // thread id
protected:
CThreadWatcher(const TThreadId& aTid);
void ConstructL();
virtual void RunL();
virtual void DoCancel();
};
class CPicoGameSession
{
public:
static TInt Do(const TPicoServRqst what, TAny *param=0);
static void freeResources();
static TBool iEmuRunning;
static TBuf<0x30> iRomInternalName;
private:
// services available
static TInt StartEmuThread();
static TInt ChangeRunState(TPicoGameState newstate, TPicoGameState newstate_next=(TPicoGameState)0);
static TInt loadROM(TPtrC16 *pptr);
static TInt changeConfig(TPicoConfig *aConfig);
static CThreadWatcher *iThreadWatcher;
};
// global
int saveLoadGame(int load, int sram=0);
#endif

307
platform/uiq3/Makefile Normal file
View file

@ -0,0 +1,307 @@
# makefile for GCCE
# settings
#dprint = 1
asm_memory = 1
asm_render = 1
asm_blit = 1
#use_musashi = 1
#up = 1
#sis = 1
# targets
all: $(EPOCROOT2)epoc32 MAKEDIRS RESOURCES PicoDrive.exe
clean :
@perl -S ermdir.pl _build
@erase 2>>nul rsc\*.rsc
@erase 2>>nul rsc\*.rsg
@erase 2>>nul rsc\PicoDrive.mb?
# paths
$(EPOCROOT2)epoc32 :
@echo Please set EPOCROOT2 environmental variable to full path to your SDK
@echo with ending slash (something like C:\Uiq_21\)
@cd : 2> NUL # do something stupid to make it silently fail
# resource compiler hates drive lettered paths
EPOCROOT2_NODRV = $(filter \\%,$(subst :, ,$(EPOCROOT2)))
EPOCLIB = $(EPOCROOT2)EPOC32\RELEASE\ARMV5
# C/C++ Compiler
CC=arm-none-symbianelf-gcc
# Linker
LD=arm-none-symbianelf-ld
# Assembler
ASM=arm-none-symbianelf-as
# Archiver
AR=arm-none-symbianelf-ar
# Strip
STRIP=arm-none-symbianelf-strip
# gcc config
GCCDEFINES = -DNDEBUG -D_UNICODE -D__GCCE__ -D__SYMBIAN32__ -D__EPOC32__ -D__MARM__ \
-D__EABI__ -D__MARM_ARMV5__ -D__EXE__ -D__SUPPORT_CPP_EXCEPTIONS__ \
-D__MARM_ARMV5__ -D__PRODUCT_INCLUDE__=\"$(EPOCROOT2)epoc32/include/variant/UIQ_3.0.hrh\"
GCCDEFINES += -D_UNZIP_SUPPORT -D__BROKEN_FWRITE
# 'CSL Arm Toolchain' stuff must be specified after Symbian includes
GCCINCLUDES = -I "$(EPOCROOT2)epoc32\include\variant" -I "$(EPOCROOT2)EPOC32\INCLUDE" -I "$(EPOCROOT2)EPOC32\INCLUDE\LIBC" \
-I "$(EPOCROOT2)\CSL Arm Toolchain\lib\gcc\arm-none-symbianelf\3.4.3\include" -I.
# -funit-at-a-time is not compatible with SDK, it either has linker problems or does not start on device
GCCCOMMFLAGS = -Wall -Wno-unknown-pragmas -fexceptions -march=armv5t -mapcs -pipe -nostdinc -msoft-float \
$(GCCINCLUDES) -include "$(EPOCROOT2)EPOC32/INCLUDE/GCCE/GCCE.h" -marm
GCCCPPFLAGS = -x c++ -Wno-ctor-dtor-privacy -O3 -fno-unit-at-a-time
GCCCFLAGS = -x c -O3 -fno-unit-at-a-time
GCCLDFLAGS = -L"$(EPOCROOT2)CSL Arm Toolchain\arm-none-symbianelf\lib" \
-L"$(EPOCROOT2)CSL Arm Toolchain\lib\gcc\arm-none-symbianelf\3.4.3" \
--target1-abs --no-undefined -nostdlib -shared -Ttext 0x8000 -Tdata 0x400000 --default-symver
# libs
LIBS = \
$(EPOCLIB)\LIB\ESTLIB.dso \
$(EPOCLIB)\urel\qikalloc.lib \
$(EPOCLIB)\LIB\euser.dso \
$(EPOCLIB)\LIB\apparc.dso \
$(EPOCLIB)\LIB\cone.dso \
$(EPOCLIB)\LIB\eikcore.dso \
$(EPOCLIB)\LIB\eikcoctl.dso \
$(EPOCLIB)\LIB\qikcore.dso \
$(EPOCLIB)\LIB\qikdlg.dso \
$(EPOCLIB)\LIB\etext.dso \
$(EPOCLIB)\LIB\bafl.dso \
$(EPOCLIB)\LIB\efsrv.dso \
$(EPOCLIB)\LIB\eikctl.dso \
$(EPOCLIB)\LIB\WS32.dso \
$(EPOCLIB)\LIB\EIKDLG.dso \
$(EPOCLIB)\LIB\GDI.dso \
$(EPOCLIB)\LIB\estor.dso \
$(EPOCLIB)\LIB\EZLIB.dso \
$(EPOCLIB)\LIB\HAL.dso \
$(EPOCLIB)\LIB\mediaclient.dso \
$(EPOCLIB)\LIB\mediaclientaudiostream.dso
LIBS += \
$(EPOCLIB)\LIB\qikallocdll.dso \
$(EPOCLIB)\UREL\usrt2_2.lib \
$(EPOCLIB)\LIB\dfpaeabi.dso \
$(EPOCLIB)\LIB\dfprvct2_2.dso \
$(EPOCLIB)\LIB\drtaeabi.dso \
$(EPOCLIB)\LIB\scppnwdl.dso \
$(EPOCLIB)\LIB\drtrvct2_2.dso
# objects
# launcher
OBJECTS += _build\App.o _build\Engine.o _build\Dialogs.o _build\CSimpleTextParser.o
# engine
OBJECTS += _build\main.o _build\vid.o _build\polledas.o _build\audio_mediaserver.o _build\debug.o
# Pico
OBJECTS += _build\Area.o _build\Cart.o _build\Utils.o _build\Memory.o _build\Misc.o \
_build\Pico.o _build\Sek.o _build\VideoPort.o _build\Draw2.o _build\Draw.o
# asm stuff
ifeq "$(asm_render)" "1"
GCCDEFINES += -D_ASM_DRAW_C
OBJECTS += _build\draw_asm.o _build\draw2_asm.o
endif
ifeq "$(asm_memory)" "1"
GCCDEFINES += -D_ASM_MEMORY_C
OBJECTS += _build\memory_asm.o
endif
# Pico - sound
OBJECTS += _build\sound.o _build\sn76496.o _build\ym2612.o
# misc
OBJECTS += _build\unzip.o _build\gzio_symb.o
# CPU cores
ifeq "$(use_musashi)" "1"
GCCDEFINES += -DEMU_M68K
OBJECTS += _build\m68kcpu.o _build\m68kopac.o _build\m68kopdm.o _build\m68kopnz.o _build\m68kops.o
else
GCCDEFINES += -DEMU_C68K
OBJECTS += _build\Cyclone.o
endif
ifeq "$(asm_blit)" "1"
OBJECTS += _build\blit_asm.o
else
OBJECTS += _build\blit.o
endif
GCCDEFINES += -D_USE_DRZ80
OBJECTS += _build\DrZ80.o
GCCDEFINES += -D_ASM_YM2612_C
OBJECTS += _build\ym2612_asm.o
# dprint
ifeq "$(dprint)" "1"
GCCDEFINES += -D__DEBUG_PRINT
endif
define crule
@echo * $<
@$(CC) -c $(GCCCOMMFLAGS) $(GCCDEFINES) $(GCCCFLAGS) $< -o $@
endef
define cpprule
@echo * $<
@$(CC) -c $(GCCCOMMFLAGS) $(GCCDEFINES) $(GCCCPPFLAGS) $< -o $@
endef
define asmrule
@echo * $<
@$(ASM) -marmv4t -mthumb-interwork -o $@ $^
endef
# object making rules
_build\App.o : App.cpp
$(cpprule)
_build\Engine.o : Engine.cpp
$(cpprule)
_build\Dialogs.o : Dialogs.cpp
$(cpprule)
_build\CSimpleTextParser.o : CSimpleTextParser.cpp
$(cpprule)
_build\main.o : engine\main.cpp
$(cpprule)
_build\vid.o : engine\vid.cpp
$(cpprule)
_build\polledas.o: engine\polledas.cpp
$(cpprule)
_build\audio_mediaserver.o : engine\audio_mediaserver.cpp
$(cpprule)
_build\debug.o : engine\debug.cpp
$(cpprule)
_build\blit.o : engine\blit.c
$(crule)
_build\Area.o : ..\..\Pico\Area.c
$(crule)
_build\Cart.o : ..\..\Pico\Cart.c
$(crule)
_build\Draw.o : ..\..\Pico\Draw.c
$(crule)
_build\Draw2.o : ..\..\Pico\Draw2.c
$(crule)
_build\Memory.o : ..\..\Pico\Memory.c
$(crule)
_build\Misc.o : ..\..\Pico\Misc.c
$(crule)
_build\Pico.o : ..\..\Pico\Pico.c
$(crule)
_build\Sek.o : ..\..\Pico\Sek.c
$(crule)
_build\Utils.o : ..\..\Pico\Utils.c
$(crule)
_build\VideoPort.o : ..\..\Pico\VideoPort.c
$(crule)
_build\sound.o : ..\..\Pico\sound\sound.c
$(crule)
_build\sn76496.o : ..\..\Pico\sound\sn76496.c
$(crule)
_build\ym2612.o : ..\..\Pico\sound\ym2612.c
$(crule)
_build\unzip.o : ..\..\unzip\unzip.c
$(crule)
_build\gzio_symb.o : ..\..\zlib\gzio_symb.c
$(crule)
_build\m68kcpu.o : ..\..\musashi\m68kcpu.c
$(crule)
_build\m68kopac.o : ..\..\musashi\m68kopac.c
$(crule)
_build\m68kopdm.o : ..\..\musashi\m68kopdm.c
$(crule)
_build\m68kopnz.o : ..\..\musashi\m68kopnz.c
$(crule)
_build\m68kops.o : ..\..\musashi\m68kops.c
$(crule)
_build\Cyclone.o : ..\..\cpu\Cyclone\proj\Cyclone.s
$(asmrule)
_build\DrZ80.o : ..\..\cpu\DrZ80\drz80.s
$(asmrule)
_build\draw_asm.o : ..\..\Pico\draw.s
$(asmrule)
_build\draw2_asm.o : ..\..\Pico\draw2.s
$(asmrule)
_build\memory_asm.o : ..\..\Pico\memory.s
$(asmrule)
_build\ym2612_asm.o : ..\..\Pico\sound\ym2612.s
$(asmrule)
_build\blit_asm.o : engine\blit.s
$(asmrule)
PicoDrive.exe : $(OBJECTS)
@echo * ld
@$(LD) $(GCCLDFLAGS) -soname PicoDrive{000a0000}[a00010f3].exe --entry _E32Startup -u _E32Startup \
$(EPOCROOT2)EPOC32\RELEASE\ARMV5\UREL\EEXE.LIB -o "_build\PicoDrive_elf.exe" -Map "_build\PicoDrive.exe.map" $(OBJECTS) $(LIBS) -lsupc++ -lgcc
# @echo * strip
# @$(STRIP) _build\PicoDrive_elf.exe
@echo * elf2e32
@elf2e32 --sid=0xa00010f3 --heap=0x00000100,0x00800000 --stack=0x00003000 \
--uid1=0x1000007a --uid2=0x100039ce --uid3=0xa00010f3 \
--capability=none --fpu=softvfp --targettype=EXE --output="$@" \
--elfinput="_build\PicoDrive_elf.exe" --linkas=PicoDrive{000a0000}[a00010f3].exe --libpath="$(EPOCLIB)\LIB"
ifeq "$(sis)" "1"
@make -C _out
ifeq "$(up)" "1"
@qup.cmd
endif
endif
MAKEDIRS : _build
_build :
# @echo * making build dir
@perl -S emkdir.pl $@
# BitMap PicoDrive.mbm
RESOURCES : rsc\PicoDrive.mbm rsc\PicoDrive.RSC rsc\PicoDrive_reg.RSC rsc\PicoDrive_loc.RSC rsc\PicoDrive.mbg
rsc\PicoDrive.mbg : rsc\PicoDrive.mbm
rsc\PicoDrive.mbm : rsc\pico18x18.bmp rsc\pico18x18m.bmp rsc\pico40x40.bmp rsc\pico40x40m.bmp rsc\pico64x64.bmp rsc\pico64x64m.bmp
@echo * $@
@perl -S epocmbm.pl -h"rsc\PicoDrive.mbg" -o"rsc\PicoDrive.mbm" -l"\Z\Resource\Apps\:rsc" \
-b"/c24rsc\pico18x18.bmp /8rsc\pico18x18m.bmp /c24rsc\pico40x40.bmp /8rsc\pico40x40m.bmp /c24rsc\pico64x64.bmp /8rsc\pico64x64m.bmp" -l"\Z\Resource\Apps\:rsc"
@perl -S ecopyfile.pl "rsc\PicoDrive.mbg" "$(EPOCROOT2)EPOC32\INCLUDE\PicoDrive.mbg"
# Resource Z\Resource\Apps\PicoDrive.RSC
rsc\PicoDrive.RSC : rsc\PicoDrive.rss picodrive.hrh
@echo * $@
@perl -S epocrc.pl -m045,046,047 -I "." -I- -I "$(EPOCROOT2_NODRV)EPOC32\include" -DLANGUAGE_SC -u "rsc\PicoDrive.rss" -o$@ \
-h"rsc\PicoDrive.rsg" -t"rsc" -l"Z\Resource\Apps:rsc"
@perl -S ecopyfile.pl "rsc\PicoDrive.rsg" "$(EPOCROOT2)EPOC32\INCLUDE\PicoDrive.RSG"
# Resource Z\private\10003a3f\apps\PicoDrive_reg.RSC
rsc\PicoDrive_reg.RSC : rsc\PicoDrive_reg.rss
@echo * $@
@perl -S epocrc.pl -m045,046,047 -I "." -I- -I "$(EPOCROOT2)EPOC32\include" -DLANGUAGE_SC -u "rsc\PicoDrive_reg.rss" -o$@ \
-t"rsc" -l"Z\private\10003a3f\apps:rsc"
# Resource Z\Resource\Apps\PicoDrive_loc.RSC
rsc\PicoDrive_loc.RSC : rsc\PicoDrive_loc.rss
@echo * $@
@perl -S epocrc.pl -m045,046,047 -I "." -I- -I "$(EPOCROOT2)EPOC32\include" -DLANGUAGE_SC -u "rsc\PicoDrive_loc.rss" -o$@ \
-t"rsc" -l"Z\Resource\Apps:rsc"

View file

@ -0,0 +1,78 @@
enum TAppMenuCommands
{
// Emu menu
EEikCmdPicoMain = 10000,
EEikCmdPicoResume,
EEikCmdPicoLoadState,
EEikCmdPicoSaveState,
EEikCmdPicoLoadROM,
EEikCmdPicoReset,
EEikCmdPicoConfig,
EEikCmdPicoKeys,
EEikCmdPicoSettings,
// Frameskip submenu
EEikCmdPicoFrameskip,
EEikCmdPicoFrameskipAuto,
EEikCmdPicoFrameskip0,
EEikCmdPicoFrameskip1,
EEikCmdPicoFrameskip2,
EEikCmdPicoFrameskip4,
EEikCmdPicoFrameskip8,
// Debug menu
EEikCmdPicoDebug,
// EEikCmdPicoDebugKillEmu,
EEikCmdPicoDebugInfo,
// config Dialog
ECtlOptDone,
// pages
ECtlOptPageMain,
ECtlOptPageSound,
ECtlOptPageMisc,
// main page
ECtlOptRotationLabel,
ECtlOptRotation,
ECtlOptRotation0,
ECtlOptRotation90,
ECtlOptRotation180,
ECtlOptRotation270,
ECtlOptScreenModeLabel,
ECtlOptScreenMode,
ECtlOptScreenModeCenter,
ECtlOptScreenModeFit,
ECtlOptScreenModeFit2,
ECtlOptUseAltRend,
ECtlOptUseAccTiming,
ECtlOptUseAccSprites,
ECtlOptShowFPS,
// sound page
ECtlOptEnableSound,
ECtlOptChipSelLabel,
ECtlOptEmulateZ80,
ECtlOptEmulateYM2612,
ECtlOptEmulateSN76496,
ECtlOptSndQLabel,
ECtlOptSndQuality,
// misc page
ECtlOpt6ButtonPad,
ECtlOptGzipStates,
ECtlOptUseSRAM,
ECtlOptMotDontUseVol,
ECtlOptRegion,
// about dialog
EEikCmdPicoAboutDoneCmd,
EEikCmdPicoAboutCreditsCmd,
ECtlPicoAboutText,
// credits
ECtlPicoCreditsText,
// debug
ECtlDebugEdit
};
#define ECtlAboutVersion 1
#define ECtlAboutLinks 2

140
platform/uiq3/PicoDrive.mmp Normal file
View file

@ -0,0 +1,140 @@
TARGET PicoDrive.exe
TARGETTYPE exe
//TARGETPATH ?
UID 0x100039CE 0xA00010F3
EPOCSTACKSIZE 0x3000 // required by CQikSelectFileDlg
EPOCHEAPSIZE 0x100 0x00800000 // required by large ROMs :)
// resource
SOURCEPATH Rsc
START RESOURCE PicoDrive.rss
HEADER
TARGETPATH \Resource\Apps
LANG SC
END
START RESOURCE PicoDrive_reg.rss
TARGETPATH \private\10003a3f\apps
END
START RESOURCE PicoDrive_loc.rss
TARGETPATH \Resource\Apps
LANG SC
END
CAPABILITY none // SwEvent // forbidden
USERINCLUDE ..\..
SYSTEMINCLUDE \epoc32\include
SYSTEMINCLUDE \epoc32\include\libc
// launcher
SOURCEPATH .
SYSTEMINCLUDE . // for port_config.h
SOURCE App.cpp
SOURCE Engine.cpp
SOURCE Dialogs.cpp
SOURCE CSimpleTextParser.cpp
// engine
SOURCEPATH engine
SOURCE main.cpp
SOURCE vid.cpp
SOURCE polledas.cpp
SOURCE debug.cpp
SOURCE audio_mediaserver.cpp
SOURCE blit.c
// pico
MACRO _UNZIP_SUPPORT
SOURCEPATH ..\..\Pico
USERINCLUDE ..\..\Pico
SOURCE Area.c
SOURCE Cart.c
SOURCE Draw.c
SOURCE Draw2.c
SOURCE Memory.c
SOURCE Misc.c
SOURCE Pico.c
SOURCE Sek.c
SOURCE Utils.c
SOURCE VideoPort.c
// pico - sound
SOURCEPATH ..\..\Pico\Sound
SOURCE sound.c
SOURCE sn76496.c
SOURCE ym2612.c
// CPU cores
MACRO EMU_M68K
SOURCEPATH ..\..\cpu\Musashi
USERINCLUDE ..\..\cpu\Musashi
SOURCE m68kcpu.c
SOURCE m68kopac.c
SOURCE m68kopdm.c
SOURCE m68kopnz.c
SOURCE m68kops.c
//MACRO _USE_MZ80
//SOURCEPATH ..\win32\z80
//SOURCE mz80_asm.obj
// misc
SOURCEPATH ..\..\unzip
USERINCLUDE ..\..\unzip
SOURCE unzip.c
SOURCEPATH ..\..\zlib
USERINCLUDE ..\..\zlib
SOURCE gzio_symb.c
// TODO: get rid of unneeded stuff
LIBRARY ESTLIB.LIB
LIBRARY euser.lib
LIBRARY apparc.lib
LIBRARY cone.lib
LIBRARY eikcore.lib
LIBRARY eikcoctl.lib
LIBRARY qikcore.lib
LIBRARY qikdlg.lib // CQikSelectFileDlg
LIBRARY etext.lib // TCharFormat
LIBRARY bafl.lib // CDesCArrayFlat
LIBRARY efsrv.lib
LIBRARY eikctl.lib
LIBRARY WS32.LIB
LIBRARY EIKDLG.LIB
//LIBRARY EGUL.LIB // CColorList
LIBRARY GDI.LIB // TTypeface
LIBRARY estor.lib // RWriteStream
LIBRARY EZLIB.LIB
LIBRARY HAL.LIB
LIBRARY mediaclient.LIB
LIBRARY mediaclientaudiostream.LIB
STATICLIBRARY qikalloc.lib
LIBRARY qikallocdll.lib
MACRO __DEBUG_PRINT
MACRO __BROKEN_FWRITE
USERINCLUDE .
START BITMAP PicoDrive.mbm
HEADER
TARGETPATH \Resource\Apps
SOURCEPATH Rsc
SOURCE c24 Pico18x18.bmp
SOURCE 8 Pico18x18m.bmp
SOURCE c24 Pico40x40.bmp
SOURCE 8 Pico40x40m.bmp
SOURCE c24 Pico64x64.bmp
SOURCE 8 Pico64x64m.bmp
END

View file

@ -0,0 +1,7 @@
all: PicoDrive.SIS
PicoDrive.SIS: ..\PicoDrive.exe ..\rsc\PicoDrive.rsc ..\rsc\PicoDrive.mbm ..\rsc\PicoDrive_loc.rsc ..\rsc\PicoDrive_reg.rsc
makesis PicoDrive.pkg
clean:
@erase 2>>nul PicoDrive.pkg

View file

@ -0,0 +1,25 @@
;
; List of localised vendor names - one per language. At least one must be provided (English [EN]).
; List must correspond to list of languages specified elsewhere in the .pkg
%{"notaz"}
; The non-localised, globally unique vendor name (mandatory)
:"notaz"
; Package header
; Name, UID3, Major, Minor, Build, Package-type
#{"PicoDrive"}, (0xA00010F3), 0, 96, 0, TYPE=SA
; ProductID for UIQ 3.0
; Product/platform version UID, Major, Minor, Build, Component name
(0x101F6300), 3, 0, 0, {"UIQ30ProductID"}
; Files to install for the application
; If you move the example to another destination then you also need to change these paths.
"..\PicoDrive.exe"-"!:\sys\bin\PicoDrive.exe"
"..\rsc\PicoDrive.rsc"-"!:\resource\apps\PicoDrive.rsc"
"..\rsc\PicoDrive.mbm"-"!:\resource\apps\PicoDrive.mbm"
"..\rsc\PicoDrive_loc.rsc"-"!:\resource\apps\PicoDrive_loc.rsc"
"..\rsc\PicoDrive_reg.rsc"-"!:\private\10003a3f\import\apps\PicoDrive_reg.rsc"

Binary file not shown.

View file

@ -0,0 +1,25 @@
;
; List of localised vendor names - one per language. At least one must be provided (English [EN]).
; List must correspond to list of languages specified elsewhere in the .pkg
%{"notaz"}
; The non-localised, globally unique vendor name (mandatory)
:"notaz"
; Package header
; Name, UID3, Major, Minor, Build, Package-type
#{"PicoDrive"}, (0xA00010F3), 0, 92, 0, TYPE=SA
; ProductID for UIQ 3.0
; Product/platform version UID, Major, Minor, Build, Component name
(0x101F6300), 3, 0, 0, {"UIQ30ProductID"}
; Files to install for the application
; If you move the example to another destination then you also need to change these paths.
"..\..\..\..\..\..\UIQ3SDK\epoc32\release\gcce\urel\PicoDrive.exe"-"!:\sys\bin\PicoDrive.exe"
"..\..\..\..\..\..\UIQ3SDK\epoc32\data\Z\Resource\Apps\PicoDrive.rsc"-"!:\resource\apps\PicoDrive.rsc"
"..\..\..\..\..\..\UIQ3SDK\epoc32\data\Z\Resource\Apps\PicoDrive_loc.rsc"-"!:\resource\apps\PicoDrive_loc.rsc"
"..\..\..\..\..\..\UIQ3SDK\epoc32\data\z\Private\10003a3f\Apps\PicoDrive_reg.rsc"-"!:\private\10003a3f\import\apps\PicoDrive_reg.rsc"
"..\..\..\..\..\..\UIQ3SDK\epoc32\data\Z\Resource\Apps\PicoDrive.mbm"-"!:\resource\apps\PicoDrive.mbm"

View file

@ -0,0 +1,110 @@
1. Keys:
If it looks confusing to you, check this tutorial first:
http://notaz.atspace.com/pico_tut/
There are no default settings.
When you start key configuration mode, black screen with dark-red squares will
appear. Also there will be little 'control' on the top with the function
name in it, and arrows on the corners of it. You can tap on these corners to
select a function. You can also tap on these squares to bind that function to
them. This way you can associate touchpad areas with game-controls or functions.
I also made a small square in every corner of the screen to be used as a virtual
button for some function, like save state. You can bind it as you like. To
bind phone buttons, simply select the function you need, and press a button
you want. To unbind any key or touchpad area, simply push or tap it again.
When finished, select 'done' and press any key. You can also press 'Power'
to exit.
You need to bind 'pause emu' function to be able exit game when ROM is loaded.
It is bound to 'back' button by default.
2. Main Settings:
Here you can set the orientation of screen and the drawing mode. The "fit"
option will scale the image so it better fits in the screen, but some detail
will be lost. "center" displays the game at the center of the screen, but
non-fitting parts are not visible then. "fit2" is simmilar to "fit" but is
a bit more stretched (fit modes are only meaningful in 0 or 180 rotation
modes).
"Fast renderer" enables faster rendering method, but it works only with some
games (some other have serious glitches or even hang).
"Accurate timing" is needed for some games to run (like Red Zone). It should
be kept off for all other games, because it slows emulation down. Some games
also need this option for proper sound, so enable this if game has any
glitches.
"Accurate sprites" fixes sprite priority problems, for example if game
character is in front of or behind some object it should not be, this option
should fix it. This option does not work in "Fast renderer" mode.
"Show FPS" shows game frames per second in format XX/YY, where XX is the
number of frames shown per previous second, and YY is the number of frames
emulated, but not necessarily shown. By calculating YY-XX you get the number
of skipped frames per second.
3. Sound settings:
Sound emulation is very picky on CPU power (in most cases sound alone uses
more CPU power than everything else altogether), but it is still possible to
play some games. When using sound, the recommended display modes are "fit 0"
and "fit 180", because these are the fastest ones. Also try "Alternative
renderer", but it might cause graphical glitches. You must use auto frameskip
when using sound, or else you will get stuttering sound. Also, it is
recommended to exit all other non-vital apps (you can use SMan for this),
disable bluetooth and any other devices your phone may have. I also noticed
that simply connecting the phone battery charger strangely slows everything
down.
"Enable sound" tries to enable sound output on your device, but that alone is
not enough to get sound. You need to enable the sound chips below:
"Z80" is secondary CPU in genesis and is mostly used to control the other 2
sound chips. So if you disable Z80, sound will be lost in most games, with
some exceptions like Sonic1. It is possible to use Z80 for other things,
some games do that and Z80 must be enabled to run them at all.
"YM2612" is a fairly complex Frequency Modulation (FM) sound synthesis chip.
It was the main sound output device in genesis and is horrible CPU hog when
is tried to be emulated in software. Disabling it gives large speed
improvement, but most of the sound is lost.
"SN76496" is programmable sound generator (PSG) chip, used for various sound
effects and music elements.
Note: if you change sound settings AFTER loading a ROM, you may need to reset
game to get sound. This is because most games initialize sound chips on
startup, and this data is lost when sound chips are being enabled/disabled.
4. Misc:
"6 button pad" will enable 6 button gamepad emulation and will add additional
X, Y, Z and MODE actions to key configuration.
Note: if you enable this, games may detect that and use different button
configuration, for example A ("high punch") will change to "low punch" in
Mortal Kombat and you will need to bind X for "high punch".
"gzip save states" enables gzip (similar to ordinary zip, but a little
different) compression on your save states to save space. The compression
ratio is 50-90%, so it's worth to enable this.
"Use SRAM saves" option enables emulation of batery-backed save RAM some game
cartridges had. RPG games used it alot, but there were some others too, like
Sonic 3. If this is enabled, <ROMname>.srm files are generated when you exit
the emulator or load another ROM. Format is compatible with other popular
emulators (like Gens and Fusion).
"Region" lets you set the region of emulated genesis machine.
5. Frameskip:
"Auto" option tries to run the game in it's original speed by skipping next
frame if the previous was rendered too slow.
"0" displays every frame, thus game runs very slow, sound skips.
"1" skips every other frame. Use this for a game which is smoother, but a bit
too slow (actually depends on display mode you use).
"2" also makes the game smoother, but it will be too fast in most areas.
"4","8" similar to above, but skips more frames and often becomes choppy.

View file

@ -0,0 +1,32 @@
/*******************************************************************
*
* File: PolledAS.h
*
* Author: Peter van Sebille (peter@yipton.net)
*
* (c) Copyright 2001, Peter van Sebille
* All Rights Reserved
*
*******************************************************************/
#ifndef __POLLED_AS_H
#define __POLLED_AS_H
class CPrivatePolledActiveScheduler;
class CPolledActiveScheduler : public CBase
{
public:
~CPolledActiveScheduler();
static CPolledActiveScheduler* NewL();
static CPolledActiveScheduler* Instance();
void Schedule();
protected:
CPolledActiveScheduler(){};
void ConstructL();
CPrivatePolledActiveScheduler* iPrivatePolledActiveScheduler;
};
#endif /* __POLLED_AS_H */

View file

@ -0,0 +1,293 @@
/*******************************************************************
*
* File: Audio_mediaserver.cpp
*
* Author: Peter van Sebille (peter@yipton.net)
*
* Modified/adapted for picodriveN by notaz, 2006
*
* (c) Copyright 2006, notaz
* (c) Copyright 2001, Peter van Sebille
* All Rights Reserved
*
*******************************************************************/
#include "audio_mediaserver.h"
#include "debug.h"
//#undef DEBUGPRINT
//#define DEBUGPRINT(x...)
const TInt KUpdatesPerSec = 10;
const TInt KBlockTime = 1000000 / KUpdatesPerSec;
const TInt KMaxLag = 200000; // max sound lag, lower values increase chance of underflow
const TInt KMaxUnderflows = 50; // max underflows/API errors we are going allow in a row (to prevent lockups)
/*******************************************
*
* CGameAudioMS
*
*******************************************/
CGameAudioMS::CGameAudioMS(TInt aRate, TBool aStereo, TInt aWritesPerSec)
: iRate(aRate), iStereo(aStereo), iWritesPerSec(aWritesPerSec)
{
}
CGameAudioMS* CGameAudioMS::NewL(TInt aRate, TBool aStereo, TInt aWritesPerSec)
{
DEBUGPRINT(_L("CGameAudioMS::NewL(%i, %i, %i)"), aRate, aStereo, aWritesPerSec);
CGameAudioMS* self = new(ELeave) CGameAudioMS(aRate, aStereo, aWritesPerSec);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(); // self
return self;
}
CGameAudioMS::~CGameAudioMS()
{
DEBUGPRINT(_L("CGameAudioMS::~CGameAudioMS()"));
if(iMdaAudioOutputStream) {
iScheduler->Schedule(); // let it finish it's stuff
iMdaAudioOutputStream->Stop();
delete iMdaAudioOutputStream;
}
if(iServer) delete iServer;
for (TInt i=0; i<KSoundBuffers; i++)
delete iSoundBuffers[i];
// Polled AS
//if(iScheduler) delete iScheduler;
}
void CGameAudioMS::ConstructL()
{
iServer = CMdaServer::NewL();
// iScheduler = CPolledActiveScheduler::NewL();
iScheduler = CPolledActiveScheduler::Instance();
switch(iRate) {
case 11025: iMdaAudioDataSettings.iSampleRate = TMdaAudioDataSettings::ESampleRate11025Hz; break;
case 16000: iMdaAudioDataSettings.iSampleRate = TMdaAudioDataSettings::ESampleRate16000Hz; break;
case 22050: iMdaAudioDataSettings.iSampleRate = TMdaAudioDataSettings::ESampleRate22050Hz; break;
case 44100: iMdaAudioDataSettings.iSampleRate = TMdaAudioDataSettings::ESampleRate44100Hz; break;
default: iMdaAudioDataSettings.iSampleRate = TMdaAudioDataSettings::ESampleRate8000Hz; break;
}
iMdaAudioDataSettings.iChannels = (iStereo) ? TMdaAudioDataSettings::EChannelsStereo : TMdaAudioDataSettings::EChannelsMono;
iMdaAudioDataSettings.iCaps = TMdaAudioDataSettings::ESampleRateFixed | iMdaAudioDataSettings.iSampleRate;
iMdaAudioDataSettings.iFlags = TMdaAudioDataSettings::ENoNetworkRouting;
int pcmFrames = iRate / iWritesPerSec;
pcmFrames += iRate - (iRate / iWritesPerSec) * iWritesPerSec; // add division remainder too for our buffer size
iBufferedFrames = iWritesPerSec / KUpdatesPerSec;
TInt bytesPerFrame = pcmFrames << (iStereo?2:1);
for (TInt i=0 ; i<KSoundBuffers ; i++)
{
iSoundBuffers[i] = HBufC8::NewL(bytesPerFrame * iBufferedFrames);
iSoundBuffers[i]->Des().FillZ (bytesPerFrame * iBufferedFrames);
}
iCurrentBuffer = 0;
iCurrentBufferSize = 0;
// here we actually test if we can create and open CMdaAudioOutputStream at all, but really create and use it later.
iMdaAudioOutputStream = CMdaAudioOutputStream::NewL(iListener, iServer);
if(iMdaAudioOutputStream) {
iVolume = iMdaAudioOutputStream->MaxVolume();
DEBUGPRINT(_L("MaxVolume: %i"), iVolume);
delete iMdaAudioOutputStream;
iMdaAudioOutputStream = 0;
}
}
// returns a pointer to buffer for next frame,
// to be used when iSoundBuffers are used directly
TInt16 *CGameAudioMS::NextFrameL(TInt aPcmFrames)
{
iCurrentPosition += aPcmFrames << (iStereo?1:0);
iCurrentBufferSize += aPcmFrames << (iStereo?2:1);
if (++iFrameCount == iBufferedFrames)
{
WriteBlockL();
}
iScheduler->Schedule();
if(iListener.iUnderflowed) {
if(iListener.iUnderflowed > KMaxUnderflows) {
delete iMdaAudioOutputStream;
iMdaAudioOutputStream = 0;
return 0;
}
UnderflowedL(); // not again!
}
return iCurrentPosition;
}
void CGameAudioMS::WriteBlockL()
{
iScheduler->Schedule();
// do not write until stream is open
if(!iListener.iIsOpen) WaitForOpenToCompleteL();
//if(!iListener.iHasCopied) WaitForCopyToCompleteL(); // almost never happens anyway and sometimes even deadlocks?
//iListener.iHasCopied = EFalse;
if(!iListener.iUnderflowed) {
TInt64 delta;
// don't write if sound is lagging too much
delta = iTime - iMdaAudioOutputStream->Position().Int64();
if (delta > MAKE_TINT64(0, KMaxLag))
// another query sometimes returns very different result
delta = iTime - iMdaAudioOutputStream->Position().Int64();
if(delta <= MAKE_TINT64(0, KMaxLag)) {
//RDebug::Print(_L("delta: %i"), iTime.Low() - iMdaAudioOutputStream->Position().Int64().Low());
iSoundBuffers[iCurrentBuffer]->Des().SetLength(iCurrentBufferSize);
iMdaAudioOutputStream->WriteL(*iSoundBuffers[iCurrentBuffer]);
iTime += KBlockTime;
} else {
DEBUGPRINT(_L("lag: %i"), I64LOW(delta));
}
}
iFrameCount = 0;
if (++iCurrentBuffer == KSoundBuffers)
iCurrentBuffer = 0;
iCurrentPosition = (TInt16*) iSoundBuffers[iCurrentBuffer]->Ptr();
iCurrentBufferSize = 0;
}
void CGameAudioMS::Pause()
{
if(!iMdaAudioOutputStream) return;
iScheduler->Schedule(); // let it finish it's stuff
iMdaAudioOutputStream->Stop();
delete iMdaAudioOutputStream;
iMdaAudioOutputStream = 0;
}
// call this before doing any playback!
TInt16 *CGameAudioMS::ResumeL()
{
DEBUGPRINT(_L("CGameAudioMS::Resume()"));
iScheduler->Schedule();
// we act a bit strange here: simulate buffer underflow, which actually starts audio
iListener.iIsOpen = ETrue;
iListener.iUnderflowed = 1;
iListener.iLastError = 0;
iFrameCount = 0;
iCurrentBufferSize = 0;
iCurrentPosition = (TInt16*) iSoundBuffers[iCurrentBuffer]->Ptr();
return iCurrentPosition;
}
// handles underflow condition
void CGameAudioMS::UnderflowedL()
{
DEBUGPRINT(_L("UnderflowedL()"));
if (iListener.iLastError != KErrUnderflow)
{
// recreate the stream
//iMdaAudioOutputStream->Stop();
if(iMdaAudioOutputStream) delete iMdaAudioOutputStream;
iMdaAudioOutputStream = CMdaAudioOutputStream::NewL(iListener, iServer);
iMdaAudioOutputStream->Open(&iMdaAudioDataSettings);
iMdaAudioOutputStream->SetAudioPropertiesL(iMdaAudioDataSettings.iSampleRate, iMdaAudioDataSettings.iChannels);
iMdaAudioOutputStream->SetVolume(iVolume); // new in UIQ3
iListener.iIsOpen = EFalse; // wait for it to open
//iListener.iHasCopied = ETrue; // but don't wait for last copy to complete
// let it open and feed some stuff to make it happy
User::After(0);
iScheduler->Schedule();
iListener.iLastError = 0;
if(!iListener.iIsOpen) WaitForOpenToCompleteL();
} else {
iListener.iLastError = iListener.iUnderflowed = 0;
}
iTime = iMdaAudioOutputStream->Position().Int64();
}
void CGameAudioMS::WaitForOpenToCompleteL()
{
DEBUGPRINT(_L("CGameAudioMS::WaitForOpenToCompleteL"));
TInt count = 20; // 2 seconds
TInt waitPeriod = 100 * 1000;
if(!iListener.iIsOpen) {
// it is often enough to do this
User::After(0);
iScheduler->Schedule();
}
while (!iListener.iIsOpen && --count)
{
User::After(waitPeriod);
iScheduler->Schedule();
}
if (!iListener.iIsOpen)
User::LeaveIfError(KErrNotSupported);
}
void CGameAudioMS::ChangeVolume(TInt aUp)
{
//DEBUGPRINT(_L("CGameAudioMS::ChangeVolume(%i)"), aUp);
if (iMdaAudioOutputStream) {
if (aUp) {
if (iVolume < iMdaAudioOutputStream->MaxVolume()) iVolume+=5;
} else {
if (iVolume > 0) iVolume-=5;
}
iMdaAudioOutputStream->SetVolume(iVolume);
}
}
void TGameAudioEventListener::MaoscOpenComplete(TInt aError)
{
DEBUGPRINT(_L("CGameAudioMS::MaoscOpenComplete, error=%d"), aError);
iIsOpen = ETrue;
if(aError) {
iLastError = aError;
iUnderflowed++;
}
else iUnderflowed = 0;
}
void TGameAudioEventListener::MaoscBufferCopied(TInt aError, const TDesC8& aBuffer)
{
if (aError)
DEBUGPRINT(_L("CGameAudioMS::MaoscBufferCopied, error=%d"), aError);
// iHasCopied = ETrue;
if(aError) { // shit!
iLastError = aError;
iUnderflowed++;
}
}
void TGameAudioEventListener::MaoscPlayComplete(TInt aError)
{
DEBUGPRINT(_L("CGameAudioMS::MaoscPlayComplete: %i"), aError);
if(aError) {
iLastError = aError;
iUnderflowed++; // never happened to me while testing, but just in case
}
}

View file

@ -0,0 +1,85 @@
/*******************************************************************
*
* File: Audio_mediaserver.h
*
* Author: Peter van Sebille (peter@yipton.net)
*
* Modified/adapted for picodriveN by notaz, 2006
*
* (c) Copyright 2006, notaz
* (c) Copyright 2001, Peter van Sebille
* All Rights Reserved
*
*******************************************************************/
#ifndef __AUDIO_MEDIASERVER_H
#define __AUDIO_MEDIASERVER_H
#include <Mda\Common\Audio.h>
#include <MdaAudioOutputStream.h>
//#include "audio.h"
#include "polledas.h"
const TInt KSoundBuffers = 4;
class TGameAudioEventListener : public MMdaAudioOutputStreamCallback
{
public: // implements MMdaAudioOutputStreamCallback
void MaoscOpenComplete(TInt aError);
void MaoscBufferCopied(TInt aError, const TDesC8& );
void MaoscPlayComplete(TInt aError);
TBool iIsOpen;
// TBool iHasCopied;
TInt iUnderflowed;
TInt iLastError;
};
class CGameAudioMS // : public IGameAudio // IGameAudio MUST be specified first!
{
public: // implements IGameAudio
TInt16 *NextFrameL(TInt aPcmFrames);
TInt16 *ResumeL();
void Pause();
void ChangeVolume(TInt aUp);
public:
~CGameAudioMS();
CGameAudioMS(TInt aRate, TBool aStereo, TInt aWritesPerSec);
static CGameAudioMS* NewL(TInt aRate, TBool aStereo, TInt aWritesPerSec);
protected:
void WriteBlockL();
void UnderflowedL();
void ConstructL();
protected:
void WaitForOpenToCompleteL();
TInt iRate;
TBool iStereo;
CMdaAudioOutputStream *iMdaAudioOutputStream;
TMdaAudioDataSettings iMdaAudioDataSettings;
TGameAudioEventListener iListener;
CPolledActiveScheduler *iScheduler;
HBufC8* iSoundBuffers[KSoundBuffers];
TInt iWritesPerSec;
TInt iBufferedFrames;
TInt16* iCurrentPosition;
TInt iCurrentBuffer;
TInt iCurrentBufferSize;
TInt iFrameCount;
CMdaServer* iServer;
TInt64 iTime;
TInt iVolume;
};
#endif /* __AUDIO_MEDIASERVER_H */

View file

@ -0,0 +1,34 @@
/*
void vidConvCpyRGB32 (void *to, void *from, int lines, int p240)
{
unsigned short *ps = (unsigned short *) from;
unsigned long *pd = (unsigned long *) to;
int x, y;
int to_x = p240 ? 240 : 224;
if(!p240) pd += 8;
for(y = 0; y < lines; y++) // ps < ps_end; ps++)
for(x = 0; x < to_x; x++, ps++)
// Convert 0000bbb0 ggg0rrr0
// to ..0 rrr00000 ggg00000 bbb00000
*(pd+y*256+x) = ((*ps&0x000F)<<20) | ((*ps&0x00F0)<<8) | ((*ps&0x0F00)>>4);
}
*/
// stubs
void vidConvCpyRGB32 (void *to, void *from, int pixels) {}
void vidConvCpyRGB32sh(void *to, void *from, int pixels) {}
void vidConvCpyRGB32hi(void *to, void *from, int pixels) {}
void vidConvCpy_90 (void *to, void *from, void *pal, int width) {}
void vidConvCpy_270 (void *to, void *from, void *pal, int width) {}
void vidConvCpy_center_0 (void *to, void *from, void *pal) {}
void vidConvCpy_center_180(void *to, void *from, void *pal) {}
void vidConvCpy_center2_40c_0 (void *to, void *from, void *pal, int lines) {}
void vidConvCpy_center2_40c_180(void *to, void *from, void *pal, int lines) {}
void vidConvCpy_center2_32c_0 (void *to, void *from, void *pal, int lines) {}
void vidConvCpy_center2_32c_180(void *to, void *from, void *pal, int lines) {}
void vidClear(void *to, int lines) {}

View file

@ -0,0 +1,22 @@
// (c) Copyright 2006 notaz, All rights reserved.
// Free for non-commercial use.
// For commercial use, separate licencing terms must be obtained.
extern "C"
{
void vidConvCpyRGB32 (void *to, void *from, int pixels);
void vidConvCpyRGB32sh(void *to, void *from, int pixels);
void vidConvCpyRGB32hi(void *to, void *from, int pixels);
void vidConvCpy_90 (void *to, void *from, void *pal, int width);
void vidConvCpy_270 (void *to, void *from, void *pal, int width);
void vidConvCpy_center_0 (void *to, void *from, void *pal);
void vidConvCpy_center_180(void *to, void *from, void *pal);
void vidConvCpy_center2_40c_0 (void *to, void *from, void *pal, int lines);
void vidConvCpy_center2_40c_180(void *to, void *from, void *pal, int lines);
void vidConvCpy_center2_32c_0 (void *to, void *from, void *pal, int lines);
void vidConvCpy_center2_32c_180(void *to, void *from, void *pal, int lines);
void vidClear(void *to, int lines);
}

695
platform/uiq3/engine/blit.s Normal file
View file

@ -0,0 +1,695 @@
@ some color conversion and blitting routines
@ (c) Copyright 2006, notaz
@ All Rights Reserved
@ Convert 0000bbb0 ggg0rrr0 0000bbb0 ggg0rrr0
@ to 00000000 rrr00000 ggg00000 bbb00000 ...
@ lr = 0x00e000e0, out: r3=lower_pix, r2=higher_pix; trashes rin
@ if sh==2, r8=0x00404040 (sh!=0 destroys flags!)
.macro convRGB32_2 rin sh=0
and r2, lr, \rin, lsr #4 @ blue
and r3, \rin, lr
orr r2, r2, r3, lsl #8 @ g0b0g0b0
mov r3, r2, lsl #16 @ g0b00000
and \rin,lr, \rin, ror #12 @ 00r000r0 (reversed)
orr r3, r3, \rin, lsr #16 @ g0b000r0
.if \sh == 1
mov r3, r3, ror #17 @ shadow mode
.elseif \sh == 2
adds r3, r3, #0x40000000 @ green
orrcs r3, r3, #0xe0000000
mov r3, r3, ror #8
adds r3, r3, #0x40000000
orrcs r3, r3, #0xe0000000
mov r3, r3, ror #16
adds r3, r3, #0x40000000
orrcs r3, r3, #0xe0000000
mov r3, r3, ror #24
orr r3, r3, r3, lsr #3
.else
mov r3, r3, ror #16 @ r3=low
orr r3, r3, r3, lsr #3
.endif
str r3, [r0], #4
mov r2, r2, lsr #16
orr r2, r2, \rin, lsl #16
.if \sh == 1
mov r2, r2, lsr #1
.elseif \sh == 2
mov r2, r2, ror #8
adds r2, r2, #0x40000000 @ blue
orrcs r2, r2, #0xe0000000
mov r2, r2, ror #8
adds r2, r2, #0x40000000
orrcs r2, r2, #0xe0000000
mov r2, r2, ror #8
adds r2, r2, #0x40000000
orrcs r2, r2, #0xe0000000
mov r2, r2, ror #8
orr r2, r2, r2, lsr #3
.else
orr r2, r2, r2, lsr #3
.endif
str r2, [r0], #4
.endm
.global vidConvCpyRGB32 @ void *to, void *from, int pixels
vidConvCpyRGB32:
stmfd sp!, {r4-r7,lr}
mov r12, r2, lsr #3 @ repeats
mov lr, #0x00e00000
orr lr, lr, #0x00e0
.loopRGB32:
subs r12, r12, #1
ldmia r1!, {r4-r7}
convRGB32_2 r4
convRGB32_2 r5
convRGB32_2 r6
convRGB32_2 r7
bgt .loopRGB32
ldmfd sp!, {r4-r7,lr}
bx lr
.global vidConvCpyRGB32sh @ void *to, void *from, int pixels
vidConvCpyRGB32sh:
stmfd sp!, {r4-r7,lr}
mov r12, r2, lsr #3 @ repeats
mov lr, #0x00e00000
orr lr, lr, #0x00e0
.loopRGB32sh:
subs r12, r12, #1
ldmia r1!, {r4-r7}
convRGB32_2 r4, 1
convRGB32_2 r5, 1
convRGB32_2 r6, 1
convRGB32_2 r7, 1
bgt .loopRGB32sh
ldmfd sp!, {r4-r7,lr}
bx lr
.global vidConvCpyRGB32hi @ void *to, void *from, int pixels
vidConvCpyRGB32hi:
stmfd sp!, {r4-r7,lr}
mov r12, r2, lsr #3 @ repeats
mov lr, #0x00e00000
orr lr, lr, #0x00e0
.loopRGB32hi:
ldmia r1!, {r4-r7}
convRGB32_2 r4, 2
convRGB32_2 r5, 2
convRGB32_2 r6, 2
convRGB32_2 r7, 2
subs r12, r12, #1
bgt .loopRGB32hi
ldmfd sp!, {r4-r7,lr}
bx lr
@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ -------- M2 stuff ---------
/*
.global vidConvCpy_90 @ void *to, void *from, int width
vidConvCpy_90:
stmfd sp!, {r4-r10,lr}
mov lr, #0x00F00000
orr lr, lr, #0x00F0
mov r12, #224/4 @ row counter
mov r10, r2, lsl #2 @ we do 2 pixel wide copies
add r8, r0, #256*4 @ parallel line
add r1, r1, #0x23000
add r1, r1, #0x00B80 @ r1+=328*223*2+8*2
mov r9, r1
mov r4, #0 @ fill bottom border
mov r5, #0
mov r6, #0
mov r7, #0
stmia r0!, {r4-r7}
stmia r0!, {r4-r7}
stmia r8!, {r4-r7}
stmia r8!, {r4-r7}
.loopM2RGB32_90:
subs r12, r12, #1
@ at first this loop was written differently: src pixels were fetched with ldm's and
@ dest was not sequential. It ran nearly 2 times slower. It seems it is very important
@ to do sequential memory access on those items, which we have more (to offload addressing bus?).
ldr r4, [r1], #-328*2
ldr r5, [r1], #-328*2
ldr r6, [r1], #-328*2
ldr r7, [r1], #-328*2
convRGB32_2 r4, 1
convRGB32_2 r5, 1
convRGB32_2 r6, 1
convRGB32_2 r7, 1
str r4, [r8], #4
str r5, [r8], #4
str r6, [r8], #4
str r7, [r8], #4
bne .loopM2RGB32_90
mov r4, #0 @ top border
mov r5, #0
mov r6, #0
stmia r0!, {r4-r6,r12}
stmia r0!, {r4-r6,r12}
stmia r8!, {r4-r6,r12}
stmia r8!, {r4-r6,r12}
subs r10, r10, #1
ldmeqfd sp!, {r4-r10,pc} @ return
add r0, r8, #16*4 @ set new dst pointer
add r8, r0, #256*4
add r9, r9, #2*2 @ fix src pointer
mov r1, r9
stmia r0!, {r4-r6,r12} @ bottom border
stmia r0!, {r4-r6,r12}
stmia r8!, {r4-r6,r12}
stmia r8!, {r4-r6,r12}
mov r12, #224/4 @ restore row counter
b .loopM2RGB32_90
@ converter for vidConvCpy_270
@ lr = 0x00F000F0, out: r3=lower_pix, r2=higher_pix; trashes rin
.macro convRGB32_3 rin
and r2, lr, \rin, lsr #4 @ blue
and r3, \rin, lr
orr r2, r2, r3, lsl #8 @ g0b0g0b0
mov r3, r2, lsl #16 @ g0b00000
and \rin,lr, \rin, ror #12 @ 00r000r0 (reversed)
orr r3, r3, \rin, lsr #16 @ g0b000r0
mov r2, r2, lsr #16
orr r2, r2, \rin, lsl #16
str r2, [r0], #4
mov \rin,r3, ror #16 @ r3=low
.endm
*/
@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ takes byte-sized pixels from r3-r6, fetches from pal and stores to r7,r8,r10,lr
@ r2=pal
.macro mode2_4pix shift
and r7, r11, r3, lsr #\shift
ldr r7, [r2, r7, lsl #2]
and r8, r11, r4, lsr #\shift
ldr r8, [r2, r8, lsl #2]
and r10,r11, r5, lsr #\shift
ldr r10,[r2, r10,lsl #2]
and lr, r11, r6, lsr #\shift
ldr lr, [r2, lr, lsl #2]
.endm
@ r2=pal, r11=0xff
.macro mode2_4pix_getpix0 dreg sreg
and \dreg, r11, \sreg
ldr \dreg, [r2, \dreg, lsl #2]
.endm
.macro mode2_4pix_getpix1 dreg sreg
and \dreg, r11, \sreg, lsr #8
ldr \dreg, [r2, \dreg, lsl #2]
.endm
.macro mode2_4pix_getpix2 dreg sreg
and \dreg, r11, \sreg, lsr #16
ldr \dreg, [r2, \dreg, lsl #2]
.endm
.macro mode2_4pix_getpix3 dreg sreg
and \dreg, r11, \sreg, lsr #24
ldr \dreg, [r2, \dreg, lsl #2]
.endm
@ takes byte-sized pixels from reg, fetches from pal and stores to r3-r6
@ r11=0xFF, r2=pal
.macro mode2_4pix2_0 reg
mode2_4pix_getpix0 r3, \reg
mode2_4pix_getpix1 r4, \reg
mode2_4pix_getpix2 r5, \reg
mode2_4pix_getpix3 r6, \reg
.endm
@ ...
.macro mode2_4pix2_180 reg
mode2_4pix_getpix3 r3, \reg
mode2_4pix_getpix2 r4, \reg
mode2_4pix_getpix1 r5, \reg
mode2_4pix_getpix0 r6, \reg
.endm
@ takes byte-sized pixels from reg, fetches from pal and stores to r3-r5
@ r11=0xFF, r2=pal, r10=0xfcfcfc, r6=tmp
.macro mode2_4pix_to3 reg is180
.if \is180
mode2_4pix_getpix3 r3, \reg
mode2_4pix_getpix2 r4, \reg
.else
mode2_4pix_getpix0 r3, \reg @ gathering loads cause a weird-hang
mode2_4pix_getpix1 r4, \reg
.endif
sub r3, r3, r3, lsr #2 @ r3 *= 0.75
add r3, r3, r4, lsr #2 @ r3 += r4 * 0.25
and r3, r3, r10
.if \is180
mode2_4pix_getpix1 r5, \reg
mode2_4pix_getpix0 r6, \reg
.else
mode2_4pix_getpix2 r5, \reg
mode2_4pix_getpix3 r6, \reg
.endif
mov r4, r4, lsr #1
add r4, r4, r5, lsr #1 @ r4 = (r4 + r5) / 2;
@ and r4, r4, r10
sub r6, r6, r6, lsr #2 @ r6 *= 0.75
add r5, r6, r5, lsr #2 @ r5 = r6 + r5 * 0.25
and r5, r5, r10
.endm
@ void *to, void *from, void *pal, int width
.macro vidConvCpyM2_landscape is270
stmfd sp!, {r4-r11,lr}
mov r11, #0xff
mov r12, #(224/4-1)<<16 @ row counter
orr r12, r12, r3, lsl #1 @ we do 4 pixel wide copies (right to left)
.if \is270
add r1, r1, #324
.else
add r1, r1, #0x11c00
add r1, r1, #0x00308 @ 328*224+8
.endif
mov r9, r1
mov r3, #0 @ fill top border
mov r4, #0
mov r5, #0
mov r6, #0
stmia r0!, {r3-r6}
stmia r0!, {r3-r6}
add r7, r0, #256*4-8*4
stmia r7!, {r3-r6}
stmia r7!, {r3-r6}
add r7, r7, #256*4-8*4
stmia r7!, {r3-r6}
stmia r7!, {r3-r6}
add r7, r7, #256*4-8*4
stmia r7!, {r3-r6}
stmia r7!, {r3-r6}
0: @ .loopM2RGB32_270:
subs r12, r12, #1<<16
.if \is270
ldr r3, [r1], #328
ldr r4, [r1], #328
ldr r5, [r1], #328
ldr r6, [r1], #328
.else
ldr r3, [r1, #-328]!
ldr r4, [r1, #-328]!
ldr r5, [r1, #-328]!
ldr r6, [r1, #-328]!
.endif
.if \is270
mode2_4pix 24
.else
mode2_4pix 0
.endif
stmia r0, {r7,r8,r10,lr}
add r0, r0, #256*4
.if \is270
mode2_4pix 16
.else
mode2_4pix 8
.endif
stmia r0, {r7,r8,r10,lr}
add r0, r0, #256*4
.if \is270
mode2_4pix 8
.else
mode2_4pix 16
.endif
stmia r0, {r7,r8,r10,lr}
add r0, r0, #256*4
.if \is270
mode2_4pix 0
.else
mode2_4pix 24
.endif
stmia r0!,{r7,r8,r10,lr}
sub r0, r0, #256*4*3
bpl 0b @ .loopM2RGB32_270
mov r3, #0 @ bottom border
mov r4, #0
mov r5, #0
mov r6, #0
stmia r0!, {r3-r6}
stmia r0!, {r3-r6}
add r0, r0, #256*4-8*4
stmia r0!, {r3-r6}
stmia r0!, {r3-r6}
add r0, r0, #256*4-8*4
stmia r0!, {r3-r6}
stmia r0!, {r3-r6}
add r0, r0, #256*4-8*4
stmia r0!, {r3-r6}
nop @ phone crashes if this is commented out. Do I stress it too much?
stmia r0!, {r3-r6}
add r12, r12, #1<<16
subs r12, r12, #1
ldmeqfd sp!, {r4-r11,pc} @ return
add r0, r0, #16*4
.if \is270
sub r9, r9, #4 @ fix src pointer
.else
add r9, r9, #4
.endif
mov r1, r9
stmia r0!, {r3-r6} @ top border
stmia r0!, {r3-r6}
add r7, r0, #256*4-8*4
stmia r7!, {r3-r6}
stmia r7!, {r3-r6}
add r7, r7, #256*4-8*4
stmia r7!, {r3-r6}
stmia r7!, {r3-r6}
add r7, r7, #256*4-8*4
stmia r7!, {r3-r6}
stmia r7!, {r3-r6}
orr r12, r12, #(224/4-1)<<16 @ restore row counter
b 0b @ .loopM2RGB32_270
.endm
.global vidConvCpy_90 @ void *to, void *from, void *pal, int width
vidConvCpy_90:
vidConvCpyM2_landscape 0
.global vidConvCpy_270 @ void *to, void *from, void *pal, int width
vidConvCpy_270:
vidConvCpyM2_landscape 1
.global vidConvCpy_center_0 @ void *to, void *from, void *pal
vidConvCpy_center_0:
stmfd sp!, {r4-r6,r11,lr}
mov r11, #0xff
add r1, r1, #8 @ not border (centering 32col here)
mov r12, #(240/4-1)<<16
orr r12, r12, #224
.loopRGB32_c0:
ldr lr, [r1], #4
subs r12, r12, #1<<16
mode2_4pix2_0 lr
stmia r0!, {r3-r6}
bpl .loopRGB32_c0
sub r12, r12, #1
adds r12, r12, #1<<16
ldmeqfd sp!, {r4-r6,r11,pc} @ return
add r0, r0, #16*4
add r1, r1, #88
orr r12, #(240/4-1)<<16
b .loopRGB32_c0
.global vidConvCpy_center_180 @ void *to, void *from, void *pal
vidConvCpy_center_180:
stmfd sp!, {r4-r6,r11,lr}
mov r11, #0xff
add r1, r1, #0x11c00
add r1, r1, #0x002B8 @ #328*224-72
mov r12, #(240/4-1)<<16
orr r12, r12, #224
.loopRGB32_c180:
ldr lr, [r1, #-4]!
subs r12, r12, #1<<16
mode2_4pix2_180 lr
stmia r0!, {r3-r6}
bpl .loopRGB32_c180
sub r12, r12, #1
adds r12, r12, #1<<16
ldmeqfd sp!, {r4-r6,r11,pc} @ return
add r0, r0, #16*4
sub r1, r1, #88
orr r12, #(240/4-1)<<16
b .loopRGB32_c180
@ note: the following code assumes that (pal[x] & 0x030303) == 0
.global vidConvCpy_center2_40c_0 @ void *to, void *from, void *pal, int lines
vidConvCpy_center2_40c_0:
stmfd sp!, {r4-r6,r10,r11,lr}
mov r11, #0xff
mov r10, #0xfc
orr r10, r10, lsl #8
orr r10, r10, lsl #8
add r1, r1, #8 @ border
mov r12, #(240/3-1)<<16
orr r12, r12, r3
.loopRGB32_c2_40c_0:
ldr lr, [r1], #4
subs r12, r12, #1<<16
mode2_4pix_to3 lr, 0
stmia r0!, {r3-r5}
bpl .loopRGB32_c2_40c_0
sub r12, r12, #1
adds r12, r12, #1<<16
ldmeqfd sp!, {r4-r6,r10,r11,pc} @ return
add r0, r0, #16*4
add r1, r1, #8
orr r12, #(240/3-1)<<16
b .loopRGB32_c2_40c_0
.global vidConvCpy_center2_40c_180 @ void *to, void *from, void *pal, int lines
vidConvCpy_center2_40c_180:
stmfd sp!, {r4-r6,r10,r11,lr}
mov r11, #0xff
mov r10, #0xfc
orr r10, r10, lsl #8
orr r10, r10, lsl #8
mov r4, #328
mla r1, r3, r4, r1
@ add r1, r1, #0x11000
@ add r1, r1, #0x00f00 @ #328*224
mov r12, #(240/3-1)<<16
orr r12, r12, r3
.loop_c2_40c_180:
ldr lr, [r1, #-4]!
subs r12, r12, #1<<16
mode2_4pix_to3 lr, 1
stmia r0!, {r3-r5}
bpl .loop_c2_40c_180
sub r12, r12, #1
adds r12, r12, #1<<16
ldmeqfd sp!, {r4-r6,r10,r11,pc} @ return
add r0, r0, #16*4
sub r1, r1, #8
orr r12, #(240/3-1)<<16
b .loop_c2_40c_180
.global vidConvCpy_center2_32c_0 @ void *to, void *from, void *pal, int lines
vidConvCpy_center2_32c_0:
stmfd sp!, {r4-r11,lr}
mov r10, #0xfc
orr r10, r10, lsl #8
orr r10, r10, lsl #8
mov r11, #0xff
add r1, r1, #8 @ border
mov r12, #(240/15-1)<<16
orr r12, r12, r3
.loop_c2_32c_0:
ldmia r1!, {r7-r9,lr}
subs r12, r12, #1<<16
mode2_4pix2_0 r7
stmia r0!, {r3-r6}
mode2_4pix2_0 r8
stmia r0!, {r3-r6}
mode2_4pix2_0 r9
stmia r0!, {r3-r6}
mode2_4pix_to3 lr, 0
stmia r0!, {r3-r5}
bpl .loop_c2_32c_0
sub r12, r12, #1
adds r12, r12, #1<<16
ldmeqfd sp!, {r4-r11,pc} @ return
add r0, r0, #16*4
add r1, r1, #64+8
orr r12, #(240/15-1)<<16
b .loop_c2_32c_0
.global vidConvCpy_center2_32c_180 @ void *to, void *from, void *pal, int lines
vidConvCpy_center2_32c_180:
stmfd sp!, {r4-r11,lr}
mov r10, #0xfc
orr r10, r10, lsl #8
orr r10, r10, lsl #8
mov r11, #0xff
mov r4, #328
mla r1, r3, r4, r1
@ add r1, r1, #0x11000
@ add r1, r1, #0x00f00 @ #328*224
mov r12, #(240/15-1)<<16
orr r12, r12, r3
.loop_c2_32c_180:
ldmdb r1!, {r7-r9,lr}
subs r12, r12, #1<<16
mode2_4pix2_180 lr
stmia r0!, {r3-r6}
mode2_4pix2_180 r9
stmia r0!, {r3-r6}
mode2_4pix2_180 r8
stmia r0!, {r3-r6}
mode2_4pix_to3 r7, 1
stmia r0!, {r3-r5}
bpl .loop_c2_32c_180
sub r12, r12, #1
adds r12, r12, #1<<16
ldmeqfd sp!, {r4-r11,pc} @ return
add r0, r0, #16*4
sub r1, r1, #64+8
orr r12, #(240/15-1)<<16
b .loop_c2_32c_180
@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
.global vidClear @ void *to, int lines
vidClear:
stmfd sp!, {lr}
mov r12, #240/16-1
orr r12, r1, r12, lsl #16
mov r1, #0
mov r2, #0
mov r3, #0
mov lr, #0
.loopVidClear:
subs r12, r12, #1<<16
stmia r0!, {r1-r3,lr}
stmia r0!, {r1-r3,lr}
stmia r0!, {r1-r3,lr}
stmia r0!, {r1-r3,lr}
bpl .loopVidClear
sub r12, r12, #1
adds r12, r12, #1<<16
ldmeqfd sp!, {pc} @ return
add r0, r0, #16*4
orr r12, #(240/16-1)<<16
b .loopVidClear

View file

@ -0,0 +1,259 @@
#include <e32svr.h> // RDebug
#include "debug.h"
#ifdef __WINS__
void ExceptionHandler(TExcType exc) {}
#else
static const wchar_t * const exception_names[] = {
L"General",
L"IntegerDivideByZero",
L"SingleStep",
L"BreakPoint",
L"IntegerOverflow",
L"BoundsCheck",
L"InvalidOpCode",
L"DoubleFault",
L"StackFault",
L"AccessViolation",
L"PrivInstruction",
L"Alignment",
L"PageFault",
L"FloatDenormal",
L"FloatDivideByZero",
L"FloatInexactResult",
L"FloatInvalidOperation",
L"FloatOverflow",
L"FloatStackCheck",
L"FloatUnderflow",
L"Abort",
L"Kill",
L"DataAbort",
L"CodeAbort",
L"MaxNumber",
L"InvalidVector",
L"UserInterrupt",
L"Unknown"
};
static void getASpace(TUint *code_start, TUint *code_end, TUint *stack_start, TUint *stack_end)
{
TUint pc, sp;
RChunk chunk;
TFullName chunkname;
TFindChunk findChunk(_L("*"));
asm volatile ("str pc, %0" : "=m" (pc) );
asm volatile ("str sp, %0" : "=m" (sp) );
while( findChunk.Next(chunkname) != KErrNotFound ) {
chunk.Open(findChunk);
if((TUint)chunk.Base()+chunk.Bottom() < pc && pc < (TUint)chunk.Base()+chunk.Top()) {
if(code_start) *code_start = (TUint)chunk.Base()+chunk.Bottom();
if(code_end) *code_end = (TUint)chunk.Base()+chunk.Top();
} else
if((TUint)chunk.Base()+chunk.Bottom() < sp && sp < (TUint)chunk.Base()+chunk.Top()) {
if(stack_start) *stack_start = (TUint)chunk.Base()+chunk.Bottom();
if(stack_end) *stack_end = (TUint)chunk.Base()+chunk.Top();
}
chunk.Close();
}
}
// tmp
#if defined(__DEBUG_PRINT)
extern "C" char *debugString();
#endif
// our very own exception handler
void ExceptionHandler(TExcType exc)
{
TUint lr, sp, i;
TUint stack_end = 0; // ending address of our stack chunk
TUint code_start = 0, code_end = 0; // starting and ending addresses of our code chunk
TUint guessed_address = 0;
DEBUGPRINT(_L("ExceptionHandler()")); // this seems to never be called
asm volatile ("str lr, %0" : "=m" (lr) );
asm volatile ("str sp, %0" : "=m" (sp) );
// first get some info about the chunks we live in
getASpace(&code_start, &code_end, 0, &stack_end);
// now we begin some black magic tricks
// we go up our stack until we pass our caller address
for(; sp < stack_end; sp += 4)
if(*(TUint *)sp == lr) break;
// there might be mirored caller address
for(i = sp + 4; i < sp + 0x300 && i < stack_end; i += 4)
if(*(TUint *)i == lr) { sp = i; break; }
// aah, it is always 0x9c bytes away from the caller address in my firmware,
// don't know how to detect it in any other way
sp += 0x9c;
guessed_address = *(TUint *)sp;
// output the info
TUint exec_show = exc;
if(exec_show > 27) exec_show = 27;
TPtrC ptrExc((TUint16 *) exception_names[exec_show]);
RDebug::Print(_L("!!!Exception %i (%S) @ 0x%08x (guessed; relative=0x%08x)"), exc, &ptrExc, guessed_address, guessed_address - code_start);
#ifdef __DEBUG_PRINT_FILE
DEBUGPRINT( _L("!!!Exception %i (%S) @ 0x%08x (guessed; relative=0x%08x)"), exc, &ptrExc, guessed_address, guessed_address - code_start);
#endif
TBuf<148> buff1;
TBuf<10> buff2;
buff1.Copy(_L(" guessed stack: "));
for(sp += 4, i = 0; i < 5 && sp < stack_end; sp += 4) {
if((*(TUint *)sp >> 28) == 5) {
if(i++) buff1.Append(_L(", "));
buff2.Format(_L("0x%08x"), *(TUint *)sp);
buff1.Append(buff2);
}
else if(code_start < *(TUint *)sp && *(TUint *)sp < code_end) {
if(i++) buff1.Append(_L(", "));
buff2.Format(_L("0x%08x"), *(TUint *)sp);
buff1.Append(buff2);
buff1.Append(_L(" ("));
buff2.Format(_L("0x%08x"), *(TUint *)sp - code_start);
buff1.Append(buff2);
buff1.Append(_L(")"));
}
}
RDebug::Print(_L("%S"), &buff1);
#ifdef __DEBUG_PRINT_FILE
DEBUGPRINT(_L("%S"), &buff1);
#endif
// tmp
#if defined(__DEBUG_PRINT)
char *ps, *cstr = debugString();
for(ps = cstr; *ps; ps++) {
if(*ps == '\n') {
*ps = 0;
dprintf(cstr);
cstr = ps+1;
}
}
#endif
// RDebug::Print(_L("Stack dump:"));
// asm volatile ("str sp, %0" : "=m" (sp) );
// for(TUint i = sp+0x400; i >= sp-16; i-=4)
// RDebug::Print(_L("%08x: %08x"), i, *(int *)i);
// more descriptive replacement of "KERN-EXEC 3" panic
buff1.Format(_L("K-EX3: %S"), &ptrExc);
User::Panic(buff1, exc);
}
#endif // ifdef __WINS__
#if defined(__DEBUG_PRINT) || defined(__WINS__)
#ifndef __DLL__
// c string dumper for RDebug::Print()
static TBuf<1024> sTextBuffer;
TDesC* DO_CONV(const char* s)
{
TPtrC8 text8((TUint8*) (s));
sTextBuffer.Copy(text8);
return &sTextBuffer;
}
#endif
#ifdef __DEBUG_PRINT_C
#include <stdarg.h> // va_*
#include <stdio.h> // vsprintf
// debug print from c code
extern "C" void dprintf(char *format, ...)
{
va_list args;
char buffer[512];
va_start(args,format);
vsprintf(buffer,format,args);
va_end(args);
DEBUGPRINT(_L("%S"), DO_CONV(buffer));
}
#endif
#ifdef __DEBUG_PRINT_FILE
#include <f32file.h>
//static RFile logFile;
// static TBool logInited = 0;
RMutex logMutex;
static void debugPrintFileInit()
{
// try to open
logMutex.CreateLocal();
RFs fserv;
fserv.Connect();
RFile logFile;
logFile.Replace(fserv, _L("C:\\logs\\pico.log"), EFileWrite|EFileShareAny);
logFile.Close();
fserv.Close();
}
// debug print to file
void debugPrintFile(TRefByValue<const TDesC> aFmt, ...)
{
if (logMutex.Handle() <= 0) debugPrintFileInit();
logMutex.Wait();
RFs fserv;
fserv.Connect();
TTime now; now.UniversalTime();
TBuf<512> tmpBuff;
TBuf8<512> tmpBuff8;
TInt size, res;
RThread thisThread;
RFile logFile;
res = logFile.Open(fserv, _L("C:\\logs\\pico.log"), EFileWrite|EFileShareAny);
if(res) goto fail1;
logFile.Size(size); logFile.Seek(ESeekStart, size);
now.FormatL(tmpBuff, _L("%H:%T:%S.%C: "));
tmpBuff8.Copy(tmpBuff);
logFile.Write(tmpBuff8);
tmpBuff8.Format(TPtr8((TUint8 *)"%03i: ", 6, 6), (TInt32) thisThread.Id());
logFile.Write(tmpBuff8);
VA_LIST args;
VA_START(args, aFmt);
tmpBuff.FormatList(aFmt, args);
VA_END(args);
tmpBuff8.Copy(tmpBuff);
logFile.Write(tmpBuff8);
logFile.Write(TPtrC8((TUint8 const *) "\n"));
logFile.Flush();
logFile.Close();
fail1:
thisThread.Close();
fserv.Close();
logMutex.Signal();
}
#endif
#endif

View file

@ -0,0 +1,27 @@
#include <e32std.h>
#define __DEBUG_PRINT_C
#define __DEBUG_PRINT_FILE
#if defined(__DEBUG_PRINT) || defined(__WINS__)
#include <e32svr.h> // RDebug
#ifdef __DEBUG_PRINT_FILE
void debugPrintFile(TRefByValue<const TDesC> aFmt, ...);
#define DEBUGPRINT debugPrintFile
#else
#define DEBUGPRINT RDebug::Print
#endif
TDesC* DO_CONV(const char* s);
#ifdef __DEBUG_PRINT_C
#ifdef __cplusplus
extern "C"
#endif
void dprintf(char *format, ...);
#endif
#else
#define DEBUGPRINT(x...)
#undef __DEBUG_PRINT_C
#undef __DEBUG_PRINT_FILE
#endif
void ExceptionHandler(TExcType exc);

View file

@ -0,0 +1,999 @@
// mainloop with window server event handling
// event polling mechnism was taken from
// Peter van Sebille's projects
// (c) Copyright 2006, notaz
// All Rights Reserved
#include <e32base.h>
#include <hal.h>
#include <e32keys.h>
#include <w32std.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include "debug.h"
#include "../Engine.h"
#include "../../../pico/picoInt.h"
#include "vid.h"
#include "polledAS.h"
//#include "audio.h"
#include "audio_mediaserver.h"
#include <EZlib.h>
#include "../../../zlib/gzio_symb.h"
//#define BENCHMARK
// scancodes we care about
enum TUsedScanCodes {
EStdKeyM600JogUp = EStdKeyDevice1,
EStdKeyM600JogDown = EStdKeyDevice2,
};
static unsigned char keyFlags[256]; // lsb->msb: key_down, pulse_only, ?, ?, ?, ?, not_configurable, disabled
static unsigned char pressedKeys[11]; // List of pressed key scancodes, up to 10
// list of areas
TPicoAreaConfigEntry areaConfig[] = {
{ TRect( 0, 0, 0, 0) },
// small corner bottons
{ TRect( 0, 0, 15, 15) },
{ TRect(224, 0, 239, 15) },
{ TRect( 0, 304, 15, 319) },
{ TRect(224, 304, 239, 319) },
// normal buttons
{ TRect( 0, 0, 79, 63) },
{ TRect( 80, 0, 159, 63) },
{ TRect(160, 0, 239, 63) },
{ TRect( 0, 64, 79, 127) },
{ TRect( 80, 64, 159, 127) },
{ TRect(160, 64, 239, 127) },
{ TRect( 0, 128, 79, 191) },
{ TRect( 80, 128, 159, 191) },
{ TRect(160, 128, 239, 191) },
{ TRect( 0, 192, 79, 255) },
{ TRect( 80, 192, 159, 255) },
{ TRect(160, 192, 239, 255) },
{ TRect( 0, 256, 79, 319) },
{ TRect( 80, 256, 159, 319) },
{ TRect(160, 256, 239, 319) },
{ TRect( 0, 0, 0, 0) }
};
// PicoPad[] format: SACB RLDU
const char *actionNames[] = {
"UP", "DOWN", "LEFT", "RIGHT", "B", "C", "A", "START",
0, 0, 0, 0, 0, 0, 0, 0, // Z, Y, X, MODE (enabled only when needed), ?, ?, ?, ?
0, 0, 0, 0, "VOLUME@UP", "VOLUME@DOWN", "NEXT@SAVE@SLOT", "PREV@SAVE@SLOT", // ?, ?, ?, ?, vol_up, vol_down, next_slot, prev_slot
0, 0, "PAUSE@EMU", "SAVE@STATE", "LOAD@STATE", 0, 0, "DONE" // ?, switch_renderer, [...], "FRAMESKIP@8", "AUTO@FRAMESKIP"
};
// globals are allowed, so why not to (ab)use them?
//TInt machineUid = 0;
int gamestate = PGS_Paused, gamestate_next = PGS_Paused;
TPicoConfig *currentConfig = 0;
static char noticeMsg[64]; // notice msg to draw
static timeval noticeMsgTime = { 0, 0 }; // when started showing
static CGameAudioMS *gameAudio = 0; // the audio object itself
static int reset_timing, pico_was_reset;
static int state_slot = 0;
extern const char *RomFileName;
extern RSemaphore initSemaphore;
extern RSemaphore pauseSemaphore;
// some forward declarations
static void MainInit();
static void MainExit();
static void DumpMemInfo();
void MainOldCleanup();
class TPicoDirectScreenAccess : public MDirectScreenAccess
{
public: // implements MDirectScreenAccess
void Restart(RDirectScreenAccess::TTerminationReasons aReason);
public: // implements MAbortDirectScreenAccess
void AbortNow(RDirectScreenAccess::TTerminationReasons aReason);
};
// just for a nicer grouping of WS related stuff
class CGameWindow
{
public:
static void ConstructResourcesL(void);
static void FreeResources(void);
static void DoKeys(void);
static void DoKeysConfig(TUint &which);
static void RunEvents(TUint32 which);
static RWsSession* iWsSession;
static RWindowGroup iWsWindowGroup;
static RWindow iWsWindow;
static CWsScreenDevice* iWsScreen;
static CWindowGc* iWindowGc;
static TRequestStatus iWsEventStatus;
// static TThreadId iLauncherThreadId;
// static RDirectScreenAccess* iDSA;
// static TRequestStatus iDSAstatus;
static TPicoDirectScreenAccess iPDSA;
static CDirectScreenAccess* iDSA;
};
static int snd_excess_add = 0, snd_excess_cnt = 0; // hack
static void updateSound(void)
{
int len = PsndLen;
snd_excess_cnt += snd_excess_add;
if (snd_excess_cnt >= 0x10000) {
snd_excess_cnt -= 0x10000;
if (PicoOpt&8) {
PsndOut[len*2] = PsndOut[len*2-2];
PsndOut[len*2+1] = PsndOut[len*2-1];
} else {
PsndOut[len] = PsndOut[len-1];
}
len++;
}
PsndOut = gameAudio->NextFrameL(len);
if(!PsndOut) { // sound output problems?
strcpy(noticeMsg, "SOUND@OUTPUT@ERROR;@SOUND@DISABLED");
gettimeofday(&noticeMsgTime, 0);
}
}
static void SkipFrame(void)
{
PicoSkipFrame=1;
PicoFrame();
PicoSkipFrame=0;
}
static void simpleWait(int thissec, int lim_time)
{
struct timeval tval;
int sleep = 0;
gettimeofday(&tval, 0);
if(thissec != tval.tv_sec) tval.tv_usec+=1000000;
sleep = lim_time - tval.tv_usec - 2000;
if (sleep > 0) {
// User::After((sleep = lim_time - tval.tv_usec));
User::AfterHighRes(sleep);
}
}
static void TargetEpocGameL()
{
char buff[24]; // fps count c string
struct timeval tval; // timing
int thissec = 0, frames_done = 0, frames_shown = 0;
int target_fps, target_frametime;
int i, lim_time;
//TRawEvent blevent;
MainInit();
buff[0] = 0;
// just to keep the backlight on (works only on UIQ2)
//blevent.Set(TRawEvent::EActive);
// loop?
for(;;) {
if(gamestate == PGS_Running) {
// switch context to other thread
User::After(50000);
// prepare window and stuff
CGameWindow::ConstructResourcesL();
// if the system has something to do, it should better do it now
User::After(50000);
//CPolledActiveScheduler::Instance()->Schedule();
// pal/ntsc might have changed, reset related stuff
if(Pico.m.pal) {
target_fps = 50;
if(!noticeMsgTime.tv_sec) strcpy(noticeMsg, "PAL@SYSTEM@/@50@FPS");
} else {
target_fps = 60;
if(!noticeMsgTime.tv_sec) strcpy(noticeMsg, "NTSC@SYSTEM@/@60@FPS");
}
target_frametime = 1000000/target_fps;
if(!noticeMsgTime.tv_sec && pico_was_reset)
gettimeofday(&noticeMsgTime, 0);
if (PsndOut) {
snd_excess_cnt = 0;
snd_excess_add = ((PsndRate - PsndLen*target_fps)<<16) / target_fps;
}
pico_was_reset = 0;
reset_timing = 1;
while(gamestate == PGS_Running) {
gettimeofday(&tval, 0);
if(reset_timing) {
reset_timing = 0;
thissec = tval.tv_sec;
frames_done = tval.tv_usec/target_frametime;
}
// show notice message?
char *notice = 0;
if(noticeMsgTime.tv_sec) {
if((tval.tv_sec*1000000+tval.tv_usec) - (noticeMsgTime.tv_sec*1000000+noticeMsgTime.tv_usec) > 2000000) // > 2.0 sec
noticeMsgTime.tv_sec = noticeMsgTime.tv_usec = 0;
else notice = noticeMsg;
}
// second changed?
if(thissec != tval.tv_sec) {
#ifdef BENCHMARK
static int bench = 0, bench_fps = 0, bench_fps_s = 0, bfp = 0, bf[4];
if(++bench == 10) {
bench = 0;
bench_fps_s = bench_fps;
bf[bfp++ & 3] = bench_fps;
bench_fps = 0;
}
bench_fps += frames_shown;
sprintf(buff, "%02i/%02i/%02i", frames_shown, bench_fps_s, (bf[0]+bf[1]+bf[2]+bf[3])>>2);
#else
if(currentConfig->iFlags & 2)
sprintf(buff, "%02i/%02i", frames_shown, frames_done);
#endif
thissec = tval.tv_sec;
if(PsndOut == 0 && currentConfig->iFrameskip >= 0) {
frames_done = frames_shown = 0;
} else {
// it is quite common for this implementation to leave 1 fame unfinished
// when second changes, but we don't want buffer to starve.
if(PsndOut && frames_done < target_fps && frames_done > target_fps-5) {
SkipFrame(); frames_done++;
}
frames_done -= target_fps; if (frames_done < 0) frames_done = 0;
frames_shown -= target_fps; if (frames_shown < 0) frames_shown = 0;
if (frames_shown > frames_done) frames_shown = frames_done;
}
}
lim_time = (frames_done+1) * target_frametime;
if(currentConfig->iFrameskip >= 0) { // frameskip enabled
for(i = 0; i < currentConfig->iFrameskip; i++) {
CGameWindow::DoKeys();
SkipFrame(); frames_done++;
if (PsndOut) { // do framelimitting if sound is enabled
gettimeofday(&tval, 0);
if(thissec != tval.tv_sec) tval.tv_usec+=1000000;
if(tval.tv_usec < lim_time) { // we are too fast
simpleWait(thissec, lim_time);
}
}
lim_time += target_frametime;
}
} else if(tval.tv_usec > lim_time) { // auto frameskip
// no time left for this frame - skip
CGameWindow::DoKeys();
SkipFrame(); frames_done++;
continue;
}
CGameWindow::DoKeys();
PicoFrame();
// check time
gettimeofday(&tval, 0);
if(thissec != tval.tv_sec) tval.tv_usec+=1000000;
// sleep if we are still too fast
if(PsndOut != 0 || currentConfig->iFrameskip < 0)
{
// TODO: check if User::After() is accurate
gettimeofday(&tval, 0);
if(thissec != tval.tv_sec) tval.tv_usec+=1000000;
if(tval.tv_usec < lim_time)
{
// we are too fast
simpleWait(thissec, lim_time);
}
}
CPolledActiveScheduler::Instance()->Schedule();
if (gamestate != PGS_Paused)
vidDrawFrame(notice, buff, frames_shown);
frames_done++; frames_shown++;
}
// save SRAM
if((currentConfig->iFlags & 1) && SRam.changed) {
saveLoadGame(0, 1);
SRam.changed = 0;
}
CGameWindow::FreeResources();
} else if(gamestate == PGS_Paused) {
DEBUGPRINT(_L("pausing.."));
pauseSemaphore.Wait();
} else if(gamestate == PGS_KeyConfig) {
// switch context to other thread
User::After(50000);
// prepare window and stuff
CGameWindow::ConstructResourcesL();
TUint whichAction = 0;
while(gamestate == PGS_KeyConfig) {
CGameWindow::DoKeysConfig(whichAction);
CPolledActiveScheduler::Instance()->Schedule();
if (gamestate != PGS_Paused)
vidKeyConfigFrame(whichAction);
User::After(150000);
}
CGameWindow::FreeResources();
} else if(gamestate == PGS_DebugHeap) {
#ifdef __DEBUG_PRINT
TInt cells = User::CountAllocCells();
TInt mem;
User::AllocSize(mem);
DEBUGPRINT(_L("worker: cels=%d, size=%d KB"), cells, mem/1024);
gamestate = gamestate_next;
#endif
} else if(gamestate == PGS_Quit) {
break;
}
}
MainExit();
}
// main initialization
static void MainInit()
{
DEBUGPRINT(_L("\r\n\r\nstarting.."));
// our thread might have been crashed previously, so many other objects may be still floating around
MainOldCleanup();
DEBUGPRINT(_L("CPolledActiveScheduler::NewL()"));
CPolledActiveScheduler::NewL(); // create Polled AS for the sound engine
// HAL::Get(HALData::EMachineUid, machineUid); // find out the machine UID
DumpMemInfo();
// try to start pico
DEBUGPRINT(_L("PicoInit();"));
PicoInit();
PicoDrawSetColorFormat(2);
PicoWriteSound = updateSound;
// if (pauseSemaphore.Handle() <= 0)
// pauseSemaphore.CreateLocal(0);
DEBUGPRINT(_L("initSemaphore.Signal()"));
initSemaphore.Signal();
}
// does not return
static void MainExit()
{
RThread thisThread;
DEBUGPRINT(_L("%i: cleaning up.."), (TInt32) thisThread.Id());
// save SRAM
if((currentConfig->iFlags & 1) && SRam.changed) {
saveLoadGame(0, 1);
SRam.changed = 0;
}
PicoExit();
// pauseSemaphore.Close();
if(gameAudio) delete gameAudio;
// Polled AS
delete CPolledActiveScheduler::Instance();
}
void MainOldCleanup()
{
DEBUGPRINT(_L("MainOldCleanup.."));
// There was previously a handle leak here, so thread stuff was not cleaned
// and I thought I would have to do it mself.
// clean any resources which might be left after a thread crash
//CGameWindow::FreeResources(ETrue);
//if(CPolledActiveScheduler::Instance())
// delete CPolledActiveScheduler::Instance();
}
static void DumpMemInfo()
{
TInt ramSize, ramSizeFree, romSize;
HAL::Get(HALData::EMemoryRAM, ramSize);
HAL::Get(HALData::EMemoryRAMFree, ramSizeFree);
HAL::Get(HALData::EMemoryROM, romSize);
DEBUGPRINT(_L("ram=%dKB, ram_free=%dKB, rom=%dKB"), ramSize/1024, ramSizeFree/1024, romSize/1024);
}
TInt EmuThreadFunction(TAny*)
{
const TUint32 exs = KExceptionAbort|KExceptionKill|KExceptionUserInterrupt|KExceptionFpe|KExceptionFault|KExceptionInteger|KExceptionDebug;
DEBUGPRINT(_L("EmuThreadFunction()"));
User::SetExceptionHandler(ExceptionHandler, exs/*(TUint32) -1*/); // does not work?
//TInt pc, sp;
//asm volatile ("str pc, %0" : "=m" (pc) );
//asm volatile ("str sp, %0" : "=m" (sp) );
//RDebug::Print(_L("executing @ 0x%08x, sp=0x%08x"), pc, sp);
/*
RDebug::Print(_L("Base Bottom Top Size RW Name"));
TBuf<4> l_r(_L("R")), l_w(_L("W")), l_d(_L("-"));
RChunk chunk;
TFullName chunkname;
TFindChunk findChunk(_L("*"));
while( findChunk.Next(chunkname) != KErrNotFound ) {
chunk.Open(findChunk);
RDebug::Print(_L("%08x %08x %08x %08x %S%S %S"), chunk.Base(), chunk.Base()+chunk.Bottom(), chunk.Base()+chunk.Top(), chunk.Size(), chunk.IsReadable() ? &l_r : &l_d, chunk.IsWritable() ? &l_w : &l_d, &chunkname);
chunk.Close();
}
*/
// can't do that, will crash here
// if(cleanup) {
// DEBUGPRINT(_L("found old CTrapCleanup, deleting.."));
// delete cleanup;
// }
CTrapCleanup *cleanup = CTrapCleanup::New();
TRAPD(error, TargetEpocGameL());
__ASSERT_ALWAYS(!error, User::Panic(_L("Picosmall"), error));
delete cleanup;
DEBUGPRINT(_L("exitting.."));
return 1;
}
void TPicoDirectScreenAccess::Restart(RDirectScreenAccess::TTerminationReasons aReason)
{
DEBUGPRINT(_L("TPicoDirectScreenAccess::Restart(%i)"), aReason);
// if (CGameWindow::iDSA) {
// TRAPD(error, CGameWindow::iDSA->StartL());
// if (error) DEBUGPRINT(_L("iDSA->StartL() error: %i"), error);
// }
}
void TPicoDirectScreenAccess::AbortNow(RDirectScreenAccess::TTerminationReasons aReason)
{
DEBUGPRINT(_L("TPicoDirectScreenAccess::AbortNow(%i)"), aReason);
// the WS wants us to stop, so let's obey
gamestate = PGS_Paused;
}
void CGameWindow::ConstructResourcesL()
{
DEBUGPRINT(_L("ConstructResourcesL()"));
// connect to window server
// tried to create it globally and not re-connect everytime,
// but my window started to lose focus strangely
iWsSession = new(ELeave) RWsSession();
User::LeaveIfError(iWsSession->Connect());
// * Tell the Window Server not to mess about with our process priority
// * Also, because of the way legacy games are written, they never sleep
// * and thus never voluntarily yield the CPU. We set our process priority
// * to EPriorityForeground and hope that a Telephony application on
// * this device runs at EPriorityForeground as well. If not, tough! ;-)
iWsSession->ComputeMode(RWsSession::EPriorityControlDisabled);
RProcess me;
me.SetPriority(EPriorityForeground);
iWsScreen = new(ELeave) CWsScreenDevice(*iWsSession);
User::LeaveIfError(iWsScreen->Construct());
// User::LeaveIfError(iWsScreen->CreateContext(iWindowGc));
iWsWindowGroup = RWindowGroup(*iWsSession);
User::LeaveIfError(iWsWindowGroup.Construct((TUint32)&iWsWindowGroup));
//iWsWindowGroup.SetOrdinalPosition(0);
//iWsWindowGroup.SetName(KServerWGName);
iWsWindowGroup.EnableScreenChangeEvents(); // flip events (EEventScreenDeviceChanged)
iWsWindowGroup.EnableFocusChangeEvents(); // EEventFocusGroupChanged
iWsWindowGroup.SetOrdinalPosition(0, 1); // TInt aPos, TInt aOrdinalPriority
iWsWindow=RWindow(*iWsSession);
User::LeaveIfError(iWsWindow.Construct(iWsWindowGroup, (TUint32)&iWsWindow));
iWsWindow.SetSize(iWsScreen->SizeInPixels());
iWsWindow.PointerFilter(EPointerFilterDrag, 0);
iWsWindow.SetPointerGrab(ETrue);
iWsWindow.SetVisible(ETrue);
iWsWindow.Activate();
#if 0
// request access through RDirectScreenAccess api, but don't care about the result
// hangs?
RRegion *dsa_region = 0;
iDSA = new(ELeave) RDirectScreenAccess(*iWsSession);
if(iDSA->Construct() == KErrNone)
iDSA->Request(dsa_region, iDSAstatus, iWsWindow);
DEBUGPRINT(_L("DSA: %i"), dsa_region ? dsa_region->Count() : -1);
#endif
TInt ret;
// request access through CDirectScreenAccess
iDSA = CDirectScreenAccess::NewL(*iWsSession, *iWsScreen, iWsWindow, iPDSA);
// now get the screenbuffer
TScreenInfoV01 screenInfo;
TPckg<TScreenInfoV01> sI(screenInfo);
UserSvr::ScreenInfo(sI);
if(!screenInfo.iScreenAddressValid)
User::Leave(KErrNotSupported);
DEBUGPRINT(_L("framebuffer=0x%08x (%dx%d)"), screenInfo.iScreenAddress,
screenInfo.iScreenSize.iWidth, screenInfo.iScreenSize.iHeight);
// vidInit
DEBUGPRINT(_L("vidInit()"));
ret = vidInit((void *)screenInfo.iScreenAddress, 0);
DEBUGPRINT(_L("vidInit() done (%i)"), ret);
User::LeaveIfError(ret);
memset(keyFlags, 0, 256);
keyFlags[EStdKeyM600JogUp] = keyFlags[EStdKeyM600JogDown] = 2; // add "pulse only" for jog up/down
keyFlags[EStdKeyOff] = 0x40; // not configurable
// try to start the audio engine
static int PsndRate_old = 0, PicoOpt_old = 0, pal_old = 0;
if(gamestate == PGS_Running && (currentConfig->iFlags & 4)) {
TInt err = 0;
if(PsndRate != PsndRate_old || (PicoOpt&11) != (PicoOpt_old&11) || Pico.m.pal != pal_old) {
// if rate changed, reset all enabled chips, else reset only those chips, which were recently enabled
//sound_reset(PsndRate != PsndRate_old ? PicoOpt : (PicoOpt&(PicoOpt^PicoOpt_old)));
sound_rerate();
}
if(!gameAudio || PsndRate != PsndRate_old || ((PicoOpt&8) ^ (PicoOpt_old&8)) || Pico.m.pal != pal_old) { // rate or stereo or pal/ntsc changed
if(gameAudio) delete gameAudio; gameAudio = 0;
DEBUGPRINT(_L("starting audio: %i len: %i stereo: %i, pal: %i"), PsndRate, PsndLen, PicoOpt&8, Pico.m.pal);
TRAP(err, gameAudio = CGameAudioMS::NewL(PsndRate, (PicoOpt&8) ? 1 : 0, Pico.m.pal ? 50 : 60));
}
if( gameAudio) {
TRAP(err, PsndOut = gameAudio->ResumeL());
}
if(err) {
if(gameAudio) delete gameAudio;
gameAudio = 0;
PsndOut = 0;
strcpy(noticeMsg, "SOUND@STARTUP@FAILED");
gettimeofday(&noticeMsgTime, 0);
}
PsndRate_old = PsndRate;
PicoOpt_old = PicoOpt;
pal_old = Pico.m.pal;
} else {
if(gameAudio) delete gameAudio;
gameAudio = 0;
PsndOut = 0;
}
CPolledActiveScheduler::Instance()->Schedule();
// start key WS event polling
iWsSession->EventReady(&iWsEventStatus);
iWsSession->Flush(); // check: short hang in UIQ2
User::After(1);
// I don't know why but the Window server sometimes hangs completely (hanging the phone too) after calling StartL()
// Is this a sync broblem? weird bug?
TRAP(ret, iDSA->StartL());
if (ret) DEBUGPRINT(_L("iDSA->StartL() error: %i"), ret);
// User::After(1);
// CPolledActiveScheduler::Instance()->Schedule();
DEBUGPRINT(_L("CGameWindow::ConstructResourcesL() finished."));
}
// this may be run even if there is nothing to free
void CGameWindow::FreeResources()
{
if(gameAudio) gameAudio->Pause();
//DEBUGPRINT(_L("CPolledActiveScheduler::Instance(): %08x"), CPolledActiveScheduler::Instance());
if(CPolledActiveScheduler::Instance())
CPolledActiveScheduler::Instance()->Schedule();
#if 0
// free RDirectScreenAccess stuff (seems to be deleted automatically after crash?)
if(iDSA) {
iDSA->Cancel();
iDSA->Close();
delete iDSA;
}
iDSA = NULL;
#endif
if(iDSA) delete iDSA;
iDSA = 0;
if(iWsSession->WsHandle() > 0 && iWsEventStatus != KRequestPending) // TODO: 2 UIQ2 (?)
iWsSession->EventReadyCancel();
if(iWsWindow.WsHandle() > 0)
iWsWindow.Close();
if(iWsWindowGroup.WsHandle() > 0)
iWsWindowGroup.Close();
// these must be deleted before calling iWsSession->Close()
if(iWsScreen) {
delete iWsScreen;
iWsScreen = NULL;
}
if(iWsSession->WsHandle() > 0) {
iWsSession->Close();
delete iWsSession;
}
vidFree();
// emu might change renderer by itself, so we may need to sync config
if(currentConfig && currentConfig->iPicoOpt != PicoOpt) {
currentConfig->iFlags |= 0x80;
}
}
void CGameWindow::DoKeys(void)
{
TWsEvent iWsEvent;
TInt iWsEventType;
unsigned long allActions = 0;
static unsigned long areaActions = 0, forceUpdate = 0;
int i, nEvents;
for(nEvents = 0; iWsEventStatus != KRequestPending; nEvents++)
{
iWsSession->GetEvent(iWsEvent);
iWsEventType = iWsEvent.Type();
// pointer events?
if(iWsEventType == EEventPointer) {
if(iWsEvent.Pointer()->iType == TPointerEvent::EButton1Up) {
areaActions = 0; // remove all directionals
} else { // if(iWsEvent.Pointer()->iType == TPointerEvent::EButton1Down) {
TPoint p = iWsEvent.Pointer()->iPosition;
const TPicoAreaConfigEntry *e = areaConfig + 1;
for(i = 0; !e->rect.IsEmpty(); e++, i++)
if(e->rect.Contains(p)) {
areaActions = currentConfig->iAreaBinds[i];
break;
}
//DEBUGPRINT(_L("pointer event: %i %i"), p.iX, p.iY);
}
}
else if(iWsEventType == EEventKeyDown || iWsEventType == EEventKeyUp) {
TInt iScanCode = iWsEvent.Key()->iScanCode;
//DEBUGPRINT(_L("key event: 0x%02x"), iScanCode);
if(iScanCode < 256)
{
if(iWsEventType == EEventKeyDown) {
keyFlags[iScanCode] |= 1;
for(i=0; i < 10; i++) {
if( pressedKeys[i] == (TUint8) iScanCode) break;
if(!pressedKeys[i]) { pressedKeys[i] = (TUint8) iScanCode; break; }
}
} else if(!(keyFlags[iScanCode]&2)) {
keyFlags[iScanCode] &= ~1;
for(i=0; i < 10; i++) {
if(pressedKeys[i] == (TUint8) iScanCode) { pressedKeys[i] = 0; break; }
}
}
// power?
if(iScanCode == EStdKeyOff) gamestate = PGS_Paused;
} else {
DEBUGPRINT(_L("weird scancode: 0x%02x"), iScanCode);
}
}
else if(iWsEventType == EEventScreenDeviceChanged) {
// ???
//User::After(500000);
//reset_timing = 1;
DEBUGPRINT(_L("EEventScreenDeviceChanged, focus: %i, our: %i"),
iWsSession->GetFocusWindowGroup(), iWsWindowGroup.Identifier());
}
else if(iWsEventType == EEventFocusGroupChanged) {
TInt focusGrpId = iWsSession->GetFocusWindowGroup();
DEBUGPRINT(_L("EEventFocusGroupChanged: %i, our: %i"),
focusGrpId, iWsWindowGroup.Identifier());
// if it is not us and not launcher that got focus, pause emu
if(focusGrpId != iWsWindowGroup.Identifier())
gamestate = PGS_Paused;
}
iWsEventStatus = KRequestPending;
iWsSession->EventReady(&iWsEventStatus);
}
if(nEvents || forceUpdate) {
allActions = areaActions;
forceUpdate = 0;
// add all pushed button actions
for(i = 9; i >= 0; i--) {
int scan = pressedKeys[i];
if(scan) {
if(keyFlags[scan] & 1) allActions |= currentConfig->iKeyBinds[scan];
if((keyFlags[scan]& 3)==3) forceUpdate = 1;
if(keyFlags[scan] & 2) keyFlags[scan] &= ~1;
}
}
PicoPad[0] = (unsigned short) allActions;
if(allActions & 0xFFFF0000) {
RunEvents(allActions >> 16);
areaActions = 0;
}
}
}
void CGameWindow::DoKeysConfig(TUint &which)
{
TWsEvent iWsEvent;
int i;
while(iWsEventStatus != KRequestPending)
{
TUint currentActCode = 1 << which;
iWsSession->GetEvent(iWsEvent);
// pointer events?
if(iWsEvent.Type() == EEventPointer) {
TPoint p = iWsEvent.Pointer()->iPosition;
TRect prev(56, 0, 120, 26);
TRect next(120, 0, 180, 26);
if(iWsEvent.Pointer()->iType == TPointerEvent::EButton1Down) {
if(prev.Contains(p)) do { which = (which-1) & 0x1F; } while(!actionNames[which]);
else if(next.Contains(p)) do { which = (which+1) & 0x1F; } while(!actionNames[which]);
else if(which == 31) gamestate = PGS_Paused; // done
else {
const TPicoAreaConfigEntry *e = areaConfig + 1;
for(i = 0; e->rect != TRect(0,0,0,0); e++, i++)
if(e->rect.Contains(p)) {
currentConfig->iAreaBinds[i] ^= currentActCode;
break;
}
}
}
}
else if(iWsEvent.Type() == EEventKeyDown || iWsEvent.Type() == EEventKeyUp)
{
TUint scan = (TUint) iWsEvent.Key()->iScanCode;
// key events?
if(iWsEvent.Type() == EEventKeyDown) {
if(which == 31) {
gamestate = PGS_Paused;
} else if (scan < 256) {
if(!(keyFlags[scan]&0x40)) currentConfig->iKeyBinds[scan] ^= currentActCode;
}
}
// power?
if(iWsEvent.Key()->iScanCode == EStdKeyOff) gamestate = PGS_Paused;
}
else if(iWsEvent.Type() == EEventFocusGroupChanged) {
TInt focusGrpId = iWsSession->GetFocusWindowGroup();
// if we lost focus, exit config mode
if(focusGrpId != iWsWindowGroup.Identifier())
gamestate = PGS_Paused;
}
// iWsEventStatus = KRequestPending;
iWsSession->EventReady(&iWsEventStatus);
}
}
void CGameWindow::RunEvents(TUint32 which)
{
if(which & 0x4000) currentConfig->iFrameskip = -1;
if(which & 0x2000) currentConfig->iFrameskip = 8;
if(which & 0x1800) { // save or load (but not both)
if(PsndOut) gameAudio->Pause(); // this may take a while, so we pause sound output
vidDrawNotice((which & 0x1000) ? "LOADING@GAME" : "SAVING@GAME");
saveLoadGame(which & 0x1000);
if(PsndOut) PsndOut = gameAudio->ResumeL();
reset_timing = 1;
}
if(which & 0x0400) gamestate = PGS_Paused;
if(which & 0x0200) { // switch renderer
if(!(currentConfig->iScreenMode == TPicoConfig::PMFit &&
(currentConfig->iScreenRotation == TPicoConfig::PRot0 || currentConfig->iScreenRotation == TPicoConfig::PRot180))) {
PicoOpt^=0x10;
vidInit(0, 1);
strcpy(noticeMsg, (PicoOpt&0x10) ? "ALT@RENDERER" : "DEFAULT@RENDERER");
gettimeofday(&noticeMsgTime, 0);
}
}
if(which & 0x00c0) {
if(which&0x0080) {
state_slot -= 1;
if(state_slot < 0) state_slot = 9;
} else {
state_slot += 1;
if(state_slot > 9) state_slot = 0;
}
sprintf(noticeMsg, "SAVE@SLOT@%i@SELECTED", state_slot);
gettimeofday(&noticeMsgTime, 0);
}
if(which & 0x0020) if(gameAudio) gameAudio->ChangeVolume(0);
if(which & 0x0010) if(gameAudio) gameAudio->ChangeVolume(1);
}
// must use wrappers, or else will run into some weird loader error (see pico/area.c)
static size_t fRead2(void *p, size_t _s, size_t _n, void *file)
{
return fread(p, _s, _n, (FILE *) file);
}
static size_t fWrite2(void *p, size_t _s, size_t _n, void *file)
{
return fwrite(p, _s, _n, (FILE *) file);
}
static size_t gzRead2(void *p, size_t, size_t _n, void *file)
{
return gzread(file, p, _n);
}
static size_t gzWrite2(void *p, size_t, size_t _n, void *file)
{
return gzwrite(file, p, _n);
}
// this function is shared between both threads
int saveLoadGame(int load, int sram)
{
int res = 0;
if(!RomFileName) return -1;
// make save filename
char saveFname[KMaxFileName];
strcpy(saveFname, RomFileName);
saveFname[KMaxFileName-8] = 0;
if(saveFname[strlen(saveFname)-4] == '.') saveFname[strlen(saveFname)-4] = 0;
if(sram) strcat(saveFname, ".srm");
else {
if(state_slot > 0 && state_slot < 10) sprintf(saveFname, "%s.%i", saveFname, state_slot);
strcat(saveFname, ".mds");
}
DEBUGPRINT(_L("saveLoad (%i, %i): %S"), load, sram, DO_CONV(saveFname));
if(sram) {
FILE *sramFile;
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) {
sramFile = fopen(saveFname, "rb");
if(!sramFile) return -1;
fread(SRam.data, 1, sram_size, sramFile);
fclose(sramFile);
} 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) {
sramFile = fopen(saveFname, "wb");
res = fwrite(SRam.data, 1, sram_size, sramFile);
res = (res != sram_size) ? -1 : 0;
fclose(sramFile);
}
}
return res;
} else {
void *PmovFile = NULL;
// 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 = fRead2;
areaWrite = fWrite2;
}
}
if(PmovFile) {
PmovState(load ? 6 : 5, PmovFile); // load/save
strcpy(noticeMsg, load ? "GAME@LOADED" : "GAME@SAVED");
if(areaRead == gzRead2)
gzclose(PmovFile);
else fclose ((FILE *) PmovFile);
PmovFile = 0;
if (load) Pico.m.dirtyPal=1;
} else {
strcpy(noticeMsg, load ? "LOAD@FAILED" : "SAVE@FAILED");
res = -1;
}
gettimeofday(&noticeMsgTime, 0);
return res;
}
}
// static class members
RWsSession* CGameWindow::iWsSession;
RWindowGroup CGameWindow::iWsWindowGroup;
RWindow CGameWindow::iWsWindow;
CWsScreenDevice* CGameWindow::iWsScreen = NULL;
CWindowGc* CGameWindow::iWindowGc = NULL;
TRequestStatus CGameWindow::iWsEventStatus = KRequestPending;
//RDirectScreenAccess* CGameWindow::iDSA;
//TRequestStatus CGameWindow::iDSAstatus = KRequestPending;
TPicoDirectScreenAccess CGameWindow::iPDSA;
CDirectScreenAccess* CGameWindow::iDSA = NULL;

View file

@ -0,0 +1,269 @@
/*******************************************************************
*
* File: PolledAS.cpp
*
* Author: Peter van Sebille (peter@yipton.net)
*
* (c) Copyright 2002, Peter van Sebille
* All Rights Reserved
*
*******************************************************************/
/*
* Oh Lord, forgive me for I have sinned.
* In their infinite wisdom, Symbian Engineers have decided that
* the Active Scheduler's queue of Active Objects is private
* and no getters are provided... sigh.
* This mere mortal will have to excercise the power of C pre-processor
* once more to circumvent the will of the gods.
*/
#include <e32std.h>
// from e32base.h
class CBase
{
public:
/**
Default constructor
*/
inline CBase() {}
IMPORT_C virtual ~CBase();
inline TAny* operator new(TUint aSize, TAny* aBase) __NO_THROW { Mem::FillZ(aBase, aSize); return aBase; }
inline TAny* operator new(TUint aSize) __NO_THROW { return User::AllocZ(aSize); }
inline TAny* operator new(TUint aSize, TLeave) { return User::AllocZL(aSize); }
inline TAny* operator new(TUint aSize, TUint aExtraSize) { return User::AllocZ(aSize + aExtraSize); }
inline TAny* operator new(TUint aSize, TLeave, TUint aExtraSize) { return User::AllocZL(aSize + aExtraSize); }
IMPORT_C static void Delete(CBase* aPtr);
protected:
IMPORT_C virtual TInt Extension_(TUint aExtensionId, TAny*& a0, TAny* a1);
private:
CBase(const CBase&);
CBase& operator=(const CBase&);
private:
};
class TRequestStatusFaked
{
public:
inline TRequestStatusFaked() : iFlags(0) {};
inline TRequestStatusFaked(TInt aVal) : iStatus(aVal), iFlags(aVal==KRequestPending ? TRequestStatusFaked::ERequestPending : 0) {}
/* inline TInt operator=(TInt aVal);
inline TBool operator==(TInt aVal) const;
*/
inline TBool operator!=(TInt aVal) const {return(iStatus!=aVal);}
/*
inline TBool operator>=(TInt aVal) const;
inline TBool operator<=(TInt aVal) const;
inline TBool operator>(TInt aVal) const;
inline TBool operator<(TInt aVal) const;
inline TInt Int() const;
private:
*/
enum
{
EActive = 1, //bit0
ERequestPending = 2, //bit1
};
TInt iStatus;
TUint iFlags;
friend class CActive;
friend class CActiveScheduler;
friend class CServer2;
};
class CActive : public CBase
{
public:
enum TPriority
{
EPriorityIdle=-100,
EPriorityLow=-20,
EPriorityStandard=0,
EPriorityUserInput=10,
EPriorityHigh=20,
};
public:
IMPORT_C ~CActive();
IMPORT_C void Cancel();
IMPORT_C void Deque();
IMPORT_C void SetPriority(TInt aPriority);
inline TBool IsActive() const {return(iStatus.iFlags&TRequestStatus::EActive);}
inline TBool IsAdded() const {return(iLink.iNext!=NULL);}
inline TInt Priority() const {return iLink.iPriority;}
protected:
IMPORT_C CActive(TInt aPriority);
IMPORT_C void SetActive();
virtual void DoCancel() =0;
virtual void RunL() =0;
IMPORT_C virtual TInt RunError(TInt aError);
protected:
IMPORT_C virtual TInt Extension_(TUint aExtensionId, TAny*& a0, TAny* a1);
public:
TRequestStatusFaked iStatus; // hope this will work
private:
// TBool iActive;
TPriQueLink iLink;
TAny* iSpare;
friend class CActiveScheduler;
friend class CServer;
friend class CServer2;
friend class CPrivatePolledActiveScheduler; // added
};
class CActiveScheduler : public CBase
{
friend class CActiveSchedulerWait;
public:
struct TLoop;
typedef TLoop* TLoopOwner;
public:
IMPORT_C CActiveScheduler();
IMPORT_C ~CActiveScheduler();
IMPORT_C static void Install(CActiveScheduler* aScheduler);
IMPORT_C static CActiveScheduler* Current();
IMPORT_C static void Add(CActive* aActive);
IMPORT_C static void Start();
IMPORT_C static void Stop();
IMPORT_C static TBool RunIfReady(TInt& aError, TInt aMinimumPriority);
IMPORT_C static CActiveScheduler* Replace(CActiveScheduler* aNewActiveScheduler);
IMPORT_C virtual void WaitForAnyRequest();
IMPORT_C virtual void Error(TInt aError) const;
IMPORT_C void Halt(TInt aExitCode) const;
IMPORT_C TInt StackDepth() const;
private:
static void Start(TLoopOwner* aOwner);
IMPORT_C virtual void OnStarting();
IMPORT_C virtual void OnStopping();
IMPORT_C virtual void Reserved_1();
IMPORT_C virtual void Reserved_2();
void Run(TLoopOwner* const volatile& aLoop);
void DoRunL(TLoopOwner* const volatile& aLoop, CActive* volatile & aCurrentObj);
friend class CPrivatePolledActiveScheduler; // added
protected:
IMPORT_C virtual TInt Extension_(TUint aExtensionId, TAny*& a0, TAny* a1);
protected:
inline TInt Level() const {return StackDepth();} // deprecated
private:
TLoop* iStack;
TPriQue<CActive> iActiveQ;
TAny* iSpare;
};
class TCleanupItem;
class CleanupStack
{
public:
IMPORT_C static void PushL(TAny* aPtr);
IMPORT_C static void PushL(CBase* aPtr);
IMPORT_C static void PushL(TCleanupItem anItem);
IMPORT_C static void Pop();
IMPORT_C static void Pop(TInt aCount);
IMPORT_C static void PopAndDestroy();
IMPORT_C static void PopAndDestroy(TInt aCount);
IMPORT_C static void Check(TAny* aExpectedItem);
inline static void Pop(TAny* aExpectedItem);
inline static void Pop(TInt aCount, TAny* aLastExpectedItem);
inline static void PopAndDestroy(TAny* aExpectedItem);
inline static void PopAndDestroy(TInt aCount, TAny* aLastExpectedItem);
};
/*
* This will declare CPrivatePolledActiveScheduler as a friend
* of all classes that define a friend. CPrivatePolledActiveScheduler needs to
* be a friend of CActive
*/
//#define friend friend class CPrivatePolledActiveScheduler; friend
/*
* This will change the:
* void DoStart();
* method in CActiveScheduler to:
* void DoStart(); friend class CPrivatePolledActiveScheduler;
* We need this to access the private datamembers in CActiveScheduler.
*/
//#define DoStart() DoStart(); friend class CPrivatePolledActiveScheduler;
//#include <e32base.h>
#include "PolledAS.h"
class CPrivatePolledActiveScheduler : public CActiveScheduler
{
public:
void Schedule();
};
void CPrivatePolledActiveScheduler::Schedule()
{
TDblQueIter<CActive> q(iActiveQ);
q.SetToFirst();
FOREVER
{
CActive *pR=q++;
if (pR)
{
//TRequestStatus::EActive = 1, //bit0
//TRequestStatus::ERequestPending = 2, //bit1
if (pR->IsActive() && pR->iStatus!=KRequestPending)
{
// pR->iActive=EFalse; // won't this cause trouble?
pR->iStatus.iFlags&=~TRequestStatusFaked::EActive;
//debugPrintFile(_L("as: %08x"), pR);
TRAPD(r,pR->RunL());
//pR->iStatus=TRequestStatus::ERequestPending;
break;
}
}
else
break;
}
}
static CPolledActiveScheduler* sPolledActiveScheduler = NULL;
CPolledActiveScheduler::~CPolledActiveScheduler()
{
sPolledActiveScheduler = NULL;
delete iPrivatePolledActiveScheduler;
}
CPolledActiveScheduler* CPolledActiveScheduler::NewL()
{
// if (sPolledActiveScheduler == NULL)
{
sPolledActiveScheduler = new(ELeave)CPolledActiveScheduler;
CleanupStack::PushL(sPolledActiveScheduler);
sPolledActiveScheduler->ConstructL();
CleanupStack::Pop();
}
return sPolledActiveScheduler;
}
void CPolledActiveScheduler::ConstructL()
{
iPrivatePolledActiveScheduler = new(ELeave) CPrivatePolledActiveScheduler;
iPrivatePolledActiveScheduler->Install(iPrivatePolledActiveScheduler);
}
void CPolledActiveScheduler::Schedule()
{
iPrivatePolledActiveScheduler->Schedule();
}
CPolledActiveScheduler* CPolledActiveScheduler::Instance()
{
// return (CPolledActiveScheduler*) CActiveScheduler::Current();
return sPolledActiveScheduler;
}

View file

@ -0,0 +1,645 @@
// EmuScan routines for Pico, also simple text and shape drawing routines.
// (c) Copyright 2006, notaz
// All Rights Reserved
#include "vid.h"
#include "../Engine.h"
#include "../../../pico/picoInt.h"
#include "blit.h"
#include "debug.h"
// global stuff
extern TPicoConfig *currentConfig;
extern TPicoAreaConfigEntry areaConfig[];
extern const char *actionNames[];
// main framebuffer
static void *screenbuff = 0; // pointer to real device video memory
//static
extern "C" { unsigned char *framebuff = 0; } // temporary buffer
const int framebuffsize = (8+320)*(8+240+8)*2+8*2; // actual framebuffer size (in bytes+to support new rendering mode)
// drawer function pointers
static void (*drawTextFps)(const char *text) = 0;
static void (*drawTextNotice)(const char *text) = 0;
// blitter
static void (*vidBlit)(int full) = 0;
// colors
const unsigned short color_red = 0x022F;
const unsigned short color_red_dim = 0x0004;
const unsigned short color_green = 0x01F1;
const unsigned short color_blue = 0x0F11;
const unsigned short color_grey = 0x0222;
// other
int txtheight_fit = 138;
// bitmasks
static const unsigned long mask_numbers[] = {
0x12244800, // 47 2F /
0x69999600, // 48 30 0
0x26222200, // 49 31 1
0x69168F00, // 50 32 2
0x69219600, // 51 33 3
0x266AF200, // 52 34 4
0xF8E11E00, // 53 35 5
0x68E99600, // 54 36 6
0x71222200, // 55 37 7
0x69699600, // 56 38 8
0x69719600, // 57 39 9
0x04004000, // 58 3A :
0x04004400, // 59 3B ;
0x01242100, // 60 3C <
0x00707000, // 61 3D =
0x04212400, // 62 3E >
0x69240400, // 63 3F ?
0x00000000, // 64 40 @ [used instead of space for now]
0x22579900, // 65 41 A
0xE9E99E00, // 66 42 B
0x69889600, // 67 43 C
0xE9999E00, // 68 44 D
0xF8E88F00, // 69 45 E
0xF8E88800, // 70 46 F
0x698B9700, // 71 47 G
0x99F99900, // 72 48 H
0x44444400, // 73 49 I
0x11119600, // 74 4A J
0x9ACCA900, // 75 4B K
0x88888F00, // 76 4C L
0x9F999900, // 77 4D M
0x9DDBB900, // 78 4E N
0x69999600, // 79 4F O
0xE99E8800, // 80 50 P
0x6999A500, // 81 51 Q
0xE99E9900, // 82 52 R
0x69429600, // 83 53 S
0x72222200, // 84 54 T
0x99999600, // 85 55 U
0x55552200, // 86 56 V
0x9999F900, // 87 57 W
0x55225500, // 88 58 X
0x55222200, // 89 59 Y
0xF1248F00, // 90 5A Z
};
////////////////////////////////
// Cram functions
static int EmuCramNull(int cram)
{
User::Panic(_L("Cram called!!"), 0);
return cram;
}
////////////////////////////////
// PicoScan functions
static int EmuScan8(unsigned int num, void *sdata)
{
DrawLineDest = framebuff + 328*(num+1) + 328*8 + 8;
return 0;
}
static int EmuScanFit0(unsigned int num, void *sdata)
{
// 0.75, 168 lines
static int u = 0, num2 = 0;
if(!num) u = num2 = 0;
DrawLineDest = framebuff + 328*(++num2) + 328*8 + 8;
u += 6666;
if(u < 10000) {
// u += 7500;
return 1;
}
u -= 10000;
return 0;
}
////////////////////////////////
// text drawers
// warning: text must be at least 1px away from screen borders
static void drawTextM2(int x, int y, const char *text)
{
unsigned char *vidmem = framebuff + 328*8 + 8;
int charmask, i, cx = x, cy;
unsigned char *l, *le;
// darken the background (left border)
for(l=vidmem+(cx-1)+(y-1)*328, le=l+8*328; l < le; l+=328) *l = 0xE0;
for(const char *p=text; *p; p++) {
cy = y;
charmask = *(mask_numbers + (*p - 0x2F));
for(l = vidmem+cx+(y-1)*328, le = l+8*328; l < le; l+=328-4) {
*l = 0xE0; l++; *l = 0xE0; l++;
*l = 0xE0; l++; *l = 0xE0; l++;
*l = 0xE0;
}
for(i=0; i < 24; i++) {
if(charmask&0x80000000) *( vidmem + (cx+(i&3)) + (cy+(i>>2))*328 ) = 0xf0;
charmask <<= 1;
}
cx += 5;
}
}
static void drawTextM2Fat(int x, int y, const char *text)
{
unsigned char *vidmem = framebuff + 328*8 + 8;
int charmask, i, cx = x&~1, cy;
unsigned short *l, *le;
// darken the background (left border)
for(l=(unsigned short *)(vidmem+(cx-2)+(y-1)*328), le=l+8*328/2; l < le; l+=328/2) *l = 0xE0;
for(const char *p=text; *p; p++) {
cy = y;
for(l = (unsigned short *)(vidmem+cx+(y-1)*328), le = l+8*328/2; l < le; l+=328/2) {
l += 4;
*l-- = 0xe0e0; *l-- = 0xe0e0; *l-- = 0xe0e0; *l-- = 0xe0e0; *l = 0xe0e0;
}
charmask = *(mask_numbers + (*p - 0x2F));
for(i=0; i < 24; i++) {
if(charmask&0x80000000) *(unsigned short *)( vidmem + cx+(i&3)*2 + (cy+(i>>2))*328 ) = 0xf0f0;
charmask <<= 1;
}
cx += 5*2;
}
}
static void drawTextFpsCenter0(const char *text)
{
if(!text) return;
drawTextM2(214, 216, text);
}
static void drawTextFpsFit0(const char *text)
{
if(!text) return;
drawTextM2Fat((Pico.video.reg[12]&1) ? 256-32 : 224-32, 160, text);
}
static void drawTextFpsFit2_0(const char *text)
{
if(!text) return;
drawTextM2Fat((Pico.video.reg[12]&1) ? 256-32 : 224-32, 216, text);
}
static void drawTextFps0(const char *text)
{
if(!text) return;
drawTextM2((Pico.video.reg[12]&1) ? 256 : 224, 216, text);
}
static void drawTextNoticeCenter0(const char *text)
{
if(!text) return;
drawTextM2(2, 216, text);
}
static void drawTextNoticeFit0(const char *text)
{
if(!text) return;
drawTextM2Fat(2, 160, text);
}
static void drawTextNoticeFit2_0(const char *text)
{
if(!text) return;
drawTextM2Fat(2, 216, text);
}
static void drawTextNotice0(const char *text)
{
if(!text) return;
drawTextM2(2, 216, text);
}
// -----------------------------------------------------------------
static int localPal[0x100];
static void fillLocalPal(void)
{
Pico.m.dirtyPal = 0;
if (PicoOpt&0x10) {
// 8bit fast renderer
vidConvCpyRGB32(localPal, Pico.cram, 0x40);
return;
}
// 8bit accurate renderer
if(Pico.video.reg[0xC]&8) { // shadow/hilight mode
vidConvCpyRGB32(localPal, Pico.cram, 0x40);
vidConvCpyRGB32sh(localPal+0x40, Pico.cram, 0x40);
vidConvCpyRGB32hi(localPal+0x80, Pico.cram, 0x40);
blockcpy(localPal+0xc0, localPal+0x40, 0x40*4);
localPal[0xe0] = 0x00000000; // reserved pixels for OSD
localPal[0xf0] = 0x00ee0000;
} else if (rendstatus & 0x20) { // mid-frame palette changes
vidConvCpyRGB32(localPal, Pico.cram, 0x40);
vidConvCpyRGB32(localPal+0x40, HighPal, 0x40);
vidConvCpyRGB32(localPal+0x80, HighPal+0x40, 0x40);
} else {
vidConvCpyRGB32(localPal, Pico.cram, 0x40);
}
}
// note: the internal 8 pixel border is taken care by asm code
static void vidBlit_90(int full)
{
unsigned char *ps = framebuff+328*8;
unsigned long *pd = (unsigned long *) screenbuff;
if (Pico.m.dirtyPal) fillLocalPal();
if(Pico.video.reg[12]&1)
vidConvCpy_90(pd, ps, localPal, 320/8);
else {
if(full) vidClear(pd, 32);
pd += 256*32;
vidConvCpy_90(pd, ps, localPal, 256/8);
if(full) vidClear(pd + 256*256, 32);
}
}
static void vidBlit_270(int full)
{
unsigned char *ps = framebuff+328*8;
unsigned long *pd = (unsigned long *) screenbuff;
if (Pico.m.dirtyPal) fillLocalPal();
if(Pico.video.reg[12]&1)
vidConvCpy_270(pd, ps, localPal, 320/8);
else {
if(full) vidClear(pd, 32);
pd += 256*32;
ps -= 64; // the blitter starts copying from the right border, so we need to adjust
vidConvCpy_270(pd, ps, localPal, 256/8);
if(full) vidClear(pd + 256*256, 32);
}
}
static void vidBlitCenter_0(int full)
{
unsigned char *ps = framebuff+328*8+8;
unsigned long *pd = (unsigned long *) screenbuff;
if (Pico.m.dirtyPal) fillLocalPal();
if(Pico.video.reg[12]&1) ps += 32;
vidConvCpy_center_0(pd, ps, localPal);
if(full) vidClear(pd + 224*256, 96);
}
static void vidBlitCenter_180(int full)
{
unsigned char *ps = framebuff+328*8+8;
unsigned long *pd = (unsigned long *) screenbuff;
if (Pico.m.dirtyPal) fillLocalPal();
if(Pico.video.reg[12]&1) ps += 32;
vidConvCpy_center_180(pd, ps, localPal);
if(full) vidClear(pd + 224*256, 96);
}
static void vidBlitFit_0(int full)
{
if (Pico.m.dirtyPal) fillLocalPal();
if(Pico.video.reg[12]&1)
vidConvCpy_center2_40c_0(screenbuff, framebuff+328*8, localPal, 168);
else vidConvCpy_center2_32c_0(screenbuff, framebuff+328*8, localPal, 168);
if(full) vidClear((unsigned long *)screenbuff + 168*256, 320-168);
}
static void vidBlitFit_180(int full)
{
if (Pico.m.dirtyPal) fillLocalPal();
if(Pico.video.reg[12]&1)
vidConvCpy_center2_40c_180(screenbuff, framebuff+328*8, localPal, 168);
else vidConvCpy_center2_32c_180(screenbuff, framebuff+328*8-64, localPal, 168);
if(full) vidClear((unsigned long *)screenbuff + 168*256, 320-168);
}
static void vidBlitFit2_0(int full)
{
if (Pico.m.dirtyPal) fillLocalPal();
if(Pico.video.reg[12]&1)
vidConvCpy_center2_40c_0(screenbuff, framebuff+328*8, localPal, 224);
else vidConvCpy_center2_32c_0(screenbuff, framebuff+328*8, localPal, 224);
if(full) vidClear((unsigned long *)screenbuff + 224*256, 96);
}
static void vidBlitFit2_180(int full)
{
if (Pico.m.dirtyPal) fillLocalPal();
if(Pico.video.reg[12]&1)
vidConvCpy_center2_40c_180(screenbuff, framebuff+328*8, localPal, 224);
else vidConvCpy_center2_32c_180(screenbuff, framebuff+328*8-64, localPal, 224);
if(full) vidClear((unsigned long *)screenbuff + 224*256, 96);
}
static void vidBlitCfg(void)
{
unsigned short *ps = (unsigned short *) framebuff;
unsigned long *pd = (unsigned long *) screenbuff;
int i;
// hangs randomly (due to repeated ldms/stms?)
//for (int i = 1; i < 320; i++, ps += 240, pd += 256)
// vidConvCpyRGB32(pd, ps, 240);
for (i = 0; i < 320; i++, pd += 16)
for (int u = 0; u < 240; u++, ps++, pd++)
*pd = ((*ps & 0xf) << 20) | ((*ps & 0xf0) << 8) | ((*ps & 0xf00) >> 4);
}
////////////////////////////////
// main functions
int vidInit(void *vidmem, int reinit)
{
if(!reinit) {
// prepare framebuffer
screenbuff = vidmem;
framebuff = (unsigned char *) malloc(framebuffsize);
if(!screenbuff) return KErrNotSupported;
if(!framebuff) return KErrNoMemory;
memset(framebuff, 0, framebuffsize);
// Cram function: go and hack Pico so it never gets called
PicoCram = EmuCramNull;
}
// select suitable blitters
vidBlit = vidBlit_270;
PicoScan = EmuScan8;
drawTextFps = drawTextFps0;
drawTextNotice = drawTextNotice0;
memset(localPal, 0, 0x100*4);
localPal[0xe0] = 0x00000000; // reserved pixels for OSD
localPal[0xf0] = 0x00ee0000;
// setup all orientation related stuff
if(currentConfig->iScreenRotation == TPicoConfig::PRot0) {
if(currentConfig->iScreenMode == TPicoConfig::PMCenter) {
vidBlit = vidBlitCenter_0;
drawTextFps = drawTextFpsCenter0;
drawTextNotice = drawTextNoticeCenter0;
} else if(currentConfig->iScreenMode == TPicoConfig::PMFit2) {
vidBlit = vidBlitFit2_0;
drawTextFps = drawTextFpsFit2_0;
drawTextNotice = drawTextNoticeFit2_0;
} else {
vidBlit = vidBlitFit_0;
drawTextFps = drawTextFpsFit0;
drawTextNotice = drawTextNoticeFit0;
PicoScan = EmuScanFit0;
}
} else if(currentConfig->iScreenRotation == TPicoConfig::PRot90) {
vidBlit = vidBlit_90;
} else if(currentConfig->iScreenRotation == TPicoConfig::PRot180) {
if(currentConfig->iScreenMode == TPicoConfig::PMCenter) {
vidBlit = vidBlitCenter_180;
drawTextFps = drawTextFpsCenter0;
drawTextNotice = drawTextNoticeCenter0;
} else if(currentConfig->iScreenMode == TPicoConfig::PMFit2) {
vidBlit = vidBlitFit2_180;
drawTextFps = drawTextFpsFit2_0;
drawTextNotice = drawTextNoticeFit2_0;
} else {
vidBlit = vidBlitFit_180;
drawTextFps = drawTextFpsFit0;
drawTextNotice = drawTextNoticeFit0;
PicoScan = EmuScanFit0;
}
} else if(currentConfig->iScreenRotation == TPicoConfig::PRot270) {
vidBlit = vidBlit_270;
}
vidBlit(1);
PicoOpt |= 0x100;
Pico.m.dirtyPal = 1;
return 0;
}
void vidFree()
{
free(framebuff);
framebuff = 0;
}
void vidDrawFrame(char *noticeStr, char *fpsStr, int num)
{
DrawLineDest = framebuff + 328*8 + 8;
// PicoFrame(); // moved to main loop
if(currentConfig->iFlags & 2)
drawTextFps(fpsStr);
drawTextNotice(noticeStr);
vidBlit(!num); // copy full frame once a second
}
// -----------------------------------------------------------------
static void drawText0(int x, int y, const char *text, long color)
{
unsigned short *vidmem=(unsigned short *)framebuff;
int charmask, i, cx = x, cy;
unsigned short *l, *le, dmask=0x0333;
// darken the background (left border)
for(l=vidmem+(cx-1)+(y-1)*240, le=vidmem+(cx-1)+(y+7)*240; l < le; l+=240)
*l = (*l >> 2) & dmask;
for(const char *p=text; *p; p++) {
cy = y;
charmask = *(mask_numbers + (*p - 0x2F));
for(l = vidmem+cx+(y-1)*240, le = vidmem+cx+(y+7)*240; l < le; l+=240-4) {
*l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask; l++;
*l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask; l++;
*l = (*l >> 2) & dmask;
}
for(i=0; i < 24; i++) {
// draw dot. Is this fast?
if(charmask&0x80000000) *( vidmem + (cx+(i&3)) + (cy+(i>>2))*240 ) = color;
charmask <<= 1;
}
cx += 5;
}
}
// draws rect with width - 1 and height - 1
static void drawRect(const TRect &rc, unsigned short color)
{
unsigned short *vidmem=(unsigned short *)framebuff;
if(rc.iTl.iX - rc.iBr.iX && rc.iTl.iY - rc.iBr.iY) {
int stepX = rc.iTl.iX < rc.iBr.iX ? 1 : -1;
int stepY = rc.iTl.iY < rc.iBr.iY ? 1 : -1;
for(int x = rc.iTl.iX;; x += stepX) {
*(vidmem + rc.iTl.iY*240 + x) = *(vidmem + (rc.iBr.iY - stepY)*240 + x) = color;
if(x == rc.iBr.iX - stepX) break;
}
for(int y = rc.iTl.iY;; y += stepY) {
*(vidmem + y*240 + rc.iTl.iX) = *(vidmem + y*240 + rc.iBr.iX - stepX) = color;
if(y == rc.iBr.iY - stepY) break;
}
}
}
// draws fullsize filled rect
static void drawRectFilled(const TRect rc, unsigned short color)
{
unsigned short *vidmem=(unsigned short *)framebuff;
if(rc.iTl.iX - rc.iBr.iX && rc.iTl.iY - rc.iBr.iY) {
int stepX = rc.iTl.iX < rc.iBr.iX ? 1 : -1;
int stepY = rc.iTl.iY < rc.iBr.iY ? 1 : -1;
for(int y = rc.iTl.iY;; y += stepY) {
for(int x = rc.iTl.iX;; x += stepX) {
*(vidmem + y*240 + x) = *(vidmem + y*240 + x) = color;
if(x == rc.iBr.iX) break;
}
if(y == rc.iBr.iY) break;
}
}
}
// direction: -1 left, 1 right
static void drawArrow0(TPoint p, int direction, unsigned short color)
{
unsigned short *vidmem=(unsigned short *)framebuff;
int width = 15;
int x = p.iX;
int y = p.iY;
for(; width > 0; x+=direction, y++, width -=2)
for(int i=0; i < width; i++)
*(vidmem + x + y*240 + i*240) = color;
}
static char *vidGetScanName(int scan)
{
static char buff[32];
if((scan >= '0' && scan <= '9') || (scan >= 'A' && scan <= 'Z')) {
buff[0] = (char) scan; buff[1] = 0;
} else {
switch(scan) {
case 0x01: strcpy(buff, "BSPACE"); break;
case 0x03: strcpy(buff, "OK"); break;
case 0x05: strcpy(buff, "SPACE"); break;
case 0x0e: strcpy(buff, "AST"); break;
case 0x0f: strcpy(buff, "HASH"); break;
case 0x12: strcpy(buff, "SHIFT"); break;
case 0x19: strcpy(buff, "ALT"); break;
case 0x79: strcpy(buff, "PLUS"); break;
case 0x7a: strcpy(buff, "DOT"); break;
case 0xa5: strcpy(buff, "JOG@UP"); break;
case 0xa6: strcpy(buff, "JOG@DOWN"); break;
case 0xb5: strcpy(buff, "INET"); break;
case 0xd4: strcpy(buff, "JOG@PUSH"); break;
case 0xd5: strcpy(buff, "BACK"); break;
default: sprintf(buff, "KEY@%02X", scan); break;
}
}
return buff;
}
void vidKeyConfigFrame(const TUint whichAction)
{
int i;
char buttonNames[128];
buttonNames[0] = 0;
memset(framebuff, 0, framebuffsize);
unsigned long currentActCode = 1 << whichAction;
// draw all "buttons" in reverse order
const TPicoAreaConfigEntry *e = areaConfig + 1; i = 0;
while(e->rect != TRect(0,0,0,0)) { e++; i++; }
for(e--, i--; e->rect != TRect(0,0,0,0); e--, i--)
drawRect(e->rect, (currentConfig->iAreaBinds[i] & currentActCode) ? color_red : color_red_dim);
// action name control
drawRectFilled(TRect(72, 2, 168, 20), color_grey); // 96x14
drawArrow0(TPoint(80, 3), -1, color_green);
drawArrow0(TPoint(160, 3), 1, color_green);
drawText0(86, 9, actionNames[whichAction], color_red);
// draw active button names if there are any
for(i = 0; i < 256; i++) {
if(currentConfig->iKeyBinds[i] & currentActCode) {
if(buttonNames[0]) strcat(buttonNames, ";@");
strcat(buttonNames, vidGetScanName(i));
}
}
if(buttonNames[0]) {
buttonNames[61] = 0; // only 60 chars fit
drawText0(6, 48, buttonNames, color_blue);
}
vidBlitCfg();
}
void vidDrawNotice(const char *txt)
{
if(framebuff) {
drawTextNotice(txt);
vidBlit(1);
}
}

View file

@ -0,0 +1,9 @@
#include <e32base.h>
// let's do it in more c-like way
int vidInit(void *vidmem, int reinit);
void vidFree();
void vidDrawFrame(char *noticeStr, char *fpsStr, int num);
void vidKeyConfigFrame(const TUint whichAction);
void vidDrawFCconfigDone();
void vidDrawNotice(const char *txt); // safe to call anytime, draws text for 1 frame

View file

@ -0,0 +1,3 @@
@cd _out
@"C:\Program Files\arch\WinRAR\WinRAR.exe" a PicoDrive.zip PicoDrive.SIS config.txt ..\..\readme.txt
@cd..

View file

@ -0,0 +1,25 @@
// port specific settings
#ifndef PORT_CONFIG_H
#define PORT_CONFIG_H
#define CPU_CALL
// draw2.c
#define START_ROW 0 // which row of tiles to start rendering at?
#define END_ROW 28 // ..end
// pico.c
#define CAN_HANDLE_240_LINES 0 // fow now
//#define dprintf(f,...) printf(f"\n",##__VA_ARGS__)
#ifdef __DEBUG_PRINT
#ifdef __cplusplus
extern "C"
#endif
void dprintf(char *format, ...);
#else
#define dprintf(x...)
#endif
#endif //PORT_CONFIG_H

View file

@ -0,0 +1,8 @@
@ .equiv START_ROW, 1
@ .equiv END_ROW, 27
@ one row means 8 pixels. If above example was used, (27-1)*8=208 lines would be rendered.
.equiv START_ROW, 0
.equiv END_ROW, 28
@ this should be set to one only for GP2X port
.equiv EXTERNAL_YM2612, 0

1
platform/uiq3/qconn.cmd Normal file
View file

@ -0,0 +1 @@
@..\..\..\qconsole-1.60\qtty-1.60\release\qtty --qc-addr M600i --qc-channel 5 --user qconsole --pass server

1
platform/uiq3/qlog.cmd Normal file
View file

@ -0,0 +1 @@
@..\..\..\qconsole-1.60\qtty-1.60\release\qtty --qc-addr M600i --qc-channel 5 --user qconsole --pass server --cmds "cat c:\logs\pico.log" exit

1
platform/uiq3/qup.cmd Normal file
View file

@ -0,0 +1 @@
@..\..\..\qconsole-1.60\qtty-1.60\release\qtty --qc-addr M600i --qc-channel 5 --user qconsole --pass server --cmds "put c:\Shared\PicoDrive.SIS _out\PicoDrive.SIS" "rundoc c:\Shared\PicoDrive.SIS" exit

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -0,0 +1,601 @@
NAME PCDR
#include <eikon.rh>
#include <eikon.rsg>
#include <qikon.rh>
#include <QikCommand.rh>
#include "picodrive.hrh"
RESOURCE RSS_SIGNATURE { }
// Defines the name of the default file the application framework creates.
// This resource must always be the second resource in the resource file.
RESOURCE TBUF { buf = "PicoDrive"; }
RESOURCE EIK_APP_INFO { }
// A view shall use the QIK_VIEW_CONFIGURATIONS resource struct to define which
// UI configurations it supports. Can also use QIK_VIEW_CONFIGURATIONS to setup
// the view to switch layout and command list automatically when changes of UI
// configuration occur. This is done with the view and command_list members of
// the QIK_VIEW_CONFIGURATIONS.
// The application supports the reference UI Configurations that are supported
// in the UIQ 3 SDK. Use the UiqEnv tool, to change the UI Configuration in the
// emulator in order to develop and test the application with varying phone styles.
RESOURCE QIK_VIEW_CONFIGURATIONS r_app_ui_configurations
{
configurations =
{
QIK_VIEW_CONFIGURATION
{
ui_config_mode = KQikPenStyleTouchPortrait;
command_list = r_app_commands;
view = r_app_layout;
},
QIK_VIEW_CONFIGURATION
{
ui_config_mode = KQikPenStyleTouchLandscape;
command_list = r_app_commands;
view = r_app_layout;
},
QIK_VIEW_CONFIGURATION
{
ui_config_mode = KQikSoftkeyStyleTouchPortrait;
command_list = r_app_commands;
view = r_app_layout;
},
QIK_VIEW_CONFIGURATION
{
ui_config_mode = KQikSoftkeyStylePortrait;
command_list = r_app_commands;
view = r_app_layout;
},
QIK_VIEW_CONFIGURATION
{
ui_config_mode = KQikSoftkeyStyleSmallPortrait;
command_list = r_app_commands;
view = r_app_layout;
}
};
}
// Commands are defined with the QIK_COMMAND_LIST struct,
// commands can also be created in code by instantiating CQikCommand.
// The control command id for debug command is a reserved id from uikon.hrh.
// The id for each command is defined in the .hrh file.
RESOURCE QIK_COMMAND_LIST r_app_commands
{
items =
{
// QIK_COMMAND { id=EEikCmdPicoMain; text="Main"; type=EQikCommandTypeDone; namedGroupLinkId=EEikCmdPicoMain; },
// QIK_COMMAND { id=EEikCmdPicoDebugInfo; text="Debug info"; type=EQikCommandTypeScreen; stateFlags=EQikCmdFlagDebugOnly; },
QIK_COMMAND { id=EEikCmdPicoFrameskip; text="Frameskip"; type=EQikCommandTypeScreen; namedGroupLinkId=EEikCmdPicoFrameskip; },
QIK_COMMAND { id=EEikCmdPicoFrameskipAuto; text="Auto"; type=EQikCommandTypeScreen; namedGroupId=EEikCmdPicoFrameskip;
groupId=EEikCmdPicoFrameskip; stateFlags=EQikCmdFlagRadioStart; },
QIK_COMMAND { id=EEikCmdPicoFrameskip0; text="0"; type=EQikCommandTypeScreen; namedGroupId=EEikCmdPicoFrameskip;
groupId=EEikCmdPicoFrameskip0; stateFlags=EQikCmdFlagRadioMiddle; },
QIK_COMMAND { id=EEikCmdPicoFrameskip1; text="1"; type=EQikCommandTypeScreen; namedGroupId=EEikCmdPicoFrameskip;
groupId=EEikCmdPicoFrameskip0; stateFlags=EQikCmdFlagRadioMiddle; },
QIK_COMMAND { id=EEikCmdPicoFrameskip2; text="2"; type=EQikCommandTypeScreen; namedGroupId=EEikCmdPicoFrameskip;
groupId=EEikCmdPicoFrameskip0; stateFlags=EQikCmdFlagRadioMiddle; },
QIK_COMMAND { id=EEikCmdPicoFrameskip4; text="4"; type=EQikCommandTypeScreen; namedGroupId=EEikCmdPicoFrameskip;
groupId=EEikCmdPicoFrameskip0; stateFlags=EQikCmdFlagRadioMiddle; },
QIK_COMMAND { id=EEikCmdPicoFrameskip8; text="8"; type=EQikCommandTypeScreen; namedGroupId=EEikCmdPicoFrameskip;
groupId=EEikCmdPicoFrameskip0; stateFlags=EQikCmdFlagRadioEnd; },
QIK_COMMAND { id=EEikCmdPicoConfig; text="Configure"; type=EQikCommandTypeScreen; namedGroupLinkId=EEikCmdPicoConfig; },
QIK_COMMAND { id=EEikCmdPicoKeys; text="Keys"; type=EQikCommandTypeScreen; namedGroupId=EEikCmdPicoConfig; },
QIK_COMMAND { id=EEikCmdPicoSettings; text="Settings"; type=EQikCommandTypeScreen; namedGroupId=EEikCmdPicoConfig; },
QIK_COMMAND { id=EEikCmdHelpAbout; text="About"; type=EQikCommandTypeScreen; namedGroupId=EEikCmdPicoConfig; },
QIK_COMMAND { id=EEikCmdPicoLoadROM; text="Load new ROM"; type=EQikCommandTypeScreen; groupId=EEikCmdPicoResume; },
QIK_COMMAND { id=EEikCmdPicoReset; text="Reset game"; type=EQikCommandTypeScreen; groupId=EEikCmdPicoResume; },
QIK_COMMAND { id=EEikCmdPicoLoadState; text="Load state"; type=EQikCommandTypeScreen; groupId=EEikCmdPicoResume; },
QIK_COMMAND { id=EEikCmdPicoSaveState; text="Save state"; type=EQikCommandTypeScreen; groupId=EEikCmdPicoResume; },
QIK_COMMAND { id=EEikCmdPicoResume; text="Resume game"; type=EQikCommandTypeScreen; groupId=EEikCmdPicoResume; cpfFlags=EQikCpfFlagIsDefault; },
QIK_COMMAND { id=EEikCmdExit; text="Exit"; type=EQikCommandTypeScreen; groupId=EEikCmdExit; }
};
}
// Defines the view by linking to the pages.
RESOURCE QIK_VIEW r_app_layout
{
pages = {};
}
/**************************************
*
* config dialog
*
**************************************/
RESOURCE DIALOG r_pico_config
{
title = "Settings";
buttons = R_EIK_BUTTONS_CANCEL_OK;
flags = EEikDialogFlagWait;
pages = r_pico_config_pages;
}
RESOURCE ARRAY r_pico_config_pages
{
items = {
PAGE
{
id = ECtlOptPageMain;
text = "Main";
lines = r_pico_config_page_main;
},
PAGE
{
id = ECtlOptPageSound;
text = "Sound";
lines = r_pico_config_page_sound;
},
PAGE
{
id = ECtlOptPageMisc;
text = "Misc";
lines = r_pico_config_page_misc;
}
};
}
RESOURCE ARRAY r_pico_config_page_main
{
items = {
DLG_LINE
{
id = ECtlOptRotationLabel;
type = EEikCtLabel;
prompt = "Screen Rotation";
control = LABEL { horiz_align = EEikLabelAlignHLeft; };
},
DLG_LINE
{
id = ECtlOptRotation;
type = EEikCtHorOptionButList;
control = HOROPBUT
{
array_id = r_pico_config_rotation_buttons;
};
},
DLG_LINE
{
id = ECtlOptScreenModeLabel;
type = EEikCtLabel;
prompt = "Screen Mode";
control = LABEL { horiz_align = EEikLabelAlignHLeft; };
},
DLG_LINE
{
id = ECtlOptScreenMode;
type = EEikCtHorOptionButList;
control = HOROPBUT
{
array_id = r_pico_config_screenmode_buttons;
};
},
DLG_LINE
{
id = ECtlOptUseAltRend;
type = EEikCtCheckBox;
prompt = "Fast renderer (inaccurate)";
},
DLG_LINE
{
id = ECtlOptUseAccTiming;
type = EEikCtCheckBox;
prompt = "Accurate timing (slower)";
},
DLG_LINE
{
id = ECtlOptUseAccSprites;
type = EEikCtCheckBox;
prompt = "Accurate sprites (slower)";
},
DLG_LINE
{
id = ECtlOptShowFPS;
type = EEikCtCheckBox;
prompt = "Show FPS";
}
};
}
RESOURCE ARRAY r_pico_config_page_sound
{
items = {
DLG_LINE
{
id = ECtlOptEnableSound;
type = EEikCtCheckBox;
prompt = "Enable sound";
},
DLG_LINE
{
id = ECtlOptChipSelLabel;
type = EEikCtLabel;
prompt = "Emulate these sound chips:";
control = LABEL { horiz_align = EEikLabelAlignHLeft; };
},
DLG_LINE
{
id = ECtlOptEmulateZ80;
type = EEikCtCheckBox;
prompt = "Z80";
},
DLG_LINE
{
id = ECtlOptEmulateYM2612;
type = EEikCtCheckBox;
prompt = "YM2612";
},
DLG_LINE
{
id = ECtlOptEmulateSN76496;
type = EEikCtCheckBox;
prompt = "SN76496 (PSG)";
},
DLG_LINE
{
id = ECtlOptSndQLabel;
type = EEikCtLabel;
prompt = "Quality (lowest is fastest)";
control = LABEL { horiz_align = EEikLabelAlignHLeft; };
},
DLG_LINE
{
id = ECtlOptSndQuality;
type = EEikCtChoiceList;
prompt = "";
control = CHOICELIST { array_id = r_pico_config_snd_quality; };
itemflags = EEikDlgItemNonFocusing;
}
};
}
RESOURCE ARRAY r_pico_config_page_misc
{
items = {
DLG_LINE
{
id = ECtlOpt6ButtonPad;
type = EEikCtCheckBox;
prompt = "6 button pad";
},
DLG_LINE
{
id = ECtlOptGzipStates;
type = EEikCtCheckBox;
prompt = "gzip save states";
},
DLG_LINE
{
id = ECtlOptUseSRAM;
type = EEikCtCheckBox;
prompt = "Use SRAM saves (.srm)";
},
DLG_LINE
{
id = ECtlOptRegion;
type = EEikCtChoiceList;
prompt = "Region:";
control = CHOICELIST { array_id = r_pico_config_region; };
itemflags = EEikDlgItemNonFocusing;
}
};
}
RESOURCE ARRAY r_pico_config_rotation_buttons
{
items = {
OPBUT { id = ECtlOptRotation0; text = "0º"; },
OPBUT { id = ECtlOptRotation90; text = "90º"; },
OPBUT { id = ECtlOptRotation180; text = "180º"; },
OPBUT { id = ECtlOptRotation270; text = "270º"; }
};
}
RESOURCE ARRAY r_pico_config_screenmode_buttons
{
items = {
OPBUT { id = ECtlOptScreenModeCenter; text = "Center"; },
OPBUT { id = ECtlOptScreenModeFit; text = "Fit"; },
OPBUT { id = ECtlOptScreenModeFit2; text = "Fit2"; }
};
}
RESOURCE ARRAY r_pico_config_snd_quality
{
items = {
LBUF { txt = "8000Hz mono"; },
LBUF { txt = "11025Hz mono"; },
LBUF { txt = "16000Hz mono"; },
LBUF { txt = "22050Hz mono"; },
LBUF { txt = "44100Hz mono"; },
LBUF { txt = "8000Hz stereo"; },
LBUF { txt = "11025Hz stereo"; },
LBUF { txt = "16000Hz stereo"; },
LBUF { txt = "22050Hz stereo"; },
LBUF { txt = "44100Hz stereo"; }
};
}
RESOURCE ARRAY r_pico_config_region
{
items = {
LBUF { txt = "Auto"; },
LBUF { txt = "Europe"; },
LBUF { txt = "USA"; },
LBUF { txt = "Japan PAL"; },
LBUF { txt = "Japan NTSC"; }
};
}
/**************************************
*
* about dialog
*
**************************************/
// A simple dialog shall use the QIK_DIALOG resource struct to
// define which UI configurations it supports.
RESOURCE QIK_DIALOG r_pico_about
{
title = "About";
configurations =
{
QIK_DIALOG_CONFIGURATION
{
ui_config_mode = 0;
container = r_pico_about_container;
command_list = r_pico_about_commands;
}
};
controls = r_pico_about_controls;
}
RESOURCE QIK_COMMAND_LIST r_pico_about_commands
{
items=
{
QIK_COMMAND
{
id = EEikCmdPicoAboutDoneCmd;
type = EQikCommandTypeDone;
text = "Done";
},
QIK_COMMAND
{
id = EEikCmdPicoAboutCreditsCmd;
type = EQikCommandTypeItem;
text = "Credits";
}
};
}
// A collection of controls that can be used throughout the various
// view/container/building block structs by using the unique handle in
// QIK_CONTROL. So you can specify how the control should be created here and
// just reference to it from other places.
RESOURCE QIK_CONTROL_COLLECTION r_pico_about_controls
{
items =
{
QIK_CONTROL
{
unique_handle = ECtlPicoAboutText;
type = EEikCtRichTextEditor;
control = r_pico_about_rtxted;
itemflags = EQikCtrlFlagIsEditInPlace;
}
};
}
// the controls themselves
RESOURCE RTXTED r_pico_about_rtxted
{
flags = EEikEdwinDisplayOnly|EEikEdwinReadOnly|EEikEdwinNoHorizScrolling;
numlines = 13;
displayMode = 1; // EDisplayModeView;
}
// Defines the content of the simple dialog and how they are laid out.
// Default layout manager is used for laying out the controls, which is a row
// layout.
RESOURCE QIK_CONTAINER_SETTINGS r_pico_about_container
{
controls =
{
QIK_CONTAINER_ITEM_CI_LI
{
type = EQikCtOnelineBuildingBlock;
control = r_pico_about_bb1;
}
};
}
// Building block that contains the label.
RESOURCE QIK_SYSTEM_BUILDING_BLOCK r_pico_about_bb1
{
content =
{
QIK_SLOT_CONTENT
{
slot_id = EQikItemSlot1;
unique_handle = ECtlPicoAboutText;
}
};
}
RESOURCE TBUF r_pico_text_about
{
buf=
"<f=Polo><s=26><a=center><fg=RgbDarkBlue>PicoDrive"\
"<p><f=Polo><s=10><a=center>for UIQ3"\
"<p><s=6> <p><f=Corinna><s=12>Version %S, by notaz."\
"<p><s=5> <p><s=10>Port based on UIQ2 version, which is based on PicoDrive 0.030 for Pocket PC by Dave"\
"<p><s=5> <p><f=Corinna><s=11><u>Email</u>: notasas@gmail.com"\
"<p><f=Corinna><s=10><u>Web</u>: http://notaz.atspace.com"\
"<p><f=Corinna><s=10><u>Dave's Web</u>: http://www.finalburn.com";
}
/**************************************
*
* credits dialog
*
**************************************/
// A simple dialog shall use the QIK_DIALOG resource struct to
// define which UI configurations it supports.
RESOURCE QIK_DIALOG r_pico_credits
{
title = "Credits and thanks";
configurations =
{
QIK_DIALOG_CONFIGURATION
{
ui_config_mode = 0;
container = r_pico_credits_container;
command_list = r_pico_credits_commands;
}
};
controls = r_pico_credits_controls;
}
RESOURCE QIK_COMMAND_LIST r_pico_credits_commands
{
items=
{
QIK_COMMAND
{
id = EEikCmdPicoAboutDoneCmd;
type = EQikCommandTypeDone;
text = "Done";
}
};
}
// A collection of controls that can be used throughout the various
// view/container/building block structs by using the unique handle in
// QIK_CONTROL. So you can specify how the control should be created here and
// just reference to it from other places.
RESOURCE QIK_CONTROL_COLLECTION r_pico_credits_controls
{
items =
{
QIK_CONTROL
{
unique_handle = ECtlPicoCreditsText;
type = EEikCtEdwin;
control = r_pico_credits_edwin;
itemflags = EQikCtrlFlagIsEditInPlace;
}
};
}
// the controls themselves
RESOURCE EDWIN r_pico_credits_edwin
{
flags = EEikEdwinDisplayOnly|EEikEdwinReadOnly|EEikEdwinNoHorizScrolling|EEikEdwinDisableAutoCurEnd;
lines = 11;
}
// Defines the content of the simple dialog and how they are laid out.
// Default layout manager is used for laying out the controls, which is a row
// layout.
RESOURCE QIK_CONTAINER_SETTINGS r_pico_credits_container
{
controls =
{
QIK_CONTAINER_ITEM_CI_LI
{
type = EQikCtOnelineBuildingBlock;
control = r_pico_credits_bb1;
}
};
}
// Building block that contains the label.
RESOURCE QIK_SYSTEM_BUILDING_BLOCK r_pico_credits_bb1
{
content =
{
QIK_SLOT_CONTENT
{
slot_id = EQikItemSlot1;
unique_handle = ECtlPicoCreditsText;
}
};
}
RESOURCE ARRAY r_pico_tbuf_credits
{
items=
{
LBUF{txt="This emulator uses code from these people / projects:";},
LBUF{txt="";},
LBUF{txt="Dave";},
LBUF{txt="- Cyclone 68000 core, Pico emulation library";},
LBUF{txt="Homepage: http://www.finalburn.com/";},
LBUF{txt="";},
LBUF{txt="Reesy & FluBBa";},
LBUF{txt="- DrZ80, the Z80 emulator written in ARM assembly.";},
LBUF{txt="Homepage: http://reesy.gp32x.de/";},
LBUF{txt="";},
LBUF{txt="Tatsuyuki Satoh, Jarek Burczynski, MultiArcadeMachineEmulator (MAME) development";},
LBUF{txt="- software implementation of Yamaha FM sound generator and";},
LBUF{txt="Texas Instruments SN76489 / SN76496 programmable tone / noise generator";},
LBUF{txt="Homepage: http://www.mame.net/";},
LBUF{txt="";},
LBUF{txt="Additional thanks:";},
LBUF{txt="- Charles MacDonald (http://cgfm2.emuviews.com/) for old but still very useful info about genesis hardware.";},
LBUF{txt="- Stéphane Dallongeville for creating Gens and making it open-source.";},
LBUF{txt="- Steve Snake for all that he has done for Genesis emulation scene.";},
LBUF{txt="- Bart Trzynadlowski for his SSFII and 68000 docs.";},
LBUF{txt="- Maze for his research (http://haze.mameworld.info).";},
LBUF{txt="- Mark and Jean-loup for zlib library.";},
LBUF{txt="- Peter van Sebille for his various open-source Symbian projects to learn from.";},
LBUF{txt="- Steve Fischer for his open-source Motorola projects.";},
LBUF{txt="- AnotherGuest for all his Symbian stuff and support.";},
LBUF{txt="- Inder for the icons.";},
LBUF{txt="- Anyone else I forgot. You know who you are.";}
};
}
/**************************************
*
* debug dialog
*
**************************************/
RESOURCE QIK_DIALOG r_pico_debug
{
title = "debug";
configurations =
{
QIK_DIALOG_CONFIGURATION
{
ui_config_mode = 0;
container = r_pico_credits_container; // stuff from credits should fit
command_list = r_pico_credits_commands;
}
};
controls = r_pico_credits_controls;
}

View file

@ -0,0 +1,20 @@
#include <AppInfo.rh>
// This file localise the applications icons and caption
RESOURCE LOCALISABLE_APP_INFO
{
caption_and_icon =
{
CAPTION_AND_ICON_INFO
{
caption = "PicoDrive";
// Icons are used to represent applications in the
// application launcher and application title bar.
// The number_of_icons value identifies how many icons
// that exist in the icon_file.
number_of_icons = 3;
// Using the application icons.
icon_file = "\\Resource\\Apps\\PicoDrive.mbm";
}
};
}

View file

@ -0,0 +1,17 @@
// All registration files need to #include appinfo.rh.
#include <AppInfo.rh>
// All registration files must define UID2, which is always
// KUidAppRegistrationResourceFile, and UID3, which is the application's UID.
UID2 KUidAppRegistrationResourceFile
UID3 0xA00010F3 // application UID
// Registration file need to containo an APP_REGISTRATION_INFO resource that
// minimally needs to provide the name of the application binary (using the
// app_file statement).
RESOURCE APP_REGISTRATION_INFO
{
app_file = "PicoDrive"; // filename of application binary (minus extension)
// Specify the location of the localisable icon/caption definition file
localisable_resource_file = "\\Resource\\Apps\\PicoDrive_loc";
}

10
platform/uiq3/version.h Normal file
View file

@ -0,0 +1,10 @@
// version number
#ifndef __VERSION_H
#define __VERSION_H
#define KPicoMajorVersionNumber 0
#define KPicoMinorVersionNumber 96
#define KPicoBuildNumber 0
#endif /* __VERSION_H */