o cleanup

This commit is contained in:
optixx
2009-04-22 20:04:28 +02:00
parent 55e3468f74
commit 0c378a9f7c
1078 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,358 @@
/*
Copyright (C) 1997-2007 ZSNES Team ( zsKnight, _Demo_, pagefault, Nach )
http://www.zsnes.com
http://sourceforge.net/projects/zsnes
https://zsnes.bountysource.com
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "../gblhdr.h"
#include <stdbool.h>
#ifdef __LIBAO__
#include <ao/ao.h>
#include <pthread.h>
#include <signal.h>
#endif
#include "../asm_call.h"
#include "../cfg.h"
#ifdef __LIBAO__
static pthread_t audio_thread;
static pthread_mutex_t audio_mutex;
static pthread_cond_t audio_wait;
static ao_device *audio_device = 0;
static volatile unsigned int samples_waiting = 0;
#endif
unsigned char *sdl_audio_buffer = 0;
int sdl_audio_buffer_len = 0, sdl_audio_buffer_fill = 0;
int sdl_audio_buffer_head = 0, sdl_audio_buffer_tail = 0;
unsigned char sound_sdl = false;
int SoundEnabled = 1;
unsigned char PrevStereoSound;
unsigned int PrevSoundQuality;
#define SAMPLE_NTSC_HI_SCALE 995ULL
#define SAMPLE_NTSC_LO 59649ULL
#define SAMPLE_PAL_HI_SCALE 1ULL
#define SAMPLE_PAL_LO 50ULL
static const int freqtab[7] = { 8000, 11025, 22050, 44100, 16000, 32000, 48000 };
#define RATE freqtab[SoundQuality = ((SoundQuality > 6) ? 1 : SoundQuality)]
struct
{
unsigned long long hi;
unsigned long long lo;
unsigned long long balance;
} sample_control;
void InitSampleControl()
{
extern unsigned char romispal;
if (romispal)
{
sample_control.hi = SAMPLE_PAL_HI_SCALE*RATE;
sample_control.lo = SAMPLE_PAL_LO;
}
else
{
sample_control.hi = SAMPLE_NTSC_HI_SCALE*RATE;
sample_control.lo = SAMPLE_NTSC_LO;
}
sample_control.balance = sample_control.hi;
}
#ifdef __LIBAO__
static void SoundWriteSamples_ao(unsigned int samples)
{
extern unsigned int BufferSizeB, BufferSizeW;
extern int DSPBuffer[1280];
void ProcessSoundBuffer();
short stemp[1280];
int *d = DSPBuffer, *end_d = 0;
short *p = stemp;
while (samples > 1280)
{
SoundWriteSamples_ao(1280);
samples -= 1280;
}
//printf("samples %d\n", samples);
BufferSizeB = samples;
BufferSizeW = samples<<1;
asm_call(ProcessSoundBuffer);
end_d = DSPBuffer+samples;
for (; d < end_d; d++, p++)
{
if ((unsigned int)(*d + 0x7FFF) < 0xFFFF) { *p = *d; continue; }
if (*d > 0x7FFF) { *p = 0x7FFF; }
else { *p = 0x8001; }
}
ao_play(audio_device, (char *)stemp, samples*2);
}
void SoundWrite_ao()
{
unsigned int samples = 0;
if (!pthread_mutex_trylock(&audio_mutex))
{
if (!samples_waiting && sample_control.lo)
{
samples = (unsigned int)((sample_control.balance/sample_control.lo) << StereoSound);
sample_control.balance %= sample_control.lo;
sample_control.balance += sample_control.hi;
samples_waiting = samples;
pthread_cond_broadcast(&audio_wait); //Send signal
}
pthread_mutex_unlock(&audio_mutex);
}
else
{
pthread_cond_broadcast(&audio_wait); //Send signal
}
}
static void *SoundThread_ao(void *useless)
{
unsigned int samples;
for (;;)
{
pthread_mutex_lock(&audio_mutex);
//The while() is there to prevent error codes from breaking havoc
while (!samples_waiting)
{
pthread_cond_wait(&audio_wait, &audio_mutex); //Wait for signal
}
samples = samples_waiting;
samples_waiting = 0;
pthread_mutex_unlock(&audio_mutex);
SoundWriteSamples_ao(samples);
}
return(0);
}
static int SoundInit_ao()
{
int driver_id = ao_driver_id(libAoDriver);
if (driver_id < 0) { driver_id = ao_default_driver_id(); }
ao_sample_format driver_format;
driver_format.bits = 16;
driver_format.channels = StereoSound+1;
driver_format.rate = freqtab[SoundQuality = ((SoundQuality > 6) ? 1 : SoundQuality)];
driver_format.byte_format = AO_FMT_LITTLE;
if (audio_device)
{
ao_close(audio_device);
}
else
{
if (pthread_create(&audio_thread, 0, SoundThread_ao, 0))
{
puts("pthread_create() failed.");
}
else if (pthread_mutex_init(&audio_mutex, 0))
{
puts("pthread_mutex_init() failed.");
}
else if (pthread_cond_init(&audio_wait, 0))
{
puts("pthread_cond_init() failed.");
}
InitSampleControl();
}
//ao_option driver_options = { "buf_size", "32768", 0 };
audio_device = ao_open_live(driver_id, &driver_format, 0);
if (audio_device)
{
ao_info *di = ao_driver_info(driver_id);
printf("\nAudio Opened.\nDriver: %s\nChannels: %u\nRate: %u\n\n", di->name, driver_format.channels, driver_format.rate);
}
else
{
SoundEnabled = 0;
puts("Audio Open Failed");
return(false);
}
return(true);
}
#endif
void SoundWrite_sdl()
{
extern int DSPBuffer[];
extern unsigned char DSPDisable;
extern unsigned int BufferSizeB, BufferSizeW, T36HZEnabled;
// Process sound
BufferSizeB = 256;
BufferSizeW = BufferSizeB+BufferSizeB;
// take care of the things we left behind last time
SDL_LockAudio();
while (sdl_audio_buffer_fill < sdl_audio_buffer_len)
{
short *p = (short*)&sdl_audio_buffer[sdl_audio_buffer_tail];
if (soundon && !DSPDisable) { asm_call(ProcessSoundBuffer); }
if (T36HZEnabled)
{
memset(p, 0, BufferSizeW);
}
else
{
int *d = DSPBuffer, *end_d = DSPBuffer+BufferSizeB;
for (; d < end_d; d++, p++)
{
if ((unsigned int)(*d + 0x7fff) < 0xffff) { *p = *d; continue; }
if (*d > 0x7fff) { *p = 0x7fff; }
else { *p = 0x8001; }
}
}
sdl_audio_buffer_fill += BufferSizeW;
sdl_audio_buffer_tail += BufferSizeW;
if (sdl_audio_buffer_tail >= sdl_audio_buffer_len) { sdl_audio_buffer_tail = 0; }
}
SDL_UnlockAudio();
}
static void SoundUpdate_sdl(void *userdata, unsigned char *stream, int len)
{
int left = sdl_audio_buffer_len - sdl_audio_buffer_head;
if (left > 0)
{
if (left <= len)
{
memcpy(stream, &sdl_audio_buffer[sdl_audio_buffer_head], left);
stream += left;
len -= left;
sdl_audio_buffer_head = 0;
sdl_audio_buffer_fill -= left;
}
if (len)
{
memcpy(stream, &sdl_audio_buffer[sdl_audio_buffer_head], len);
sdl_audio_buffer_head += len;
sdl_audio_buffer_fill -= len;
}
}
}
static int SoundInit_sdl()
{
const int samptab[7] = { 1, 1, 2, 4, 2, 4, 4 };
SDL_AudioSpec audiospec;
SDL_AudioSpec wanted;
SDL_CloseAudio();
if (sdl_audio_buffer)
{
free(sdl_audio_buffer);
sdl_audio_buffer = 0;
}
sdl_audio_buffer_len = 0;
wanted.freq = RATE;
wanted.channels = StereoSound+1;
wanted.samples = samptab[SoundQuality] * 128 * wanted.channels;
wanted.format = AUDIO_S16LSB;
wanted.userdata = 0;
wanted.callback = SoundUpdate_sdl;
if (SDL_OpenAudio(&wanted, &audiospec) < 0)
{
SoundEnabled = 0;
return(false);
}
SDL_PauseAudio(0);
sdl_audio_buffer_len = audiospec.size*2;
sdl_audio_buffer_len = (sdl_audio_buffer_len + 255) & ~255; // Align to SPCSize
if (!(sdl_audio_buffer = malloc(sdl_audio_buffer_len)))
{
SDL_CloseAudio();
puts("Audio Open Failed");
SoundEnabled = 0;
return(false);
}
sound_sdl = true;
printf("\nAudio Opened.\nDriver: Simple DirectMedia Layer output\nChannels: %u\nRate: %u\n\n", wanted.channels, wanted.freq);
return(true);
}
int InitSound()
{
sound_sdl = false;
if (!SoundEnabled)
{
return(false);
}
PrevSoundQuality = SoundQuality;
PrevStereoSound = StereoSound;
#ifdef __LIBAO__
if (strcmp(libAoDriver, "sdl") && !(!strcmp(libAoDriver, "auto") && !strcmp(ao_driver_info(ao_default_driver_id())->name, "null")))
{
return(SoundInit_ao());
}
#endif
return(SoundInit_sdl());
}
void DeinitSound()
{
#ifdef __LIBAO__
if (audio_device)
{
pthread_kill(audio_thread, SIGTERM);
pthread_mutex_destroy(&audio_mutex);
pthread_cond_destroy(&audio_wait);
ao_close(audio_device);
}
#endif
SDL_CloseAudio();
if (sdl_audio_buffer) { free(sdl_audio_buffer); }
}

View File

@@ -0,0 +1,39 @@
/*
Copyright (C) 1997-2007 ZSNES Team ( zsKnight, _Demo_, pagefault, Nach )
http://www.zsnes.com
http://sourceforge.net/projects/zsnes
https://zsnes.bountysource.com
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef AUDIO_H
#define AUDIO_H
void InitSampleControl();
int InitSound();
void DeinitSound();
#ifdef __LIBAO__
void SoundWrite_ao();
#endif
void SoundWrite_sdl();
extern int SoundEnabled;
extern unsigned char PrevStereoSound;
extern unsigned int PrevSoundQuality;
extern unsigned char sound_sdl;
#endif

View File

@@ -0,0 +1,446 @@
/*
Copyright (C) 1997-2007 ZSNES Team ( zsKnight, _Demo_, pagefault, Nach )
http://www.zsnes.com
http://sourceforge.net/projects/zsnes
https://zsnes.bountysource.com
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "../gblhdr.h"
/*
Functions for battery probing on Linux by Nach
I believe Linux 2.4.x+ is needed for ACPI support
but it'll compile fine for older versions too
Special thanks David Lee Lambert for most of the code here
*/
#ifdef linux
#include <dirent.h>
#include <math.h>
int CheckBattery()
{
int battery = -1; //No battery / Can't get info
const char *ac = "/proc/acpi/ac_adapter/";
//Check ac adapter
DIR *ac_dir = opendir(ac);
if (ac_dir)
{
char fnbuf[40]; // longer than len(ac)+len(HEXDIGIT*4)+len({state|info})
FILE *fp;
const char *pattern = " %39[^:]: %39[ -~]"; // for sscanf
char line[80], key[40], arg[40];
struct dirent *ent;
while ((ent = readdir(ac_dir)))
{
if (ent->d_name[0] == '.') { continue; }
snprintf(fnbuf, 40, "%s%s/state", ac, ent->d_name);
fp = fopen(fnbuf, "r");
if (fp)
{
while (fgets(line, 80, fp) && sscanf(line, pattern, key, arg) == 2)
{
if (!strcmp(key, "state"))
{
if (!strcmp(arg, "on-line"))
{
battery = 0;
}
else if (!strcmp(arg, "off-line"))
{
battery = 1;
break;
}
}
}
fclose(fp);
}
}
closedir(ac_dir);
}
return(battery);
}
static int BatteryLifeTime;
static int BatteryLifePercent;
static void update_battery_info()
{
const char *batt = "/proc/acpi/battery/";
//Check batteries
DIR *batt_dir = opendir(batt);
if (batt_dir)
{
char fnbuf[40]; // longer than len(ac)+len(HEXDIGIT*4)+len({state|info})
FILE *fp;
const char *pattern = " %39[^:]: %39[ -~]"; // for sscanf
char line[80], key[40], arg[40];
float x, design_capacity = 0.0f, remaining_capacity = 0.0f, present_rate = 0.0f, full_capacity = 0.0f;
struct dirent *ent;
while ((ent = readdir(batt_dir)))
{
if (ent->d_name[0] == '.') { continue; }
snprintf(fnbuf, 40, "%s%s/info", batt, ent->d_name);
fp = fopen(fnbuf, "r");
if (fp)
{
while (fgets(line, 80, fp) && sscanf(line, pattern, key, arg) == 2)
{
if (!strcmp(key, "design capacity") && sscanf(arg, "%g", &x) == 1)
{
design_capacity += x;
}
else if (!strcmp(key, "last full capacity") && sscanf(arg, "%g", &x) == 1)
{
full_capacity += x;
}
}
fclose(fp);
}
snprintf(fnbuf, 40, "%s%s/state", batt, ent->d_name);
fp = fopen(fnbuf, "r");
if (fp)
{
int charging = 0;
while (fgets(line, 80, fp) && sscanf(line, pattern, key, arg) == 2)
{
if (!strcmp(key, "charging state"))
{
if (!strcmp(arg, "discharging"))
{
charging = -1;
}
else if (!strcmp(arg, "charging"))
{
charging = 1;
}
}
else if (!strcmp(key, "present rate") && sscanf(arg, "%g", &x) == 1)
{
present_rate += charging * x;
charging = 0;
}
else if (!strcmp(key, "remaining capacity") && sscanf(arg, "%g:", &x) == 1)
{
remaining_capacity += x;
charging = 0;
}
}
fclose(fp);
}
}
if (design_capacity > 0.0f)
{
BatteryLifePercent = (int)floorf(remaining_capacity / ((full_capacity > 0.0f) ? full_capacity : design_capacity) * 100.0);
if (BatteryLifePercent > 100) { BatteryLifePercent = 100; }
if (present_rate < 0.0f)
{
// Linux specifies rates in mWh or mAh
BatteryLifeTime = (int)floorf(remaining_capacity / (-present_rate) * 3600.0);
}
}
closedir(batt_dir);
}
}
int CheckBatteryTime()
{
BatteryLifeTime = -1;
update_battery_info();
return(BatteryLifeTime);
}
int CheckBatteryPercent()
{
BatteryLifePercent = -1;
update_battery_info();
return(BatteryLifePercent);
}
/*
Functions for battery on FreeBSD/DragonFly by Nach
If there's another FreeBSD based OS that doesn't
define one of these three, please let me know.
*/
#elif (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__))
#include <sys/types.h>
#include <sys/sysctl.h>
int CheckBattery()
{
int state;
size_t state_len = sizeof(state);
if (!sysctlbyname("hw.acpi.battery.state", &state, &state_len, 0, 0))
{
if ((state > -1) && (state < 7)) //7 == failure
{
if (!state || state&2)
{
return(0); //Plugged in
}
return(1); //Running off of battery
}
}
return(-1);
}
//Note that I have not yet gotten anyone to test if this function has correct info returned
int CheckBatteryTime()
{
int batt_time;
size_t batt_time_len = sizeof(batt_time);
if (!sysctlbyname("hw.acpi.battery.time", &batt_time, &batt_time_len, 0, 0))
{
if (batt_time > -1)
{
return(batt_time * 60);
}
}
return(-1);
}
int CheckBatteryPercent()
{
int life = -1;
size_t life_len = sizeof(life);
sysctlbyname("hw.acpi.battery.life", &life, &life_len, 0, 0);
return(life);
}
/*
Functions for battery on NetBSD/OpenBSD by Nach
If there's another NetBSD based OS that uses
the same API, please let me know.
Note this was the least tested section for all
the battery specific code.
*/
#elif (defined(__NetBSD__) || defined(__OpenBSD__))
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <machine/apmvar.h>
#ifndef APM_BATT_ABSENT
#define APM_BATT_ABSENT APM_BATTERY_ABSENT
#endif
int CheckBattery()
{
int fd = open("/dev/apm", O_RDONLY);
if (fd != -1)
{
struct apm_power_info info;
if (!ioctl(fd, APM_IOC_GETPOWER, &info) &&
(info.battery_state != APM_BATT_UNKNOWN) && (info.battery_state != APM_BATT_ABSENT))
{
close(fd);
if ((info.battery_state == APM_BATT_CHARGING) || (info.ac_state == APM_AC_ON)) { return(0); } //Plugged in
return(1); //Running off of battery
}
close(fd);
}
return(-1);
}
int CheckBatteryTime()
{
int fd = open("/dev/apm", O_RDONLY);
if (fd != -1)
{
struct apm_power_info info;
if (!ioctl(fd, APM_IOC_GETPOWER, &info) && (info.minutes_left > 0) && (info.minutes_left < 0xFFFF))
{
close(fd);
return(info.minutes_left*60);
}
close(fd);
}
return(-1);
}
int CheckBatteryPercent()
{
int fd = open("/dev/apm", O_RDONLY);
if (fd != -1)
{
struct apm_power_info info;
if (!ioctl(fd, APM_IOC_GETPOWER, &info))
{
close(fd);
return((info.battery_life == 255) ? 100 : info.battery_life);
}
close(fd);
}
return(-1);
}
/*
Functions for battery on Mac OS X by drizztbsd, Nach
If you have issues, please report.
*/
#elif defined(__APPLE__)
#include <sys/types.h>
#include <math.h>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/ps/IOPowerSources.h>
#include <IOKit/ps/IOPSkeys.h>
static int stringsAreEqual(CFStringRef a, CFStringRef b)
{
if (!a || !b)
{
return(0);
}
return(CFStringCompare(a, b, 0) == kCFCompareEqualTo);
}
static int BatteryLifeTime;
static int BatteryLifePercent;
static int HasBattery;
static void update_battery_info()
{
CFTypeRef powerBlob = IOPSCopyPowerSourcesInfo();
CFArrayRef powerSourcesList = IOPSCopyPowerSourcesList(powerBlob);
unsigned int count = CFArrayGetCount(powerSourcesList);
unsigned int i;
unsigned int tmp;
char ret;
int totalCurrentCapacity = 0, totalMaxCapacity = 0;
BatteryLifeTime = -1;
BatteryLifePercent = -1;
HasBattery = -1;
for (i = 0; i < count; ++i)
{
CFTypeRef powerSource;
CFDictionaryRef description;
powerSource = CFArrayGetValueAtIndex(powerSourcesList, i);
description = IOPSGetPowerSourceDescription(powerBlob, powerSource);
//continue if one battery is not present
if (CFDictionaryGetValue(description, CFSTR(kIOPSIsPresentKey)) == kCFBooleanFalse)
{
continue;
}
if (stringsAreEqual(CFDictionaryGetValue(description, CFSTR(kIOPSTransportTypeKey)), CFSTR(kIOPSInternalType)))
{
int currentCapacity, maxCapacity;
CFStringRef currentState = CFDictionaryGetValue(description, CFSTR(kIOPSPowerSourceStateKey));
CFNumberRef timeToEmptyNum = CFDictionaryGetValue(description, CFSTR(kIOPSTimeToEmptyKey));
if (CFEqual(currentState, CFSTR(kIOPSACPowerValue)) && (HasBattery != 1))
{
HasBattery = 0;
}
else if (CFEqual(currentState, CFSTR(kIOPSBatteryPowerValue)))
{
CFNumberRef timeToEmptyNum = CFDictionaryGetValue(description, CFSTR(kIOPSTimeToEmptyKey));
if(CFNumberGetValue(timeToEmptyNum, kCFNumberIntType, &tmp))
{
if (BatteryLifeTime > -1)
{
BatteryLifeTime += tmp;
}
else
{
BatteryLifeTime = tmp;
}
}
HasBattery = 1;
}
CFNumberRef currentCapacityNum = CFDictionaryGetValue(description, CFSTR(kIOPSCurrentCapacityKey));
CFNumberRef maxCapacityNum = CFDictionaryGetValue(description, CFSTR(kIOPSMaxCapacityKey));
if (CFNumberGetValue(currentCapacityNum, kCFNumberIntType, &currentCapacity) && CFNumberGetValue(maxCapacityNum, kCFNumberIntType, &maxCapacity))
{
totalCurrentCapacity += currentCapacity;
totalMaxCapacity += maxCapacity;
}
}
}
CFRelease(powerSourcesList);
CFRelease(powerBlob);
if (totalCurrentCapacity && totalMaxCapacity)
{
BatteryLifePercent = (int)roundf((totalCurrentCapacity / (float)totalMaxCapacity) * 100.0f);
}
}
int CheckBattery()
{
update_battery_info();
return(HasBattery);
}
int CheckBatteryTime()
{
update_battery_info();
if (BatteryLifeTime > -1)
{
return(BatteryLifeTime * 60);
}
return(-1);
}
int CheckBatteryPercent()
{
update_battery_info();
return(BatteryLifePercent);
}
#else //Not Linux, FreeBSD/DragonFlyBSD, NetBSD/OpenBSD, Mac OS X
int CheckBattery()
{
return(-1);
}
int CheckBatteryTime()
{
return(-1);
}
int CheckBatteryPercent()
{
return(-1);
}
#endif

