- Program settings are now managed by the CConfig class.

- Moved Logger.h to OSD/, cleaned up comments.
- Command line and config file parsing have been rewritten.
- Began replacing C standard library headers with C++ versions (eg. stdio.h -> cstdio). I think I got most of them, but not all.
This commit is contained in:
Bart Trzynadlowski 2011-08-19 20:43:07 +00:00
parent 5e1ea75374
commit d318efe58c
21 changed files with 908 additions and 462 deletions

View file

@ -156,7 +156,7 @@ endif
# Objects and Dependencies
#
HEADERS = Src/Supermodel.h Src/OSD/SDL/Types.h
OBJ = $(OBJ_DIR)/PPCDisasm.obj $(OBJ_DIR)/Games.obj $(OBJ_DIR)/INIFile.obj $(OBJ_DIR)/BlockFile.obj $(OBJ_DIR)/93C46.obj \
OBJ = $(OBJ_DIR)/PPCDisasm.obj $(OBJ_DIR)/Games.obj $(OBJ_DIR)/Config.obj $(OBJ_DIR)/INIFile.obj $(OBJ_DIR)/BlockFile.obj $(OBJ_DIR)/93C46.obj \
$(OBJ_DIR)/ROMLoad.obj $(OBJ_DIR)/unzip.obj $(OBJ_DIR)/ioapi.obj $(OBJ_DIR)/Error.obj $(OBJ_DIR)/glew.obj $(OBJ_DIR)/Shader.obj \
$(OBJ_DIR)/Real3D.obj $(OBJ_DIR)/Render3D.obj $(OBJ_DIR)/Models.obj $(OBJ_DIR)/Render2D.obj $(OBJ_DIR)/TileGen.obj \
$(OBJ_DIR)/Model3.obj $(OBJ_DIR)/ppc.obj $(OBJ_DIR)/Main.obj $(OBJ_DIR)/Audio.obj $(OBJ_DIR)/Thread.obj $(OBJ_DIR)/SoundBoard.obj \

31
Src/Config.cpp Normal file
View file

@ -0,0 +1,31 @@
/**
** Supermodel
** A Sega Model 3 Arcade Emulator.
** Copyright 2011 Bart Trzynadlowski
**
** This file is part of Supermodel.
**
** Supermodel is free software: you can redistribute it and/or modify it under
** the terms of the GNU General Public License as published by the Free
** Software Foundation, either version 3 of the License, or (at your option)
** any later version.
**
** Supermodel is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
** more details.
**
** You should have received a copy of the GNU General Public License along
** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
**/
/*
* Config.cpp
*
* Program-wide configuration settings.
*/
#include "Config.h"
CConfig g_Config;

71
Src/Config.h Normal file
View file

@ -0,0 +1,71 @@
/**
** Supermodel
** A Sega Model 3 Arcade Emulator.
** Copyright 2011 Bart Trzynadlowski
**
** This file is part of Supermodel.
**
** Supermodel is free software: you can redistribute it and/or modify it under
** the terms of the GNU General Public License as published by the Free
** Software Foundation, either version 3 of the License, or (at your option)
** any later version.
**
** Supermodel is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
** more details.
**
** You should have received a copy of the GNU General Public License along
** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
**/
/*
* Config.h
*
* Header file for program-wide configuration settings.
*/
#ifndef INCLUDED_CONFIG_H
#define INCLUDED_CONFIG_H
#include "Supermodel.h"
/*
* CConfig:
*
* Class defining all configuration settings. Inherits settings from classes
* defined throughout the program.
*
* Conventions
* -----------
* - Modules and classes should only use the members of their own configuration
* class, so long as this is practical. This is left to programmer
* discretion. The intent is that one class, CReal3D for example, should not
* need information from another unrelated class, CModel3, unless explicitly
* passed to it. On the other hand, the OSD layer may have a legitimate
* need to use the renderer's video settings rather than maintaining its own.
* - Member variables that have a limited range of allowable values must be
* private and accessed through accessor members (SetVar(), GetVar()). The
* accessors must ensure that a value outside the allowable range is never
* returned and must clamp or reset to a default when an invalid setting
* is passed. Warnings may be printed.
* - Strings should be copied and retained locally.
* - Constructors must be defined and must initialize to the program default.
* - User-tunable settings should be stored here, not necessarily every
* concievable parameter a class initializer might take.
*/
class CConfig: public COSDConfig, public CRender3DConfig, public CModel3Config, public CSoundBoardConfig, public CDSBConfig
{
};
/*
* g_Config:
*
* Program-wide configuration settings object.
*/
extern CConfig g_Config;
#endif // INCLUDED_CONFIG_H

View file

@ -1283,7 +1283,7 @@ void CRender3D::SetStep(int stepID)
DebugLog("Render3D set to Step %d.%d\n", (step>>4)&0xF, step&0xF);
}
BOOL CRender3D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, const char *vsFile, const char *fsFile)
BOOL CRender3D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes)
{
// Allocate memory for texture buffer
textureBuffer = new(std::nothrow) GLfloat[512*512*4];
@ -1331,6 +1331,8 @@ BOOL CRender3D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned
yOffs = yOffset;
// Load shaders
const char *vsFile = g_Config.vertexShaderFile.size() ? g_Config.vertexShaderFile.c_str() : NULL;
const char *fsFile = g_Config.fragmentShaderFile.size() ? g_Config.fragmentShaderFile.c_str() : NULL;
if (OKAY != LoadShaderProgram(&shaderProgram,&vertexShader,&fragmentShader,vsFile,fsFile,vertexShaderSource,fragmentShaderSource))
return FAIL;

View file

@ -163,9 +163,27 @@ struct ModelCache
/******************************************************************************
CRender3D Class Definition
CRender3D Classes
******************************************************************************/
/*
* CRender3DConfig:
*
* Settings used by CRender3D.
*/
class CRender3DConfig
{
public:
string vertexShaderFile; // path to vertex shader or "" to use internal shader
string fragmentShaderFile; // fragment shader
// Defaults
CRender3DConfig(void)
{
// nothing to do, strings will be clear to begin with
}
};
/*
* CRender3D:
*
@ -244,30 +262,27 @@ public:
void SetStep(int stepID);
/*
* Init(xOffset, yOffset, xRes, yRes, vsFile, fsFile):
* Init(xOffset, yOffset, xRes, yRes):
*
* One-time initialization of the context. Must be called before any other
* members (meaning it should be called even before being attached to any
* other objects that want to use it).
*
* External shader files are loaded according to configuration settings.
*
* Parameters:
* xOffset X offset of display surface in pixels (in case resolution
* is smaller than the true display surface).
* yOffset Y offset.
* xRes Horizontal resolution of display surface in pixels.
* yRes Vertical resolution.
* vsFile External vertex shader path. If NULL, the internal
* shader is used.
* fsFile External fragment shader path. If NULL, the internal
* shader is used.
*
* Returns:
* OKAY is successful, otherwise FAILED if a non-recoverable error
* occurred. Any allocated memory will not be freed until the
* destructor is called. Prints own error messages.
*/
BOOL Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes,
const char *vsFile, const char *fsFile);
BOOL Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes);
/*
* CRender3D(void):

View file

@ -26,10 +26,8 @@
*
* To-Do List
* ----------
* - Allow default section name to be set at any time. To support this, must
* allow for multiple sections with the same name to co-exist. The search
* procedure must look through all sections rather than stopping at the
* first section match. This is easy enough to add.
* - Add an iterator to retrieve all settings associated with a given section.
* This will allow detection of invalid setting names, if the caller desires.
* - Add boolean on/off, true/false keywords.
* - Note that linePtr does not necessarily correspond to actual lines in the
* file (newlines should be counted by the tokenizer for that).

View file

@ -63,7 +63,8 @@ public:
*
* Returns:
* OKAY if the setting was found, FAIL otherwise. The type is not
* checked.
* checked. If the setting is not found, the output parameter will not
* be modified.
*/
BOOL Get(string SectionName, string SettingName, int& value);
BOOL Get(string SectionName, string SettingName, unsigned& value);

