blob: ec9f4109ebbe261196bb1afae5107ff7f594c922 [file] [log] [blame] [raw]
/*
YAPE - Yet Another Plus/4 Emulator
The program emulates the Commodore 264 family of 8 bit microcomputers
This program is free software, you are welcome to distribute it,
and/or modify it under certain conditions. For more information,
read 'Copying'.
(c) 2000, 2001, 2005, 2007 Attila Gr�z
(c) 2005 VENESZ Roland
*/
#include "archdep.h"
#include <stdio.h>
#ifdef _WIN32
// fixes a missing export in SDL2 for VS 2015
#if _MSC_VER >= 1900
FILE _iob[] = { *stdin, *stdout, *stderr };
extern "C" FILE * __cdecl __iob_func(void)
{
return _iob;
}
#endif
#endif
// forward declarations
static void flipMaxFps(void *v);
unsigned int tick_50hz, tick_vsync, fps;
static unsigned int framesShown = 50;
static const unsigned int maxFpsValues[] = { 100, 60, 50, 25, 10 };
static unsigned int maxFps = 100;
static unsigned int maxFpsIndex = 0;
rvar_t archDepSettings[] = {
{ "Maximum framerate", "MaxFrameRate", flipMaxFps, &maxFps, RVAR_INT, NULL },
{ NULL, NULL, NULL, NULL, NULL, NULL }
};
static void flipMaxFps(void *v)
{
maxFpsIndex = (maxFpsIndex + 1) % (sizeof(maxFpsValues) / sizeof(maxFpsValues[0]));
maxFps = maxFpsValues[maxFpsIndex];
}
/* functions for Windows */
#if defined(_WIN32)
static HANDLE handle;
static WIN32_FIND_DATA rec;
static char temp[512];
static BOOL showDriveLetters = FALSE;
static DWORD driveBitFields;
static UINT currentDriveIndex;
static char currentDrive[MAX_PATH];
/* file management */
void ad_exit_drive_selector()
{
showDriveLetters = FALSE;
}
static int ad_get_next_drive()
{
do {
driveBitFields >>= 1;
currentDriveIndex++;
} while (!(driveBitFields & 1) && driveBitFields != 0);
if (driveBitFields) {
sprintf(currentDrive, "%c:/", 'A' + currentDriveIndex);
return 1;
} else {
return 0;
}
}
static void ad_get_first_drive()
{
currentDriveIndex = 0;
driveBitFields = GetLogicalDrives();
while (!(driveBitFields & 1) && driveBitFields != 0) {
driveBitFields >>= 1;
currentDriveIndex++;
}
sprintf(currentDrive, "%c:/", 'A' + currentDriveIndex);
}
int ad_get_curr_dir(char *pathstring)
{
return GetCurrentDirectory(MAX_PATH, pathstring);
}
int ad_set_curr_dir(char *path)
{
char origPath[MAX_PATH];
char cp[MAX_PATH];
GetCurrentDirectory(MAX_PATH, origPath);
BOOL retval = SetCurrentDirectory(path);
if (retval) {
if (!strcmp(path, "..")) {
GetCurrentDirectory(MAX_PATH, cp);
// root reached?
if (!strcmp(cp, origPath)) {
showDriveLetters = TRUE;
} else {
showDriveLetters = FALSE;
}
}
}
return retval;
}
int ad_find_first_file(const char *filefilter)
{
if (showDriveLetters) {
ad_get_first_drive();
return 1;
} else {
handle = FindFirstFile( filefilter, &rec);
if (handle != INVALID_HANDLE_VALUE) return 1;
return 0;
}
}
char *ad_return_current_filename(void)
{
if (showDriveLetters) {
return currentDrive;
} else {
return (char *) rec.cFileName;
}
}
UI_FileTypes ad_return_current_filetype(void)
{
if (showDriveLetters)
return FT_VOLUME;
else if (rec.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
return FT_DIR;
else
return FT_FILE;
}
unsigned int ad_get_current_filesize(void)
{
return (unsigned int) rec.nFileSizeLow;
}
int ad_find_next_file(void)
{
if (showDriveLetters) {
return ad_get_next_drive();
} else {
return FindNextFile( handle, &rec);
}
}
int ad_find_file_close(void)
{
if (showDriveLetters)
return 1;
return FindClose(handle);
}
int ad_makedirs(char *path)
{
strcpy(temp,path);
strcat(temp, "/yape");
CreateDirectory(temp, NULL);
return 1;
}
#endif /* end of Windows functions */
#if defined(_WIN32) || defined(__EMSCRIPTEN__)
static unsigned int timeelapsed;
void ad_vsync_init(void)
{
timeelapsed = SDL_GetTicks();
}
bool ad_vsync(bool sync)
{
unsigned int time_limit = timeelapsed + 20;
static unsigned int nextFrameTime = timeelapsed + (1000 / maxFps);
timeelapsed = SDL_GetTicks();
if (sync) {
if (time_limit > timeelapsed) {
int nr10ms = ((time_limit - timeelapsed) / 10) * 10;
SDL_Delay(nr10ms);
timeelapsed = SDL_GetTicks();
while (time_limit > timeelapsed) {
SDL_Delay(0);
timeelapsed = SDL_GetTicks();
}
}
}
if (nextFrameTime > timeelapsed) {
return false;
} else {
nextFrameTime = timeelapsed + ((1000 + maxFps / 2) / maxFps);
framesShown++;
return true;
}
}
unsigned int ad_get_fps(unsigned int &framesDrawn)
{
static unsigned int fps = 100;
static unsigned int g_TotElapsed = SDL_GetTicks();
static unsigned int g_TotFrames = 0;
if (g_TotElapsed + 2000 < timeelapsed) {
g_TotElapsed = SDL_GetTicks();
fps = g_TotFrames;
g_TotFrames = 0;
framesDrawn = framesShown / 2;
framesShown = 0;
} else
g_TotFrames++;
return fps;
}
#endif
#if !defined(_WIN32)
/* ---------- UNIX ---------- */
#include <stdio.h>
#include <unistd.h>
#include <glob.h>
#include <dirent.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#define INVALID_HANDLE_VALUE 0x00
glob_t gl;
unsigned int gl_curr;
unsigned int gl_currsize;
char temp[512];
char sem_vsync, sem_fps;
void ad_exit_drive_selector()
{
//
}
int ad_get_curr_dir(char *pathstring, size_t size)
{
char *p = getcwd(pathstring, size);
return 1;
}
int ad_get_curr_dir(char *pathstring)
{
size_t size = 512;
getcwd(pathstring, size);
return !!pathstring;
}
int ad_set_curr_dir(char *path)
{
if (chdir(path) == 0) return 1;
return 0;
}
int ad_find_first_file(const char *filefilter)
{
// We will search in the current working directory.
if (glob(filefilter, 0, NULL, &gl) != 0) return 0;
gl_curr = 0; gl_currsize = 0;
return 1;
}
char *ad_return_current_filename(void)
{
// fprintf(stderr, "File: %s parsed\n", gl.gl_pathv[gl_curr]);
if (!gl.gl_pathc)
return 0;
return (char *) gl.gl_pathv[gl_curr];
}
UI_FileTypes ad_return_current_filetype(void)
{
// Probably too kludgy but I dunno Unix so who cares...
DIR *dirp;
if (gl.gl_pathv && (dirp = opendir(gl.gl_pathv[gl_curr])) != NULL) {
closedir(dirp);
return FT_DIR;
} else
return FT_FILE;
}
unsigned int ad_get_current_filesize(void)
{
struct stat buf;
// Size cache!
if (gl_currsize != 0) return gl_currsize;
// If the file size actually is 0, subsequent calls to this
// function will stat the file over and over again. I don't care.
if (stat(gl.gl_pathv[gl_curr], &buf) == 0) {
return (gl_currsize = (unsigned int) buf.st_size);
} else return 0;
}
int ad_find_next_file(void)
{
if (++gl_curr >= gl.gl_pathc) {
// No more matches: we don't need the glob any more.
//globfree(&gl);
return 0;
}
gl_currsize = 0;
return 1;
}
int ad_find_file_close(void)
{
return 1;
}
int ad_makedirs(char *path)
{
// Possible buffer overflow fixed.
strncpy(temp, path, 512);
if (strlen(temp) > 506) return 0;
strcat(temp, "/yape");
mkdir(temp, 0777);
return 1;
}
#endif
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__)
void _ad_vsync_sigalrm_handler(int signal)
{
sem_vsync = 0x01;
// Refresh FPS every 3 seconds. To avoid race condition, do
// it in the next call if tick_vsync is locked.
if (++tick_50hz >= 3*20 && sem_fps != 0x00) {
fps = (int) (50 * ((double) tick_vsync / (double) tick_50hz));
tick_vsync = 0;
tick_50hz = 0;
}
}
void ad_vsync_init(void)
{
struct sigaction ac;
// Initialization
sem_vsync = 0x01;
sem_fps = 0x01;
tick_vsync = 0;
tick_50hz = 0;
fps = 50;
ac.sa_handler = _ad_vsync_sigalrm_handler;
sigemptyset(&ac.sa_mask);
ac.sa_flags = 0;
if (sigaction(SIGALRM, &ac, NULL) == 0) ualarm(100, 20000);
}
bool ad_vsync(bool sync)
{
if (sync) {
while (sem_vsync == 0x00) usleep(VSYNC_LATENCY);
sem_vsync = 0x00;
}
sem_fps = 0x00;
tick_vsync++;
sem_fps = 0x01;
return true;
}
unsigned int ad_get_fps(unsigned int &framesDrawn)
{
framesDrawn = fps;
return fps << 1;
}
#endif