View File

@@ -0,0 +1,412 @@
/*
Copyright (C) 1997-2007 ZSNES Team ( zsKnight, _Demo_, pagefault, Nach )
http://www.zsnes.com
http://sourceforge.net/projects/zsnes
https://zsnes.bountysource.com
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "../cfg.h"
#include "../gblhdr.h"
#include "../asm_call.h"
#define BYTE unsigned char
#define WORD unsigned short
#define DWORD unsigned long
//C++ style code in C
#define bool unsigned char
#define true 1
#define false 0
// FUNCTIONS
void hq2x_16b(void);
// VIDEO VARIABLES
extern SDL_Surface *surface;
extern int SurfaceX, SurfaceY;
extern int SurfaceLocking;
extern DWORD BitDepth;
// OPENGL VARIABLES
static unsigned short *glvidbuffer = 0;
static GLuint gltextures[4];
static int gltexture256, gltexture512;
static int glfilters = GL_NEAREST;
static int glscanready = 0;
extern Uint8 GUIOn2;
extern unsigned int vidbuffer;
extern unsigned char curblank;
extern BYTE GUIRESIZE[];
void gl_clearwin();
void UpdateVFrame();
void gl_scanlines();
bool OGLModeCheck();
int gl_start(int width, int height, int req_depth, int FullScreen)
{
Uint32 flags = SDL_DOUBLEBUF | SDL_HWSURFACE | SDL_HWPALETTE | SDL_OPENGL;
int i;
flags |= (GUIRESIZE[cvidmode] ? SDL_RESIZABLE : 0);
flags |= (FullScreen ? SDL_FULLSCREEN : 0);
SurfaceX = width; SurfaceY = height;
surface = SDL_SetVideoMode(SurfaceX, SurfaceY, req_depth, flags);
if (surface == NULL)
{
fprintf(stderr, "Could not set %dx%d-GL video mode.\n",SurfaceX, SurfaceY);
return false;
}
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
#if (SDL_MAJOR_VERSION > 1) || ((SDL_MINOR_VERSION > 2) || ((SDL_MINOR_VERSION == 2) && (SDL_PATCHLEVEL >= 10)))
SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
#endif
if (!glvidbuffer)
{
glvidbuffer = (unsigned short *) malloc(512 * 512 * sizeof(short));
}
gl_clearwin();
SDL_WarpMouse(SurfaceX / 4, SurfaceY / 4);
// Grab mouse in fullscreen mode
FullScreen ? SDL_WM_GrabInput(SDL_GRAB_ON) :
SDL_WM_GrabInput(SDL_GRAB_OFF);
SDL_WM_SetCaption("ZSNES", "ZSNES");
SDL_ShowCursor(0);
/* Setup some GL stuff */
glEnable(GL_TEXTURE_1D);
glEnable(GL_TEXTURE_2D);
glViewport(0, 0, SurfaceX, SurfaceY);
/*
* gltextures[0]: 2D texture, 256x224
* gltextures[1]: 2D texture, 512x224
* gltextures[3]: 1D texture, 256 lines of alternating alpha
*/
glGenTextures(4, gltextures);
for (i = 0; i < 3; i++) {
glBindTexture(GL_TEXTURE_2D, gltextures[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, glfilters);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, glfilters);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
}
if (scanlines) gl_scanlines();
return true;
}
void gl_end()
{
if (glvidbuffer)
{
glDeleteTextures(4, gltextures);
free(glvidbuffer);
glvidbuffer = 0;
}
}
extern DWORD AddEndBytes;
extern DWORD NumBytesPerLine;
extern unsigned char *WinVidMemStart;
extern unsigned char NGNoTransp;
void copy640x480x16bwin(void);
extern unsigned char SpecialLine[224]; /* 0 if lo-res, > 0 if hi-res */
void gl_clearwin()
{
glClear(GL_COLOR_BUFFER_BIT);
memset(glvidbuffer, 0, 512 * 448 * 2);
}
/* gl_drawspan:
* Puts a quad on the screen for hires/lores portions, starting at line start,
* and ending at line end..
* Builds the 256x256/512x256 textures if gltexture256 or gltexture512 == 0
*/
static void gl_drawspan(int hires, int start, int end)
{
int i, j;
switch (hires)
{
case 0:
break;
case 3:
case 7:
hires = 2;
break;
default:
hires = 1;
break;
}
if (hires)
{
if (hires != gltexture512)
{
unsigned short *vbuf1 = &((unsigned short *) vidbuffer)[16];
unsigned short *vbuf2 = &((unsigned short *) vidbuffer)[75036 * 2 + 16];
unsigned short *vbuf = &glvidbuffer[0];
if (hires>1) // mode 7
{
for (j = 224; j--;)
{
for (i = 256; i--;)
*vbuf++ = *vbuf1++;
for (i = 256; i--;)
*vbuf++ = *vbuf2++;
vbuf1 += 32;
vbuf2 += 32;
}
glBindTexture(GL_TEXTURE_2D, gltextures[1]);
glTexImage2D(GL_TEXTURE_2D, 0, 3, 256, 512, 0,
GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
glvidbuffer);
gltexture512 = 2;
}
else
{
for (j = 224; j--;)
{
for (i = 256; i--;)
{
*vbuf++ = *vbuf1++;
*vbuf++ = *vbuf2++;
}
vbuf1 += 32;
vbuf2 += 32; // skip the two 16-pixel-wide columns
}
glBindTexture(GL_TEXTURE_2D, gltextures[1]);
glTexImage2D(GL_TEXTURE_2D, 0, 3, 512, 256, 0,
GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
glvidbuffer);
gltexture512 = 1;
}
}
glBindTexture(GL_TEXTURE_2D, gltextures[1]);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, (224.0 / 256.0) * (start / 224.0));
glVertex2f(-1.0f, (112 - start) / 112.0);
glTexCoord2f(1.0f, (224.0 / 256.0) * (start / 224.0));
glVertex2f(1.0f, (112 - start) / 112.0);
glTexCoord2f(1.0f, (224.0 / 256.0) * (end / 224.0));
glVertex2f(1.0f, (112 - end) / 112.0);
glTexCoord2f(0.0f, (224.0 / 256.0) * (end / 224.0));
glVertex2f(-1.0f, (112 - end) / 112.0);
glEnd();
}
else
{
glBindTexture(GL_TEXTURE_2D, gltextures[0]);
if (!gltexture256)
{
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 16);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 288);
glTexImage2D(GL_TEXTURE_2D, 0, 3, 256, 256, 0,
GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
((unsigned short *) vidbuffer) + 288);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
gltexture256 = 1;
}
glBegin(GL_QUADS);
glTexCoord2f(0.0f, (224.0 / 256.0) * (start / 224.0));
glVertex2f(-1.0f, (112 - start) / 112.0);
glTexCoord2f(1.0f, (224.0 / 256.0) * (start / 224.0));
glVertex2f(1.0f, (112 - start) / 112.0);
glTexCoord2f(1.0f, (224.0 / 256.0) * (end / 224.0));
glVertex2f(1.0f, (112 - end) / 112.0);
glTexCoord2f(0.0f, (224.0 / 256.0) * (end / 224.0));
glVertex2f(-1.0f, (112 - end) / 112.0);
glEnd();
}
}
void gl_drawwin()
{
int i;
NGNoTransp = 0; // Set this value to 1 within the appropriate
// video mode if you want to add a custom
// transparency routine or hardware
// transparency. This only works if
// the value of newengen is equal to 1.
// (see ProcessTransparencies in newgfx16.asm
// for ZSNES' current transparency code)
UpdateVFrame();
if (curblank || !OGLModeCheck())
return;
if (BilinearFilter)
{
glfilters = GL_LINEAR;
if (GUIOn2 && !FilteredGUI)
glfilters = GL_NEAREST;
}
else
{
glfilters = GL_NEAREST;
}
if (SurfaceX >= 512 && (hqFilter || En2xSaI))
{
AddEndBytes = 0;
NumBytesPerLine = 1024;
WinVidMemStart = (void *) glvidbuffer;
if (hqFilter) hq2x_16b();
else asm_call(copy640x480x16bwin);
/* Display 1 512x448 quad for the 512x448 buffer */
glBindTexture(GL_TEXTURE_2D, gltextures[1]);
glTexEnvi(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_DECAL);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 512, 512, 0,
GL_RGB, GL_UNSIGNED_SHORT_5_6_5, glvidbuffer);
glDisable (GL_DEPTH_TEST);
glDisable (GL_LIGHTING);
glDisable (GL_BLEND);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(1.0f, 1.0f, -1.0f);
glTexCoord2f(1.0f, 448.0f / 512.0f);
glVertex3f(1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 448.0f / 512.0f);
glVertex3f(-1.0f, -1.0f, -1.0f);
glEnd();
}
else
{
/*
* This code splits the hires/lores portions up, and draws
* them with gl_drawspan
*/
int lasthires, lasthires_line = 0;
gltexture256 = gltexture512 = 0;
lasthires = SpecialLine[1];
for (i = 0; i < 224; i++)
{
if (SpecialLine[i + 1])
{
if (lasthires)
continue;
gl_drawspan(lasthires, lasthires_line, i);
lasthires = SpecialLine[i + 1];
lasthires_line = i;
}
else
{
if (!lasthires)
continue;
gl_drawspan(lasthires, lasthires_line, i);
lasthires = SpecialLine[i + 1];
lasthires_line = i;
}
}
if (i - lasthires_line > 1)
gl_drawspan(lasthires, lasthires_line, i);
/*
* This is here rather than right outside this if because the
* GUI doesn't allow scanlines to be selected while filters are
* on.. There is no technical reason they can't be on while
* filters are on, however. Feel free to change the GUI, and
* move this outside the if (En2xSaI) {}, if you do.
*/
if (scanlines)
{
glDisable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
if (scanlines != glscanready) gl_scanlines();
glBlendFunc(GL_DST_COLOR, GL_ZERO);
glBindTexture(GL_TEXTURE_1D, gltextures[3]);
glBegin(GL_QUADS);
for (i = 0; i < SurfaceY; i += 256)
{
glTexCoord1f(0.0f);
glVertex3f(-1.0f, (SurfaceY - i * 2.0) / SurfaceY, -1.0f);
glTexCoord1f(0.0f);
glVertex3f(1.0f, (SurfaceY - i * 2.0) / SurfaceY, -1.0f);
glTexCoord1f(1.0f);
glVertex3f(1.0f, (SurfaceY - (i + 256) * 2.0) / SurfaceY, -1.0f);
glTexCoord1f(1.0f);
glVertex3f(-1.0f, (SurfaceY - (i + 256) * 2.0) / SurfaceY, -1.0f);
}
glEnd();
glDisable(GL_BLEND);
glEnable(GL_TEXTURE_2D);
}
}
SDL_GL_SwapBuffers();
}
void gl_scanlines(void)
{
GLubyte scanbuffer[256][4];
int i, j = scanlines==1 ? 0 : (scanlines==2 ? 192 : 128);
for (i = 0; i < 256; i += 2)
{
scanbuffer[i][0] = scanbuffer[i][1] = scanbuffer[i][2] = j;
scanbuffer[i][3] = 0xFF;
scanbuffer[i+1][0] = scanbuffer[i+1][1] = scanbuffer[i+1][2] = 0xFF;
scanbuffer[i+1][3] = 0xFF;
}
glBindTexture(GL_TEXTURE_1D, gltextures[3]);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 256, 0, GL_RGBA,
GL_UNSIGNED_BYTE, scanbuffer);
glscanready = scanlines;
}

