1341 lines
29 KiB
C
1341 lines
29 KiB
C
/*
|
|
Copyright (C) 1997-2005 ZSNES Team ( zsKnight, _Demo_, pagefault, Nach )
|
|
|
|
http://www.zsnes.com
|
|
http://sourceforge.net/projects/zsnes
|
|
|
|
This program 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 2 of the License, or (at your option) any later
|
|
version.
|
|
|
|
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 "sw_draw.h"
|
|
#include "gl_draw.h"
|
|
|
|
#include "SDL_thread.h"
|
|
|
|
#include <sys/time.h>
|
|
#include <time.h>
|
|
|
|
typedef unsigned char BYTE;
|
|
typedef unsigned short WORD;
|
|
typedef unsigned long DWORD;
|
|
typedef Uint32 UINT32;
|
|
typedef long long _int64;
|
|
typedef long long LARGE_INTEGER;
|
|
|
|
typedef enum { FALSE = 0, TRUE = 1 } BOOL;
|
|
typedef enum vidstate_e { vid_null, vid_none, vid_soft, vid_gl } vidstate_t;
|
|
|
|
// SOUND RELATED VARIABLES
|
|
SDL_AudioSpec audiospec;
|
|
int SoundEnabled = 1;
|
|
BYTE PrevStereoSound;
|
|
DWORD PrevSoundQuality;
|
|
Uint8 *Buffer = NULL;
|
|
int Buffer_len = 0, Buffer_fill = 0;
|
|
int Buffer_head = 0, Buffer_tail = 0;
|
|
|
|
extern BYTE StereoSound;
|
|
extern DWORD SoundQuality;
|
|
extern int DSPBuffer[];
|
|
|
|
/* NETWORK RELATED VARIABLES */
|
|
extern int packettimeleft[256];
|
|
extern int PacketCounter;
|
|
extern int CounterA;
|
|
extern int CounterB;
|
|
|
|
/* VIDEO VARIABLES */
|
|
SDL_Surface *surface;
|
|
int SurfaceLocking = 0;
|
|
int SurfaceX, SurfaceY;
|
|
static DWORD WindowWidth = 256;
|
|
static DWORD WindowHeight = 224;
|
|
static DWORD FullScreen = 0;
|
|
static vidstate_t sdl_state = vid_null;
|
|
static int UseOpenGL = 0;
|
|
static const int BitDepth = 16;
|
|
DWORD FirstVid = 1;
|
|
|
|
extern void SwitchFullScreen (void);
|
|
extern unsigned char cvidmode;
|
|
DWORD SMode=0;
|
|
DWORD DSMode=0;
|
|
DWORD prevHQMode=-1;
|
|
|
|
extern DWORD converta;
|
|
extern DWORD *BitConv32Ptr;
|
|
extern DWORD *RGBtoYUVPtr;
|
|
extern unsigned char hqFilter;
|
|
|
|
extern BYTE GUIWFVID[];
|
|
extern BYTE GUISMODE[];
|
|
extern BYTE GUIDSMODE[];
|
|
extern BYTE GUIHQ2X[];
|
|
extern BYTE GUIHQ3X[];
|
|
extern BYTE GUIHQ4X[];
|
|
extern BYTE GUIRESIZE[];
|
|
|
|
/* JOYSTICK AND KEYBOARD INPUT */
|
|
SDL_Joystick *JoystickInput[5];
|
|
unsigned int AxisOffset[5] = {256 + 128 + 64}; // per joystick offsets in
|
|
unsigned int ButtonOffset[5] = {448}; // pressed. We have 128 + 64
|
|
unsigned int HatOffset[5] = {448}; // bytes for all joysticks. We
|
|
unsigned int BallOffset[5] = {448}; // can control all 5 players.
|
|
int shiftptr = 0;
|
|
int offset;
|
|
DWORD numlockptr;
|
|
|
|
extern unsigned char pressed[];
|
|
extern int CurKeyPos;
|
|
extern int CurKeyReadPos;
|
|
extern int KeyBuffer[16];
|
|
|
|
/* MOUSE INPUT */
|
|
float MouseMinX = 0;
|
|
float MouseMaxX = 256;
|
|
float MouseMinY = 0;
|
|
float MouseMaxY = 223;
|
|
int MouseX, MouseY;
|
|
float MouseMoveX, MouseMoveY;
|
|
int MouseMove2X, MouseMove2Y;
|
|
Uint8 MouseButton;
|
|
float MouseXScale = 1.0;
|
|
float MouseYScale = 1.0;
|
|
DWORD LastUsedPos = 0;
|
|
DWORD CurMode = -1;
|
|
|
|
extern BYTE GUIOn;
|
|
extern BYTE GUIOn2;
|
|
static BYTE IsActivated = 1;
|
|
|
|
/* TIMER VARIABLES/MACROS */
|
|
#define UPDATE_TICKS_GAME (1000.855001760297741789468390082/60.0) // milliseconds per world update
|
|
#define UPDATE_TICKS_GAMEPAL (20) // milliseconds per world update
|
|
#define UPDATE_TICKS_GUI (1000.0/36.0) // milliseconds per world update
|
|
#define UPDATE_TICKS_UDP (1000.0/60.0) // milliseconds per world update
|
|
|
|
int T60HZEnabled = 0;
|
|
int T36HZEnabled = 0;
|
|
short SystemTimewHour;
|
|
short SystemTimewMinute;
|
|
short SystemTimewSecond;
|
|
float end, end2;
|
|
float start, start2;
|
|
float update_ticks_pc, update_ticks_pc2;
|
|
|
|
static SDL_sem *sem_frames = NULL;
|
|
|
|
void sem_sleep_rdy(void);
|
|
void sem_sleep_die(void);
|
|
|
|
static struct timeval sem_start;
|
|
// void sem_StartTicks(void);
|
|
float sem_GetTicks(void);
|
|
|
|
extern unsigned char romispal;
|
|
|
|
/* FUNCTION DECLARATIONS */
|
|
void clearwin (void);
|
|
void drawscreenwin(void);
|
|
void initwinvideo();
|
|
void ProcessKeyBuf(int scancode);
|
|
void LinuxExit(void);
|
|
void UpdateSound(void *userdata, Uint8 * stream, int len);
|
|
|
|
extern int GUI36hzcall(void);
|
|
extern int Game60hzcall(void);
|
|
extern void SoundProcess();
|
|
_int64 copymaskRB = 0x001FF800001FF800LL;
|
|
_int64 copymaskG = 0x0000FC000000FC00LL;
|
|
_int64 copymagic = 0x0008010000080100LL;
|
|
_int64 coef = 0x0066009a0066009aLL;
|
|
#ifdef __OPENGL__
|
|
extern void gl_clearwin(void);
|
|
#endif
|
|
|
|
static void adjustMouseXScale(void)
|
|
{
|
|
MouseXScale = (MouseMaxX - MouseMinX) / ((float) WindowWidth);
|
|
}
|
|
|
|
static void adjustMouseYScale(void)
|
|
{
|
|
MouseYScale = (MouseMaxY - MouseMinY) / ((float) WindowHeight);
|
|
}
|
|
|
|
int Main_Proc(void)
|
|
{
|
|
SDL_Event event;
|
|
|
|
while (SDL_PollEvent(&event))
|
|
{
|
|
switch (event.type)
|
|
{
|
|
case SDL_ACTIVEEVENT:
|
|
IsActivated = event.active.gain;
|
|
break;
|
|
case SDL_KEYDOWN:
|
|
if ((event.key.keysym.sym == SDLK_RETURN) &&
|
|
(event.key.keysym.mod & KMOD_ALT)) {
|
|
SwitchFullScreen();
|
|
break;
|
|
}
|
|
if (event.key.keysym.sym == SDLK_LSHIFT ||
|
|
event.key.keysym.sym == SDLK_RSHIFT)
|
|
shiftptr = 1;
|
|
if (event.key.keysym.mod & KMOD_NUM)
|
|
numlockptr = 1;
|
|
else
|
|
numlockptr = 0;
|
|
if (event.key.keysym.scancode - 8 >= 0)
|
|
{
|
|
//if (pressed[event.key.keysym.scancode - 8] != 2)
|
|
pressed[event.key.keysym.scancode - 8] = 1;
|
|
ProcessKeyBuf(event.key.keysym.sym);
|
|
}
|
|
break;
|
|
|
|
case SDL_KEYUP:
|
|
if (event.key.keysym.sym == SDLK_LSHIFT ||
|
|
event.key.keysym.sym == SDLK_RSHIFT)
|
|
shiftptr = 0;
|
|
if (event.key.keysym.scancode - 8 >= 0)
|
|
pressed[event.key.keysym.scancode - 8] = 0;
|
|
break;
|
|
|
|
case SDL_MOUSEMOTION:
|
|
if (FullScreen)
|
|
{
|
|
MouseX += event.motion.xrel;
|
|
MouseY += event.motion.yrel;
|
|
}
|
|
else
|
|
{
|
|
MouseX = ((int) ((float) event.motion.x) * MouseXScale);
|
|
MouseY = ((int) ((float) event.motion.y) * MouseYScale);
|
|
}
|
|
|
|
if (MouseX < MouseMinX) MouseX = MouseMinX;
|
|
if (MouseX > MouseMaxX) MouseX = MouseMaxX;
|
|
if (MouseY < MouseMinY) MouseY = MouseMinY;
|
|
if (MouseY > MouseMaxY) MouseY = MouseMaxY;
|
|
break;
|
|
|
|
case SDL_MOUSEBUTTONDOWN:
|
|
/*
|
|
button 2 = enter (i.e. select)
|
|
button 4 = mouse wheel up (treat as "up" key)
|
|
button 5 = mouse wheel down (treat as "down" key)
|
|
*/
|
|
switch (event.button.button)
|
|
{
|
|
case 4:
|
|
ProcessKeyBuf(SDLK_UP);
|
|
break;
|
|
case 5:
|
|
ProcessKeyBuf(SDLK_DOWN);
|
|
break;
|
|
case 2:
|
|
ProcessKeyBuf(SDLK_RETURN);
|
|
// Yes, this is intentional - DDOI
|
|
default:
|
|
MouseButton = MouseButton | event.button.button;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case SDL_MOUSEBUTTONUP:
|
|
MouseButton =
|
|
MouseButton & ~event.button.button;
|
|
break;
|
|
|
|
case SDL_JOYHATMOTION: // POV hats act as direction pad
|
|
offset = HatOffset[event.jhat.which];
|
|
if (offset >= (256 + 128 + 64)) break;
|
|
switch (event.jhat.value)
|
|
{
|
|
case SDL_HAT_CENTERED:
|
|
pressed[offset] = 0;
|
|
pressed[offset + 1] = 0;
|
|
pressed[offset + 2] = 0;
|
|
pressed[offset + 3] = 0;
|
|
break;
|
|
case SDL_HAT_UP:
|
|
pressed[offset + 3] = 1;
|
|
pressed[offset + 2] = 0;
|
|
break;
|
|
case SDL_HAT_RIGHTUP:
|
|
pressed[offset] = 1;
|
|
pressed[offset + 3] = 1;
|
|
pressed[offset + 1] = 0;
|
|
pressed[offset + 2] = 0;
|
|
break;
|
|
case SDL_HAT_RIGHT:
|
|
pressed[offset] = 1;
|
|
pressed[offset + 1] = 0;
|
|
break;
|
|
case SDL_HAT_RIGHTDOWN:
|
|
pressed[offset] = 1;
|
|
pressed[offset + 2] = 1;
|
|
pressed[offset + 1] = 0;
|
|
pressed[offset + 3] = 0;
|
|
break;
|
|
case SDL_HAT_DOWN:
|
|
pressed[offset + 2] = 1;
|
|
pressed[offset + 3] = 0;
|
|
break;
|
|
case SDL_HAT_LEFTDOWN:
|
|
pressed[offset + 1] = 1;
|
|
pressed[offset + 2] = 1;
|
|
pressed[offset] = 0;
|
|
pressed[offset + 3] = 0;
|
|
break;
|
|
case SDL_HAT_LEFT:
|
|
pressed[offset + 1] = 1;
|
|
pressed[offset] = 0;
|
|
break;
|
|
case SDL_HAT_LEFTUP:
|
|
pressed[offset + 1] = 1;
|
|
pressed[offset + 3] = 1;
|
|
pressed[offset] = 0;
|
|
pressed[offset + 2] = 0;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
/*
|
|
joystick trackball code untested; change the test
|
|
values if the motion is too sensitive (or not
|
|
sensitive enough)
|
|
*/
|
|
case SDL_JOYBALLMOTION:
|
|
offset = BallOffset[event.jball.which];
|
|
offset += event.jball.ball;
|
|
if (offset >= (256 + 128 + 64)) break;
|
|
if (event.jball.xrel < -100)
|
|
{
|
|
pressed[offset] = 0;
|
|
pressed[offset + 1] = 1;
|
|
}
|
|
if (event.jball.xrel > 100)
|
|
{
|
|
pressed[offset] = 1;
|
|
pressed[offset + 1] = 0;
|
|
}
|
|
if (event.jball.yrel < -100)
|
|
{
|
|
pressed[offset + 2] = 0;
|
|
pressed[offset + 3] = 1;
|
|
}
|
|
if (event.jball.yrel > 100)
|
|
{
|
|
pressed[offset + 2] = 1;
|
|
pressed[offset + 3] = 0;
|
|
}
|
|
break;
|
|
|
|
case SDL_JOYAXISMOTION:
|
|
offset = AxisOffset[event.jaxis.which];
|
|
offset += event.jaxis.axis * 2;
|
|
if (offset >= (256 + 128 + 64)) break;
|
|
// printf("DEBUG axis offset: %d\n", offset);
|
|
if (event.jaxis.value < -16384)
|
|
{
|
|
pressed[offset + 1] = 1;
|
|
pressed[offset + 0] = 0;
|
|
}
|
|
else if (event.jaxis.value > 16384)
|
|
{
|
|
pressed[offset + 0] = 1;
|
|
pressed[offset + 1] = 0;
|
|
}
|
|
else
|
|
{
|
|
pressed[offset + 0] = 0;
|
|
pressed[offset + 1] = 0;
|
|
}
|
|
break;
|
|
|
|
case SDL_JOYBUTTONDOWN:
|
|
offset = ButtonOffset[event.jbutton.which];
|
|
offset += event.jbutton.button;
|
|
// printf("DEBUG button offset: %d\n", offset);
|
|
if (offset >= (256 + 128 + 64)) break;
|
|
pressed[offset] = 1;
|
|
break;
|
|
|
|
case SDL_JOYBUTTONUP:
|
|
offset = ButtonOffset[event.jbutton.which];
|
|
offset += event.jbutton.button;
|
|
// printf("DEBUG button offset: %d\n", offset);
|
|
if (offset >= (256 + 64)) break;
|
|
pressed[offset] = 0;
|
|
break;
|
|
case SDL_QUIT:
|
|
LinuxExit();
|
|
break;
|
|
#ifdef __OPENGL__
|
|
case SDL_VIDEORESIZE:
|
|
if(!GUIRESIZE[cvidmode]) {
|
|
surface = SDL_SetVideoMode(WindowWidth, WindowHeight,
|
|
BitDepth, surface->flags & ~SDL_RESIZABLE);
|
|
adjustMouseXScale();
|
|
adjustMouseYScale();
|
|
break;
|
|
}
|
|
WindowWidth = SurfaceX = event.resize.w;
|
|
WindowHeight = SurfaceY = event.resize.h;
|
|
surface = SDL_SetVideoMode(WindowWidth,
|
|
WindowHeight, BitDepth, surface->flags);
|
|
adjustMouseXScale();
|
|
adjustMouseYScale();
|
|
glViewport(0,0, WindowWidth, WindowHeight);
|
|
glFlush();
|
|
gl_clearwin();
|
|
break;
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void ProcessKeyBuf(int scancode)
|
|
{
|
|
int accept = 0;
|
|
int vkeyval = 0;
|
|
|
|
if (((scancode >= 'A') && (scancode <= 'Z')) ||
|
|
((scancode >= 'a') && (scancode <= 'z')) ||
|
|
(scancode == SDLK_ESCAPE) || (scancode == SDLK_SPACE) ||
|
|
(scancode == SDLK_BACKSPACE) || (scancode == SDLK_RETURN) ||
|
|
(scancode == SDLK_TAB))
|
|
{
|
|
accept = 1;
|
|
vkeyval = scancode;
|
|
}
|
|
if ((scancode >= '0') && (scancode <= '9'))
|
|
{
|
|
accept = 1;
|
|
vkeyval = scancode;
|
|
if (shiftptr)
|
|
{
|
|
switch (scancode)
|
|
{
|
|
case '1': vkeyval = '!'; break;
|
|
case '2': vkeyval = '@'; break;
|
|
case '3': vkeyval = '#'; break;
|
|
case '4': vkeyval = '$'; break;
|
|
case '5': vkeyval = '%'; break;
|
|
case '6': vkeyval = '^'; break;
|
|
case '7': vkeyval = '&'; break;
|
|
case '8': vkeyval = '*'; break;
|
|
case '9': vkeyval = '('; break;
|
|
case '0': vkeyval = ')'; break;
|
|
}
|
|
}
|
|
}
|
|
if ((scancode >= SDLK_KP0) && (scancode <= SDLK_KP9))
|
|
{
|
|
if (numlockptr)
|
|
{
|
|
accept = 1;
|
|
vkeyval = scancode - SDLK_KP0 + '0';
|
|
}
|
|
else
|
|
{
|
|
|
|
switch (scancode)
|
|
{
|
|
case SDLK_KP9: vkeyval = 256 + 73; accept = 1; break;
|
|
case SDLK_KP8: vkeyval = 256 + 72; accept = 1; break;
|
|
case SDLK_KP7: vkeyval = 256 + 71; accept = 1; break;
|
|
case SDLK_KP6: vkeyval = 256 + 77; accept = 1; break;
|
|
case SDLK_KP5: vkeyval = 256 + 76; accept = 1; break;
|
|
case SDLK_KP4: vkeyval = 256 + 75; accept = 1; break;
|
|
case SDLK_KP3: vkeyval = 256 + 81; accept = 1; break;
|
|
case SDLK_KP2: vkeyval = 256 + 80; accept = 1; break;
|
|
case SDLK_KP1: vkeyval = 256 + 79; accept = 1; break;
|
|
}
|
|
} // end no-numlock
|
|
} // end testing of keypad
|
|
if (!shiftptr)
|
|
{
|
|
switch (scancode)
|
|
{
|
|
case SDLK_MINUS: vkeyval = '-'; accept = 1; break;
|
|
case SDLK_EQUALS: vkeyval = '='; accept = 1; break;
|
|
case SDLK_LEFTBRACKET: vkeyval = '['; accept = 1; break;
|
|
case SDLK_RIGHTBRACKET: vkeyval = ']'; accept = 1; break;
|
|
case SDLK_SEMICOLON: vkeyval = ';'; accept = 1; break;
|
|
case SDLK_COMMA: vkeyval = ','; accept = 1; break;
|
|
case SDLK_PERIOD: vkeyval = '.'; accept = 1; break;
|
|
case SDLK_SLASH: vkeyval = '/'; accept = 1; break;
|
|
case SDLK_QUOTE: vkeyval = '`'; accept = 1; break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (scancode)
|
|
{
|
|
case SDLK_MINUS: vkeyval = '_'; accept = 1; break;
|
|
case SDLK_EQUALS: vkeyval = '+'; accept = 1; break;
|
|
case SDLK_LEFTBRACKET: vkeyval = '{'; accept = 1; break;
|
|
case SDLK_RIGHTBRACKET: vkeyval = '}'; accept = 1; break;
|
|
case SDLK_SEMICOLON: vkeyval = ':'; accept = 1; break;
|
|
case SDLK_QUOTE: vkeyval = '"'; accept = 1; break;
|
|
case SDLK_COMMA: vkeyval = '<'; accept = 1; break;
|
|
case SDLK_PERIOD: vkeyval = '>'; accept = 1; break;
|
|
case SDLK_SLASH: vkeyval = '?'; accept = 1; break;
|
|
case SDLK_BACKQUOTE: vkeyval = '~'; accept = 1; break;
|
|
case SDLK_BACKSLASH: vkeyval = '|'; accept = 1; break;
|
|
}
|
|
}
|
|
switch (scancode)
|
|
{
|
|
case SDLK_PAGEUP: vkeyval = 256 + 73; accept = 1; break;
|
|
case SDLK_UP: vkeyval = 256 + 72; accept = 1; break;
|
|
case SDLK_HOME: vkeyval = 256 + 71; accept = 1; break;
|
|
case SDLK_RIGHT: vkeyval = 256 + 77; accept = 1; break;
|
|
case SDLK_LEFT: vkeyval = 256 + 75; accept = 1; break;
|
|
case SDLK_PAGEDOWN: vkeyval = 256 + 81; accept = 1; break;
|
|
case SDLK_DOWN: vkeyval = 256 + 80; accept = 1; break;
|
|
case SDLK_END: vkeyval = 256 + 79; accept = 1; break;
|
|
case SDLK_KP_PLUS: vkeyval = '+'; accept = 1; break;
|
|
case SDLK_KP_MINUS: vkeyval = '-'; accept = 1; break;
|
|
case SDLK_KP_MULTIPLY: vkeyval = '*'; accept = 1; break;
|
|
case SDLK_KP_DIVIDE: vkeyval = '/'; accept = 1; break;
|
|
case SDLK_KP_PERIOD: vkeyval = '.'; accept = 1; break;
|
|
}
|
|
|
|
if (accept)
|
|
{
|
|
KeyBuffer[CurKeyPos] = vkeyval;
|
|
CurKeyPos++;
|
|
if (CurKeyPos == 16)
|
|
CurKeyPos = 0;
|
|
}
|
|
}
|
|
|
|
int InitSound(void)
|
|
{
|
|
SDL_AudioSpec wanted;
|
|
const int samptab[7] = { 1, 1, 2, 4, 2, 4, 4 };
|
|
const int freqtab[7] = { 8000, 11025, 22050, 44100, 16000, 32000, 48000 };
|
|
|
|
SDL_CloseAudio();
|
|
|
|
if (!SoundEnabled)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (Buffer)
|
|
free(Buffer);
|
|
Buffer = NULL;
|
|
Buffer_len = 0;
|
|
|
|
PrevSoundQuality = SoundQuality;
|
|
PrevStereoSound = StereoSound;
|
|
|
|
if (SoundQuality > 6)
|
|
SoundQuality = 1;
|
|
wanted.freq = freqtab[SoundQuality];
|
|
|
|
if (StereoSound)
|
|
{
|
|
wanted.channels = 2;
|
|
}
|
|
else
|
|
{
|
|
wanted.channels = 1;
|
|
}
|
|
|
|
wanted.samples = samptab[SoundQuality] * 128 * wanted.channels;
|
|
|
|
wanted.format = AUDIO_S16LSB;
|
|
wanted.userdata = NULL;
|
|
wanted.callback = UpdateSound;
|
|
|
|
if (SDL_OpenAudio(&wanted, &audiospec) < 0)
|
|
{
|
|
fprintf(stderr, "Sound init failed!\n");
|
|
fprintf(stderr, "freq: %d, channels: %d, samples: %d\n",
|
|
wanted.freq, wanted.channels, wanted.samples);
|
|
SoundEnabled = 0;
|
|
return FALSE;
|
|
}
|
|
SDL_PauseAudio(0);
|
|
|
|
Buffer_len = (audiospec.size * 2);
|
|
Buffer_len = (Buffer_len + 255) & ~255; /* Align to SPCSize */
|
|
Buffer = malloc(Buffer_len);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
int ReInitSound(void)
|
|
{
|
|
return InitSound();
|
|
}
|
|
|
|
BOOL InitJoystickInput(void)
|
|
{
|
|
int i, max_num_joysticks;
|
|
int num_axes, num_buttons, num_hats, num_balls;
|
|
int js_fail = 0;
|
|
|
|
for (i = 0; i < 5; i++)
|
|
JoystickInput[i] = NULL;
|
|
|
|
// If it is possible to use SDL_NumJoysticks
|
|
// before initialising SDL_INIT_JOYSTICK then
|
|
// this call can be replaced with SDL_InitSubSystem
|
|
SDL_InitSubSystem (SDL_INIT_JOYSTICK);
|
|
max_num_joysticks = SDL_NumJoysticks();
|
|
if (!max_num_joysticks)
|
|
{
|
|
printf("ZSNES could not find any joysticks.\n");
|
|
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
|
return FALSE;
|
|
}
|
|
SDL_JoystickEventState(SDL_ENABLE);
|
|
|
|
if (max_num_joysticks > 5) max_num_joysticks = 5;
|
|
|
|
for (i = 0; i < max_num_joysticks; i++)
|
|
{
|
|
JoystickInput[i] = SDL_JoystickOpen(i);
|
|
num_axes = SDL_JoystickNumAxes(JoystickInput[i]);
|
|
num_buttons = SDL_JoystickNumButtons(JoystickInput[i]);
|
|
num_hats = SDL_JoystickNumHats(JoystickInput[i]);
|
|
num_balls = SDL_JoystickNumBalls(JoystickInput[i]);
|
|
printf("Device %i %s\n", i, SDL_JoystickName(i));
|
|
printf(" %i axis, %i buttons, %i hats, %i balls\n",
|
|
num_axes, num_buttons, num_hats, num_balls);
|
|
|
|
if (js_fail)
|
|
{
|
|
printf("Warning: Joystick won't work.\n");
|
|
continue;
|
|
}
|
|
if (i == 0)
|
|
{
|
|
AxisOffset[0] = 256; // After key data
|
|
ButtonOffset[0] = AxisOffset[0] + num_axes * 2;
|
|
// printf("ButtonOffset %d\n", ButtonOffset[0]);
|
|
HatOffset[0] = ButtonOffset[0] + num_buttons;
|
|
// printf("HatOffset %d\n", HatOffset[0]);
|
|
BallOffset[0] = HatOffset[0] + num_hats * 4;
|
|
// printf("BallOffset %d\n", BallOffset[0]);
|
|
if ((BallOffset[0] + num_balls * 4) >= (256 + 128 + 64))
|
|
js_fail = 1;
|
|
}
|
|
else
|
|
{
|
|
AxisOffset[i] = BallOffset[i - 1] +
|
|
SDL_JoystickNumBalls(JoystickInput[i - 1]);
|
|
ButtonOffset[i] = AxisOffset[i] + num_axes * 2;
|
|
HatOffset[i] = ButtonOffset[i] + num_buttons;
|
|
BallOffset[i] = HatOffset[i] + num_hats * 4;
|
|
if ((BallOffset[i] + num_balls * 4) >= (256 + 128 + 64))
|
|
js_fail = 1;
|
|
|
|
}
|
|
if (js_fail)
|
|
{
|
|
printf("Warning: Too many buttons, axes, hats and/or Balls!\n");
|
|
printf("Warning: Joystick won't work fully.\n");
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL InitInput()
|
|
{
|
|
InitJoystickInput();
|
|
return TRUE;
|
|
}
|
|
|
|
int startgame(void)
|
|
{
|
|
int status;
|
|
|
|
if (sdl_state != vid_null)
|
|
{
|
|
if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER |
|
|
SDL_INIT_VIDEO) < 0)
|
|
{
|
|
fprintf(stderr, "Could not initialize SDL: %s", SDL_GetError());
|
|
return FALSE;
|
|
}
|
|
sdl_state = vid_none;
|
|
}
|
|
|
|
sem_sleep_rdy();
|
|
|
|
if (sdl_state == vid_soft) sw_end();
|
|
#ifdef __OPENGL__
|
|
else if (sdl_state == vid_gl) gl_end();
|
|
|
|
SDL_Init(SDL_INIT_VIDEO);
|
|
|
|
if (UseOpenGL)
|
|
{
|
|
status = gl_start(WindowWidth, WindowHeight, BitDepth, FullScreen);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
status = sw_start(WindowWidth, WindowHeight, BitDepth, FullScreen);
|
|
}
|
|
|
|
if (!status) return FALSE;
|
|
sdl_state = (UseOpenGL ? vid_gl : vid_soft);
|
|
return TRUE;
|
|
}
|
|
|
|
void LinuxExit(void)
|
|
{
|
|
if (sdl_state != vid_null)
|
|
{
|
|
SDL_WM_GrabInput(SDL_GRAB_OFF); // probably redundant
|
|
sem_sleep_die();
|
|
SDL_Quit();
|
|
}
|
|
exit(0);
|
|
}
|
|
|
|
void endgame()
|
|
{
|
|
LinuxExit();
|
|
}
|
|
|
|
|
|
void Start60HZ(void)
|
|
{
|
|
update_ticks_pc2 = UPDATE_TICKS_UDP;
|
|
if (romispal == 1)
|
|
{
|
|
update_ticks_pc = UPDATE_TICKS_GAMEPAL;
|
|
}
|
|
else
|
|
{
|
|
update_ticks_pc = UPDATE_TICKS_GAME;
|
|
}
|
|
|
|
start = sem_GetTicks();
|
|
start2 = sem_GetTicks();
|
|
T36HZEnabled = 0;
|
|
T60HZEnabled = 1;
|
|
}
|
|
|
|
void Stop60HZ(void)
|
|
{
|
|
T60HZEnabled = 0;
|
|
}
|
|
|
|
void Start36HZ(void)
|
|
{
|
|
update_ticks_pc2 = UPDATE_TICKS_UDP;
|
|
update_ticks_pc = UPDATE_TICKS_GUI;
|
|
|
|
start = sem_GetTicks();
|
|
start2 = sem_GetTicks();
|
|
T60HZEnabled = 0;
|
|
T36HZEnabled = 1;
|
|
}
|
|
|
|
void Stop36HZ(void)
|
|
{
|
|
T36HZEnabled = 0;
|
|
}
|
|
|
|
void init_hqNx(void)
|
|
{
|
|
DWORD color32;
|
|
DWORD *p;
|
|
int i, j, k, r, g, b, Y, u, v;
|
|
|
|
for(i = 0, p = BitConv32Ptr; i < 65536; i++, p++) {
|
|
color32=((i&0xF800)<<8)+
|
|
((i&0x07E0)<<5)+
|
|
((i&0x001F)<<3)+0xFF000000;
|
|
|
|
*p = color32;
|
|
}
|
|
|
|
for (i=0; i<32; i++)
|
|
for (j=0; j<64; j++)
|
|
for (k=0; k<32; k++) {
|
|
r = i << 3;
|
|
g = j << 2;
|
|
b = k << 3;
|
|
Y = (r + g + b) >> 2;
|
|
u = 128 + ((r - b) >> 2);
|
|
v = 128 + ((-r + 2*g -b)>>3);
|
|
RGBtoYUVPtr[(i << 11) + (j << 5) + k] = (Y<<16) + (u<<8) + v;
|
|
}
|
|
}
|
|
|
|
void initwinvideo(void)
|
|
{
|
|
DWORD newmode = 0;
|
|
|
|
init_hqNx();
|
|
|
|
if (CurMode != cvidmode)
|
|
{
|
|
CurMode = cvidmode;
|
|
newmode = 1;
|
|
WindowWidth = 256;
|
|
WindowHeight = 224;
|
|
|
|
FullScreen = GUIWFVID[cvidmode];
|
|
#ifdef __OPENGL__
|
|
UseOpenGL = 0;
|
|
if (cvidmode > 3)
|
|
UseOpenGL = 1;
|
|
#else
|
|
if (cvidmode > 3)
|
|
cvidmode = 2; // set it to the default 512x448 W
|
|
#endif
|
|
|
|
switch (cvidmode)
|
|
{
|
|
//case 0:
|
|
//case 4;
|
|
case 1:
|
|
default:
|
|
WindowWidth = 256;
|
|
WindowHeight = 224;
|
|
break;
|
|
case 2:
|
|
case 5:
|
|
case 18: // Variable
|
|
WindowWidth = 512;
|
|
WindowHeight = 448;
|
|
break;
|
|
case 3:
|
|
case 6:
|
|
case 7:
|
|
WindowWidth = 640;
|
|
WindowHeight = 480;
|
|
break;
|
|
case 8:
|
|
WindowWidth = 640;
|
|
WindowHeight = 576;
|
|
break;
|
|
case 9:
|
|
WindowWidth = 768;
|
|
WindowHeight = 672;
|
|
break;
|
|
case 10:
|
|
case 11:
|
|
WindowWidth = 800;
|
|
WindowHeight = 600;
|
|
break;
|
|
case 12:
|
|
WindowWidth = 896;
|
|
WindowHeight = 784;
|
|
break;
|
|
case 13:
|
|
case 14:
|
|
WindowWidth = 1024;
|
|
WindowHeight = 768;
|
|
break;
|
|
case 15:
|
|
WindowWidth = 1024;
|
|
WindowHeight = 896;
|
|
break;
|
|
case 16:
|
|
WindowWidth = 1280;
|
|
WindowHeight = 1024;
|
|
break;
|
|
case 17:
|
|
WindowWidth = 1600;
|
|
WindowHeight = 1200;
|
|
break;
|
|
}
|
|
adjustMouseXScale();
|
|
adjustMouseYScale();
|
|
}
|
|
|
|
if (startgame() != TRUE)
|
|
{
|
|
/* Exit zsnes if SDL could not be initialized */
|
|
if (sdl_state == vid_null)
|
|
LinuxExit ();
|
|
else
|
|
return;
|
|
}
|
|
|
|
if (newmode == 1)
|
|
clearwin();
|
|
|
|
if (FirstVid == 1)
|
|
{
|
|
FirstVid = 0;
|
|
|
|
InitSound();
|
|
InitInput();
|
|
}
|
|
|
|
if (((PrevStereoSound != StereoSound)
|
|
|| (PrevSoundQuality != SoundQuality)))
|
|
ReInitSound();
|
|
}
|
|
|
|
void CheckTimers(void)
|
|
{
|
|
int i;
|
|
|
|
//QueryPerformanceCounter((LARGE_INTEGER*)&end2);
|
|
end2 = sem_GetTicks();
|
|
|
|
while ((end2 - start2) >= update_ticks_pc2)
|
|
{
|
|
if (CounterA > 0)
|
|
CounterA--;
|
|
if (CounterB > 0)
|
|
CounterB--;
|
|
if (PacketCounter)
|
|
{
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
if (packettimeleft[i] > 0)
|
|
packettimeleft[i]--;
|
|
}
|
|
}
|
|
start2 += update_ticks_pc2;
|
|
}
|
|
|
|
if (T60HZEnabled)
|
|
{
|
|
//QueryPerformanceCounter((LARGE_INTEGER*)&end);
|
|
end = sem_GetTicks();
|
|
|
|
while ((end - start) >= update_ticks_pc)
|
|
{
|
|
/*
|
|
_asm{
|
|
pushad
|
|
call Game60hzcall
|
|
popad
|
|
}
|
|
*/
|
|
Game60hzcall();
|
|
SDL_SemPost(sem_frames);
|
|
start += update_ticks_pc;
|
|
}
|
|
}
|
|
|
|
if (T36HZEnabled)
|
|
{
|
|
//QueryPerformanceCounter((LARGE_INTEGER*)&end);
|
|
end = sem_GetTicks();
|
|
|
|
while ((end - start) >= update_ticks_pc)
|
|
{
|
|
/*
|
|
_asm{
|
|
pushad
|
|
call GUI36hzcall
|
|
popad
|
|
}
|
|
*/
|
|
GUI36hzcall();
|
|
start += update_ticks_pc;
|
|
}
|
|
}
|
|
}
|
|
|
|
//Why in the world did someone make this use signed values??? -Nach
|
|
void UpdateSound(void *userdata, Uint8 * stream, int len)
|
|
{
|
|
int left = Buffer_len - Buffer_head;
|
|
|
|
if (left < 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (left <= len)
|
|
{
|
|
memcpy(stream, &Buffer[Buffer_head], left);
|
|
stream += left;
|
|
len -= left;
|
|
Buffer_head = 0;
|
|
Buffer_fill -= left;
|
|
}
|
|
|
|
if (len)
|
|
{
|
|
memcpy(stream, &Buffer[Buffer_head], len);
|
|
Buffer_head += len;
|
|
Buffer_fill -= len;
|
|
}
|
|
}
|
|
|
|
void sem_sleep(void)
|
|
{
|
|
end = update_ticks_pc - (sem_GetTicks() - start) - .2f;
|
|
if (end>0.f) SDL_SemWaitTimeout(sem_frames, (int)end);
|
|
}
|
|
|
|
static SDL_Thread *sem_threadid = NULL;
|
|
static int sem_threadrun;
|
|
|
|
int sem_thread(void *param)
|
|
{
|
|
while (sem_threadrun)
|
|
{
|
|
if (T60HZEnabled)
|
|
{
|
|
SDL_SemPost(sem_frames);
|
|
usleep(romispal ? 2000 : 1000);
|
|
}
|
|
else
|
|
usleep(20000);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
void sem_sleep_rdy(void)
|
|
{
|
|
if (sem_frames) return;
|
|
sem_frames = SDL_CreateSemaphore(0);
|
|
sem_threadrun = 1;
|
|
sem_threadid = SDL_CreateThread(sem_thread, 0);
|
|
}
|
|
|
|
void sem_sleep_die(void)
|
|
{
|
|
if (sem_threadid)
|
|
{
|
|
sem_threadrun = 0;
|
|
SDL_WaitThread(sem_threadid, NULL);
|
|
sem_threadid = NULL;
|
|
}
|
|
if (sem_frames)
|
|
{
|
|
SDL_DestroySemaphore(sem_frames);
|
|
sem_frames = NULL;
|
|
}
|
|
}
|
|
|
|
void UpdateVFrame(void)
|
|
{
|
|
const int SPCSize = 256;
|
|
int i;
|
|
|
|
//Quick fix for GUI CPU usage
|
|
if (GUIOn || GUIOn2) usleep(6000);
|
|
|
|
CheckTimers();
|
|
Main_Proc();
|
|
|
|
/* Process sound */
|
|
|
|
/* take care of the things we left behind last time */
|
|
SDL_LockAudio();
|
|
while (Buffer_fill < Buffer_len) {
|
|
short *ptr = (short*)&Buffer[Buffer_tail];
|
|
|
|
SoundProcess();
|
|
|
|
for (i = 0; i < SPCSize; i++, ptr++)
|
|
{
|
|
if (T36HZEnabled)
|
|
{
|
|
*ptr = 0;
|
|
}
|
|
else
|
|
{
|
|
if (DSPBuffer[i] > 32767)
|
|
*ptr = 32767;
|
|
else if (DSPBuffer[i] < -32767)
|
|
*ptr = -32767;
|
|
else
|
|
*ptr = DSPBuffer[i];
|
|
}
|
|
}
|
|
|
|
Buffer_fill += SPCSize * 2;
|
|
Buffer_tail += SPCSize * 2;
|
|
if (Buffer_tail >= Buffer_len) Buffer_tail = 0;
|
|
}
|
|
SDL_UnlockAudio();
|
|
}
|
|
|
|
void clearwin()
|
|
{
|
|
/* If we're vid_null and we get here, there's a problem */
|
|
/* elsewhere - DDOI */
|
|
if (sdl_state == vid_none) return;
|
|
|
|
#ifdef __OPENGL__
|
|
if (UseOpenGL)
|
|
gl_clearwin();
|
|
else
|
|
#endif
|
|
sw_clearwin();
|
|
}
|
|
|
|
void drawscreenwin(void)
|
|
{
|
|
/* Just in case - DDOI */
|
|
if (sdl_state == vid_none) return;
|
|
|
|
#ifdef __OPENGL__
|
|
if (UseOpenGL)
|
|
gl_drawwin();
|
|
else
|
|
#endif
|
|
sw_drawwin();
|
|
}
|
|
|
|
int GetMouseX(void)
|
|
{
|
|
return ((int) MouseX);
|
|
}
|
|
int GetMouseY(void)
|
|
{
|
|
return ((int) MouseY);
|
|
}
|
|
|
|
int GetMouseMoveX(void)
|
|
{
|
|
// InputRead();
|
|
//SDL_GetRelativeMouseState(&MouseMove2X, NULL);
|
|
SDL_GetRelativeMouseState(&MouseMove2X, &MouseMove2Y);
|
|
return (MouseMove2X);
|
|
}
|
|
|
|
int GetMouseMoveY(void)
|
|
{
|
|
return (MouseMove2Y);
|
|
}
|
|
int GetMouseButton(void)
|
|
{
|
|
return ((int) MouseButton);
|
|
}
|
|
|
|
void SetMouseMinX(int MinX)
|
|
{
|
|
MouseMinX = MinX;
|
|
adjustMouseXScale();
|
|
}
|
|
void SetMouseMaxX(int MaxX)
|
|
{
|
|
MouseMaxX = MaxX;
|
|
adjustMouseXScale();
|
|
}
|
|
void SetMouseMinY(int MinY)
|
|
{
|
|
MouseMinY = MinY;
|
|
adjustMouseYScale();
|
|
}
|
|
void SetMouseMaxY(int MaxY)
|
|
{
|
|
MouseMaxY = MaxY;
|
|
adjustMouseYScale();
|
|
}
|
|
void SetMouseX(int X)
|
|
{
|
|
MouseX = X;
|
|
}
|
|
void SetMouseY(int Y)
|
|
{
|
|
MouseY = Y;
|
|
}
|
|
|
|
void GetLocalTime()
|
|
{
|
|
time_t current;
|
|
struct tm *timeptr;
|
|
|
|
time(¤t);
|
|
timeptr = localtime(¤t);
|
|
SystemTimewHour = timeptr->tm_hour;
|
|
SystemTimewMinute = timeptr->tm_min;
|
|
SystemTimewSecond = timeptr->tm_sec;
|
|
}
|
|
|
|
/* evul, maybe should use something other than constructor method */
|
|
void __attribute__ ((stdcall, constructor)) sem_StartTicks()
|
|
{
|
|
gettimeofday(&sem_start, NULL);
|
|
}
|
|
|
|
float sem_GetTicks()
|
|
{
|
|
struct timeval now;
|
|
float ticks;
|
|
|
|
gettimeofday(&now, NULL);
|
|
ticks=((float)(now.tv_sec-sem_start.tv_sec))*1000.f+((float)(now.tv_usec-sem_start.tv_usec))*.001f;
|
|
return(ticks);
|
|
}
|
|
|
|
|
|
|
|
//Introducing the secure browser opener for POSIX systems ;) -Nach
|
|
|
|
#include <sys/param.h>
|
|
#include <paths.h>
|
|
#include <grp.h>
|
|
|
|
#ifndef OPEN_MAX
|
|
#define OPEN_MAX 256
|
|
#endif
|
|
|
|
//C++ style code in C
|
|
#define bool unsigned char
|
|
#define true 1
|
|
#define false 0
|
|
|
|
//Taken from the secure programming cookbook, slightly modified
|
|
bool spc_drop_privileges() {
|
|
gid_t newgid = getgid(), oldgid = getegid();
|
|
uid_t newuid = getuid(), olduid = geteuid();
|
|
|
|
/* 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 (setregid(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);
|
|
}
|
|
|
|
void spc_sanitize_files() {
|
|
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++) close(fd);
|
|
|
|
/* Verify that the standard descriptors are open. If they're not, attempt to
|
|
* open them using /dev/null. If any are unsuccessful, abort.
|
|
*/
|
|
for (fd = 0; fd < 3; fd++)
|
|
if (fstat(fd, &st) == -1 && (errno != EBADF || !open_devnull(fd))) abort();
|
|
}
|
|
|
|
pid_t spc_fork() {
|
|
pid_t childpid;
|
|
|
|
if ((childpid = fork()) == -1) return -1;
|
|
|
|
//If this us the parent proccess nothing more to do
|
|
if (childpid != 0) return childpid;
|
|
|
|
//This is the child proccess
|
|
|
|
spc_sanitize_files();
|
|
|
|
/*
|
|
There actually is a bug here which I submitted to the authors of the book -Nach
|
|
|
|
The bug is as follows:
|
|
The parent returns the child proccess ID in event of success.
|
|
The child returns 0 on success if and only if it's spc_drop_privileges() call is successful.
|
|
It is possible that the parent will return with a pid > 0, while the child never returns
|
|
from spc_fork thus causing a programming error.
|
|
|
|
The function should be rewritten that the parent doesn't return till it knows if the
|
|
child is able to return or not. And then return -1 or the child pid.
|
|
|
|
For out purposes in ZSNES to launch a browser, this bug does not effect us. But
|
|
be careful if you copy this code to use somewhere else.
|
|
*/
|
|
if (!spc_drop_privileges()) //Failed to drop special privleges
|
|
{
|
|
exit(0);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void LaunchBrowser(char *browser)
|
|
{
|
|
char *arglist[] = { browser, "http://www.zsnes.com/", 0 };
|
|
execvp(browser, arglist);
|
|
}
|
|
|
|
void ZsnesPage()
|
|
{
|
|
if (spc_fork()) //If fork failed, or we are the parent
|
|
{
|
|
MouseX = 0;
|
|
MouseY = 0;
|
|
return;
|
|
}
|
|
|
|
//We are now the child proccess
|
|
|
|
//If any of these LaunchBrowser() calls return that means it failed and we should try the next one
|
|
LaunchBrowser("mozilla");
|
|
LaunchBrowser("mozilla-firefox");
|
|
LaunchBrowser("konqueror");
|
|
LaunchBrowser("lynx");
|
|
LaunchBrowser("links");
|
|
|
|
exit(0); //All browser launches failed, oh well
|
|
}
|
|
|