View file

@ -1,45 +0,0 @@
#ifndef INCLUDED_LOGGER_H
#define INCLUDED_LOGGER_H
#include <stdarg.h>
/*
* CLogger
*
* Abstract class that receives log messages from Supermodel.
*/
class CLogger
{
public:
void DebugLog(const char *fmt, ...)
{
va_list vl;
va_start(vl, fmt);
DebugLog(fmt, vl);
va_end(vl);
}
void InfoLog(const char *fmt, ...)
{
va_list vl;
va_start(vl, fmt);
InfoLog(fmt, vl);
va_end(vl);
}
void ErrorLog(const char *fmt, ...)
{
va_list vl;
va_start(vl, fmt);
ErrorLog(fmt, vl);
va_end(vl);
}
virtual void DebugLog(const char *fmt, va_list vl) = 0;
virtual void InfoLog(const char *fmt, va_list vl) = 0;
virtual void ErrorLog(const char *fmt, va_list vl) = 0;
};
#endif // INCLUDED_LOGGER_H

View file

@ -139,8 +139,14 @@ int CDSBResampler::UpSampleAndMix(INT16 *outL, INT16 *outR, INT16 *inL, INT16 *i
int delta = (inRate<<8)/outRate; // (1/fout)/(1/fin)=fin/fout, 24.8 fixed point
int outIdx = 0;
int inIdx = 0;
INT16 leftSample, rightSample;
INT16 v[2];
INT32 leftSample, rightSample, leftSoundSample, rightSoundSample;
INT32 v[2], musicVol, soundVol;
// Obtain program volume settings and convert to 24.8 fixed point (0-200 -> 0x00-0x200)
musicVol = g_Config.GetMusicVolume();
soundVol = g_Config.GetSoundVolume();
musicVol = (INT32) ((float) 0x100 * (float) musicVol / 100.0f);
soundVol = (INT32) ((float) 0x100 * (float) soundVol / 100.0f);
// Scale volume from 0x00-0xFF -> 0x00-0x100 (24.8 fixed point)
v[0] = (INT16) ((float) 0x100 * (float) volumeL / 255.0f);
@ -153,13 +159,17 @@ int CDSBResampler::UpSampleAndMix(INT16 *outL, INT16 *outR, INT16 *inL, INT16 *i
leftSample = ((int)inL[inIdx]*pFrac+(int)inL[inIdx+1]*nFrac) >> 8; // left channel
rightSample = ((int)inR[inIdx]*pFrac+(int)inR[inIdx+1]*nFrac) >> 8; // right channel
// Apply volume
leftSample = (leftSample*v[0]) >> 8;
rightSample = (rightSample*v[0]) >> 8;
// Apply DSB volume and then overall music volume setting
leftSample = (leftSample*v[0]*musicVol) >> 16; // multiplied by two 24.8 numbers, shift back by 16
rightSample = (rightSample*v[0]*musicVol) >> 16;
// Apply sound volume setting
leftSoundSample = (outL[outIdx]*soundVol) >> 8;
rightSoundSample = (outR[outIdx]*soundVol) >> 8;
// Mix and output
outL[outIdx] = MixAndClip(outL[outIdx], leftSample);
outR[outIdx] = MixAndClip(outR[outIdx], rightSample);
outL[outIdx] = MixAndClip(leftSoundSample, leftSample);
outR[outIdx] = MixAndClip(rightSoundSample, rightSample);
outIdx++;
// Time step
@ -413,6 +423,15 @@ void CDSB1::RunFrame(INT16 *audioL, INT16 *audioR)
int cycles;
UINT8 v;
if (!g_Config.emulateDSB)
{
// DSB code applies SCSP volume, too, so we must still mix
memset(mpegL, 0, (32000/60+2)*sizeof(INT16));
memset(mpegR, 0, (32000/60+2)*sizeof(INT16));
retainedSamples = Resampler.UpSampleAndMix(audioL, audioR, mpegL, mpegR, 0, 0, 44100/60, 32000/60+2, 44100, 32000);
return;
}
// While FIFO not empty, fire interrupts, run for up to one frame
for (cycles = (4000000/60)/4; (cycles > 0) && (fifoIdxR != fifoIdxW); )
{
@ -948,6 +967,15 @@ void CDSB2::SendCommand(UINT8 data)
void CDSB2::RunFrame(INT16 *audioL, INT16 *audioR)
{
#ifdef SUPERMODEL_SOUND
if (!g_Config.emulateDSB)
{
// DSB code applies SCSP volume, too, so we must still mix
memset(mpegL, 0, (32000/60+2)*sizeof(INT16));
memset(mpegR, 0, (32000/60+2)*sizeof(INT16));
retainedSamples = Resampler.UpSampleAndMix(audioL, audioR, mpegL, mpegR, volume[0], volume[1], 44100/60, 32000/60+2, 44100, 32000);
return;
}
M68KSetContext(&M68K);
//printf("DSB2 run frame PC=%06X\n", M68KGetPC());

View file

@ -35,6 +35,71 @@
#include "CPU/Bus.h"
/******************************************************************************
Configuration
Because DSB code mixes both the sound board SCSP and MPEG audio together, both
volume settings are stored here (for now).
******************************************************************************/
/*
* CDSBConfig:
*
* Settings used by CDSB.
*/
class CDSBConfig
{
public:
bool emulateDSB; // DSB emulation (enabled if TRUE)
// Sound (SCSP) volume (0-200, 100 being full amplitude)
inline void SetSoundVolume(unsigned vol)
{
if (vol > 200)
{
ErrorLog("Sound volume cannot exceed 200%%; setting to 100%%.\n");
vol = 100;
}
soundVol = vol;
}
inline unsigned GetSoundVolume(void)
{
return soundVol;
}
// Music (DSB MPEG) volume (0-200)
inline void SetMusicVolume(unsigned vol)
{
if (vol > 200)
{
ErrorLog("Music volume cannot exceed 200%%; setting to 100%%.\n");
vol = 100;
}
musicVol = vol;
}
inline unsigned GetMusicVolume(void)
{
return musicVol;
}
// Defaults
CDSBConfig(void)
{
emulateDSB = true;
soundVol = 100;
musicVol = 100;
}
private:
unsigned soundVol;
unsigned musicVol;
};
/******************************************************************************
Resampling

View file

@ -184,9 +184,9 @@
*/
#include <new>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include "Supermodel.h"
/******************************************************************************
@ -1870,7 +1870,7 @@ void CModel3::ClearNVRAM(void)
void CModel3::RunFrame(void)
{
// See if currently running multi-threaded
if (multiThreaded)
if (g_Config.multiThreaded)
{
// If so, check all threads are up and running
if (!StartThreads())
@ -1924,7 +1924,7 @@ void CModel3::RunFrame(void)
ThreadError:
ErrorLog("Threading error in CModel3::RunFrame: %s\nSwitching back to single-threaded mode.\n", CThread::GetLastError());
multiThreaded = false;
g_Config.multiThreaded = false;
}
bool CModel3::StartThreads()
@ -1966,7 +1966,7 @@ bool CModel3::StartThreads()
ThreadError:
ErrorLog("Unable to create threads and/or synchronization objects: %s\nSwitching back to single-threaded mode.\n", CThread::GetLastError());
DeleteThreadObjects();
multiThreaded = false;
g_Config.multiThreaded = false;
return false;
}
@ -2066,7 +2066,7 @@ void CModel3::RunSoundBoardThread()
ThreadError:
ErrorLog("Threading error in sound board thread: %s\nSwitching back to single-threaded mode.\n", CThread::GetLastError());
multiThreaded = false;
g_Config.multiThreaded = false;
}
#ifdef SUPERMODEL_DRIVEBOARD
@ -2097,14 +2097,14 @@ void CModel3::RunDriveBoardThread()
ThreadError:
ErrorLog("Threading error in drive board thread: %s\nSwitching back to single-threaded mode.\n", CThread::GetLastError());
multiThreaded = false;
g_Config.multiThreaded = false;
}
#endif
void CModel3::RunMainBoardFrame(void)
{
// Run the PowerPC for a frame
ppc_execute(ppcFrequency/60-10000);
ppc_execute(g_Config.GetPowerPCFrequency()*1000000/60-10000);
//printf("PC=%08X LR=%08X\n", ppc_get_pc(), ppc_get_lr());
// VBlank
@ -2612,16 +2612,10 @@ void CModel3::AttachInputs(CInputs *InputsPtr)
}
// Model 3 initialization. Some initialization is deferred until ROMs are loaded in LoadROMSet()
BOOL CModel3::Init(unsigned ppcFrequencyParam, BOOL multiThreadedParam)
BOOL CModel3::Init(void)
{
float memSizeMB = (float)MEMORY_POOL_SIZE/(float)0x100000;
// PowerPC frequency
ppcFrequency = ppcFrequencyParam;
if (ppcFrequency < 1000000)
ppcFrequency = 1000000;
multiThreaded = !!multiThreadedParam;
// Allocate all memory for ROMs and PPC RAM
memoryPool = new(std::nothrow) UINT8[MEMORY_POOL_SIZE];
if (NULL == memoryPool)
@ -2689,7 +2683,7 @@ CModel3::CModel3(void)
securityPtr = 0;
multiThreaded = true;
g_Config.multiThreaded = true;
startedThreads = false;
sndBrdThread = NULL;
#ifdef SUPERMODEL_DRIVEBOARD

View file

@ -22,12 +22,48 @@
/*
* Model3.h
*
* Header file defining the CModel3 and CModel3Inputs classes.
* Header file defining the CModel3, CModel3Config, and CModel3Inputs classes.
*/
#ifndef INCLUDED_MODEL3_H
#define INCLUDED_MODEL3_H
/*
* CModel3Config:
*
* Settings used by CModel3.
*/
class CModel3Config
{
public:
bool multiThreaded; // Multi-threading (enabled if TRUE)
// PowerPC clock frequency in MHz (minimum: 1 MHz)
inline void SetPowerPCFrequency(unsigned f)
{
if ((f<1) || (f>1000))
{
ErrorLog("PowerPC frequency must be between 1 and 1000 MHz; setting to 40 MHz.");
f = 40;
}
ppcFrequency = f*1000000;
}
inline unsigned GetPowerPCFrequency(void)
{
return ppcFrequency/1000000;
}
// Defaults
CModel3Config(void)
{
multiThreaded = false; // disable by default
ppcFrequency = 40*1000000; // 40 MHz
}
private:
unsigned ppcFrequency; // in Hz
};
/*
* CModel3:
*
@ -228,20 +264,16 @@ public:
void AttachInputs(CInputs *InputsPtr);
/*
* Init(ppcFrequencyParam, multiThreadedParam):
* Init(void):
*
* One-time initialization of the context. Must be called prior to all
* other members. Allocates memory and initializes device states.
*
* Parameters:
* ppcFrequencyParam PowerPC frequency in Hz. If less than 1 MHz,
* will be clamped to 1 MHz.
*
* Returns:
* OKAY is successful, otherwise FAILED if a non-recoverable error
* occurred. Prints own error messages.
*/
BOOL Init(unsigned ppcFrequencyParam, BOOL multiThreadedParam);
BOOL Init(void);
/*
* CModel3(void):
@ -321,10 +353,8 @@ private:
// PowerPC
PPC_FETCH_REGION PPCFetchRegions[3];
unsigned ppcFrequency; // clock frequency (Hz)
// Multiple threading
bool multiThreaded; // True if should run CPUs in multiple threads, otherwise everything is run in a single thread
bool startedThreads; // True if threads have been created and started
CThread *sndBrdThread; // Sound board thread
#ifdef SUPERMODEL_DRIVEBOARD

View file

@ -58,7 +58,7 @@
#include "Supermodel.h"
// DEBUG
//#define SUPERMODEL_LOG_AUDIO // define this to log all audio to sound.bin
#define SUPERMODEL_LOG_AUDIO // define this to log all audio to sound.bin
#ifdef SUPERMODEL_LOG_AUDIO
static FILE *soundFP;
#endif
@ -362,10 +362,17 @@ void CSoundBoard::RunFrame(void)
{
#ifdef SUPERMODEL_SOUND
// Run sound board first to generate SCSP audio
M68KSetContext(&M68K);
SCSP_Update();
M68KGetContext(&M68K);
//memset(audioL, 0, 44100/60*sizeof(INT16));memset(audioR, 0, 44100/60*sizeof(INT16)); // clear, I want DSB only
if (g_Config.emulateSCSP)
{
M68KSetContext(&M68K);
SCSP_Update();
M68KGetContext(&M68K);
}
else
{
memset(audioL, 0, 44100/60*sizeof(INT16));
memset(audioR, 0, 44100/60*sizeof(INT16));
}
// Run DSB and mix with existing audio
if (NULL != DSB)

View file

@ -32,6 +32,23 @@
#include "CPU/Bus.h"
#include "Model3/DSB.h"
/*
* CSoundBoardConfig:
*
* Settings used by CSoundBoard.
*/
class CSoundBoardConfig
{
public:
bool emulateSCSP; // SCSP emulation (enabled if TRUE)
// Defaults
CSoundBoardConfig(void)
{
emulateSCSP = true;
}
};
/*
* CSoundBoard:
*

286
Src/OSD/Logger.h Normal file
View file

@ -0,0 +1,286 @@
/*
* Logger.h
*
* Header file for message logging. The OSD code is expected to set up a
* default logger (CFileLogger).
*/
#ifndef INCLUDED_LOGGER_H
#define INCLUDED_LOGGER_H
#include "Types.h"
#include <cstdio>
#include <cstdarg>
#include <cstring>
/******************************************************************************
Class Definitions
******************************************************************************/
/*
* CLogger
*
* Abstract class that receives log messages from Supermodel's log functions.
* The logger object handles actual output of messages. Use the function-based
* message logging interface to generate messages.
*/
class CLogger
{
public:
/*
* DebugLog(fmt, ...):
* DebugLog(fmt, vl):
*
* Prints to debug log. If DEBUG is not defined, will end up doing nothing.
*
* Parameters:
* fmt printf()-style format string.
* ... Variable number of parameters, corresponding to format
* string.
* vl Variable arguments already stored in a list.
*/
void DebugLog(const char *fmt, ...)
{
va_list vl;
va_start(vl, fmt);
DebugLog(fmt, vl);
va_end(vl);
}
virtual void DebugLog(const char *fmt, va_list vl) = 0;
/*
* InfoLog(fmt, ...):
* InfoLog(fmt, vl):
*
* Prints to error log but does not output an error to stderr. This is
* useful for printing session information to the error log.
*
* Parameters:
* fmt printf()-style format string.
* ... Variable number of parameters, corresponding to format
* string.
* vl Variable arguments already stored in a list.
*/
void InfoLog(const char *fmt, ...)
{
va_list vl;
va_start(vl, fmt);
InfoLog(fmt, vl);
va_end(vl);
}
virtual void InfoLog(const char *fmt, va_list vl) = 0;
/*
* ErrorLog(fmt, ...):
* ErrorLog(fmt, vl):
*
* Prints to error log and outputs an error message to stderr.
*
* Parameters:
* fmt printf()-style format string.
* ... Variable number of parameters, corresponding to format
* string.
* vl Variable arguments already stored in a list.
*/
void ErrorLog(const char *fmt, ...)
{
va_list vl;
va_start(vl, fmt);
ErrorLog(fmt, vl);
va_end(vl);
}
virtual void ErrorLog(const char *fmt, va_list vl) = 0;
};
/*
* CFileLogger:
*
* Default logger that logs to debug and error log files. Files are opened and
* closed for each message in order to preserve contents in case of program
* crash.
*/
class CFileLogger : public CLogger
{
public:
void DebugLog(const char *fmt, va_list vl)
{
#ifdef DEBUG
char string[1024];
FILE *fp;
fp = fopen(m_debugLogFile, "ab");
if (NULL != fp)
{
vsprintf(string, fmt, vl);
fprintf(fp, string);
fclose(fp);
}
#endif // DEBUG
}
void InfoLog(const char *fmt, va_list vl)
{
char string[4096];
FILE *fp;
vsprintf(string, fmt, vl);
fp = fopen(m_errorLogFile, "ab");
if (NULL != fp)
{
fprintf(fp, "%s\n", string);
fclose(fp);
}
CLogger::DebugLog("Info: ");
CLogger::DebugLog(string);
CLogger::DebugLog("\n");
}
void ErrorLog(const char *fmt, va_list vl)
{
char string[4096];
FILE *fp;
vsprintf(string, fmt, vl);
fprintf(stderr, "Error: %s\n", string);
fp = fopen(m_errorLogFile, "ab");
if (NULL != fp)
{
fprintf(fp, "%s\n", string);
fclose(fp);
}
CLogger::DebugLog("Error: ");
CLogger::DebugLog(string);
CLogger::DebugLog("\n");
}
/*
* ClearLogs():
*
* Clears all log files.
*/
void ClearLogs(void)
{
#ifdef DEBUG
ClearLog(m_debugLogFile, "Supermodel v"SUPERMODEL_VERSION" Debug Log");
#endif // DEBUG
ClearLog(m_errorLogFile, "Supermodel v"SUPERMODEL_VERSION" Error Log");
}
/*
* ClearLog(file, title):
*
* Clears a log file.
*
* Parameters:
* file File name.
* title A string that is written to the file after it is cleared.
*/
void ClearLog(const char *file, const char *title)
{
FILE *fp = fopen(file, "w");
if (NULL != fp)
{
unsigned i;
fprintf(fp, "%s\n", title);
for (i = 0; i < strlen(title); i++)
fputc('-', fp);
fprintf(fp, "\n\n");
fclose(fp);
}
}
/*
* CFileLogger(debugLogFile, errorLogFile):
*
* Constructor. Specifies debug and error log files to use.
*/
CFileLogger(const char *debugLogFile, const char *errorLogFile) :
m_debugLogFile(debugLogFile), m_errorLogFile(errorLogFile)
{
}
private:
const char *m_debugLogFile;
const char *m_errorLogFile;
};
/******************************************************************************
Log Functions
Message logging interface. All messages are passed by the OSD layer to the
currently active logger object.
******************************************************************************/
/*
* DebugLog(fmt, ...):
*
* Prints debugging information. The OSD layer may choose to print this to a
* log file, the screen, neither, or both. Newlines and other formatting codes
* must be explicitly included.
*
* Parameters:
* fmt A format string (the same as printf()).
* ... Variable number of arguments, as required by format string.
*/
extern void DebugLog(const char *fmt, ...);
/*
* ErrorLog(fmt, ...):
*
* Prints error information. Errors need not require program termination and
* may simply be informative warnings to the user. Newlines should not be
* included in the format string -- they are automatically added at the end of
* a line.
*
* Parameters:
* fmt A format string (the same as printf()).
* ... Variable number of arguments, as required by format string.
*
* Returns:
* Must always return FAIL.
*/
extern BOOL ErrorLog(const char *fmt, ...);
/*
* InfoLog(fmt, ...);
*
* Prints information to the error log file but does not print to stderr. This
* is useful for logging non-error information. Newlines are automatically
* appended.
*
* Parameters:
* fmt Format string (same as printf()).
* ... Variable number of arguments as required by format string.
*/
extern void InfoLog(const char *fmt, ...);
/*
* SetLogger(Logger):
*
* Sets the logger object to use.
*
* Parameters:
* Logger New logger object. If NULL, log messages will not be output.
*/
extern void SetLogger(CLogger *Logger);
/*
* GetLogger(void):
*
* Returns:
* Current logger object (NULL if none has been set).
*/
extern CLogger *GetLogger(void);
#endif // INCLUDED_LOGGER_H

View file

@ -40,10 +40,10 @@
*/
#include <new>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdarg>
#include "Pkgs/glew.h"
#ifdef SUPERMODEL_OSX
#include <SDL/SDL.h>
@ -57,15 +57,69 @@
#include "DirectInputSystem.h"
#endif
CLogger *GetLogger();
void SetLogger(CLogger *logger);
/******************************************************************************
Error and Debug Logging
******************************************************************************/
// Log file names
#define DEBUG_LOG_FILE "debug.log"
#define ERROR_LOG_FILE "error.log"
// Logger object is used to redirect log messages appropriately
static CLogger *s_Logger = NULL;
CLogger *GetLogger()
{
return s_Logger;
}
void SetLogger(CLogger *Logger)
{
s_Logger = Logger;
}
void DebugLog(const char *fmt, ...)
{
if (s_Logger == NULL)
return;
va_list vl;
va_start(vl, fmt);
s_Logger->DebugLog(fmt, vl);
va_end(vl);
}
void InfoLog(const char *fmt, ...)
{
if (s_Logger == NULL)
return;
va_list vl;
va_start(vl, fmt);
s_Logger->InfoLog(fmt, vl);
va_end(vl);
}
BOOL ErrorLog(const char *fmt, ...)
{
if (s_Logger == NULL)
return FAIL;
va_list vl;
va_start(vl, fmt);
s_Logger->ErrorLog(fmt, vl);
va_end(vl);
return FAIL;
}
/******************************************************************************
Display Management
******************************************************************************/
/*
* Position and size of rectangular region within OpenGL display to render to
* Position and size of rectangular region within OpenGL display to render to.
* Unlike the g_Config object, these end up containing the actual resolution
* (and computed offsets within the viewport) that will be rendered based on
* what was obtained from SDL.
*/
unsigned xOffset, yOffset; // offset of renderer output within OpenGL viewport
unsigned xRes, yRes; // renderer output resolution (can be smaller than GL viewport)
@ -162,8 +216,11 @@ static BOOL CreateGLScreen(const char *caption, unsigned *xOffsetPtr, unsigned *
return 0;
}
/******************************************************************************
Configuration
Configuration file management and input settings.
******************************************************************************/
#define CONFIG_FILE_PATH "Config/Supermodel.ini"
@ -172,19 +229,12 @@ static BOOL CreateGLScreen(const char *caption, unsigned *xOffsetPtr, unsigned *
";\n"
// Create and configure inputs
static CInputs *CreateInputs(CInputSystem *InputSystem, BOOL configure)
static bool ConfigureInputs(CInputs *Inputs, bool configure)
{
// Create and initialize inputs
CInputs* Inputs = new CInputs(InputSystem);
if (!Inputs->Initialize())
{
ErrorLog("Unable to initalize inputs.\n");
return NULL;
}
// Open and parse configuration file
CINIFile INI;
INI.Open(CONFIG_FILE_PATH); // doesn't matter if it exists or not, will get overwritten
INI.SetDefaultSectionName("Global");
INI.Parse();
Inputs->ReadFromINIFile(&INI, "Global");
@ -195,10 +245,7 @@ static CInputs *CreateInputs(CInputSystem *InputSystem, BOOL configure)
// Open an SDL window
unsigned xOffset, yOffset, xRes=496, yRes=384;
if (OKAY != CreateGLScreen("Supermodel - Configuring Inputs...",&xOffset,&yOffset,&xRes,&yRes,FALSE,FALSE))
{
ErrorLog("Unable to start SDL to configure inputs.\n");
return NULL;
}
return (bool) ErrorLog("Unable to start SDL to configure inputs.\n");
// Configure the inputs
if (Inputs->ConfigureInputs(NULL, xOffset, yOffset, xRes, yRes))
@ -216,9 +263,82 @@ static CInputs *CreateInputs(CInputSystem *InputSystem, BOOL configure)
puts("");
}
return Inputs;
INI.Close();
return OKAY;
}
// Apply configuration settings from configuration file
static void ApplySettings(CInputs *Inputs, CINIFile *INI, const char *section)
{
unsigned x;
string String;
// Model 3
if (OKAY == INI->Get(section, "MultiThreaded", x))
g_Config.multiThreaded = x ? true : false;
if (OKAY == INI->Get(section, "PowerPCFrequency", x))
g_Config.SetPowerPCFrequency(x);
// 3D renderer
INI->Get(section, "VertexShader", g_Config.vertexShaderFile);
INI->Get(section, "FragmentShader", g_Config.fragmentShaderFile);
// SCSP and DSB
if (OKAY == INI->Get(section, "SoundVolume", x))
g_Config.SetSoundVolume(x);
if (OKAY == INI->Get(section, "MusicVolume", x))
g_Config.SetMusicVolume(x);
if (OKAY == INI->Get(section, "EmulateSCSP", x))
g_Config.emulateSCSP = x ? true : false;
if (OKAY == INI->Get(section, "EmulateDSB", x))
g_Config.emulateDSB = x ? true : false;
// OSD
INI->Get(section, "XResolution", g_Config.xRes);
INI->Get(section, "YResolution", g_Config.yRes);
if (OKAY == INI->Get(section, "FullScreen", x))
g_Config.fullScreen = x ? true : false;
if (OKAY == INI->Get(section, "Throttle", x))
g_Config.throttle = x ? true : false;
if (OKAY == INI->Get(section, "ShowFrameRate", x))
g_Config.showFPS = x ? true : false;
// Inputs
if (Inputs != NULL)
Inputs->ReadFromINIFile(INI, section);
}
// Read settings (from a specific section) from the config file
static void ReadConfigFile(CInputs *Inputs, const char *section)
{
CINIFile INI;
INI.Open(CONFIG_FILE_PATH);
INI.SetDefaultSectionName("Global"); // required to read settings not associated with a specific section
INI.Parse();
ApplySettings(Inputs, &INI, section);
INI.Close();
}
// Debug
static void DumpConfig(void)
{
printf("MultiThreaded = %d\n", g_Config.multiThreaded);
printf("PowerPCFrequency = %d\n", g_Config.GetPowerPCFrequency());
printf("EmulateSCSP = %d\n", g_Config.emulateSCSP);
printf("EmulateDSB = %d\n", g_Config.emulateDSB);
printf("VertexShader = %s\n", g_Config.vertexShaderFile.c_str());
printf("FragmentShader = %s\n", g_Config.fragmentShaderFile.c_str());
printf("XResolution = %d\n", g_Config.xRes);
printf("YResolution = %d\n", g_Config.yRes);
printf("FullScreen = %d\n", g_Config.fullScreen);
printf("Throttle = %d\n", g_Config.throttle);
printf("ShowFrameRate = %d\n", g_Config.showFPS);
printf("InputSystem = %s\n", g_Config.GetInputSystem());
printf("\n");
}
/******************************************************************************
Save States and NVRAM
@ -364,14 +484,11 @@ static void LoadNVRAM(CModel3 *Model3)
******************************************************************************/
#ifdef SUPERMODEL_DEBUGGER
int Supermodel(const char *zipFile, CModel3 *Model3, CInputs *Inputs, Debugger::CDebugger *Debugger, unsigned ppcFrequency, BOOL multiThreaded,
unsigned xResParam, unsigned yResParam, BOOL keepAspectRatio, BOOL fullScreen, BOOL noThrottle, BOOL showFPS,
const char *vsFile, const char *fsFile)
int Supermodel(const char *zipFile, CModel3 *Model3, CInputs *Inputs, Debugger::CDebugger *Debugger, CINIFile *CmdLine)
{
CLogger *oldLogger;
#else
int Supermodel(const char *zipFile, CInputs *Inputs, unsigned ppcFrequency, BOOL multiThreaded, unsigned xResParam, unsigned yResParam,
BOOL keepAspectRatio, BOOL fullScreen, BOOL noThrottle, BOOL showFPS, const char *vsFile, const char *fsFile)
int Supermodel(const char *zipFile, CInputs *Inputs, CINIFile *CmdLine)
{
CModel3 *Model3 = new CModel3();
#endif // SUPERMODEL_DEBUGGER
@ -385,23 +502,30 @@ int Supermodel(const char *zipFile, CInputs *Inputs, unsigned ppcFrequency, BOOL
BOOL paused = 0;
// Info log user options
InfoLog("PowerPC frequency: %d Hz", ppcFrequency);
InfoLog("Resolution: %dx%d (%s)", xResParam, yResParam, fullScreen?"full screen":"windowed");
InfoLog("Frame rate limiting: %s", noThrottle?"Disabled":"Enabled");
InfoLog("PowerPC frequency: %d Hz", g_Config.GetPowerPCFrequency());
InfoLog("Resolution requested: %dx%d (%s)", g_Config.xRes, g_Config.yRes, g_Config.fullScreen?"full screen":"windowed");
InfoLog("Frame rate limiting: %s", g_Config.throttle?"Enabled":"Disabled");
// Initialize and load ROMs
Model3->Init(ppcFrequency, multiThreaded);
if (OKAY != Model3->Init())
return 1;
if (OKAY != Model3->LoadROMSet(Model3GameList, zipFile))
return 1;
// Apply game-specific settings and then, lastly, command line settings
ReadConfigFile(Inputs, Model3->GetGameInfo()->id);
//DumpConfig();
ApplySettings(Inputs, CmdLine, "Global");
//DumpConfig();
// Load NVRAM
LoadNVRAM(Model3);
// Start up SDL and open a GL window
xRes = xResParam;
yRes = yResParam;
xRes = g_Config.xRes;
yRes = g_Config.yRes;
sprintf(titleStr, "Supermodel - %s", Model3->GetGameInfo()->title);
if (OKAY != CreateGLScreen(titleStr,&xOffset,&yOffset,&xRes,&yRes,keepAspectRatio,fullScreen))
if (OKAY != CreateGLScreen(titleStr,&xOffset,&yOffset,&xRes,&yRes,TRUE,g_Config.fullScreen))
return 1;
// Initialize audio system
@ -409,7 +533,7 @@ int Supermodel(const char *zipFile, CInputs *Inputs, unsigned ppcFrequency, BOOL
return 1;
// Hide mouse if fullscreen
Inputs->GetInputSystem()->SetMouseVisibility(!fullScreen);
Inputs->GetInputSystem()->SetMouseVisibility(!g_Config.fullScreen);
// Attach the inputs to the emulator
Model3->AttachInputs(Inputs);
@ -417,7 +541,7 @@ int Supermodel(const char *zipFile, CInputs *Inputs, unsigned ppcFrequency, BOOL
// Initialize the renderer
if (OKAY != Render2D->Init(xOffset, yOffset, xRes, yRes))
goto QuitError;
if (OKAY != Render3D->Init(xOffset, yOffset, xRes, yRes, vsFile, fsFile))
if (OKAY != Render3D->Init(xOffset, yOffset, xRes, yRes))
goto QuitError;
Model3->AttachRenderers(Render2D,Render3D);
@ -521,7 +645,7 @@ int Supermodel(const char *zipFile, CInputs *Inputs, unsigned ppcFrequency, BOOL
// Dump input states
Inputs->DumpState(Model3->GetGameInfo());
}
else if (Inputs->uiToggleCursor->Pressed() && fullScreen)
else if (Inputs->uiToggleCursor->Pressed() && g_Config.fullScreen)
{
// Toggle cursor in full screen mode
showCursor = !showCursor;
@ -536,8 +660,8 @@ int Supermodel(const char *zipFile, CInputs *Inputs, unsigned ppcFrequency, BOOL
else if (Inputs->uiToggleFrLimit->Pressed())
{
// Toggle frame limiting
noThrottle = !noThrottle;
printf("Frame limiting: %s\n", noThrottle?"Off":"On");
g_Config.throttle = !g_Config.throttle;
printf("Frame limiting: %s\n", g_Config.throttle?"On":"Off");
}
#ifdef SUPERMODEL_DEBUGGER
else if (Inputs->uiEnterDebugger->Pressed())
@ -554,7 +678,7 @@ int Supermodel(const char *zipFile, CInputs *Inputs, unsigned ppcFrequency, BOOL
currentTicks = currentFPSTicks;
// FPS
if (showFPS)
if (g_Config.showFPS)
{
++fpsFramesElapsed;
if((currentFPSTicks-prevFPSTicks) >= 1000) // update FPS every 1 second (each tick is 1 ms)
@ -567,7 +691,7 @@ int Supermodel(const char *zipFile, CInputs *Inputs, unsigned ppcFrequency, BOOL
}
// Frame limiting/paused
if (paused || !noThrottle)
if (paused || g_Config.throttle)
{
++framesElapsed;
targetTicks = startTicks + (unsigned) ((float)framesElapsed * 1000.0f/60.0f);
@ -643,204 +767,6 @@ QuitError:
}
/******************************************************************************
Error and Debug Logging
******************************************************************************/
static CLogger *s_logger = NULL;
/*
* Returns the current logger.
*/
CLogger *GetLogger()
{
return s_logger;
}
/*
* Sets the current logger.
*/
void SetLogger(CLogger *logger)
{
s_logger = logger;
}
/*
* DebugLog(fmt, ...):
*
* Logs a debug message with the logger.
*
* Parameters:
* fmt Format string (same as printf()).
* ... Variable number of arguments as required by format string.
*/
void DebugLog(const char *fmt, ...)
{
if (s_logger == NULL)
return;
va_list vl;
va_start(vl, fmt);
s_logger->DebugLog(fmt, vl);
va_end(vl);
}
/*
* InfoLog(fmt, ...);
*
* Logs an info message with the logger.
*
* Parameters:
* fmt Format string (same as printf()).
* ... Variable number of arguments as required by format string.
*/
void InfoLog(const char *fmt, ...)
{
if (s_logger == NULL)
return;
va_list vl;
va_start(vl, fmt);
s_logger->InfoLog(fmt, vl);
va_end(vl);
}
/*
* ErrorLog(fmt, ...):
*
* Logs an error message with the logger.
*
* Parameters:
* fmt Format string (same as printf()).
* ... Variable number of arguments as required by format string.
*
* Returns:
* Always returns FAIL.
*/
BOOL ErrorLog(const char *fmt, ...)
{
if (s_logger == NULL)
return FAIL;
va_list vl;
va_start(vl, fmt);
s_logger->ErrorLog(fmt, vl);
va_end(vl);
return FAIL;
}
#define DEBUG_LOG_FILE "debug.log"
#define ERROR_LOG_FILE "error.log"
/*
* Default logger that logs to debug and error log files.
*/
class CFileLogger : public CLogger
{
private:
const char *m_debugLogFile;
const char *m_errorLogFile;
public:
CFileLogger(const char *debugLogFile, const char *errorLogFile) :
m_debugLogFile(debugLogFile), m_errorLogFile(errorLogFile)
{
//
}
/*
* DebugLog(fmt, ...):
*
* Prints to debug log. The file is opened and closed each time so that its
* contents are preserved even if the program crashes.
*/
void DebugLog(const char *fmt, va_list vl)
{
#ifdef DEBUG
char string[1024];
FILE *fp;
fp = fopen(m_debugLogFile, "ab");
if (NULL != fp)
{
vsprintf(string, fmt, vl);
fprintf(fp, string);
fclose(fp);
}
#endif // DEBUG
}
/*
* InfoLog(fmt, ...);
*
* Prints information to the error log file but does not print to stderr. This
* is useful for logging non-error information.
*/
void InfoLog(const char *fmt, va_list vl)
{
char string[4096];
FILE *fp;
vsprintf(string, fmt, vl);
fp = fopen(m_errorLogFile, "ab");
if (NULL != fp)
{
fprintf(fp, "%s\n", string);
fclose(fp);
}
CLogger::DebugLog("Info: ");
CLogger::DebugLog(string);
CLogger::DebugLog("\n");
}
/*
* ErrorLog(fmt, ...):
*
* Prints an error to stderr and the error log file.
*/
void ErrorLog(const char *fmt, va_list vl)
{
char string[4096];
FILE *fp;
vsprintf(string, fmt, vl);
fprintf(stderr, "Error: %s\n", string);
fp = fopen(m_errorLogFile, "ab");
if (NULL != fp)
{
fprintf(fp, "%s\n", string);
fclose(fp);
}
CLogger::DebugLog("Error: ");
CLogger::DebugLog(string);
CLogger::DebugLog("\n");
}
void ClearLogs()
{
#ifdef DEBUG
ClearLog(DEBUG_LOG_FILE, "Supermodel v"SUPERMODEL_VERSION" Debug Log");
#endif // DEBUG
ClearLog(ERROR_LOG_FILE, "Supermodel v"SUPERMODEL_VERSION" Error Log");
}
// Clear log file
void ClearLog(const char *file, const char *title)
{
FILE *fp = fopen(file, "w");
if (NULL != fp)
{
unsigned i;
fprintf(fp, "%s\n", title);
for (i = 0; i < strlen(title); i++)
fputc('-', fp);
fprintf(fp, "\n\n");
fclose(fp);
}
}
};
/******************************************************************************
Diagnostic Commands
******************************************************************************/
@ -988,10 +914,12 @@ static void Help(void)
puts("");
puts("General Options:");
puts(" -?, -h Print this help text");
puts(" -print-games List supported games");
puts(" -print-games List supported games and quit");
puts("");
puts("Emulation Options:");
puts(" -ppc-frequency=<f> Set PowerPC frequency in MHz [Default: 25]");
puts(" -ppc-frequency=<f> Set PowerPC frequency in MHz [Default: 40]");
puts(" -no-scsp Disable Sega Custom Sound Processor (sound effects)");
puts(" -no-dsb Disable Digital Sound Board (MPEG music)");
puts(" -multi-threaded Enable multi-threading");
#ifdef SUPERMODEL_DEBUGGER
puts(" -disable-debugger Completely disable debugger functionality");
@ -1007,6 +935,10 @@ static void Help(void)
puts(" -vert-shader=<file> Load 3D vertex shader from external file");
puts(" -frag-shader=<file> Load 3D fragment shader from external file");
#endif
puts("");
puts("Audio Options:");
puts(" -sound-volume=<v> Set volume of sound effects in % [Default: 100]");
puts(" -music-volume=<v> Set volume of MPEG music in % [Default: 100]");
puts("");
puts("Input Options:");
puts(" -input-system=<s> Set input system [Default: SDL]");
@ -1017,7 +949,7 @@ static void Help(void)
#ifdef DEBUG
puts(" -dis=<addr>[,n] Disassemble PowerPC code from CROM");
#endif
puts(" -print-gl-info Print extensive OpenGL information\n");
puts(" -print-gl-info Print extensive OpenGL information and quit\n");
}
// Print game list
@ -1045,13 +977,14 @@ static void PrintGameList(void)
*/
int main(int argc, char **argv)
{
CINIFile CmdLine; // not associated with any files, holds command line options
int i, ret;
int cmd=0, fileIdx=0, cmdMultiThreaded=0, cmdFullScreen=0, cmdNoThrottle=0, cmdShowFPS=0, cmdPrintInputs=0, cmdConfigInputs=0, cmdPrintGames=0, cmdDis=0, cmdPrintGLInfo=0;
int fileIdx=0;
bool cmdPrintInputs=false, cmdConfigInputs=false, cmdDis=false;
#ifdef SUPERMODEL_DEBUGGER
int cmdDisableDebugger = 0, cmdEnterDebugger=0;
int cmdEnterDebugger=false;
#endif // SUPERMODEL_DEBUGGER
unsigned n, xRes=496, yRes=384, ppcFrequency=25000000;
char *vsFile = NULL, *fsFile = NULL, *inpSysName = NULL;
unsigned n;
UINT32 addr;
Title();
@ -1065,8 +998,21 @@ int main(int argc, char **argv)
CFileLogger Logger(DEBUG_LOG_FILE, ERROR_LOG_FILE);
Logger.ClearLogs();
SetLogger(&Logger);
// Read global settings from INI file
ReadConfigFile(NULL, "Global");
//DumpConfig();
// Parse command line
/*
* Parse command line.
*
* Settings are stored in CmdLine so that they can be applied later, after
* game-specific settings are read from the configuration file (which
* requires the ROM set to be identified and therefore is done later).
*
* Some commands are processed here directly.
*/
CmdLine.SetDefaultSectionName("Global"); // command line settings are global-level
for (i = 1; i < argc; i++)
{
if (!strcmp(argv[i],"-h") || !strcmp(argv[i],"-?"))
@ -1075,7 +1021,10 @@ int main(int argc, char **argv)
return 0;
}
else if (!strcmp(argv[i],"-print-games"))
cmd = cmdPrintGames = 1;
{
PrintGameList();
return 0;
}
else if (!strncmp(argv[i],"-ppc-frequency",14))
{
int f;
@ -1083,21 +1032,45 @@ int main(int argc, char **argv)
if (ret != 1)
ErrorLog("-ppc-frequency requires a frequency.");
else
{
if ((f<1) || (f>1000)) // limit to 1-1000MHz
ErrorLog("PowerPC frequency must be between 1 and 1000 MHz. Ignoring.");
else
ppcFrequency = f*1000000;
}
CmdLine.Set("Global", "PowerPCFrequency", f);
}
else if (!strcmp(argv[i],"-multi-threaded"))
{
n = 1;
CmdLine.Set("Global", "MultiThreaded", n);
}
else if (!strncmp(argv[i],"-multi-threaded", 16))
cmd = cmdMultiThreaded = 1;
#ifdef SUPERMODEL_DEBUGGER
else if (!strncmp(argv[i],"-disable-debugger",17))
cmd = cmdDisableDebugger = 1;
else if (!strncmp(argv[i],"-enter-debugger",15))
cmd = cmdEnterDebugger = 1;
else if (!strncmp(argv[i],"-disable-debugger"))
g_Config.disableDebugger = true;
else if (!strcmp(argv[i],"-enter-debugger"))
cmdEnterDebugger = true;
#endif // SUPERMODEL_DEBUGGER
else if (!strncmp(argv[i],"-sound-vol",10))
{
ret = sscanf(&argv[i][10],"=%d",&n);
if (ret != 1)
ErrorLog("-sound-vol requires a volume setting.");
else
CmdLine.Set("Global", "SoundVolume", n);
}
else if (!strncmp(argv[i],"-music-vol",10))
{
ret = sscanf(&argv[i][10],"=%d",&n);
if (ret != 1)
ErrorLog("-music-vol requires a volume setting.");
else
CmdLine.Set("Global", "MusicVolume", n);
}
else if (!strcmp(argv[i], "-no-scsp"))
{
n = 0;
CmdLine.Set("Global", "EmulateSCSP", n);
}
else if (!strcmp(argv[i], "-no-dsb"))
{
n = 0;
CmdLine.Set("Global", "EmulateDSB", n);
}
else if (!strncmp(argv[i],"-res",4))
{
unsigned x, y;
@ -1107,56 +1080,68 @@ int main(int argc, char **argv)
ErrorLog("-res requires both a width and a height.");
else
{
xRes = x;
yRes = y;
CmdLine.Set("Global", "XResolution", x);
CmdLine.Set("Global", "YResolution", y);
}
}
else if (!strcmp(argv[i],"-fullscreen"))
cmd = cmdFullScreen = 1;
{
n = 1;
CmdLine.Set("Global", "FullScreen", n);
}
else if (!strcmp(argv[i],"-no-throttle"))
cmd = cmdNoThrottle = 1;
{
n = 0;
CmdLine.Set("Global", "Throttle", n);
}
else if (!strcmp(argv[i],"-show-fps"))
cmd = cmdShowFPS = 1;
{
n = 1;
CmdLine.Set("Global", "ShowFrameRate", n);
}
else if (!strncmp(argv[i],"-vert-shader=",13))
{
if (argv[i][13] == '\0')
ErrorLog("-vert-shader requires a file path.");
else
vsFile = &argv[i][13];
CmdLine.Set("Global", "VertexShader", &argv[i][13]);
}
else if (!strncmp(argv[i],"-frag-shader=",13))
{
if (argv[i][13] == '\0')
ErrorLog("-frag-shader requires a file path.");
else
fsFile = &argv[i][13];
CmdLine.Set("Global", "FragmentShader", &argv[i][13]);
}
else if (!strncmp(argv[i],"-input-system=", 14))
{
if (argv[i][14] == '\0')
ErrorLog("-input-system requires an input system name.");
else
inpSysName = &argv[i][14];
CmdLine.Set("Global", "InputSystem", &argv[i][14]);
}
else if (!strcmp(argv[i],"-print-inputs"))
cmd = cmdPrintInputs = 1;
cmdPrintInputs = true;
else if (!strcmp(argv[i],"-config-inputs"))
cmd = cmdConfigInputs = 1;
cmdConfigInputs = true;
else if (!strncmp(argv[i],"-dis",4))
{
ret = sscanf(&argv[i][4],"=%X,%X",&addr,&n);
if (ret == 1)
{
n = 16;
cmd = cmdDis = 1;
cmdDis = true;
}
else if (ret == 2)
cmd = cmdDis = 1;
cmdDis = true;
else
ErrorLog("-dis requires address and, optionally, number of instructions.");
}
else if (!strcmp(argv[i],"-print-gl-info"))
cmd = cmdPrintGLInfo = 1;
{
PrintGLInfo(FALSE);
return 0;
}
else if (argv[i][0] == '-')
ErrorLog("Ignoring invalid option: %s.", argv[i]);
else
@ -1175,6 +1160,7 @@ int main(int argc, char **argv)
return 1;
}
// Create input system (default is SDL) and debugger
CInputSystem *InputSystem = NULL;
CInputs *Inputs = NULL;
int exitCode = 0;
@ -1183,27 +1169,33 @@ int main(int argc, char **argv)
Debugger::CSupermodelDebugger *Debugger = NULL;
#endif // SUPERMODEL_DEBUGGER
// Create input system (default is SDL)
if (inpSysName == NULL || stricmp(inpSysName, "sdl") == 0)
if (stricmp(g_Config.GetInputSystem(), "sdl") == 0)
InputSystem = new CSDLInputSystem();
#ifdef SUPERMODEL_WIN32
else if (stricmp(inpSysName, "dinput") == 0)
else if (stricmp(g_Config.GetInputSystem(), "dinput") == 0)
InputSystem = new CDirectInputSystem(false, false, false);
else if (stricmp(inpSysName, "xinput") == 0)
else if (stricmp(g_Config.GetInputSystem(), "xinput") == 0)
InputSystem = new CDirectInputSystem(false, true, false);
else if (stricmp(inpSysName, "rawinput") == 0)
else if (stricmp(g_Config.GetInputSystem(), "rawinput") == 0)
InputSystem = new CDirectInputSystem(true, false, false);
#endif // SUPERMODEL_WIN32
else
{
ErrorLog("Unknown input system: '%s'.\n", inpSysName);
ErrorLog("Unknown input system: '%s'.\n", g_Config.GetInputSystem());
exitCode = 1;
goto Exit;
}
// Create inputs from input system (configuring them if required)
Inputs = CreateInputs(InputSystem, cmdConfigInputs);
if (Inputs == NULL)
Inputs = new CInputs(InputSystem);
if (!Inputs->Initialize())
{
ErrorLog("Unable to initalize inputs.\n");
exitCode = 1;
goto Exit;
}
if (ConfigureInputs(Inputs, cmdConfigInputs))
{
exitCode = 1;
goto Exit;
@ -1215,22 +1207,7 @@ int main(int argc, char **argv)
InputSystem->PrintSettings();
}
// Process commands that don't require ROM set
if (cmd)
{
if (cmdPrintGames)
{
PrintGameList();
goto Exit;
}
if (cmdPrintGLInfo)
{
PrintGLInfo(FALSE);
goto Exit;
}
}
// From this point onwards, a ROM set is needed
if (fileIdx == 0)
{
ErrorLog("No ROM set specified.");
@ -1238,22 +1215,18 @@ int main(int argc, char **argv)
goto Exit;
}
// Process commands that require ROMs
if (cmd)
{
if (cmdDis)
{
if (OKAY != DisassembleCROM(argv[fileIdx], addr, n))
exitCode = 1;
goto Exit;
}
if (cmdDis)
{
if (OKAY != DisassembleCROM(argv[fileIdx], addr, n))
exitCode = 1;
goto Exit;
}
#ifdef SUPERMODEL_DEBUGGER
// Create Model3
Model3 = new CModel3();
// Create Supermodel debugger unless debugging is disabled
if (!cmdDisableDebugger)
if (!g_Config.disableDebugger)
{
Debugger = new Debugger::CSupermodelDebugger(Model3, Inputs, &Logger);
// If -enter-debugger option was set force debugger to break straightaway
@ -1261,13 +1234,13 @@ int main(int argc, char **argv)
Debugger->ForceBreak(true);
}
// Fire up Supermodel with debugger
exitCode = Supermodel(argv[fileIdx],Model3,Inputs,Debugger,ppcFrequency,cmdMultiThreaded,xRes,yRes,TRUE,cmdFullScreen,cmdNoThrottle,cmdShowFPS,vsFile,fsFile);
exitCode = Supermodel(argv[fileIdx],Model3,Inputs,Debugger,&CmdLine);
if (Debugger != NULL)
delete Debugger;
delete Model3;
#else
// Fire up Supermodel
exitCode = Supermodel(argv[fileIdx],Inputs,ppcFrequency,cmdMultiThreaded,xRes,yRes,TRUE,cmdFullScreen,cmdNoThrottle,cmdShowFPS,vsFile,fsFile);
exitCode = Supermodel(argv[fileIdx],Inputs,&CmdLine);
#endif // SUPERMODEL_DEBUGGER
Exit:

View file

@ -25,6 +25,8 @@
* Fundamental data types. This file is used by both C++ and C modules, so it
* must NOT include any C++-specific constructs. Some modules may elect to
* include it directly rather than through Supermodel.h.
*
* All ports must define this file.
*/
#ifndef INCLUDED_TYPES_H

View file

@ -119,7 +119,7 @@ int g,snd_eof=0;
if (header.protection_bit==0) getcrc();
printf("%d Hz, layer %d\n", t_sampling_frequency[header.ID][header.sampling_frequency], header.layer);
//printf("%d Hz, layer %d\n", t_sampling_frequency[header.ID][header.sampling_frequency], header.layer);
if (setup_audio(&header)!=0) {
warn("Cannot set up audio. Exiting\n");

View file

@ -523,7 +523,7 @@ static int min_cycles = 99999999;
if (cnt2-cnt1 < min_cycles) {
min_cycles = cnt2-cnt1;
printf("%d cycles\n", min_cycles);
//printf("%d cycles\n", min_cycles);
}
#endif
@ -546,7 +546,7 @@ static int min_cycles = 99999999;
if (cnt2-cnt1 < min_cycles) {
min_cycles = cnt2-cnt1;
printf("%d cycles, sfb %d\n", min_cycles, sfb);
//printf("%d cycles, sfb %d\n", min_cycles, sfb);
}
#endif

View file

@ -1503,7 +1503,7 @@ static int min_cycles = 99999999;
if (cnt2-cnt1 < min_cycles) {
min_cycles = cnt2-cnt1;
printf("%d, %d cycles, %d\n", cnt3-cnt1, min_cycles, start);
//printf("%d, %d cycles, %d\n", cnt3-cnt1, min_cycles, start);
}
#endif
}

View file

@ -28,6 +28,12 @@
#ifndef INCLUDED_SUPERMODEL_H
#define INCLUDED_SUPERMODEL_H
// Used throughout Supermodel
#include <cstdio>
#include <cstdlib>
#include <cstring>
/******************************************************************************
Program-Wide Definitions
******************************************************************************/
@ -38,8 +44,11 @@
/******************************************************************************
OS-Dependent (OSD) Items
Everything here must be provided by the OSD layer. Include files should be
located in the OSD directories for each port.
Everything here must be provided by the OSD layer. The following include files
must be located in the OSD directories for each port:
Types.h Defines fundamental data types.
OSDConfig.h COSDConfig class (OSD-specific configuration settings).
******************************************************************************/
// stricmp() is non-standard, apparently...
@ -49,6 +58,7 @@
#define stricmp strcasecmp
#endif
/*
* Fundamental Data Types:
*
@ -68,58 +78,21 @@
* specific stuff. Some modules may choose to include it directly rather than
* use Supermodel.h, so it must exist.
*/
#include "Types.h"
// OSD Interfaces
#include "Thread.h"
#include "Audio.h"
#include "Types.h" // located in OSD/<port>/ directory
/*
* Error and Debug Logging
* OSD Header Files
*/
/*
* DebugLog(fmt, ...):
*
* Prints debugging information. The OSD layer may choose to print this to a
* log file, the screen, neither, or both. Newlines and other formatting codes
* must be explicitly included.
*
* Parameters:
* fmt A format string (the same as printf()).
* ... Variable number of arguments, as required by format string.
*/
extern void DebugLog(const char *fmt, ...);
// Error logging interface
#include "OSD/Logger.h"
/*
* ErrorLog(fmt, ...):
*
* Prints error information. Errors need not require program termination and
* may simply be informative warnings to the user. Newlines should not be
* included in the format string -- they are automatically added at the end of
* a line.
*
* Parameters:
* fmt A format string (the same as printf()).
* ... Variable number of arguments, as required by format string.
*
* Returns:
* Must always return FAIL.
*/
extern BOOL ErrorLog(const char *fmt, ...);
// OSD configuration
#include "OSDConfig.h" // located in OSD/<port>/ directory
/*
* InfoLog(fmt, ...);
*
* Prints information to the error log file but does not print to stderr. This
* is useful for logging non-error information. Newlines are automatically
* appended.
*
* Parameters:
* fmt Format string (same as printf()).
* ... Variable number of arguments as required by format string.
*/
extern void InfoLog(const char *fmt, ...);
// OSD Interfaces
#include "OSD/Thread.h"
#include "OSD/Audio.h"
/******************************************************************************
@ -128,10 +101,7 @@ extern void InfoLog(const char *fmt, ...);
All primary header files for modules used throughout Supermodel are included
here, except for external packages and APIs.
******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Games.h"
#include "ROMLoad.h"
#include "INIFile.h"
@ -168,6 +138,7 @@ extern void InfoLog(const char *fmt, ...);
#include "Model3/SoundBoard.h"
#include "Model3/DSB.h"
#include "Model3/Model3.h"
#include "Config.h"
/******************************************************************************