View File

@@ -0,0 +1,33 @@
/*
Copyright (C) 1997-2007 ZSNES Team ( zsKnight, _Demo_, pagefault, Nach )
http://www.zsnes.com
http://sourceforge.net/projects/zsnes
https://zsnes.bountysource.com
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef GL_DRAW_h
#define GL_DRAW_h 1
int gl_start(int width, int height, int req_depth, int FullScreen);
void gl_end();
void gl_clearwin();
void gl_drawwin();
#endif

View File

@@ -0,0 +1,355 @@
/*
Copyright (C) 1997-2007 ZSNES Team ( zsKnight, _Demo_, pagefault, Nach )
http://www.zsnes.com
http://sourceforge.net/projects/zsnes
https://zsnes.bountysource.com
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "gblhdr.h"
#include <sys/param.h>
#include <sys/wait.h>
#include <signal.h>
#include <paths.h>
#include <grp.h>
#include <pwd.h>
#ifndef OPEN_MAX
#define OPEN_MAX 256
#endif
#include "safelib.h"
#include "../argv.h"
//C++ style code in C
#define bool unsigned char
#define true 1
#define false 0
//Introducing secure forking ;) -Nach
//Taken from the secure programming cookbook, somewhat modified
static bool spc_drop_privileges()
{
gid_t newgid = getgid(), oldgid = getegid();
uid_t newuid = getuid(), olduid = geteuid();
char *name = getlogin();
struct passwd *userinfo;
if (!olduid && name && (userinfo = getpwnam(name)) && userinfo->pw_uid)
{
setgroups(1, &userinfo->pw_gid);
#if !defined(linux)
setegid(userinfo->pw_gid);
if (setgid(userinfo->pw_gid) == -1) { return(false); }
#else
if (setregid(userinfo->pw_gid, userinfo->pw_gid) == -1) { return(false); }
#endif
#if !defined(linux)
seteuid(userinfo->pw_uid);
if (setuid(userinfo->pw_uid) == -1) { return(false); }
#else
if (setreuid(userinfo->pw_uid, userinfo->pw_uid) == -1) { return(false); }
#endif
if ((setegid(oldgid) != -1) || (getegid() != userinfo->pw_gid)) { return(false); }
if ((seteuid(olduid) != -1) || (geteuid() != userinfo->pw_uid)) { return(false); }
}
else
{
//If root privileges are to be dropped, be sure to pare down the ancillary
//groups for the process before doing anything else because the setgroups()
//system call requires root privileges. Drop ancillary groups regardless of
//whether privileges are being dropped temporarily or permanently.
if (!olduid) setgroups(1, &newgid);
if (newgid != oldgid)
{
#if !defined(linux)
setegid(newgid);
if (setgid(newgid) == -1) { return(false); }
#else
if (setregid(newgid, newgid) == -1) { return(false); }
#endif
}
if (newuid != olduid)
{
#if !defined(linux)
seteuid(newuid);
if (setuid(newuid) == -1) { return(false); }
#else
if (setreuid(newuid, newuid) == -1) { return(false); }
#endif
}
//verify that the changes were successful
if (newgid != oldgid && (setegid(oldgid) != -1 || getegid() != newgid)) { return(false); }
if (newuid != olduid && (seteuid(olduid) != -1 || geteuid() != newuid)) { return(false); }
}
return(true);
}
static int open_devnull(int fd)
{
FILE *f = 0;
if (!fd) { f = freopen(_PATH_DEVNULL, "rb", stdin); }
else if (fd == 1) { f = freopen(_PATH_DEVNULL, "wb", stdout); }
else if (fd == 2) { f = freopen(_PATH_DEVNULL, "wb", stderr); }
return(f && fileno(f) == fd);
}
static bool array_contains(int *a, size_t size, int key)
{
size_t i;
for (i = 0; i < size; i++)
{
if (a[i] == key) { return(true); }
}
return(false);
}
static bool spc_sanitize_files(int *a, size_t size, int skip)
{
int fd, fds;
struct stat st;
//Make sure all open descriptors other than the standard ones are closed
if ((fds = getdtablesize()) == -1)
{
fds = OPEN_MAX;
}
for (fd = 3; fd < fds; fd++)
{
if ((fd != skip) && !array_contains(a, size, fd)) { close(fd); }
}
//Verify that the standard descriptors are open. If they're not, attempt to
//open them using /dev/null. If any are unsuccessful, fail.
for (fd = 0; fd < 3; fd++)
{
if (fstat(fd, &st) == -1 && (errno != EBADF || !open_devnull(fd)))
{
return(false);
}
}
return(true);
}
//Pass array of file descriptors to leave open
pid_t safe_fork(int *a, size_t size)
{
int filedes[2];
if (!pipe(filedes))
{
char success = 0;
pid_t childpid;
if ((childpid = fork()) == -1) //Fork Failed
{
close(filedes[0]);
close(filedes[1]);
return(-1);
}
if (childpid) //Parent Process
{
close(filedes[1]); //Close writing
read(filedes[0], &success, 1);
close(filedes[0]);
if (success)
{
return(childpid);
}
waitpid(childpid, 0, 0);
return(-1);
}
//This is the child proccess
close(filedes[0]); //Close reading
if (!spc_sanitize_files(a, size, filedes[1]) || !spc_drop_privileges())
{
write(filedes[1], &success, 1);
close(filedes[1]);
_exit(0);
}
success = 1;
write(filedes[1], &success, 1);
close(filedes[1]);
return(0);
}
return(-1);
}
//Introducing a popen which doesn't return until it knows for sure of program launched or couldn't open -Nach
//Forks, parent is paused until child successfully execs (returns child pid) or child exits (returns failure)
static pid_t parent_pause_fork()
{
int filedes[2];
if (!pipe(filedes))
{
int pid = fork();
if (pid == -1) //Failed
{
close(filedes[0]);
close(filedes[1]);
}
else if (pid > 0) //Parent
{
char success = 1;
close(filedes[1]);
read(filedes[0], &success, 1);
close(filedes[0]);
if (success)
{
return(pid);
}
waitpid(pid, 0, 0);
}
else //Child
{
close(filedes[0]);
fcntl(filedes[1], F_SETFD, FD_CLOEXEC);
return(-filedes[1]);
}
}
return(0);
}
static void close_child(pid_t pid)
{
char success = 0;
write(-pid, &success, 1);
close(-pid);
_exit(0);
}
#define IS_PARENT(x) ((x) > 0)
#define IS_CHILD(x) ((x) < 0)
#define IS_FAIL(x) ((x) == 0)
static struct fp_pid_link
{
FILE *fp;
pid_t pid;
struct fp_pid_link *next;
} fp_pids = { 0, 0, 0 };
FILE *safe_popen(char *command, const char *mode)
{
//filedes[0] is for reading
//filedes[1] is for writing.
int filedes[2];
if (mode && (*mode == 'r' || *mode == 'w') && !pipe(filedes))
{
pid_t childpid = parent_pause_fork();
if (IS_PARENT(childpid))
{
FILE *fp;
if (*mode == 'r')
{
close(filedes[1]);
fp = fdopen(filedes[0], "r");
}
else
{
close(filedes[0]);
fp = fdopen(filedes[1], "w");
}
if (fp)
{
struct fp_pid_link *link = &fp_pids;
while (link->next)
{
link = link->next;
}
link->next = (struct fp_pid_link *)malloc(sizeof(struct fp_pid_link));
if (link->next)
{
link->next->fp = fp;
link->next->pid = childpid;
link->next->next = 0;
return(fp);
}
fclose(fp);
}
kill(childpid, SIGTERM);
waitpid(childpid, 0, 0);
}
else if (IS_CHILD(childpid))
{
char **argv = build_argv(command);
if (argv)
{
if (*mode == 'r')
{
dup2(filedes[1], STDOUT_FILENO);
}
else
{
dup2(filedes[0], STDIN_FILENO);
}
if (spc_sanitize_files(0, 0, -childpid) && spc_drop_privileges())
{
execvp(argv[0], argv);
}
free(argv);
}
close_child(childpid);
}
close(filedes[0]);
close(filedes[1]);
}
return(0);
}
void safe_pclose(FILE *fp)
{
struct fp_pid_link *link = &fp_pids;
while (link->next && link->next->fp != fp)
{
link = link->next;
}
if (link->next->fp == fp)
{
struct fp_pid_link *dellink = link->next;
fclose(fp);
waitpid(link->next->pid, 0, 0);
link->next = link->next->next;
free(dellink);
}
}

View File

@@ -0,0 +1,36 @@
/*
Copyright (C) 1997-2007 ZSNES Team ( zsKnight, _Demo_, pagefault, Nach )
http://www.zsnes.com
http://sourceforge.net/projects/zsnes
https://zsnes.bountysource.com
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef SAFELIB_H
#define SAFELIB_H
#include <stdio.h>
#include <sys/types.h>
pid_t safe_fork(int *, size_t);
FILE *safe_popen(char *, const char *);
void safe_pclose(FILE *);
#define popen safe_popen
#define pclose safe_pclose
#endif

View File

@@ -0,0 +1,806 @@
;Copyright (C) 1997-2007 ZSNES Team ( zsKnight, _Demo_, pagefault, Nach )
;
;http://www.zsnes.com
;http://sourceforge.net/projects/zsnes
;https://zsnes.bountysource.com
;
;This program is free software; you can redistribute it and/or
;modify it under the terms of the GNU General Public License
;version 2 as published by the Free Software Foundation.
;
;This program 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 this program; if not, write to the Free Software
;Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
%include "macros.mac"
EXTSYM getchar,PrevFSMode,sem_sleep,SBHDMA,putchar,Start60HZ
EXTSYM pressed,AdjustFrequency,vidbufferofsb,vidbuffer,clearwin
EXTSYM Stop60HZ,initwinvideo,vesa2_rpos,vesa2_gpos,vesa2_bpos,vesa2_rposng
EXTSYM vesa2_gposng,vesa2_bposng,vesa2_usbit,vesa2_clbit,vesa2_clbitng
EXTSYM vesa2_clbitng2,vesa2_clbitng3,vesa2red10,res640,res480,cbitmode,cvidmode
EXTSYM vesa2_bits,vesa2_x,vesa2_y,genfulladdtab,GUICPC,drawscreenwin
EXTSYM ConvertToAFormat,HalfTrans,UnusedBit,UnusedBitXor
EXTSYM ngrposng,nggposng,ngbposng,HalfTransB,HalfTransC,UpdateVFrame,GetMouseX
EXTSYM GetMouseY,GetMouseMoveX,GetMouseMoveY,GetMouseButton,T36HZEnabled
EXTSYM MouseButton,Start36HZ,Stop36HZ,CheckTimers,vesa2_rfull,vesa2_rtrcl
EXTSYM vesa2_rtrcla,vesa2_gfull,vesa2_gtrcl,vesa2_gtrcla,vesa2_bfull,vesa2_btrcl
EXTSYM vesa2_btrcla,Init_2xSaIMMXW,V8Mode,GrayscaleMode,PrevWinMode
EXTSYM pl1upk,pl1downk,pl1leftk,pl1rightk,pl1startk,pl1selk
EXTSYM pl1Ak,pl1Bk,pl1Xk,pl1Yk,pl1Lk,pl1Rk
EXTSYM pl2upk,pl2downk,pl2leftk,pl2rightk,pl2startk,pl2selk
EXTSYM pl2Ak,pl2Bk,pl2Xk,pl2Yk,pl2Lk,pl2Rk
EXTSYM pl3upk,pl3downk,pl3leftk,pl3rightk,pl3startk,pl3selk
EXTSYM pl3Ak,pl3Bk,pl3Xk,pl3Yk,pl3Lk,pl3Rk
EXTSYM pl4upk,pl4downk,pl4leftk,pl4rightk,pl4startk,pl4selk
EXTSYM pl4Ak,pl4Bk,pl4Xk,pl4Yk,pl4Lk,pl4Rk
EXTSYM pl5upk,pl5downk,pl5leftk,pl5rightk,pl5startk,pl5selk
EXTSYM pl5Ak,pl5Bk,pl5Xk,pl5Yk,pl5Lk,pl5Rk
%ifdef __OPENGL__
EXTSYM Clear2xSaIBuffer
%endif
; NOTE: For timing, Game60hzcall should be called at 50hz or 60hz (depending
; on romispal) after a call to InitPreGame and before DeInitPostGame are
; made. GUI36hzcall should be called at 36hz after a call GUIInit and
; before GUIDeInit.
SECTION .text
NEWSYM StartUp
ret
; SystemInit - Initialize all Joystick stuff, load in all configuration data,
; parse commandline data, obtain current directory (One time initialization)
NEWSYM SystemInit
; Be sure to set SBHDMA to a value other than 0 if 16bit sound exists
mov byte[SBHDMA],1
ret
NEWSYM PrintStr ; Print ASCIIZ string
pushad
.next
mov al,[edx]
or al,al
jz .finish
push edx
mov dl,al
push edx
call putchar
pop edx
pop edx
inc edx
jmp .next
.finish
popad
ret
SECTION .data
NEWSYM wfkey, db 0
SECTION .text
NEWSYM WaitForKey ; Wait for a key to be pressed
pushad
call getchar
mov [wfkey],al
popad
mov al,[wfkey]
; return key in al
ret
SECTION .data
NEWSYM CurKeyPos, dd 0
NEWSYM CurKeyReadPos, dd 0
NEWSYM KeyBuffer, times 16 dd 0
SECTION .text
NEWSYM Check_Key
mov al,[CurKeyPos]
cmp al,[CurKeyReadPos]
jne .yeskey
xor al,al
ret
.yeskey
mov al,0FFh
ret
NEWSYM Get_Key
; wait if there are no keys in buffer, then return key in al
; for extended keys, return a 0, then the extended key afterwards
xor eax,eax
.nokey
; call JoyRead
mov al,[CurKeyReadPos]
cmp al,[CurKeyPos]
je .nokey
test word[KeyBuffer+eax*4],100h
jnz .upper
mov al,[KeyBuffer+eax*4]
inc dword[CurKeyReadPos]
and dword[CurKeyReadPos],0Fh
ret
.upper
sub word[KeyBuffer+eax*4],100h
xor al,al
ret
NEWSYM Get_Memfree
mov eax,02000000h
ret
NEWSYM Output_Text ; Output character (ah=02h) or string (ah=09h)
pushad
; This function usually displays an error message on-screen
cmp ah,02h
je .char
cmp ah,09h
je .string
ret
.char
push edx
call putchar
pop edx
popad
ret
.string
pushad
call PrintStr ; print edx
popad
popad
ret
NEWSYM InitPreGame ; Executes before starting/continuing a game
mov byte[pressed+1],2
pushad
call Start60HZ
%ifdef __OPENGL__
call drawscreenwin
%endif
call initwinvideo
popad
mov al,[GrayscaleMode]
cmp al,[V8Mode]
je .nochangemode
xor byte[V8Mode],1
xor al,al
.nochangemode
pushad
call AdjustFrequency
popad
pushad
xor eax,eax
mov edi,[vidbufferofsb]
mov ecx,288*128
rep stosd
popad
pushad
call clearwin
popad
ret
NEWSYM SetupPreGame ; Executes after pre-game init, can execute multiple
; times after a single InitPreGame
mov byte[pressed+1],2
ret
NEWSYM DeInitPostGame ; Called after game is ended
pushad
call Stop60HZ
popad
ret
; ****************************
; Video Stuff
; ****************************
; ** init video mode functions **
SECTION .data
NEWSYM firstvideo, dd 1
SECTION .text
NEWSYM initvideo ; Returns 1 in videotroub if trouble occurs
mov byte[res640],1
mov byte[res480],1
mov byte[cbitmode],1
mov word[vesa2_x],512
mov word[vesa2_y],480
mov byte[vesa2_bits],16
mov dword[vesa2_bits],16
mov dword[vesa2_rpos],11
mov dword[vesa2_gpos],5
mov dword[vesa2_bpos],0
mov byte[vesa2red10],0
mov byte[vesa2_rposng],11
mov byte[vesa2_gposng],5
mov byte[vesa2_bposng],0
mov dword[vesa2_clbitng],1111011111011110b
mov dword[vesa2_clbitng2],11110111110111101111011111011110b
mov dword[vesa2_clbitng2+4],11110111110111101111011111011110b
mov dword[vesa2_clbitng3],0111101111101111b
pushad
call initwinvideo
popad
movzx eax,byte[cvidmode]
cmp byte[GUIWFVID+eax],0
je .prevwinmode
mov [PrevFSMode],al
jmp .doneprevmode
.prevwinmode
mov [PrevWinMode],al
.doneprevmode
cmp dword[firstvideo],1
je .skipinitgfx
pushad
call InitializeGfxStuff
popad
.skipinitgfx
mov dword[firstvideo],0
pushad
call InitializeGfxStuff
popad
ret
NEWSYM deinitvideo
ret
; ** copy video mode functions **
SECTION .data
NEWSYM converta, dd 0
%ifdef __OPENGL__
NEWSYM blinit, db 1
%endif
SECTION .text
NEWSYM DrawScreen ; In-game screen render w/ triple buffer check
cmp dword[converta],1
jne near .skipconv
pushad
mov dword[UnusedBit], 10000000000000001000000000000000b
mov dword[HalfTrans], 01111011110111100111101111011110b
mov dword[UnusedBitXor], 01111111111111110111111111111111b
mov dword[UnusedBit+4], 10000000000000001000000000000000b
mov dword[HalfTrans+4], 01111011110111100111101111011110b
mov dword[UnusedBitXor+4],01111111111111110111111111111111b
mov dword[HalfTransB], 00000100001000010000010000100001b
mov dword[HalfTransB+4], 00000100001000010000010000100001b
mov dword[HalfTransC], 01111011110111100111101111011110b
mov dword[HalfTransC+4], 01111011110111100111101111011110b
mov dword[ngrposng],10
mov dword[nggposng],5
mov dword[ngbposng],0
call ConvertToAFormat
popad
.skipconv
pushad
call drawscreenwin
%ifdef __OPENGL__
cmp byte[blinit],1
jne .noreinit
call initwinvideo
call Clear2xSaIBuffer
mov byte[blinit],0
.noreinit
%endif
popad
ret
NEWSYM vidpastecopyscr ; GUI screen render
pushad
mov eax,[vidbuffer]
mov ecx,224*288
mov edx,ecx
sub ecx,288
dec edx
.loop
movzx ebx,byte[eax+edx]
mov bx,[GUICPC+ebx*2]
mov [eax+edx*2],bx
dec edx
dec ecx
jnz .loop
popad
jmp DrawScreen
; ** Video Mode Variables **
SECTION .data
; Total Number of Video Modes
%ifdef __OPENGL__
NEWSYM NumVideoModes, dd 23
%else
NEWSYM NumVideoModes, dd 5
%endif
; GUI Video Mode Names - Make sure that all names are of the same length
; and end with a NULL terminator
NEWSYM GUIVideoModeNames
db '256x224 R W',0 ;0
db '256x224 R F',0 ;1
db '512x448 DR W',0 ;2
db '512x448 DR F',0 ;3
db '640x480 DR F',0 ;4
%ifdef __OPENGL__
db '256x224 O R W',0 ;5
db '512x448 ODR W',0 ;6
db '640x480 ODS F',0 ;7
db '640x480 ODS W',0 ;8
db '640x560 ODR W',0 ;9
db '768x672 ODR W',0 ;10
db '800x600 ODS F',0 ;11
db '800x600 ODS W',0 ;12
db '896x784 ODR W',0 ;13
db '1024x768 ODS F',0 ;14
db '1024x768 ODS W',0 ;15
db '1024x896 ODR W',0 ;16
db '1280x960 ODS F',0 ;17
db '1280x1024 ODS F',0 ;18
db '1600x1200 ODS F',0 ;19
db 'VARIABLE ODR W',0 ;20
db 'VARIABLE ODS W',0 ;21
db 'CUSTOM OD F',0 ;22
%endif
; Video Mode Feature Availability (1 = Available, 0 = Not Available)
; Left side starts with Video Mode 0
; vid mode column = 0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2
NEWSYM GUII2VID, db 0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; Interpolation
NEWSYM GUIWFVID, db 0,1,0,1,1,0,0,1,0,0,0,1,0,0,1,0,0,1,1,1,0,0,1 ; Fullscreen
NEWSYM GUIDSIZE, db 0,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 ; D Modes
NEWSYM GUIKEEP43, db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1 ; Keep 4:3 Ratio
NEWSYM GUIM7VID, db 0,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 ; Hires Mode 7
NEWSYM GUIHQ2X, db 0,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 ; Hq2x Filter
NEWSYM GUIHQ3X, db 0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; (Hq3x Filter)
NEWSYM GUIHQ4X, db 0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; (Hq4x Filter)
NEWSYM GUINTVID, db 0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; NTSC Filter
NEWSYM GUIRESIZE, db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0 ; SDL Resizable
%ifdef __OPENGL__
NEWSYM GUIBIFIL, db 0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 ; SDL Bilinear Filter
%endif
SECTION .text
; ****************************
; Input Device Stuff
; ****************************
; Variables related to Input Device Routines:
; pl1selk,pl1startk,pl1upk,pl1downk,pl1leftk,pl1rightk,pl1Xk,
; pl1Ak,pl1Lk,pl1Yk,pl1Bk,pl1Rk
; (Change 1 to 2,3,4 for other players)
; Each of these variables contains the corresponding key pressed value
; for the key data
; pressed[]
; - This is an array of pressed/released data (bytes) where the
; corresponding key pressed value is used as the index. The value
; for each entry is 0 for released and 1 for pressed. Also, when
; writing keyboard data to this array, be sure to first check if
; the value of the array entry is 2 or not. If it is 2, do not write 1
; to that array entry. (however, you can write 0 to it)
; As an example, to access Player 1 L button press data, it is
; done like : pressed[pl1Lk]
; The 3 character key description of that array entry is accessed by the
; GUI through ScanCodeListing[pl1Lk*3]
; Note: When storing the input device configuration of a dynamic input
; device system (ie. Win9x) rather than a static system (ie. Dos), it
; is best to store in the name of the device and relative button
; assignments in the configuration file, then convert it to ZSNES'
; numerical corresponding key format after reading from it. And then
; convert it back when writing to it back.
NEWSYM UpdateDevices ; One-time input device init
ret
NEWSYM JoyRead
pushad
call UpdateVFrame
popad
ret
SECTION .data
; Total Number of Input Devices
NEWSYM NumInputDevices, dd 2
; Input Device Names
NEWSYM GUIInputNames
db 'NONE ',0
db 'KEYBOARD/GAMEPAD',0
db ' ',0
db ' ',0
db ' ',0
db ' ',0
db ' ',0
db ' ',0
db ' ',0
db ' ',0
db ' ',0
db ' ',0
db ' ',0
db ' ',0
db ' ',0
db ' ',0
; GUI Description codes for each corresponding key pressed value
NEWSYM ScanCodeListing
db '---','ESC',' 1 ',' 2 ',' 3 ',' 4 ',' 5 ',' 6 ' ; 00h
db ' 7 ',' 8 ',' 9 ',' 0 ',' - ',' = ','BKS','TAB'
db ' Q ',' W ',' E ',' R ',' T ',' Y ',' U ',' I ' ; 10h
db ' O ',' P ',' [ ',' ] ','RET','LCT',' A ',' S '
db ' D ',' F ',' G ',' H ',' J ',' K ',' L ',' : ' ; 20h
db ' " ',' ~ ','LSH',' \ ',' Z ',' X ',' C ',' V '
db ' B ',' N ',' M ',' , ',' . ',' / ','RSH',' * ' ; 30h
db 'LAL','SPC','CAP','F1 ','F2 ','F3 ','F4 ','F5 '
db 'F6 ','F7 ','F8 ','F9 ','F10','NUM','SCR','KP7' ; 40h
db 'KP8','KP9','KP-','KP4','KP5','KP6','KP+','KP1'
db 'KP2','KP3','KP0','KP.',' ',' ','OEM','F11' ; 50h
db 'F12','HOM','UP ','PGU','LFT','5DH','RGT','END'
db 'DWN','PGD','INS','DEL','64H','65H','66H','67H' ; 60h
db '68H','69H','6AH','6BH','6CH','6DH','6EH','6FH'
db '70H','71H','72H','73H','74H','75H','76H','77H' ; 70h
db '78H','79H','7AH','7BH','7CH','7DH','7EH','7FH'
; Keyboard continued (Direct Input)
db '80H','81H','82H','83H','84H','85H','86H','87H' ; 80h
db '88H','89H','8AH','8BH','8CH','8DH','8EH','8FH'
db '90H','91H','92H','93H','94H','95H','96H','97H' ; 90h
db '98H','99H','9AH','9BH','9CH','9DH','9EH','9FH'
db 'A0H','A1H','A2H','A3H','A4H','A5H','A6H','A7H' ; A0h
db 'A8H','A9H','AAH','ABH','ACH','ADH','AEH','AFH'
db 'B0H','B1H','B2H','B3H','B4H','B5H','B6H','B7H' ; B0h
db 'B8H','B9H','BAH','BBH','BCH','BDH','BEH','BFH'
db 'C0H','C1H','C2H','C3H','C4H','C5H','C6H','C7H' ; C0h
db 'C8H','C9H','CAH','CBH','CCH','CDH','CEH','CFH'
db 'D0H','D1H','D2H','D3H','D4H','D5H','D6H','D7H' ; D0h
db 'D8H','D9H','DAH','DBH','DCH','DDH','DEH','DFH'
db 'E0H','E1H','E2H','E3H','E4H','E5H','E6H','E7H' ; E0h
db 'E8H','E9H','EAH','EBH','ECH','EDH','EEH','EFH'
db 'F0H','F1H','F2H','F3H','F4H','F5H','F6H','F7H' ; F0h
db 'F8H','F9H','FAH','FBH','FCH','FDH','FEH','FFH'
; Joystick Stuff
db 'J00','J01','J02','J03','J04','J05','J06','J07' ; 100h
db 'J08','J09','J0A','J0B','J0C','J0D','J0E','J0F'
db 'J10','J11','J12','J13','J14','J15','J16','J17' ; 110h
db 'J18','J19','J1A','J1B','J1C','J1D','J1E','J1F'
db 'J20','J21','J22','J23','J24','J25','J26','J27' ; 120h
db 'J28','J29','J2A','J2B','J2C','J2D','J2E','J2F'
db 'J30','J31','J32','J33','J34','J35','J36','J37' ; 130h
db 'J38','J39','J3A','J3B','J3C','J3D','J3E','J3F'
db 'J40','J41','J42','J43','J44','J45','J46','J47' ; 140h
db 'J48','J49','J4A','J4B','J4C','J4D','J4E','J4F'
db 'J50','J51','J52','J53','J54','J55','J56','J57' ; 150h
db 'J58','J59','J5A','J5B','J5C','J5D','J5E','J5F'
db 'J60','J61','J62','J63','J64','J65','J66','J67' ; 160h
db 'J68','J69','J6A','J6B','J6C','J6D','J6E','J6F'
db 'J70','J71','J72','J73','J74','J75','J76','J77' ; 170h
db 'J78','J79','J7A','J7B','J7C','J7D','J7E','J7F'
%ifdef __UNIXSDL__
; Extra Joystick Stuff
db 'J80','J81','J82','J83','J84','J85','J86','J87' ; 180h
db 'J88','J89','J8A','J8B','J8C','J8D','J8E','J8F'
db 'J90','J91','J92','J93','J94','J95','J96','J97' ; 190h
db 'J98','J99','J9A','J9B','J9C','J9D','J9E','J9F'
db 'JA0','JA1','JA2','JA3','JA4','JA5','JA6','JA7' ; 2A0h
db 'JA8','JA9','JAA','JAB','JAC','JAD','JAE','JAF'
db 'JB0','JB1','JB2','JB3','JB4','JB5','JB6','JB7' ; 2B0h
db 'JB8','JB9','JBA','JBB','JBC','JBD','JBE','JBF'
%else
; Extra Stuff (180h) (Parallel Port)
db 'PPB','PPY','PSL','PST','PUP','PDN','PLT','PRT' ; 180h
db 'PPA','PPX','PPL','PPR',' ',' ',' ',' '
db 'P2B','P2Y','P2S','P2T','P2U','P2D','P2L','P2R' ; 190h
db 'P2A','P2X','P2L','P2R',' ',' ',' ',' '
db 'PPB','PPY','PSL','PST','PUP','PDN','PLT','PRT' ; 2A0h
db 'PPA','PPX','PPL','PPR',' ',' ',' ',' '
db 'P2B','P2Y','P2S','P2T','P2U','P2D','P2L','P2R' ; 2B0h
db 'P2A','P2X','P2L','P2R',' ',' ',' ',' '
%endif
SECTION .text
; ****************************
; Mouse Stuff
; ****************************
NEWSYM Init_Mouse
; return non-zero if successful
mov eax,01h
ret
SECTION .data
NEWSYM WMouseX, dd 0
NEWSYM WMouseY, dd 0
NEWSYM WMouseMoveX, dd 0
NEWSYM WMouseMoveY, dd 0
NEWSYM WMouseButton, dd 0
SECTION .text
NEWSYM Get_MouseData ; Returns both pressed and coordinates
; bx : bit 0 = left button, bit 1 = right button
; cx = Mouse X Position, dx = Mouse Y Position
pushad
call GetMouseX
mov [WMouseX],eax
call GetMouseY
mov [WMouseY],eax
call GetMouseButton
mov [WMouseButton],eax
popad
mov cx,[WMouseX]
mov dx,[WMouseY]
mov bx,[WMouseButton]
ret
NEWSYM Set_MouseXMax
ret
NEWSYM Set_MouseYMax
ret
NEWSYM Set_MousePosition
ret
NEWSYM Get_MousePositionDisplacement
; returns x,y displacement in pixel in cx,dx
pushad
call GetMouseMoveX
mov [WMouseMoveX],eax
call GetMouseMoveY
mov [WMouseMoveY],eax
popad
mov cx,[WMouseMoveX]
mov dx,[WMouseMoveY]
ret
NEWSYM MouseWindow
pushad
or byte[MouseButton],2
mov byte[T36HZEnabled],1
call GetMouseButton
and byte[MouseButton],0FDh
popad
ret
NEWSYM GUIInit
pushad
call Start36HZ
popad
ret
NEWSYM GUIDeInit
pushad
call Stop36HZ
popad
ret
; ****************************
; Sound Stuff
; ****************************
NEWSYM StopSound
call Start36HZ
call JoyRead
ret
NEWSYM StartSound
call Start60HZ
call JoyRead
ret
NEWSYM delay
ret
NEWSYM Check60hz
; Call the timer update function here
pushad
call CheckTimers
call sem_sleep
popad
ret
SECTION .data
BitPosR db 11
BitPosG db 5
BitPosB db 0
BitSizeR db 5
BitSizeG db 6
BitSizeB db 5
SECTION .text
InitializeGfxStuff:
; Process Red Stuff
mov al,[BitPosR]
mov cl,al
mov bx,1
shl bx,cl
cmp byte[BitSizeR],6
jne .no6bit
mov [vesa2_usbit],bx
inc al
.no6bit
or [vesa2_clbit],bx
mov [vesa2_rpos],al
dec al
mov cl,al
mov bx,001Fh
cmp cl,0FFh
je .shrr
shl bx,cl
jmp .shlr
.shrr
shr bx,1
.shlr
mov [vesa2_rfull],bx
add al,5
mov bx,1
mov cl,al
shl bx,cl
mov [vesa2_rtrcl],bx
xor bx,0FFFFh
mov [vesa2_rtrcla],bx
; Process Green Stuff
mov al,[BitPosG]
mov cl,al
mov bx,1
shl bx,cl
cmp byte[BitSizeG],6
jne .no6bitb
mov [vesa2_usbit],bx
inc al
.no6bitb
or [vesa2_clbit],bx
mov [vesa2_gpos],al
dec al
mov cl,al
mov bx,001Fh
cmp cl,0FFh
je .shrg
shl bx,cl
jmp .shlg
.shrg
shr bx,1
.shlg
mov [vesa2_gfull],bx
add al,5
mov bx,1
mov cl,al
shl bx,cl
mov [vesa2_gtrcl],bx
xor bx,0FFFFh
mov [vesa2_gtrcla],bx
; Process Blue Stuff
mov al,[BitPosB]
mov cl,al
mov bx,1
shl bx,cl
cmp byte[BitSizeB],6
jne .no6bitc
mov [vesa2_usbit],bx
inc al
.no6bitc
or [vesa2_clbit],bx
mov [vesa2_bpos],al
dec al
mov cl,al
mov bx,001Fh
cmp cl,0FFh
je .shrb
shl bx,cl
jmp .shlb
.shrb
shr bx,1
.shlb
mov [vesa2_bfull],bx
add al,5
mov bx,1
mov cl,al
shl bx,cl
mov [vesa2_btrcl],bx
xor bx,0FFFFh
mov [vesa2_btrcla],bx
xor word[vesa2_clbit],0FFFFh
call genfulladdtab
cmp byte[converta],1
je .red10
mov eax,565
jmp .red11
.red10
mov eax,555
.red11
push eax
call Init_2xSaIMMXW
pop eax
ret
%macro SetDefaultKey2 13
mov dword[%1upk],%4 ; Up
mov dword[%1downk],%5 ; Down
mov dword[%1leftk],%6 ; Left
mov dword[%1rightk],%7 ; Right
mov dword[%1startk],%3 ; Start
mov dword[%1selk],%2 ; Select
mov dword[%1Ak],%9 ; A
mov dword[%1Bk],%12 ; B
mov dword[%1Xk],%8 ; X
mov dword[%1Yk],%11 ; Y
mov dword[%1Lk],%10 ; L
mov dword[%1Rk],%13 ; R
%endmacro
%macro SetDefaultKey 12
cmp bh,0
jne %%nopl1
SetDefaultKey2 pl1,%1,%2,%3,%4,%5,%6,%7,%8,%9,%10,%11,%12
%%nopl1
cmp bh,1
jne %%nopl2
SetDefaultKey2 pl2,%1,%2,%3,%4,%5,%6,%7,%8,%9,%10,%11,%12
%%nopl2
cmp bh,2
jne %%nopl3
SetDefaultKey2 pl3,%1,%2,%3,%4,%5,%6,%7,%8,%9,%10,%11,%12
%%nopl3
cmp bh,3
jne %%nopl4
SetDefaultKey2 pl4,%1,%2,%3,%4,%5,%6,%7,%8,%9,%10,%11,%12
%%nopl4
cmp bh,4
jne %%nopl5
SetDefaultKey2 pl5,%1,%2,%3,%4,%5,%6,%7,%8,%9,%10,%11,%12
%%nopl5
%endmacro
NEWSYM SetInputDevice
; bl = device #, bh = player # (0-4)
; Sets keys according to input device selected
cmp bl,0
jne near .nozero
SetDefaultKey 0,0,0,0,0,0,0,0,0,0,0,0
ret
.nozero
cmp bh,1
je near .input2
%ifdef __UNIXSDL__
SetDefaultKey 54,28,90,96,92,94,31,45,32,30,44,46
%else
SetDefaultKey 54,28,200,208,203,205,31,45,32,30,44,46
%endif
ret
.input2
%ifdef __UNIXSDL__
SetDefaultKey 56,29,36,50,49,51,98,89,91,99,95,97
%else
SetDefaultKey 56,29,36,50,49,51,210,199,201,211,207,209
%endif
ret

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,21 @@
/*
Copyright (C) 1997-2007 ZSNES Team ( zsKnight, _Demo_, pagefault, Nach )
http://www.zsnes.com
http://sourceforge.net/projects/zsnes
https://zsnes.bountysource.com
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

View File

@@ -0,0 +1,21 @@
/*
Copyright (C) 1997-2007 ZSNES Team ( zsKnight, _Demo_, pagefault, Nach )
http://www.zsnes.com
http://sourceforge.net/projects/zsnes
https://zsnes.bountysource.com
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

View File

@@ -0,0 +1,237 @@
/*
Copyright (C) 1997-2007 ZSNES Team ( zsKnight, _Demo_, pagefault, Nach )
http://www.zsnes.com
http://sourceforge.net/projects/zsnes
https://zsnes.bountysource.com
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "../gblhdr.h"
#include "../cfg.h"
#include "../asm_call.h"
#define BYTE unsigned char
#define WORD unsigned short
#define DWORD unsigned long
//C++ style code in C
#define bool unsigned char
#define true 1
#define false 0
void CheckFrame();
// VIDEO VARIABLES
extern SDL_Surface *surface;
extern int SurfaceX, SurfaceY;
extern int SurfaceLocking;
extern unsigned int vidbuffer;
extern DWORD converta;
extern unsigned char curblank;
extern int frametot;
extern BYTE GUIOn,GUIOn2;
void UpdateVFrame(void);
void NTSCFilterInit();
void NTSCFilterDraw(int SurfaceX, int SurfaceY, int pitch, unsigned char * buffer);
bool OGLModeCheck();
void initwinvideo();
bool sw_start(int width, int height, int req_depth, int FullScreen)
{
//unsigned int color32, p;
//int i;
#ifndef __MACOSX__
Uint32 flags = SDL_DOUBLEBUF | SDL_HWSURFACE;
#else
Uint32 flags = SDL_SWSURFACE;
#endif
DWORD GBitMask;
flags |= (FullScreen ? SDL_FULLSCREEN : 0);
if (NTSCFilter) NTSCFilterInit();
SurfaceX = width; SurfaceY = height;
surface = SDL_SetVideoMode(SurfaceX, SurfaceY, req_depth, flags);
if (surface == NULL) {
fprintf (stderr, "Could not set %dx%d video mode: %s\n", SurfaceX, SurfaceY, SDL_GetError ());
return false;
}
SurfaceLocking = SDL_MUSTLOCK(surface);
SDL_WarpMouse(SurfaceX/4,SurfaceY/4);
// Grab mouse in fullscreen mode
FullScreen ? SDL_WM_GrabInput(SDL_GRAB_ON) : SDL_WM_GrabInput(SDL_GRAB_OFF);
SDL_WM_SetCaption ("ZSNES","ZSNES");
SDL_ShowCursor(0);
// Check hardware for 565/555
GBitMask = surface->format->Gmask;
if(GBitMask != 0x07E0) converta = 1;
else converta = 0;
return true;
}
void sw_end() {
// Do nothing
}
static void LockSurface(void)
{
if (SurfaceLocking) SDL_LockSurface(surface);
}
static void UnlockSurface(void)
{
if (SurfaceLocking) SDL_UnlockSurface(surface);
SDL_Flip(surface);
}
extern DWORD AddEndBytes;
extern DWORD NumBytesPerLine;
extern unsigned char *WinVidMemStart;
extern unsigned char NGNoTransp;
extern unsigned short resolutn;
void copy640x480x16bwin(void);
void hq2x_16b(void);
void hq3x_16b(void);
void hq4x_16b(void);
void ClearWin16 (void);
void DrawWin256x224x16(void);
void DrawWin320x240x16(void);
DWORD ScreenPtr;
DWORD SurfBufD;
DWORD pitch;
void sw_clearwin()
{
pitch = surface->pitch;
SurfBufD = (DWORD) surface->pixels;
LockSurface();
ClearWin16();
UnlockSurface();
}
extern unsigned char prevNTSCMode;
extern unsigned char changeRes;
extern unsigned char prevKeep4_3Ratio;
void sw_drawwin()
{
NGNoTransp = 0; // Set this value to 1 within the appropriate
// video mode if you want to add a custom
// transparency routine or hardware
// transparency. This only works if
// the value of newengen is equal to 1.
// (see ProcessTransparencies in newgfx16.asm
// for ZSNES' current transparency code)
UpdateVFrame();
if (curblank || OGLModeCheck()) return;
LockSurface();
if (NTSCFilter != prevNTSCMode) initwinvideo();
if (changeRes) initwinvideo();
if (prevKeep4_3Ratio != Keep4_3Ratio) initwinvideo();
ScreenPtr = vidbuffer;
ScreenPtr += 16*2+32*2+256*2;
if (resolutn == 239) ScreenPtr+=8*288*2;
pitch = surface->pitch;
SurfBufD = (DWORD) surface->pixels;
if (SurfBufD == 0) {
UnlockSurface();
return;
}
if (SurfaceX == 256 && SurfaceY == 224) DrawWin256x224x16();
else if (SurfaceX == 320 && SurfaceY == 240) DrawWin320x240x16();
else if((SurfaceX == 512 && SurfaceY == 448))
{
AddEndBytes = pitch-1024;
NumBytesPerLine = pitch;
WinVidMemStart = (void*)SurfBufD;
if (hqFilter)
{
switch (hqFilter)
{
case 1:
hq2x_16b();
break;
case 2:
//hq3x_16b();
break;
case 3:
//hq4x_16b();
break;
default:
break;
}
}
else asm_call(copy640x480x16bwin);
}
else if ((SurfaceX == 602) && NTSCFilter)
{
AddEndBytes = pitch-1024;
NumBytesPerLine = pitch;
WinVidMemStart = (void*)SurfBufD;
NTSCFilterDraw(SurfaceX, SurfaceY, pitch, WinVidMemStart);
}
else if (SurfaceX == 640 && SurfaceY == 480)
{
AddEndBytes = pitch-1024;
NumBytesPerLine = pitch;
WinVidMemStart = (void*) (SurfBufD + 16*640*2 + 64*2);
if (hqFilter)
{
switch (hqFilter)
{
case 1:
hq2x_16b();
break;
case 2:
//hq3x_16b();
break;
case 3:
//hq4x_16b();
break;
default:
break;
}
}
else if (NTSCFilter) NTSCFilterDraw(SurfaceX, SurfaceY, pitch, WinVidMemStart-16*640*2-64*2); else asm_call(copy640x480x16bwin);
}
UnlockSurface();
}

View File

@@ -0,0 +1,33 @@
/*
Copyright (C) 1997-2007 ZSNES Team ( zsKnight, _Demo_, pagefault, Nach )
http://www.zsnes.com
http://sourceforge.net/projects/zsnes
https://zsnes.bountysource.com
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef SW_DRAW_h
#define SW_DRAW_h 1
int sw_start(int width, int height, int req_depth, int FullScreen);
void sw_end();
void sw_clearwin();
void sw_drawwin();
#endif

View File

@@ -0,0 +1,215 @@
.TH "ZSNES v1.51" 1
.SH NAME
ZSNES - Super Nintendo console emulator
.SH SYNOPSIS
.B ZSNES
[-?] [-1 #] [-2 #] [-dd] [-dh] [-f #] [-g #] [-h | -l] [-j] [-js #] [-k #] [-m] [-mc] [-md] [-ml #] [-n #] [-o] [-p #] [-r #] [-s] [-sa] [-t | -u] [-v #] [-y] [-z] [-zm #] [-zs #] [romname]
.SH DESCRIPTION
.B ZSNES
is an emulator for the Super Nintendo video game console. It is written in a combination of x86 assembly, C, C++, and PSR. It is currently available on Windows, DOS, x86 Linux, x86 Mac OS X, and x86 BSD.
Visit http://www.zsnes.com/ for the latest updates.
.SH OPTIONS
Note: Many of these options can also be set in the GUI.
.TP
.B -?
Display command-line help
.TP
.B -1 # / -2 #
Set controls for Player 1/2
.nf
\fI0\fP = None \fI1\fP = Keyboard/Gamepad
.fi
.TP
.B -dd
Disable sound DSP emulation
.TP
.B -dh
Disable game hacks
.TP
.B -f #
Enable frame skipping, where \fB#\fP is a numerical value from \fI0-9\fP
.TP
.B -g #
Specify gamma correction value, where \fB#\fP is a numerical value from \fI0-15\fP
.TP
.B -h
Force HiROM. Cannot be used with \fB-l\fP
.TP
.B -j
Disable Mouse (Automatically turns off right mouse click)
.TP
.B -js #
Adjust joystick sensitivity, where \fB#\fP is a numerical value from \fI0-32767\fP
.TP
.B -k #
Set volume level, where \fB#\fP is a numerical value from \fI1-100\fP
.TP
.B -l
Force LoROM. Cannot be used with \fB-h\fP
.TP
.B -m
Disable GUI (Must specify ROM filename)
.TP
.B -mc
Exit ZSNES when closing a movie (use with \fB-zm\fP)
.TP
.B -md
Dump raw video (use with \fB-zm\fP)
.TP
.B -ml
Define movie dump length in amount of frames (use with \fB-md\fP)
.TP
.B -n #
Enable scanlines (when available), where
.B #
is one of:
.nf
\fl0\fP = none \fI1\fP = full \fI2\fP = 25%
\fI3\fP = 50%
.fi
.TP
.B -o
Disable MMX support
.TP
.B -p #
Change the clock speed of the main CPU, where
.B #
is a numerical value from \fI50-150\fP. 100 is the normal speed. Changing this value may have adverse side effects.
.TP
.B -r #
Set audio sampling rate, where
.B #
is one of:
.nf
\fI0\fP = 8 KHz \fI1\fP = 11.025 KHz \fI2\fP = 22.05 KHz
\fI3\fP = 44.1 KHz \fI4\fP = 16 KHz \fI5\fP = 32 KHz
\fI6\fP = 48 KHz
.fi
.TP
.B -s
Enable SPC700/DSP emulation (Sound)
.TP
.B -sa
Show files with all extensions (*.*) in GUI. Default is to only show files with one of the extensions listed in
.B romname
.TP
.B -t
Force NTSC (60 Hz) timing. Cannot be used with \fB-u\fP
.TP
.B -u
Force PAL (50 Hz) timing. Cannot be used with \fB-t\fP
.TP
.B -v #
Select video mode, where
.B #
is one of:
.nf
\fI0\fP = 256x224 R W \fI1\fP = 256x224 R F \fI2\fP = 512x448 DR W
\fI3\fP = 512x448 DR F \fI4\fP = 640x480 DR F \fI5\fP = 256x224 OR W
\fI6\fP = 512x448 ODR \fI7\fP = 640x480 ODS F \fI8\fP = 640x480 ODS W
\fI9\fP = 640x560 ODR W \fI10\fP = 768x672 ODR W \fI11\fP = 800x600 ODS F
\fI12\fP = 800x600 ODS W \fI13\fP = 896x784 ODR W \fI14\fP = 1024x768 ODS F
\fI15\fP = 1024x768 ODS W \fI16\fP = 1024x896 ODR W \fI17\fP = 1280x960 ODS F
\fI18\fP = 1280x1024 ODS F \fI19\fP = 1600x1200 ODS F \fI20\fP = VARIABLE ODR W
\fI21\fP = VARIABLE ODS W \fI22\fP = CUSTOM OD F
.fi
.TP
.B -y
Enable Interpolation
.TP
.B -z
Disable stereo sound. Stereo sound is enabled by default
.TP
.B -zm #
Auto load specified movie on startup, where \fB#\fP is a numerical value from \fI0-9\fP
.TP
.B -zs #
Auto load specified save state on startup, where \fB#\fP is a numerical value from \fI0-99\fP
.TP
.B romname
Name of ROM to auto-load
.B romname
is of the format \fBfilename.ext\fP, where
.B .ext
is one of
SMC, SFC, SWC, FIG, MGD, MGH, UFO, BIN, GD3, GD7, USA, EUR, JAP, AUS, ST, BS, DX2, 048, 058, 078, 1 or A. You can also load ROMs which have been compressed with GZip, Zip or JMA.
.SH "FILES AND DIRECTORIES"
.TP
ZSNES
The main program.
.TP
~/.zsnes
This is the directory where ZSNES configuration files are stored. By default, it is also the directory where save states, screenshots, SPC dumps and ZMV movie files are stored, but you can change this behaviour by editing zsnesl.cfg. This directory is created by ZSNES.
.TP
~/.zsnes/zsnesl.cfg
This file is where configuration settings for ZSNES are stored. It is in a human-readable format and can be edited by hand. It is created by ZSNES.
.TP
~/.zsnes/zmovie.cfg
This file is where settings specific to AVI dumping are saved. It is created by ZSNES.
.TP
~/.zsnes/zfont.txt
This file allows you to customize the fonts in the GUI. Enable "Use Custom Font" in the GUI Options menu. It is created by ZSNES.
.TP
~/.zsnes/zinput.cfg
This file is where input configuration settings for ZSNES are stored.
.B If for some reason you update your version of ZSNES and it keeps crashing before you can do anything, you should try deleting the above .cfg files and let ZSNES create new ones.
.SH "SPECIAL CHIP GAMES"
Many games on the Super Nintendo used custom CPUs in addition to the main SNES CPU. Some of these CPUs have not been fully reverse-engineered, and games that use them may either not work or may experience strange bugs.
You can find more information about these special CPUs at:
http://users.tpg.com.au/advlink/dsp/
http://nsrt.edgeemu.com/INFO/chipinfo.htm
.SH "GRAPHICS PACKS"
Some games based on the SPC7110 chip, such as Far East of Eden Zero, can use special graphics packs to work around unemulated portions of their custom CPU. These graphics packs must be stored in individual directories within the save directory, which is specified in zsnesl.cfg. By default, this is ~/.zsnes. The directory name of each graphics pack must be capitalized and all files within that directory must be in lowercase.
The proper directory name for a given graphics pack can be found in the readme file included with that pack.
NOTE: As of version 1.40, games which use the S-DD1 chip (Star Ocean and Street Fighter Alpha 2) do not require graphics packs.
.SH "REPORTING BUGS"
You can report bugs using the bug tracker at the ZSNES BountySource page, located at
http://zsnes.bountysource.com/development/
.SH AUTHORS
Please refer to the "About" section of the documentation.
.SH ZSNES RELATED WEBSITES
.TP
ZSNES Home Page:
http://www.zsnes.com/
.TP
ZSNES Board:
http://board.zsnes.com/
.TP
ZSNES Project Page:
https://zsnes.bountysource.com/
.TP
ZSNES Repository (SubVersioN):
https://svn.bountysource.com/zsnes/trunk/
.TP
ZSNES Documentation Online:
http://zsnes-docs.sf.net/
.TP
ZSNES IRC:
#zsnes on irc.freenode.net
.TP
ZSNES Docs IRC:
#zsnes-docs on irc.freenode.net
.SH "COPYRIGHT NOTICE"
Copyright \(co 1997-2007 ZSNES Team
Permission is granted to copy and distribute this manual under the terms of the GNU Free Documentation License.

View File

@@ -0,0 +1,9 @@
[Desktop Entry]
Encoding=UTF-8
Name=ZSNES
Type=Application
Comment=SNES (Super Nintendo) emulator that uses x86 assembly
Exec=zsnes
Path=
Icon=zsnes.png
Categories=Application;Game;Emulator;