mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-11-06 04:52:16 +00:00
4209 lines
112 KiB
C
4209 lines
112 KiB
C
// Windows DIB/DirectDraw interface layer
|
|
// for the Build Engine
|
|
// by Jonathon Fowler (jonof@edgenetwk.com)
|
|
//
|
|
// This is all very ugly.
|
|
//
|
|
// Written for DirectX 6.0
|
|
|
|
#ifndef _WIN32
|
|
#error winlayer.c is for Windows only.
|
|
#endif
|
|
|
|
#define DIRECTINPUT_VERSION 0x0500
|
|
#define DIRECTDRAW_VERSION 0x0600
|
|
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
#include <ddraw.h>
|
|
#include <dinput.h>
|
|
#ifndef DIK_PAUSE
|
|
# define DIK_PAUSE 0xC5
|
|
#endif
|
|
#include <math.h>
|
|
|
|
#include "dxdidf.h" // comment this out if c_dfDI* is being reported as multiply defined
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <signal.h>
|
|
#include <stdarg.h>
|
|
|
|
#if defined(USE_OPENGL) && defined(POLYMOST)
|
|
#include "glbuild.h"
|
|
#endif
|
|
|
|
#include "compat.h"
|
|
#include "winlayer.h"
|
|
#include "pragmas.h"
|
|
#include "build.h"
|
|
#include "a.h"
|
|
#include "osd.h"
|
|
|
|
|
|
// undefine to restrict windowed resolutions to conventional sizes
|
|
#define ANY_WINDOWED_SIZE
|
|
|
|
int _buildargc = 0;
|
|
const char **_buildargv = NULL;
|
|
static char *argvbuf = NULL;
|
|
extern int app_main(int argc, const char *argv[]);
|
|
extern void app_crashhandler(void);
|
|
|
|
// Windows crud
|
|
static HINSTANCE hInstance = 0;
|
|
static HWND hWindow = 0;
|
|
#define WINDOW_STYLE (WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX)
|
|
#define WindowClass "buildapp"
|
|
static BOOL window_class_registered = FALSE;
|
|
static HANDLE instanceflag = NULL;
|
|
|
|
int backgroundidle = 1;
|
|
int is_vista = 0;
|
|
|
|
static WORD sysgamma[3][256];
|
|
extern int curbrightness, gammabrightness;
|
|
|
|
#if defined(USE_OPENGL) && defined(POLYMOST)
|
|
// OpenGL stuff
|
|
static HGLRC hGLRC = 0;
|
|
char nofog=0;
|
|
static char nogl=0;
|
|
#endif
|
|
|
|
static LPTSTR GetWindowsErrorMsg(DWORD code);
|
|
static const char * GetDDrawError(HRESULT code);
|
|
static const char * GetDInputError(HRESULT code);
|
|
static void ShowErrorBox(const char *m);
|
|
static void ShowDDrawErrorBox(const char *m, HRESULT r);
|
|
static void ShowDInputErrorBox(const char *m, HRESULT r);
|
|
static BOOL CheckWinVersion(void);
|
|
static LRESULT CALLBACK WndProcCallback(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
static BOOL InitDirectDraw(void);
|
|
static void UninitDirectDraw(void);
|
|
static int RestoreDirectDrawMode(void);
|
|
static void ReleaseDirectDrawSurfaces(void);
|
|
static BOOL InitDirectInput(void);
|
|
static void UninitDirectInput(void);
|
|
static void GetKeyNames(void);
|
|
static void AcquireInputDevices(char acquire, signed char device);
|
|
static void ProcessInputDevices(void);
|
|
static int SetupDirectDraw(int width, int height);
|
|
static void UninitDIB(void);
|
|
static int SetupDIB(int width, int height);
|
|
static void ReleaseOpenGL(void);
|
|
static void UninitOpenGL(void);
|
|
static int SetupOpenGL(int width, int height, int bitspp);
|
|
static BOOL RegisterWindowClass(void);
|
|
static BOOL CreateAppWindow(int modenum);
|
|
static void DestroyAppWindow(void);
|
|
static void SaveSystemColours(void);
|
|
static void SetBWSystemColours(void);
|
|
static void RestoreSystemColours(void);
|
|
static void ProcessMouse(void);
|
|
|
|
|
|
// video
|
|
static int desktopxdim=0,desktopydim=0,desktopbpp=0,modesetusing=-1;
|
|
int xres=-1, yres=-1, fullscreen=0, bpp=0, bytesperline=0, imageSize=0;
|
|
intptr_t frameplace=0;
|
|
int lockcount=0;
|
|
static int curvidmode = -1;
|
|
static int customxdim = 640, customydim = 480, custombpp = 8, customfs = 0;
|
|
static unsigned modeschecked=0;
|
|
unsigned maxrefreshfreq=60;
|
|
char modechange=1, repaintneeded=0;
|
|
char offscreenrendering=0;
|
|
int glcolourdepth=32;
|
|
char videomodereset = 0;
|
|
|
|
// input and events
|
|
char inputdevices=0;
|
|
char quitevent=0, appactive=1, realfs=0;
|
|
volatile int mousex=0, mousey=0, mouseb=0;
|
|
static unsigned int mousewheel[2] = { 0,0 };
|
|
#define MouseWheelFakePressTime (50) // getticks() is a 1000Hz timer, and the button press is faked for 100ms
|
|
int *joyaxis = NULL, joyb=0, *joyhat = NULL;
|
|
char joyisgamepad=0, joynumaxes=0, joynumbuttons=0, joynumhats=0;
|
|
|
|
static char taskswitching=1;
|
|
|
|
char keystatus[256], keyfifo[KEYFIFOSIZ], keyfifoplc, keyfifoend;
|
|
unsigned char keyasciififo[KEYFIFOSIZ], keyasciififoplc, keyasciififoend;
|
|
unsigned char remap[256];
|
|
int remapinit=0;
|
|
static unsigned char keynames[256][24];
|
|
static unsigned int lastKeyDown = 0;
|
|
static unsigned int lastKeyTime = 0;
|
|
|
|
void (*keypresscallback)(int,int) = 0;
|
|
void (*mousepresscallback)(int,int) = 0;
|
|
void (*joypresscallback)(int,int) = 0;
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
// MAIN CRAP
|
|
//=================================================================================================
|
|
|
|
|
|
//
|
|
// win_gethwnd() -- gets the window handle
|
|
//
|
|
int win_gethwnd(void)
|
|
{
|
|
return (int)hWindow;
|
|
}
|
|
|
|
|
|
//
|
|
// win_gethinstance() -- gets the application instance
|
|
//
|
|
int win_gethinstance(void)
|
|
{
|
|
return (int)hInstance;
|
|
}
|
|
|
|
|
|
//
|
|
// win_allowtaskswitching() -- captures/releases alt+tab hotkeys
|
|
//
|
|
void win_allowtaskswitching(int onf)
|
|
{
|
|
if (onf == taskswitching) return;
|
|
|
|
if (onf)
|
|
{
|
|
UnregisterHotKey(0,0);
|
|
UnregisterHotKey(0,1);
|
|
}
|
|
else
|
|
{
|
|
RegisterHotKey(0,0,MOD_ALT,VK_TAB);
|
|
RegisterHotKey(0,1,MOD_ALT|MOD_SHIFT,VK_TAB);
|
|
}
|
|
|
|
taskswitching = onf;
|
|
}
|
|
|
|
|
|
//
|
|
// win_checkinstance() -- looks for another instance of a Build app
|
|
//
|
|
int win_checkinstance(void)
|
|
{
|
|
if (!instanceflag) return 0;
|
|
return (WaitForSingleObject(instanceflag,0) == WAIT_TIMEOUT);
|
|
}
|
|
|
|
|
|
//
|
|
// wm_msgbox/wm_ynbox() -- window-manager-provided message boxes
|
|
//
|
|
int wm_msgbox(char *name, char *fmt, ...)
|
|
{
|
|
char buf[2048];
|
|
va_list va;
|
|
|
|
va_start(va,fmt);
|
|
vsprintf(buf,fmt,va);
|
|
va_end(va);
|
|
|
|
MessageBox(hWindow,buf,name,MB_OK|MB_TASKMODAL);
|
|
return 0;
|
|
}
|
|
int wm_ynbox(char *name, char *fmt, ...)
|
|
{
|
|
char buf[2048];
|
|
va_list va;
|
|
int r;
|
|
|
|
va_start(va,fmt);
|
|
vsprintf(buf,fmt,va);
|
|
va_end(va);
|
|
|
|
r = MessageBox((HWND)win_gethwnd(),buf,name,MB_YESNO|MB_TASKMODAL);
|
|
if (r==IDYES) return 1;
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// wm_setapptitle() -- changes the window title
|
|
//
|
|
void wm_setapptitle(char *name)
|
|
{
|
|
if (name)
|
|
{
|
|
Bstrncpy(apptitle, name, sizeof(apptitle)-1);
|
|
apptitle[ sizeof(apptitle)-1 ] = 0;
|
|
}
|
|
|
|
if (hWindow) SetWindowText(hWindow, apptitle);
|
|
startwin_settitle(apptitle);
|
|
}
|
|
|
|
//
|
|
// SignalHandler() -- called when we've sprung a leak
|
|
//
|
|
static void SignalHandler(int signum)
|
|
{
|
|
switch (signum)
|
|
{
|
|
case SIGSEGV:
|
|
printOSD("Fatal Signal caught: SIGSEGV. Bailing out.\n");
|
|
app_crashhandler();
|
|
uninitsystem();
|
|
if (stdout) fclose(stdout);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// WinMain() -- main Windows entry point
|
|
//
|
|
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
|
|
{
|
|
int r;
|
|
char *argp;
|
|
FILE *fp;
|
|
HDC hdc;
|
|
|
|
UNREFERENCED_PARAMETER(lpCmdLine);
|
|
UNREFERENCED_PARAMETER(nCmdShow);
|
|
|
|
hInstance = hInst;
|
|
|
|
if (CheckWinVersion() || hPrevInst)
|
|
{
|
|
MessageBox(0, "This application must be run under Windows 95/98/Me or Windows 2000/XP or better.",
|
|
apptitle, MB_OK|MB_ICONSTOP);
|
|
return -1;
|
|
}
|
|
|
|
hdc = GetDC(NULL);
|
|
r = GetDeviceCaps(hdc, BITSPIXEL);
|
|
ReleaseDC(NULL, hdc);
|
|
if (r < 8)
|
|
{
|
|
MessageBox(0, "This application requires a desktop colour depth of 256-colours or more.",
|
|
apptitle, MB_OK|MB_ICONSTOP);
|
|
return -1;
|
|
}
|
|
|
|
// carve up the commandline into more recognizable pieces
|
|
argvbuf = strdup(GetCommandLine());
|
|
_buildargc = 0;
|
|
if (argvbuf)
|
|
{
|
|
char quoted = 0, instring = 0, swallownext = 0;
|
|
char *p,*wp; int i;
|
|
for (p=wp=argvbuf; *p; p++)
|
|
{
|
|
if (*p == ' ')
|
|
{
|
|
if (instring && !quoted)
|
|
{
|
|
// end of a string
|
|
*(wp++) = 0;
|
|
instring = 0;
|
|
}
|
|
else if (instring)
|
|
{
|
|
*(wp++) = *p;
|
|
}
|
|
}
|
|
else if (*p == '"' && !swallownext)
|
|
{
|
|
if (instring && quoted)
|
|
{
|
|
// end of a string
|
|
if (p[1] == ' ')
|
|
{
|
|
*(wp++) = 0;
|
|
instring = 0;
|
|
quoted = 0;
|
|
}
|
|
else
|
|
{
|
|
quoted = 0;
|
|
}
|
|
}
|
|
else if (instring && !quoted)
|
|
{
|
|
quoted = 1;
|
|
}
|
|
else if (!instring)
|
|
{
|
|
instring = 1;
|
|
quoted = 1;
|
|
_buildargc++;
|
|
}
|
|
}
|
|
else if (*p == '\\' && p[1] == '"' && !swallownext)
|
|
{
|
|
swallownext = 1;
|
|
}
|
|
else
|
|
{
|
|
if (!instring) _buildargc++;
|
|
instring = 1;
|
|
*(wp++) = *p;
|
|
swallownext = 0;
|
|
}
|
|
}
|
|
*wp = 0;
|
|
|
|
_buildargv = (const char**)malloc(sizeof(char*)*_buildargc);
|
|
wp = argvbuf;
|
|
for (i=0; i<_buildargc; i++,wp++)
|
|
{
|
|
_buildargv[i] = wp;
|
|
while (*wp) wp++;
|
|
}
|
|
}
|
|
|
|
// pipe standard outputs to files
|
|
if ((argp = Bgetenv("BUILD_LOGSTDOUT")) != NULL)
|
|
if (!Bstrcasecmp(argp, "TRUE"))
|
|
{
|
|
fp = freopen("stdout.txt", "w", stdout);
|
|
if (!fp)
|
|
{
|
|
fp = fopen("stdout.txt", "w");
|
|
}
|
|
if (fp) setvbuf(fp, 0, _IONBF, 0);
|
|
*stdout = *fp;
|
|
*stderr = *fp;
|
|
}
|
|
|
|
#if defined(USE_OPENGL) && defined(POLYMOST)
|
|
if ((argp = Bgetenv("BUILD_NOFOG")) != NULL)
|
|
nofog = Batol(argp);
|
|
#endif
|
|
|
|
// install signal handlers
|
|
signal(SIGSEGV, SignalHandler);
|
|
|
|
if (RegisterWindowClass()) return -1;
|
|
|
|
#ifdef DISCLAIMER
|
|
MessageBox(0,
|
|
DISCLAIMER,
|
|
"Notice",
|
|
MB_OK|MB_ICONINFORMATION);
|
|
#endif
|
|
|
|
atexit(uninitsystem);
|
|
|
|
instanceflag = CreateSemaphore(NULL, 1,1, WindowClass);
|
|
|
|
startwin_open();
|
|
baselayer_init();
|
|
|
|
r = app_main(_buildargc, _buildargv);
|
|
|
|
fclose(stdout);
|
|
|
|
startwin_close();
|
|
if (instanceflag) CloseHandle(instanceflag);
|
|
|
|
if (argvbuf) free(argvbuf);
|
|
|
|
return r;
|
|
}
|
|
|
|
|
|
static int set_maxrefreshfreq(const osdfuncparm_t *parm)
|
|
{
|
|
int freq;
|
|
if (parm->numparms == 0)
|
|
{
|
|
if (maxrefreshfreq == 0)
|
|
OSD_Printf("\"maxrefreshfreq\" is \"No maximum\"\n");
|
|
else
|
|
OSD_Printf("\"maxrefreshfreq\" is \"%d\"\n",maxrefreshfreq);
|
|
return OSDCMD_OK;
|
|
}
|
|
if (parm->numparms != 1) return OSDCMD_SHOWHELP;
|
|
|
|
freq = Batol(parm->parms[0]);
|
|
if (freq < 0) return OSDCMD_SHOWHELP;
|
|
|
|
maxrefreshfreq = (unsigned)freq;
|
|
modeschecked = 0;
|
|
|
|
return OSDCMD_OK;
|
|
}
|
|
|
|
static int set_windowpos(const osdfuncparm_t *parm)
|
|
{
|
|
if (parm->numparms == 0)
|
|
{
|
|
OSD_Printf("\"r_windowpositioning\" is \"%d\"\n",windowpos);
|
|
return OSDCMD_OK;
|
|
}
|
|
if (parm->numparms != 1) return OSDCMD_SHOWHELP;
|
|
|
|
windowpos = Batol(parm->parms[0])>0;
|
|
OSD_Printf("r_windowpositioning %d\n",windowpos);
|
|
|
|
return OSDCMD_OK;
|
|
}
|
|
|
|
//
|
|
// initsystem() -- init systems
|
|
//
|
|
|
|
static void print_os_version(void)
|
|
{
|
|
OSVERSIONINFO osv;
|
|
const char *ver = NULL;
|
|
// I was going to call this 'windows_9x_is_awful', but I couldn't justify ever setting it to 0
|
|
int awful_windows_9x = 0;
|
|
|
|
osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
GetVersionEx(&osv);
|
|
|
|
switch (osv.dwPlatformId)
|
|
{
|
|
case VER_PLATFORM_WIN32_NT:
|
|
if (osv.dwMajorVersion == 5)
|
|
{
|
|
switch (osv.dwMinorVersion)
|
|
{
|
|
case 0:
|
|
ver = "2000";
|
|
break;
|
|
case 1:
|
|
ver = "XP";
|
|
break;
|
|
case 2:
|
|
ver = "Server 2003";
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
if (osv.dwMajorVersion == 6 && osv.dwMinorVersion == 0)
|
|
{
|
|
ver = "Vista";
|
|
is_vista = 1;
|
|
}
|
|
break;
|
|
|
|
case VER_PLATFORM_WIN32_WINDOWS:
|
|
awful_windows_9x = 1;
|
|
if (osv.dwMinorVersion < 10)
|
|
ver = "95";
|
|
else if (osv.dwMinorVersion < 90)
|
|
ver = "98";
|
|
else ver = "Me";
|
|
break;
|
|
|
|
default:
|
|
ver = "Unknown";
|
|
initprintf("OS: Unknown OS\n");
|
|
return;
|
|
}
|
|
|
|
if (ver != NULL)
|
|
{
|
|
initprintf("OS: Windows %s (Version %lu.%lu.%lu)\n", ver, osv.dwMajorVersion, osv.dwMinorVersion,
|
|
awful_windows_9x?osv.dwBuildNumber&0xffff:osv.dwBuildNumber);
|
|
if (osv.szCSDVersion[0])
|
|
initprintf(" - %s\n", osv.szCSDVersion);
|
|
}
|
|
}
|
|
|
|
|
|
int initsystem(void)
|
|
{
|
|
DEVMODE desktopmode;
|
|
|
|
initprintf("Initializing Windows DirectX/GDI system interface\n");
|
|
|
|
// get the desktop dimensions before anything changes them
|
|
ZeroMemory(&desktopmode, sizeof(DEVMODE));
|
|
desktopmode.dmSize = sizeof(DEVMODE);
|
|
EnumDisplaySettings(NULL,ENUM_CURRENT_SETTINGS,&desktopmode);
|
|
|
|
desktopxdim = desktopmode.dmPelsWidth;
|
|
desktopydim = desktopmode.dmPelsHeight;
|
|
desktopbpp = desktopmode.dmBitsPerPel;
|
|
|
|
if (desktopbpp <= 8)
|
|
// save the system colours
|
|
SaveSystemColours();
|
|
|
|
memset(curpalette, 0, sizeof(palette_t) * 256);
|
|
|
|
atexit(uninitsystem);
|
|
|
|
frameplace=0;
|
|
lockcount=0;
|
|
|
|
print_os_version();
|
|
|
|
#if defined(USE_OPENGL) && defined(POLYMOST)
|
|
if (loadgldriver(getenv("BUILD_GLDRV")))
|
|
{
|
|
initprintf("Failed loading OpenGL driver. GL modes will be unavailable.\n");
|
|
nogl = 1;
|
|
}
|
|
#endif
|
|
|
|
// try and start DirectDraw
|
|
if (InitDirectDraw())
|
|
initprintf("DirectDraw initialization failed. Fullscreen modes will be unavailable.\n");
|
|
|
|
OSD_RegisterFunction("maxrefreshfreq", "maxrefreshfreq: maximum display frequency to set for OpenGL Polymost modes (0=no maximum)", set_maxrefreshfreq);
|
|
OSD_RegisterFunction("r_windowpositioning", "r_windowpositioning: enable/disable window position memory", set_windowpos);
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// uninitsystem() -- uninit systems
|
|
//
|
|
void uninitsystem(void)
|
|
{
|
|
DestroyAppWindow();
|
|
|
|
startwin_close();
|
|
|
|
uninitinput();
|
|
uninittimer();
|
|
|
|
win_allowtaskswitching(1);
|
|
|
|
#if defined(USE_OPENGL) && defined(POLYMOST)
|
|
unloadgldriver();
|
|
#endif
|
|
}
|
|
|
|
|
|
//
|
|
// initprintf() -- prints a string to the intitialization window
|
|
//
|
|
void initprintf(const char *f, ...)
|
|
{
|
|
va_list va;
|
|
char buf[1024];
|
|
|
|
va_start(va, f);
|
|
Bvsnprintf(buf, 1024, f, va);
|
|
va_end(va);
|
|
OSD_Printf(buf);
|
|
startwin_puts(buf);
|
|
handleevents();
|
|
}
|
|
|
|
|
|
//
|
|
// debugprintf() -- sends a debug string to the debugger
|
|
//
|
|
void debugprintf(const char *f, ...)
|
|
{
|
|
#ifdef DEBUGGINGAIDS
|
|
va_list va;
|
|
char buf[1024];
|
|
|
|
if (!IsDebuggerPresent()) return;
|
|
|
|
va_start(va,f);
|
|
Bvsnprintf(buf, 1024, f, va);
|
|
va_end(va);
|
|
|
|
OutputDebugString(buf);
|
|
#else
|
|
UNREFERENCED_PARAMETER(f);
|
|
#endif
|
|
}
|
|
|
|
|
|
//
|
|
// handleevents() -- process the Windows message queue
|
|
// returns !0 if there was an important event worth checking (like quitting)
|
|
//
|
|
int handleevents(void)
|
|
{
|
|
int rv=0;
|
|
MSG msg;
|
|
|
|
//if (frameplace && fullscreen) printf("Offscreen buffer is locked!\n");
|
|
|
|
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
|
{
|
|
if (msg.message == WM_QUIT)
|
|
quitevent = 1;
|
|
|
|
if (startwin_idle((void*)&msg) > 0) continue;
|
|
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
ProcessInputDevices();
|
|
|
|
if (!appactive || quitevent) rv = -1;
|
|
|
|
sampletimer();
|
|
|
|
return rv;
|
|
}
|
|
|
|
inline void idle(void)
|
|
{
|
|
Sleep(1);
|
|
}
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
// INPUT (MOUSE/KEYBOARD/JOYSTICK?)
|
|
//=================================================================================================
|
|
|
|
#define KEYBOARD 0
|
|
#define MOUSE 1
|
|
#define JOYSTICK 2
|
|
#define NUM_INPUTS 3
|
|
|
|
static HMODULE hDInputDLL = NULL;
|
|
static LPDIRECTINPUTA lpDI = NULL;
|
|
static LPDIRECTINPUTDEVICE2A lpDID[NUM_INPUTS] = { NULL, NULL, NULL };
|
|
static BOOL bDInputInited = FALSE;
|
|
#define INPUT_BUFFER_SIZE 32
|
|
static GUID guidDevs[NUM_INPUTS];
|
|
|
|
static char devacquired[NUM_INPUTS] = { 0,0,0 };
|
|
static HANDLE inputevt[NUM_INPUTS] = {0,0,0};
|
|
static int joyblast=0;
|
|
static char volatile moustat = 0, mousegrab = 0;
|
|
HANDLE mousethread;
|
|
|
|
static struct
|
|
{
|
|
char *name;
|
|
LPDIRECTINPUTDEVICE2A *did;
|
|
const DIDATAFORMAT *df;
|
|
} devicedef[NUM_INPUTS] =
|
|
{
|
|
{ "keyboard", &lpDID[KEYBOARD], &c_dfDIKeyboard },
|
|
{ "mouse", &lpDID[MOUSE], &c_dfDIMouse },
|
|
{ "joystick", &lpDID[JOYSTICK], &c_dfDIJoystick }
|
|
};
|
|
static struct _joydef
|
|
{
|
|
const char *name;
|
|
unsigned ofs; // directinput 'dwOfs' value
|
|
} *axisdefs = NULL, *buttondefs = NULL, *hatdefs = NULL;
|
|
|
|
struct _joydevicefeature
|
|
{
|
|
unsigned int ofs;
|
|
const char *name;
|
|
};
|
|
struct _joydevicedefn
|
|
{
|
|
unsigned int devid; // is the value of DIDEVICEINSTANCE.guidProduct.Data1
|
|
int nfeatures;
|
|
struct _joydevicefeature *features;
|
|
};
|
|
|
|
// This is to give more realistic names to the buttons, axes, etc on a controller than
|
|
// those the driver reports. Curse inconsistency.
|
|
struct _joydevicefeature joyfeatures_C20A046D[] = // Logitech WingMan RumblePad USB
|
|
{
|
|
{ 0, "Left Stick X" }, { 4, "Left Stick Y" }, { 8, "Right Stick X" },
|
|
{ 20, "Right Stick Y" }, { 24, "Throttle" },
|
|
};
|
|
struct _joydevicefeature joyfeatures_C218046D[] = // Logitech RumblePad 2 USB
|
|
{
|
|
{ 0, "Left Stick X" }, { 4, "Left Stick Y" }, { 8, "Right Stick X" },
|
|
{ 20, "Right Stick Y" }, { 32, "D-Pad" }, { 48, "Button 1" },
|
|
{ 49, "Button 2" }, { 50, "Button 3" }, { 51, "Button 4" },
|
|
{ 52, "Button 5" }, { 53, "Button 6" }, { 54, "Button 7" },
|
|
{ 55, "Button 8" }, { 56, "Button 9" }, { 57, "Button 10" },
|
|
{ 58, "Left Stick Press" }, { 59, "Right Stick Press" },
|
|
};
|
|
#define featurecount(x) (sizeof(x)/sizeof(struct _joydevicefeature))
|
|
static struct _joydevicedefn *thisjoydef = NULL, joyfeatures[] =
|
|
{
|
|
{ 0xC20A046D, featurecount(joyfeatures_C20A046D), joyfeatures_C20A046D }, // Logitech WingMan RumblePad USB
|
|
{ 0xC218046D, featurecount(joyfeatures_C218046D), joyfeatures_C218046D }, // Logitech RumblePad 2 USB
|
|
};
|
|
#undef featurecount
|
|
|
|
// I don't see any pressing need to store the key-up events yet
|
|
#define SetKey(key,state) { \
|
|
keystatus[remap[key]] = state; \
|
|
if (state) { \
|
|
keyfifo[keyfifoend] = remap[key]; \
|
|
keyfifo[(keyfifoend+1)&(KEYFIFOSIZ-1)] = state; \
|
|
keyfifoend = ((keyfifoend+2)&(KEYFIFOSIZ-1)); \
|
|
} \
|
|
}
|
|
|
|
|
|
//
|
|
// initinput() -- init input system
|
|
//
|
|
int initinput(void)
|
|
{
|
|
int i;
|
|
moustat=0;
|
|
memset(keystatus, 0, sizeof(keystatus));
|
|
if (!remapinit)for (i=0;i<256;i++)remap[i]=i;remapinit=1;
|
|
keyfifoplc = keyfifoend = 0;
|
|
keyasciififoplc = keyasciififoend = 0;
|
|
|
|
inputdevices = 0;
|
|
joyisgamepad=0, joynumaxes=0, joynumbuttons=0, joynumhats=0;
|
|
|
|
if (InitDirectInput())
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// uninitinput() -- uninit input system
|
|
//
|
|
void uninitinput(void)
|
|
{
|
|
uninitmouse();
|
|
UninitDirectInput();
|
|
}
|
|
|
|
|
|
//
|
|
// bgetchar, bkbhit, bflushchars -- character-based input functions
|
|
//
|
|
unsigned char bgetchar(void)
|
|
{
|
|
unsigned char c;
|
|
if (keyasciififoplc == keyasciififoend) return 0;
|
|
c = keyasciififo[keyasciififoplc];
|
|
keyasciififoplc = ((keyasciififoplc+1)&(KEYFIFOSIZ-1));
|
|
//OSD_Printf("bgetchar %d, %d-%d\n",c,keyasciififoplc,keyasciififoend);
|
|
return c;
|
|
}
|
|
|
|
int bkbhit(void)
|
|
{
|
|
return (keyasciififoplc != keyasciififoend);
|
|
}
|
|
|
|
void bflushchars(void)
|
|
{
|
|
keyasciififoplc = keyasciififoend = 0;
|
|
}
|
|
|
|
|
|
//
|
|
// set{key|mouse|joy}presscallback() -- sets a callback which gets notified when keys are pressed
|
|
//
|
|
void setkeypresscallback(void (*callback)(int, int)) { keypresscallback = callback; }
|
|
void setmousepresscallback(void (*callback)(int, int)) { mousepresscallback = callback; }
|
|
void setjoypresscallback(void (*callback)(int, int)) { joypresscallback = callback; }
|
|
|
|
|
|
DWORD WINAPI MouseFunc()
|
|
{
|
|
while (moustat&&lpDID[MOUSE])
|
|
{
|
|
if (!appactive)Sleep(50);else
|
|
if ((WaitForSingleObject(inputevt[MOUSE], INFINITE)) == WAIT_OBJECT_0)
|
|
{
|
|
ProcessMouse();
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
//
|
|
// initmouse() -- init mouse input
|
|
//
|
|
int initmouse(void)
|
|
{
|
|
DWORD threadid;
|
|
|
|
if (moustat) return 0;
|
|
|
|
initprintf("Initializing mouse... ");
|
|
|
|
moustat=1;
|
|
mousethread = CreateThread
|
|
(
|
|
NULL,
|
|
0,
|
|
MouseFunc,
|
|
NULL,
|
|
CREATE_SUSPENDED,
|
|
&threadid
|
|
);
|
|
|
|
if (!mousethread)
|
|
{
|
|
initprintf("FAILED!\n");
|
|
return 0;
|
|
}
|
|
|
|
SetThreadPriority(mousethread, THREAD_PRIORITY_HIGHEST);
|
|
ResumeThread(mousethread);
|
|
initprintf("OK\n");
|
|
|
|
// grab input
|
|
grabmouse(1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// uninitmouse() -- uninit mouse input
|
|
//
|
|
void uninitmouse(void)
|
|
{
|
|
if (!moustat) return;
|
|
|
|
grabmouse(0);
|
|
moustat=mousegrab=0;
|
|
SetEvent(inputevt[MOUSE]);
|
|
if (WaitForSingleObject(mousethread, 300) == WAIT_OBJECT_0)
|
|
initprintf("DirectInput: Mouse thread has exited\n");
|
|
else
|
|
initprintf("DirectInput: Mouse thread failed to exit!\n");
|
|
}
|
|
|
|
|
|
//
|
|
// grabmouse() -- show/hide mouse cursor
|
|
//
|
|
void grabmouse(char a)
|
|
{
|
|
if (!moustat) return;
|
|
|
|
mousegrab = a;
|
|
AcquireInputDevices(a,MOUSE); // only release or grab the mouse
|
|
|
|
mousex = 0;
|
|
mousey = 0;
|
|
mouseb = 0;
|
|
}
|
|
|
|
|
|
//
|
|
// readmousexy() -- return mouse motion information
|
|
//
|
|
void readmousexy(int *x, int *y)
|
|
{
|
|
if (!moustat || !devacquired[MOUSE] || !mousegrab) { *x = *y = 0; return; }
|
|
*x = mousex;
|
|
*y = mousey;
|
|
mousex -= *x;
|
|
mousey -= *y;
|
|
}
|
|
|
|
|
|
//
|
|
// readmousebstatus() -- return mouse button information
|
|
//
|
|
void readmousebstatus(int *b)
|
|
{
|
|
if (!moustat || !devacquired[MOUSE] || !mousegrab) *b = 0;
|
|
else *b = mouseb;
|
|
}
|
|
|
|
|
|
//
|
|
// setjoydeadzone() -- sets the dead and saturation zones for the joystick
|
|
//
|
|
void setjoydeadzone(int axis, unsigned short dead, unsigned short satur)
|
|
{
|
|
DIPROPDWORD dipdw;
|
|
HRESULT result;
|
|
|
|
if (!lpDID[JOYSTICK]) return;
|
|
|
|
if (dead > 10000) dead = 10000;
|
|
if (satur > 10000) satur = 10000;
|
|
if (dead >= satur) dead = satur-100;
|
|
if (axis >= joynumaxes) return;
|
|
|
|
memset(&dipdw, 0, sizeof(dipdw));
|
|
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
|
|
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
|
if (axis < 0)
|
|
{
|
|
dipdw.diph.dwObj = 0;
|
|
dipdw.diph.dwHow = DIPH_DEVICE;
|
|
}
|
|
else
|
|
{
|
|
dipdw.diph.dwObj = axisdefs[axis].ofs;
|
|
dipdw.diph.dwHow = DIPH_BYOFFSET;
|
|
}
|
|
dipdw.dwData = dead;
|
|
|
|
result = IDirectInputDevice2_SetProperty(lpDID[JOYSTICK], DIPROP_DEADZONE, &dipdw.diph);
|
|
if FAILED(result)
|
|
{
|
|
//ShowDInputErrorBox("Failed setting joystick dead zone", result);
|
|
initprintf("Failed setting joystick dead zone: %s\n", GetDInputError(result));
|
|
return;
|
|
}
|
|
|
|
dipdw.dwData = satur;
|
|
|
|
result = IDirectInputDevice2_SetProperty(lpDID[JOYSTICK], DIPROP_SATURATION, &dipdw.diph);
|
|
if FAILED(result)
|
|
{
|
|
//ShowDInputErrorBox("Failed setting joystick saturation point", result);
|
|
initprintf("Failed setting joystick saturation point: %s\n", GetDInputError(result));
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// getjoydeadzone() -- gets the dead and saturation zones for the joystick
|
|
//
|
|
void getjoydeadzone(int axis, unsigned short *dead, unsigned short *satur)
|
|
{
|
|
DIPROPDWORD dipdw;
|
|
HRESULT result;
|
|
|
|
if (!dead || !satur) return;
|
|
if (!lpDID[JOYSTICK]) { *dead = *satur = 0; return; }
|
|
if (axis >= joynumaxes) { *dead = *satur = 0; return; }
|
|
|
|
memset(&dipdw, 0, sizeof(dipdw));
|
|
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
|
|
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
|
if (axis < 0)
|
|
{
|
|
dipdw.diph.dwObj = 0;
|
|
dipdw.diph.dwHow = DIPH_DEVICE;
|
|
}
|
|
else
|
|
{
|
|
dipdw.diph.dwObj = axisdefs[axis].ofs;
|
|
dipdw.diph.dwHow = DIPH_BYOFFSET;
|
|
}
|
|
|
|
result = IDirectInputDevice2_GetProperty(lpDID[JOYSTICK], DIPROP_DEADZONE, &dipdw.diph);
|
|
if FAILED(result)
|
|
{
|
|
//ShowDInputErrorBox("Failed getting joystick dead zone", result);
|
|
initprintf("Failed getting joystick dead zone: %s\n", GetDInputError(result));
|
|
return;
|
|
}
|
|
|
|
*dead = dipdw.dwData;
|
|
|
|
result = IDirectInputDevice2_GetProperty(lpDID[JOYSTICK], DIPROP_SATURATION, &dipdw.diph);
|
|
if FAILED(result)
|
|
{
|
|
//ShowDInputErrorBox("Failed getting joystick saturation point", result);
|
|
initprintf("Failed getting joystick saturation point: %s\n", GetDInputError(result));
|
|
return;
|
|
}
|
|
|
|
*satur = dipdw.dwData;
|
|
}
|
|
|
|
|
|
void releaseallbuttons(void)
|
|
{
|
|
int i;
|
|
|
|
if (mousepresscallback)
|
|
{
|
|
if (mouseb & 1) mousepresscallback(1, 0);
|
|
if (mouseb & 2) mousepresscallback(2, 0);
|
|
if (mouseb & 4) mousepresscallback(3, 0);
|
|
if (mouseb & 8) mousepresscallback(4, 0);
|
|
if (mousewheel[0]>0) mousepresscallback(5,0);
|
|
if (mousewheel[1]>0) mousepresscallback(6,0);
|
|
}
|
|
mousewheel[0]=mousewheel[1]=0;
|
|
mouseb = 0;
|
|
|
|
if (joypresscallback)
|
|
{
|
|
for (i=0;i<32;i++)
|
|
if (joyb & (1<<i)) joypresscallback(i+1, 0);
|
|
}
|
|
joyb = joyblast = 0;
|
|
|
|
for (i=0;i<256;i++)
|
|
{
|
|
//if (!keystatus[i]) continue;
|
|
//if (OSD_HandleKey(i, 0) != 0) {
|
|
OSD_HandleKey(i, 0);
|
|
SetKey(i, 0);
|
|
if (keypresscallback) keypresscallback(i, 0);
|
|
//}
|
|
}
|
|
lastKeyDown = lastKeyTime = 0;
|
|
}
|
|
|
|
|
|
//
|
|
// InitDirectInput() -- get DirectInput started
|
|
//
|
|
|
|
// device enumerator
|
|
static BOOL CALLBACK InitDirectInput_enum(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef)
|
|
{
|
|
const char *d;
|
|
|
|
UNREFERENCED_PARAMETER(pvRef);
|
|
|
|
#define COPYGUID(d,s) memcpy(&d,&s,sizeof(GUID))
|
|
|
|
switch (lpddi->dwDevType&0xff)
|
|
{
|
|
case DIDEVTYPE_KEYBOARD:
|
|
inputdevices |= (1<<KEYBOARD);
|
|
d = "KEYBOARD";
|
|
COPYGUID(guidDevs[KEYBOARD],lpddi->guidInstance);
|
|
break;
|
|
case DIDEVTYPE_MOUSE:
|
|
inputdevices |= (1<<MOUSE);
|
|
d = "MOUSE";
|
|
COPYGUID(guidDevs[MOUSE],lpddi->guidInstance);
|
|
break;
|
|
case DIDEVTYPE_JOYSTICK:
|
|
{
|
|
int i;
|
|
inputdevices |= (1<<JOYSTICK);
|
|
joyisgamepad = ((lpddi->dwDevType & (DIDEVTYPEJOYSTICK_GAMEPAD<<8)) != 0);
|
|
d = joyisgamepad ? "GAMEPAD" : "JOYSTICK";
|
|
COPYGUID(guidDevs[JOYSTICK],lpddi->guidInstance);
|
|
|
|
thisjoydef = NULL;
|
|
for (i=0; i<(int)(sizeof(joyfeatures)/sizeof(joyfeatures[0])); i++)
|
|
{
|
|
if (lpddi->guidProduct.Data1 == joyfeatures[i].devid)
|
|
{
|
|
thisjoydef = &joyfeatures[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Outputs the GUID of the joystick to the console
|
|
/*
|
|
initprintf("GUID = {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n",
|
|
lpddi->guidProduct.Data1,
|
|
lpddi->guidProduct.Data2, lpddi->guidProduct.Data3,
|
|
lpddi->guidProduct.Data4[0], lpddi->guidProduct.Data4[1],
|
|
lpddi->guidProduct.Data4[2], lpddi->guidProduct.Data4[3],
|
|
lpddi->guidProduct.Data4[4], lpddi->guidProduct.Data4[5],
|
|
lpddi->guidProduct.Data4[6], lpddi->guidProduct.Data4[7]
|
|
);
|
|
*/
|
|
}
|
|
break;
|
|
default:
|
|
d = "OTHER"; break;
|
|
}
|
|
|
|
initprintf(" * %s: %s\n", d, lpddi->tszProductName);
|
|
|
|
return DIENUM_CONTINUE;
|
|
}
|
|
|
|
static const char *joyfindnameforofs(int ofs)
|
|
{
|
|
int i;
|
|
if (!thisjoydef) return NULL;
|
|
for (i=0;i<thisjoydef->nfeatures;i++)
|
|
{
|
|
if (ofs == (int)thisjoydef->features[i].ofs)
|
|
return Bstrdup(thisjoydef->features[i].name);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static BOOL CALLBACK InitDirectInput_enumobjects(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef)
|
|
{
|
|
int *typecounts = (int*)pvRef;
|
|
|
|
if (lpddoi->dwType & DIDFT_AXIS)
|
|
{
|
|
//initprintf(" Axis: %s (dwOfs=%d)\n", lpddoi->tszName, lpddoi->dwOfs);
|
|
|
|
axisdefs[ typecounts[0] ].name = joyfindnameforofs(lpddoi->dwOfs);
|
|
if (!axisdefs[ typecounts[0] ].name)
|
|
axisdefs[ typecounts[0] ].name = Bstrdup(lpddoi->tszName);
|
|
axisdefs[ typecounts[0] ].ofs = lpddoi->dwOfs;
|
|
|
|
typecounts[0]++;
|
|
}
|
|
else if (lpddoi->dwType & DIDFT_BUTTON)
|
|
{
|
|
//initprintf(" Button: %s (dwOfs=%d)\n", lpddoi->tszName, lpddoi->dwOfs);
|
|
|
|
buttondefs[ typecounts[1] ].name = joyfindnameforofs(lpddoi->dwOfs);
|
|
if (!buttondefs[ typecounts[1] ].name)
|
|
buttondefs[ typecounts[1] ].name = Bstrdup(lpddoi->tszName);
|
|
buttondefs[ typecounts[1] ].ofs = lpddoi->dwOfs;
|
|
|
|
typecounts[1]++;
|
|
}
|
|
else if (lpddoi->dwType & DIDFT_POV)
|
|
{
|
|
//initprintf(" POV: %s (dwOfs=%d)\n", lpddoi->tszName, lpddoi->dwOfs);
|
|
|
|
hatdefs[ typecounts[2] ].name = joyfindnameforofs(lpddoi->dwOfs);
|
|
if (!hatdefs[ typecounts[2] ].name)
|
|
hatdefs[ typecounts[2] ].name = Bstrdup(lpddoi->tszName);
|
|
hatdefs[ typecounts[2] ].ofs = lpddoi->dwOfs;
|
|
|
|
typecounts[2]++;
|
|
}
|
|
|
|
return DIENUM_CONTINUE;
|
|
}
|
|
|
|
#define HorribleDInputDeath( x, y ) \
|
|
ShowDInputErrorBox(x,y); \
|
|
UninitDirectInput(); \
|
|
return TRUE
|
|
|
|
static BOOL InitDirectInput(void)
|
|
{
|
|
HRESULT result;
|
|
HRESULT(WINAPI *aDirectInputCreateA)(HINSTANCE, DWORD, LPDIRECTINPUTA *, LPUNKNOWN);
|
|
DIPROPDWORD dipdw;
|
|
LPDIRECTINPUTDEVICEA dev;
|
|
LPDIRECTINPUTDEVICE2A dev2;
|
|
DIDEVCAPS didc;
|
|
|
|
int devn;
|
|
|
|
if (bDInputInited) return FALSE;
|
|
|
|
initprintf("Initializing DirectInput...\n");
|
|
|
|
// load up the DirectInput DLL
|
|
if (!hDInputDLL)
|
|
{
|
|
initprintf(" - Loading DINPUT.DLL\n");
|
|
hDInputDLL = LoadLibrary("DINPUT.DLL");
|
|
if (!hDInputDLL)
|
|
{
|
|
ShowErrorBox("Error loading DINPUT.DLL");
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// get the pointer to DirectInputCreate
|
|
aDirectInputCreateA = (void *)GetProcAddress(hDInputDLL, "DirectInputCreateA");
|
|
if (!aDirectInputCreateA) ShowErrorBox("Error fetching DirectInputCreateA()");
|
|
|
|
// create a new DirectInput object
|
|
initprintf(" - Creating DirectInput object\n");
|
|
result = aDirectInputCreateA(hInstance, DIRECTINPUT_VERSION, &lpDI, NULL);
|
|
if FAILED(result) { HorribleDInputDeath("DirectInputCreateA() failed", result); }
|
|
else if (result != DI_OK) initprintf(" Created DirectInput object with warning: %s\n",GetDInputError(result));
|
|
|
|
// enumerate devices to make us look fancy
|
|
initprintf(" - Enumerating attached input devices\n");
|
|
inputdevices = 0;
|
|
result = IDirectInput_EnumDevices(lpDI, 0, InitDirectInput_enum, NULL, DIEDFL_ATTACHEDONLY);
|
|
if FAILED(result) { HorribleDInputDeath("Failed enumerating attached input devices", result); }
|
|
else if (result != DI_OK) initprintf(" Enumerated input devices with warning: %s\n",GetDInputError(result));
|
|
if (!(inputdevices & (1<<KEYBOARD)))
|
|
{
|
|
ShowErrorBox("No keyboard detected!");
|
|
UninitDirectInput();
|
|
return TRUE;
|
|
}
|
|
|
|
// ***
|
|
// create the devices
|
|
// ***
|
|
for (devn = 0; devn < NUM_INPUTS; devn++)
|
|
{
|
|
if ((inputdevices & (1<<devn)) == 0) continue;
|
|
*devicedef[devn].did = NULL;
|
|
|
|
initprintf(" - Creating %s device\n", devicedef[devn].name);
|
|
result = IDirectInput_CreateDevice(lpDI, &guidDevs[devn], &dev, NULL);
|
|
if FAILED(result) { HorribleDInputDeath("Failed creating device", result); }
|
|
else if (result != DI_OK) initprintf(" Created device with warning: %s\n",GetDInputError(result));
|
|
|
|
result = IDirectInputDevice_QueryInterface(dev, &IID_IDirectInputDevice2, (LPVOID *)&dev2);
|
|
IDirectInputDevice_Release(dev);
|
|
if FAILED(result) { HorribleDInputDeath("Failed querying DirectInput2 interface for device", result); }
|
|
else if (result != DI_OK) initprintf(" Queried IDirectInputDevice2 interface with warning: %s\n",GetDInputError(result));
|
|
|
|
result = IDirectInputDevice2_SetDataFormat(dev2, devicedef[devn].df);
|
|
if FAILED(result) { IDirectInputDevice_Release(dev2); HorribleDInputDeath("Failed setting data format", result); }
|
|
else if (result != DI_OK) initprintf(" Set data format with warning: %s\n",GetDInputError(result));
|
|
|
|
inputevt[devn] = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (inputevt[devn] == NULL)
|
|
{
|
|
IDirectInputDevice_Release(dev2);
|
|
ShowErrorBox("Couldn't create event object");
|
|
UninitDirectInput();
|
|
return TRUE;
|
|
}
|
|
|
|
result = IDirectInputDevice2_SetEventNotification(dev2, inputevt[devn]);
|
|
if FAILED(result) { IDirectInputDevice_Release(dev2); HorribleDInputDeath("Failed setting event object", result); }
|
|
else if (result != DI_OK) initprintf(" Set event object with warning: %s\n",GetDInputError(result));
|
|
|
|
IDirectInputDevice2_Unacquire(dev2);
|
|
|
|
memset(&dipdw, 0, sizeof(dipdw));
|
|
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
|
|
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
|
dipdw.diph.dwObj = 0;
|
|
dipdw.diph.dwHow = DIPH_DEVICE;
|
|
dipdw.dwData = INPUT_BUFFER_SIZE;
|
|
|
|
result = IDirectInputDevice2_SetProperty(dev2, DIPROP_BUFFERSIZE, &dipdw.diph);
|
|
if FAILED(result) { IDirectInputDevice_Release(dev2); HorribleDInputDeath("Failed setting buffering", result); }
|
|
else if (result != DI_OK) initprintf(" Set buffering with warning: %s\n",GetDInputError(result));
|
|
|
|
// set up device
|
|
if (devn == JOYSTICK)
|
|
{
|
|
int typecounts[3] = {0,0,0};
|
|
|
|
memset(&didc, 0, sizeof(didc));
|
|
didc.dwSize = sizeof(didc);
|
|
result = IDirectInputDevice2_GetCapabilities(dev2, &didc);
|
|
if FAILED(result) { IDirectInputDevice_Release(dev2); HorribleDInputDeath("Failed getting joystick capabilities", result); }
|
|
else if (result != DI_OK) initprintf(" Fetched joystick capabilities with warning: %s\n",GetDInputError(result));
|
|
|
|
joynumaxes = (char)didc.dwAxes;
|
|
joynumbuttons = min(32,(char)didc.dwButtons);
|
|
joynumhats = (char)didc.dwPOVs;
|
|
initprintf("Joystick has %d axes, %d buttons, and %d hat(s).\n",joynumaxes,joynumbuttons,joynumhats);
|
|
|
|
axisdefs = (struct _joydef *)Bcalloc(didc.dwAxes, sizeof(struct _joydef));
|
|
buttondefs = (struct _joydef *)Bcalloc(didc.dwButtons, sizeof(struct _joydef));
|
|
hatdefs = (struct _joydef *)Bcalloc(didc.dwPOVs, sizeof(struct _joydef));
|
|
|
|
joyaxis = (int *)Bcalloc(didc.dwAxes, sizeof(int));
|
|
joyhat = (int *)Bcalloc(didc.dwPOVs, sizeof(int));
|
|
|
|
result = IDirectInputDevice2_EnumObjects(dev2, InitDirectInput_enumobjects, (LPVOID)typecounts, DIDFT_ALL);
|
|
if FAILED(result) { IDirectInputDevice_Release(dev2); HorribleDInputDeath("Failed getting joystick features", result); }
|
|
else if (result != DI_OK) initprintf(" Fetched joystick features with warning: %s\n",GetDInputError(result));
|
|
}
|
|
|
|
*devicedef[devn].did = dev2;
|
|
}
|
|
|
|
GetKeyNames();
|
|
memset(devacquired, 0, sizeof(devacquired));
|
|
|
|
bDInputInited = TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// UninitDirectInput() -- clean up DirectInput
|
|
//
|
|
static void UninitDirectInput(void)
|
|
{
|
|
int devn;
|
|
int i;
|
|
|
|
if (bDInputInited) initprintf("Uninitializing DirectInput...\n");
|
|
|
|
AcquireInputDevices(0,-1);
|
|
|
|
if (axisdefs)
|
|
{
|
|
for (i=joynumaxes-1; i>=0; i--) if (axisdefs[i].name) free((void*)axisdefs[i].name);
|
|
free(axisdefs); axisdefs = NULL;
|
|
}
|
|
if (buttondefs)
|
|
{
|
|
for (i=joynumbuttons-1; i>=0; i--) if (buttondefs[i].name) free((void*)buttondefs[i].name);
|
|
free(buttondefs); buttondefs = NULL;
|
|
}
|
|
if (hatdefs)
|
|
{
|
|
for (i=joynumhats-1; i>=0; i--) if (hatdefs[i].name) free((void*)hatdefs[i].name);
|
|
free(hatdefs); hatdefs = NULL;
|
|
}
|
|
|
|
for (devn = 0; devn < NUM_INPUTS; devn++)
|
|
{
|
|
if (*devicedef[devn].did)
|
|
{
|
|
initprintf(" - Releasing %s device\n", devicedef[devn].name);
|
|
|
|
if (devn != JOYSTICK) IDirectInputDevice2_SetEventNotification(*devicedef[devn].did, NULL);
|
|
|
|
IDirectInputDevice2_Release(*devicedef[devn].did);
|
|
*devicedef[devn].did = NULL;
|
|
}
|
|
if (inputevt[devn])
|
|
{
|
|
CloseHandle(inputevt[devn]);
|
|
inputevt[devn] = NULL;
|
|
}
|
|
}
|
|
|
|
if (lpDI)
|
|
{
|
|
initprintf(" - Releasing DirectInput object\n");
|
|
IDirectInput_Release(lpDI);
|
|
lpDI = NULL;
|
|
}
|
|
|
|
if (hDInputDLL)
|
|
{
|
|
initprintf(" - Unloading DINPUT.DLL\n");
|
|
FreeLibrary(hDInputDLL);
|
|
hDInputDLL = NULL;
|
|
}
|
|
|
|
bDInputInited = FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// GetKeyNames() -- retrieves the names for all the keys on the keyboard
|
|
//
|
|
static void GetKeyNames(void)
|
|
{
|
|
int i;
|
|
DIDEVICEOBJECTINSTANCE key;
|
|
HRESULT res;
|
|
char tbuf[MAX_PATH];
|
|
|
|
memset(keynames,0,sizeof(keynames));
|
|
for (i=0;i<256;i++)
|
|
{
|
|
ZeroMemory(&key,sizeof(key));
|
|
key.dwSize = sizeof(DIDEVICEOBJECTINSTANCE);
|
|
|
|
res = IDirectInputDevice_GetObjectInfo(*devicedef[KEYBOARD].did, &key, i, DIPH_BYOFFSET);
|
|
if (FAILED(res)) continue;
|
|
|
|
CharToOem(key.tszName, tbuf);
|
|
strncpy((char *)keynames[i], tbuf, sizeof(keynames[i])-1);
|
|
}
|
|
}
|
|
|
|
const unsigned char *getkeyname(int num)
|
|
{
|
|
if ((unsigned)num >= 256) return NULL;
|
|
return keynames[num];
|
|
}
|
|
|
|
const unsigned char *getjoyname(int what, int num)
|
|
{
|
|
switch (what)
|
|
{
|
|
case 0: // axis
|
|
if ((unsigned)num > (unsigned)joynumaxes) return NULL;
|
|
return (unsigned char *)axisdefs[num].name;
|
|
|
|
case 1: // button
|
|
if ((unsigned)num > (unsigned)joynumbuttons) return NULL;
|
|
return (unsigned char *)buttondefs[num].name;
|
|
|
|
case 2: // hat
|
|
if ((unsigned)num > (unsigned)joynumhats) return NULL;
|
|
return (unsigned char *)hatdefs[num].name;
|
|
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// AcquireInputDevices() -- (un)acquires the input devices
|
|
//
|
|
static void AcquireInputDevices(char acquire, signed char device)
|
|
{
|
|
DWORD flags;
|
|
HRESULT result;
|
|
int i;
|
|
|
|
if (!bDInputInited) return;
|
|
if (!hWindow) return;
|
|
|
|
if (acquire)
|
|
{
|
|
// if (!appactive) return; // why acquire when inactive?
|
|
for (i=0; i<NUM_INPUTS; i++)
|
|
{
|
|
if (! *devicedef[i].did) continue;
|
|
if (device != -1 && i != device) continue; // don't touch other devices if only the mouse is wanted
|
|
else if (!mousegrab && i == MOUSE) continue; // don't grab the mouse if we don't want it grabbed
|
|
|
|
IDirectInputDevice2_Unacquire(*devicedef[i].did);
|
|
|
|
if (i == MOUSE/* && fullscreen*/) flags = DISCL_FOREGROUND|DISCL_EXCLUSIVE;
|
|
else flags = DISCL_FOREGROUND|DISCL_NONEXCLUSIVE;
|
|
|
|
result = IDirectInputDevice2_SetCooperativeLevel(*devicedef[i].did, hWindow, flags);
|
|
if (FAILED(result))
|
|
initprintf("IDirectInputDevice2_SetCooperativeLevel(%s): %s\n",
|
|
devicedef[i].name, GetDInputError(result));
|
|
|
|
if (SUCCEEDED(IDirectInputDevice2_Acquire(*devicedef[i].did)))
|
|
devacquired[i] = 1;
|
|
else
|
|
devacquired[i] = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
releaseallbuttons();
|
|
|
|
for (i=0; i<NUM_INPUTS; i++)
|
|
{
|
|
if (! *devicedef[i].did) continue;
|
|
if (device != -1 && i != device) continue; // don't touch other devices if only the mouse is wanted
|
|
|
|
IDirectInputDevice2_Unacquire(*devicedef[i].did);
|
|
|
|
result = IDirectInputDevice2_SetCooperativeLevel(*devicedef[i].did, hWindow, DISCL_FOREGROUND|DISCL_NONEXCLUSIVE);
|
|
if (FAILED(result))
|
|
initprintf("IDirectInputDevice2_SetCooperativeLevel(%s): %s\n",
|
|
devicedef[i].name, GetDInputError(result));
|
|
|
|
devacquired[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void ProcessMouse()
|
|
{
|
|
DWORD i;
|
|
unsigned t;
|
|
int result;
|
|
DIDEVICEOBJECTDATA didod[INPUT_BUFFER_SIZE];
|
|
DWORD dwElements = INPUT_BUFFER_SIZE;
|
|
|
|
while (1)
|
|
{
|
|
t = getticks();
|
|
if (!mousegrab) break;
|
|
result = IDirectInputDevice2_GetDeviceData(lpDID[MOUSE], sizeof(DIDEVICEOBJECTDATA),
|
|
(LPDIDEVICEOBJECTDATA)&didod, &dwElements, 0);
|
|
|
|
if (FAILED(result) || !dwElements)break;
|
|
|
|
if (result == DI_OK)
|
|
{
|
|
// process the mouse events
|
|
// mousex=0;
|
|
// mousey=0;
|
|
for (i=0; i<dwElements; i++)
|
|
{
|
|
switch (didod[i].dwOfs)
|
|
{
|
|
case DIMOFS_BUTTON0:
|
|
if (didod[i].dwData & 0x80) mouseb |= 1;
|
|
else mouseb &= ~1;
|
|
if (mousepresscallback)
|
|
mousepresscallback(1, (mouseb&1)==1);
|
|
break;
|
|
case DIMOFS_BUTTON1:
|
|
if (didod[i].dwData & 0x80) mouseb |= 2;
|
|
else mouseb &= ~2;
|
|
if (mousepresscallback)
|
|
mousepresscallback(2, (mouseb&2)==2);
|
|
break;
|
|
case DIMOFS_BUTTON2:
|
|
if (didod[i].dwData & 0x80) mouseb |= 4;
|
|
else mouseb &= ~4;
|
|
if (mousepresscallback)
|
|
mousepresscallback(3, (mouseb&4)==4);
|
|
break;
|
|
case DIMOFS_BUTTON3:
|
|
if (didod[i].dwData & 0x80) mouseb |= 8;
|
|
else mouseb &= ~8;
|
|
if (mousepresscallback)
|
|
mousepresscallback(4, (mouseb&8)==8);
|
|
break;
|
|
case DIMOFS_X:
|
|
mousex += (short)didod[i].dwData; break;
|
|
case DIMOFS_Y:
|
|
mousey += (short)didod[i].dwData; break;
|
|
case DIMOFS_Z:
|
|
if ((int)didod[i].dwData > 0) // wheel up
|
|
{
|
|
if (mousewheel[0] > 0 && mousepresscallback) mousepresscallback(5,0);
|
|
mousewheel[0] = t;
|
|
mouseb |= 16; if (mousepresscallback) mousepresscallback(5, 1);
|
|
}
|
|
else if ((int)didod[i].dwData < 0) // wheel down
|
|
{
|
|
if (mousewheel[1] > 0 && mousepresscallback) mousepresscallback(6,0);
|
|
mousewheel[1] = t;
|
|
mouseb |= 32; if (mousepresscallback) mousepresscallback(6, 1);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// ProcessInputDevices() -- processes the input devices
|
|
//
|
|
static void ProcessInputDevices(void)
|
|
{
|
|
DWORD i;
|
|
HRESULT result;
|
|
|
|
DIDEVICEOBJECTDATA didod[INPUT_BUFFER_SIZE];
|
|
DWORD dwElements = INPUT_BUFFER_SIZE;
|
|
DWORD ev;
|
|
unsigned t,u;
|
|
unsigned idevnums[NUM_INPUTS], numdevs = 0;
|
|
HANDLE waithnds[NUM_INPUTS];
|
|
|
|
for (t = 0; t < NUM_INPUTS; t++)
|
|
{
|
|
if (*devicedef[t].did&&t!=MOUSE)
|
|
{
|
|
result = IDirectInputDevice2_Poll(*devicedef[t].did);
|
|
if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED)
|
|
{
|
|
if (SUCCEEDED(IDirectInputDevice2_Acquire(*devicedef[t].did)))
|
|
{
|
|
devacquired[t] = 1;
|
|
IDirectInputDevice2_Poll(*devicedef[t].did);
|
|
}
|
|
else
|
|
{
|
|
devacquired[t] = 0;
|
|
}
|
|
}
|
|
|
|
if (devacquired[t])
|
|
{
|
|
waithnds[numdevs] = inputevt[t];
|
|
idevnums[numdevs] = t;
|
|
numdevs++;
|
|
}
|
|
}
|
|
}
|
|
|
|
t = getticks();
|
|
|
|
// do this here because we only want the wheel to signal once, but hold the state for a moment
|
|
if (mousegrab)
|
|
{
|
|
if (mousewheel[0] > 0 && t - mousewheel[0] > MouseWheelFakePressTime)
|
|
{
|
|
if (mousepresscallback) mousepresscallback(5,0);
|
|
mousewheel[0] = 0; mouseb &= ~16;
|
|
}
|
|
if (mousewheel[1] > 0 && t - mousewheel[1] > MouseWheelFakePressTime)
|
|
{
|
|
if (mousepresscallback) mousepresscallback(6,0);
|
|
mousewheel[1] = 0; mouseb &= ~32;
|
|
}
|
|
}
|
|
|
|
if (numdevs == 0) return; // nothing to do
|
|
|
|
// use event objects so that we can quickly get indication of when data is ready
|
|
// to be read and input events processed
|
|
ev = MsgWaitForMultipleObjects(numdevs, waithnds, FALSE, 0, 0);
|
|
if (/*(ev >= WAIT_OBJECT_0) &&*/ (ev < (WAIT_OBJECT_0+numdevs)))
|
|
{
|
|
switch (idevnums[ev - WAIT_OBJECT_0])
|
|
{
|
|
case KEYBOARD: // keyboard
|
|
if (!lpDID[KEYBOARD]) break;
|
|
result = IDirectInputDevice2_GetDeviceData(lpDID[KEYBOARD], sizeof(DIDEVICEOBJECTDATA),
|
|
(LPDIDEVICEOBJECTDATA)&didod, &dwElements, 0);
|
|
if (result == DI_OK)
|
|
{
|
|
DWORD k, numlockon = FALSE;
|
|
|
|
numlockon = (GetKeyState(VK_NUMLOCK) & 1);
|
|
|
|
// process the key events
|
|
for (i=0; i<dwElements; i++)
|
|
{
|
|
k = didod[i].dwOfs;
|
|
|
|
if (k == DIK_PAUSE) continue; // fucking pause
|
|
|
|
//if (IsDebuggerPresent() && k == DIK_F12) continue;
|
|
|
|
// hook in the osd
|
|
if (OSD_HandleKey(k, (didod[i].dwData & 0x80)) != 0)
|
|
{
|
|
SetKey(k, (didod[i].dwData & 0x80) == 0x80);
|
|
|
|
if (keypresscallback)
|
|
keypresscallback(k, (didod[i].dwData & 0x80) == 0x80);
|
|
}
|
|
|
|
if (((lastKeyDown & 0x7fffffffl) == k) && !(didod[i].dwData & 0x80))
|
|
lastKeyDown = 0;
|
|
else if (didod[i].dwData & 0x80)
|
|
{
|
|
lastKeyDown = k;
|
|
lastKeyTime = t;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case JOYSTICK: // joystick
|
|
if (!lpDID[JOYSTICK]) break;
|
|
result = IDirectInputDevice2_GetDeviceData(lpDID[JOYSTICK], sizeof(DIDEVICEOBJECTDATA),
|
|
(LPDIDEVICEOBJECTDATA)&didod, &dwElements, 0);
|
|
if (result == DI_OK)
|
|
{
|
|
int j;
|
|
|
|
for (i=0; i<dwElements; i++)
|
|
{
|
|
// check axes
|
|
for (j=0; j<joynumaxes; j++)
|
|
{
|
|
if (axisdefs[j].ofs != didod[i].dwOfs) continue;
|
|
joyaxis[j] = didod[i].dwData - 32767;
|
|
break;
|
|
}
|
|
if (j<joynumaxes) continue;
|
|
|
|
// check buttons
|
|
for (j=0; j<joynumbuttons; j++)
|
|
{
|
|
if (buttondefs[j].ofs != didod[i].dwOfs) continue;
|
|
if (didod[i].dwData & 0x80) joyb |= (1<<j);
|
|
else joyb &= ~(1<<j);
|
|
if (joypresscallback)
|
|
joypresscallback(j+1, (didod[i].dwData & 0x80)==0x80);
|
|
break;
|
|
}
|
|
if (j<joynumbuttons) continue;
|
|
|
|
// check hats
|
|
for (j=0; j<joynumhats; j++)
|
|
{
|
|
if (hatdefs[j].ofs != didod[i].dwOfs) continue;
|
|
joyhat[j] = didod[i].dwData;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
OSD_Printf("axes:");
|
|
for (i=0;i<joynumaxes;i++) OSD_Printf(" %d", joyaxis[i]);
|
|
OSD_Printf(" - buttons: %x - hats:", joyb);
|
|
for (i=0;i<joynumhats;i++) OSD_Printf(" %d", joyhat[i]);
|
|
OSD_Printf("\n");
|
|
*/
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// key repeat
|
|
// this is like this because the period of t is 1000ms
|
|
if (lastKeyDown > 0)
|
|
{
|
|
u = (1000 + t - lastKeyTime)%1000;
|
|
if ((u >= 250) && !(lastKeyDown&0x80000000l))
|
|
{
|
|
if (OSD_HandleKey(lastKeyDown, 1) != 0)
|
|
SetKey(lastKeyDown, 1);
|
|
lastKeyDown |= 0x80000000l;
|
|
lastKeyTime = t;
|
|
}
|
|
else if ((u >= 30) && (lastKeyDown&0x80000000l))
|
|
{
|
|
if (OSD_HandleKey(lastKeyDown&(0x7fffffffl), 1) != 0)
|
|
SetKey(lastKeyDown&(0x7fffffffl), 1);
|
|
lastKeyTime = t;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// ShowDInputErrorBox() -- shows an error message box for a DirectInput error
|
|
//
|
|
static void ShowDInputErrorBox(const char *m, HRESULT r)
|
|
{
|
|
TCHAR msg[1024];
|
|
|
|
wsprintf(msg, "%s: %s", m, GetDInputError(r));
|
|
MessageBox(0, msg, apptitle, MB_OK|MB_ICONSTOP);
|
|
}
|
|
|
|
|
|
//
|
|
// GetDInputError() -- stinking huge list of error messages since MS didn't want to include
|
|
// them in the DLL
|
|
//
|
|
static const char * GetDInputError(HRESULT code)
|
|
{
|
|
switch (code)
|
|
{
|
|
case DI_OK:
|
|
return "DI_OK";
|
|
case DI_BUFFEROVERFLOW:
|
|
return "DI_BUFFEROVERFLOW";
|
|
case DI_DOWNLOADSKIPPED:
|
|
return "DI_DOWNLOADSKIPPED";
|
|
case DI_EFFECTRESTARTED:
|
|
return "DI_EFFECTRESTARTED";
|
|
case DI_POLLEDDEVICE:
|
|
return "DI_POLLEDDEVICE";
|
|
case DI_TRUNCATED:
|
|
return "DI_TRUNCATED";
|
|
case DI_TRUNCATEDANDRESTARTED:
|
|
return "DI_TRUNCATEDANDRESTARTED";
|
|
case DIERR_ACQUIRED:
|
|
return "DIERR_ACQUIRED";
|
|
case DIERR_ALREADYINITIALIZED:
|
|
return "DIERR_ALREADYINITIALIZED";
|
|
case DIERR_BADDRIVERVER:
|
|
return "DIERR_BADDRIVERVER";
|
|
case DIERR_BETADIRECTINPUTVERSION:
|
|
return "DIERR_BETADIRECTINPUTVERSION";
|
|
case DIERR_DEVICEFULL:
|
|
return "DIERR_DEVICEFULL";
|
|
case DIERR_DEVICENOTREG:
|
|
return "DIERR_DEVICENOTREG";
|
|
case DIERR_EFFECTPLAYING:
|
|
return "DIERR_EFFECTPLAYING";
|
|
case DIERR_HASEFFECTS:
|
|
return "DIERR_HASEFFECTS";
|
|
case DIERR_GENERIC:
|
|
return "DIERR_GENERIC";
|
|
case DIERR_HANDLEEXISTS:
|
|
return "DIERR_HANDLEEXISTS";
|
|
case DIERR_INCOMPLETEEFFECT:
|
|
return "DIERR_INCOMPLETEEFFECT";
|
|
case DIERR_INPUTLOST:
|
|
return "DIERR_INPUTLOST";
|
|
case DIERR_INVALIDPARAM:
|
|
return "DIERR_INVALIDPARAM";
|
|
case DIERR_MOREDATA:
|
|
return "DIERR_MOREDATA";
|
|
case DIERR_NOAGGREGATION:
|
|
return "DIERR_NOAGGREGATION";
|
|
case DIERR_NOINTERFACE:
|
|
return "DIERR_NOINTERFACE";
|
|
case DIERR_NOTACQUIRED:
|
|
return "DIERR_NOTACQUIRED";
|
|
case DIERR_NOTBUFFERED:
|
|
return "DIERR_NOTBUFFERED";
|
|
case DIERR_NOTDOWNLOADED:
|
|
return "DIERR_NOTDOWNLOADED";
|
|
case DIERR_NOTEXCLUSIVEACQUIRED:
|
|
return "DIERR_NOTEXCLUSIVEACQUIRED";
|
|
case DIERR_NOTFOUND:
|
|
return "DIERR_NOTFOUND";
|
|
case DIERR_NOTINITIALIZED:
|
|
return "DIERR_NOTINITIALIZED";
|
|
case DIERR_OLDDIRECTINPUTVERSION:
|
|
return "DIERR_OLDDIRECTINPUTVERSION";
|
|
case DIERR_OUTOFMEMORY:
|
|
return "DIERR_OUTOFMEMORY";
|
|
case DIERR_UNSUPPORTED:
|
|
return "DIERR_UNSUPPORTED";
|
|
case E_PENDING:
|
|
return "E_PENDING";
|
|
default:
|
|
break;
|
|
}
|
|
return "Unknown error";
|
|
}
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
// TIMER
|
|
//=================================================================================================
|
|
|
|
static int64 timerfreq=0;
|
|
static int timerlastsample=0;
|
|
int timerticspersec=0;
|
|
static void (*usertimercallback)(void) = NULL;
|
|
|
|
// This timer stuff is all Ken's idea.
|
|
|
|
//
|
|
// installusertimercallback() -- set up a callback function to be called when the timer is fired
|
|
//
|
|
void (*installusertimercallback(void (*callback)(void)))(void)
|
|
{
|
|
void (*oldtimercallback)(void);
|
|
|
|
oldtimercallback = usertimercallback;
|
|
usertimercallback = callback;
|
|
|
|
return oldtimercallback;
|
|
}
|
|
|
|
|
|
//
|
|
// inittimer() -- initialize timer
|
|
//
|
|
int inittimer(int tickspersecond)
|
|
{
|
|
int64 t;
|
|
|
|
if (timerfreq) return 0; // already installed
|
|
|
|
// initprintf("Initializing timer\n");
|
|
|
|
// OpenWatcom seems to want us to query the value into a local variable
|
|
// instead of the global 'timerfreq' or else it gets pissed with an
|
|
// access violation
|
|
if (!QueryPerformanceFrequency((LARGE_INTEGER*)&t))
|
|
{
|
|
ShowErrorBox("Failed fetching timer frequency");
|
|
return -1;
|
|
}
|
|
timerfreq = t;
|
|
timerticspersec = tickspersecond;
|
|
QueryPerformanceCounter((LARGE_INTEGER*)&t);
|
|
timerlastsample = (int)(t*timerticspersec / timerfreq);
|
|
|
|
usertimercallback = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// uninittimer() -- shut down timer
|
|
//
|
|
void uninittimer(void)
|
|
{
|
|
if (!timerfreq) return;
|
|
|
|
timerfreq=0;
|
|
timerticspersec = 0;
|
|
}
|
|
|
|
//
|
|
// sampletimer() -- update totalclock
|
|
//
|
|
void sampletimer(void)
|
|
{
|
|
int64 i;
|
|
int n;
|
|
|
|
if (!timerfreq) return;
|
|
|
|
QueryPerformanceCounter((LARGE_INTEGER*)&i);
|
|
n = (int)(i*timerticspersec / timerfreq) - timerlastsample;
|
|
if (n>0)
|
|
{
|
|
totalclock += n;
|
|
timerlastsample += n;
|
|
}
|
|
|
|
if (usertimercallback) for (; n>0; n--) usertimercallback();
|
|
}
|
|
|
|
|
|
//
|
|
// getticks() -- returns the windows ticks count
|
|
//
|
|
unsigned int getticks(void)
|
|
{
|
|
int64 i;
|
|
if (timerfreq == 0) return 0;
|
|
QueryPerformanceCounter((LARGE_INTEGER*)&i);
|
|
return (unsigned int)(i*longlong(1000)/timerfreq);
|
|
}
|
|
|
|
|
|
//
|
|
// gettimerfreq() -- returns the number of ticks per second the timer is configured to generate
|
|
//
|
|
int gettimerfreq(void)
|
|
{
|
|
return timerticspersec;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
// VIDEO
|
|
//=================================================================================================
|
|
|
|
// DirectDraw objects
|
|
static HMODULE hDDrawDLL = NULL;
|
|
static LPDIRECTDRAW lpDD = NULL;
|
|
static LPDIRECTDRAWSURFACE lpDDSPrimary = NULL;
|
|
static LPDIRECTDRAWSURFACE lpDDSBack = NULL;
|
|
static char * lpOffscreen = NULL;
|
|
static LPDIRECTDRAWPALETTE lpDDPalette = NULL;
|
|
static BOOL bDDrawInited = FALSE;
|
|
static DWORD DDdwCaps = 0, DDdwCaps2 = 0;
|
|
|
|
// DIB stuff
|
|
static HDC hDC = NULL; // opengl shares this
|
|
static HDC hDCSection = NULL;
|
|
static HBITMAP hDIBSection = NULL;
|
|
static HPALETTE hPalette = NULL;
|
|
static VOID *lpPixels = NULL;
|
|
|
|
#define NUM_SYS_COLOURS 25
|
|
static int syscolouridx[NUM_SYS_COLOURS] =
|
|
{
|
|
COLOR_SCROLLBAR, // 1
|
|
COLOR_BACKGROUND,
|
|
COLOR_ACTIVECAPTION,
|
|
COLOR_INACTIVECAPTION,
|
|
COLOR_MENU,
|
|
COLOR_WINDOW,
|
|
COLOR_WINDOWFRAME,
|
|
COLOR_MENUTEXT,
|
|
COLOR_WINDOWTEXT,
|
|
COLOR_CAPTIONTEXT, // 10
|
|
COLOR_ACTIVEBORDER,
|
|
COLOR_INACTIVEBORDER,
|
|
COLOR_APPWORKSPACE,
|
|
COLOR_HIGHLIGHT,
|
|
COLOR_HIGHLIGHTTEXT,
|
|
COLOR_BTNFACE,
|
|
COLOR_BTNSHADOW,
|
|
COLOR_GRAYTEXT,
|
|
COLOR_BTNTEXT,
|
|
COLOR_INACTIVECAPTIONTEXT, // 20
|
|
COLOR_BTNHIGHLIGHT,
|
|
COLOR_3DDKSHADOW,
|
|
COLOR_3DLIGHT,
|
|
COLOR_INFOTEXT,
|
|
COLOR_INFOBK // 25
|
|
};
|
|
static DWORD syscolours[NUM_SYS_COLOURS];
|
|
static char system_colours_saved = 0, bw_colours_set = 0;
|
|
|
|
static int setgammaramp(WORD gt[3][256]);
|
|
static int getgammaramp(WORD gt[3][256]);
|
|
|
|
//
|
|
// checkvideomode() -- makes sure the video mode passed is legal
|
|
//
|
|
int checkvideomode(int *x, int *y, int c, int fs, int forced)
|
|
{
|
|
int i, nearest=-1, dx, dy, odx=9999, ody=9999;
|
|
|
|
getvalidmodes();
|
|
|
|
// fix up the passed resolution values to be multiples of 8
|
|
// and at least 320x200 or at most MAXXDIMxMAXYDIM
|
|
if (*x < 320) *x = 320;
|
|
if (*y < 200) *y = 200;
|
|
if (*x > MAXXDIM) *x = MAXXDIM;
|
|
if (*y > MAXYDIM) *y = MAXYDIM;
|
|
*x &= 0xfffffff8l;
|
|
|
|
for (i=0; i<validmodecnt; i++)
|
|
{
|
|
if (validmode[i].bpp != c) continue;
|
|
if (validmode[i].fs != fs) continue;
|
|
dx = klabs(validmode[i].xdim - *x);
|
|
dy = klabs(validmode[i].ydim - *y);
|
|
if (!(dx | dy)) // perfect match
|
|
{
|
|
nearest = i;
|
|
break;
|
|
}
|
|
if ((dx <= odx) && (dy <= ody))
|
|
{
|
|
nearest = i;
|
|
odx = dx; ody = dy;
|
|
}
|
|
}
|
|
|
|
#ifdef ANY_WINDOWED_SIZE
|
|
if (!forced && (fs&1) == 0 && (nearest < 0 || validmode[nearest].xdim!=*x || validmode[nearest].ydim!=*y))
|
|
{
|
|
// check the colour depth is recognised at the very least
|
|
for (i=0;i<validmodecnt;i++)
|
|
if (validmode[i].bpp == c)
|
|
return 0x7fffffffl;
|
|
return -1; // strange colour depth
|
|
}
|
|
#endif
|
|
|
|
if (nearest < 0)
|
|
{
|
|
// no mode that will match (eg. if no fullscreen modes)
|
|
return -1;
|
|
}
|
|
|
|
*x = validmode[nearest].xdim;
|
|
*y = validmode[nearest].ydim;
|
|
|
|
return nearest; // JBF 20031206: Returns the mode number
|
|
}
|
|
|
|
|
|
//
|
|
// setvideomode() -- set the video mode
|
|
//
|
|
int setvideomode(int x, int y, int c, int fs)
|
|
{
|
|
char i,inp[NUM_INPUTS];
|
|
int modenum;
|
|
|
|
if ((fs == fullscreen) && (x == xres) && (y == yres) && (c == bpp) &&
|
|
!videomodereset)
|
|
{
|
|
OSD_ResizeDisplay(xres,yres);
|
|
return 0;
|
|
}
|
|
|
|
modenum = checkvideomode(&x,&y,c,fs,0);
|
|
if (modenum < 0) return -1;
|
|
if (modenum == 0x7fffffff)
|
|
{
|
|
customxdim = x;
|
|
customydim = y;
|
|
custombpp = c;
|
|
customfs = fs;
|
|
}
|
|
|
|
for (i=0;i<NUM_INPUTS;i++) inp[i] = devacquired[i];
|
|
AcquireInputDevices(0,-1);
|
|
|
|
if (hWindow && gammabrightness)
|
|
{
|
|
setgammaramp(sysgamma);
|
|
gammabrightness = 0;
|
|
}
|
|
|
|
initprintf("Setting video mode %dx%d (%d-bit %s)\n",
|
|
x,y,c, ((fs&1) ? "fullscreen" : "windowed"));
|
|
|
|
if (CreateAppWindow(modenum)) return -1;
|
|
|
|
if (!gammabrightness)
|
|
{
|
|
float f = 1.0 + ((float)curbrightness / 10.0);
|
|
if (getgammaramp(sysgamma) >= 0) gammabrightness = 1;
|
|
if (gammabrightness && setgamma(f,f,f) < 0) gammabrightness = 0;
|
|
}
|
|
|
|
for (i=0;i<NUM_INPUTS;i++) if (inp[i]) AcquireInputDevices(1,i);
|
|
modechange=1;
|
|
videomodereset = 0;
|
|
//baselayer_onvideomodechange(c>8);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// getvalidmodes() -- figure out what video modes are available
|
|
//
|
|
#define ADDMODE(x,y,c,f,n) if (validmodecnt<MAXVALIDMODES) { \
|
|
validmode[validmodecnt].xdim=x; \
|
|
validmode[validmodecnt].ydim=y; \
|
|
validmode[validmodecnt].bpp=c; \
|
|
validmode[validmodecnt].fs=f; \
|
|
validmode[validmodecnt].extra=n; \
|
|
validmodecnt++; \
|
|
initprintf(" - %dx%d %d-bit %s\n", x, y, c, (f&1)?"fullscreen":"windowed"); \
|
|
}
|
|
|
|
#define CHECK(w,h) if ((w < maxx) && (h < maxy))
|
|
|
|
#if defined(USE_OPENGL) && defined(POLYMOST)
|
|
static void cdsenummodes(void)
|
|
{
|
|
DEVMODE dm;
|
|
int i = 0, j = 0;
|
|
|
|
struct { unsigned x,y,bpp,freq; } modes[MAXVALIDMODES];
|
|
int nmodes=0;
|
|
unsigned maxx = MAXXDIM, maxy = MAXYDIM;
|
|
|
|
|
|
ZeroMemory(&dm,sizeof(DEVMODE));
|
|
dm.dmSize = sizeof(DEVMODE);
|
|
while (EnumDisplaySettings(NULL, j, &dm))
|
|
{
|
|
if (dm.dmBitsPerPel > 8)
|
|
{
|
|
for (i=0;i<nmodes;i++)
|
|
{
|
|
if (modes[i].x == dm.dmPelsWidth
|
|
&& modes[i].y == dm.dmPelsHeight
|
|
&& modes[i].bpp == dm.dmBitsPerPel)
|
|
break;
|
|
}
|
|
if ((i==nmodes) ||
|
|
(dm.dmDisplayFrequency <= maxrefreshfreq && dm.dmDisplayFrequency > modes[i].freq && maxrefreshfreq > 0) ||
|
|
(dm.dmDisplayFrequency > modes[i].freq && maxrefreshfreq == 0))
|
|
{
|
|
if (i==nmodes) nmodes++;
|
|
|
|
modes[i].x = dm.dmPelsWidth;
|
|
modes[i].y = dm.dmPelsHeight;
|
|
modes[i].bpp = dm.dmBitsPerPel;
|
|
modes[i].freq = dm.dmDisplayFrequency;
|
|
}
|
|
}
|
|
|
|
j++;
|
|
ZeroMemory(&dm,sizeof(DEVMODE));
|
|
dm.dmSize = sizeof(DEVMODE);
|
|
}
|
|
|
|
for (i=0;i<nmodes;i++)
|
|
{
|
|
CHECK(modes[i].x, modes[i].y)
|
|
ADDMODE(modes[i].x, modes[i].y, modes[i].bpp, 1, modes[i].freq);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// mode enumerator
|
|
static HRESULT WINAPI getvalidmodes_enum(DDSURFACEDESC *ddsd, VOID *udata)
|
|
{
|
|
unsigned maxx = MAXXDIM, maxy = MAXYDIM;
|
|
|
|
UNREFERENCED_PARAMETER(udata);
|
|
|
|
if (ddsd->ddpfPixelFormat.dwRGBBitCount == 8)
|
|
{
|
|
CHECK(ddsd->dwWidth, ddsd->dwHeight)
|
|
ADDMODE(ddsd->dwWidth, ddsd->dwHeight, ddsd->ddpfPixelFormat.dwRGBBitCount, 1,-1);
|
|
}
|
|
|
|
return(DDENUMRET_OK);
|
|
}
|
|
|
|
static int sortmodes(const struct validmode_t *a, const struct validmode_t *b)
|
|
{
|
|
int x;
|
|
|
|
if ((x = a->fs - b->fs) != 0) return x;
|
|
if ((x = a->bpp - b->bpp) != 0) return x;
|
|
if ((x = a->xdim - b->xdim) != 0) return x;
|
|
if ((x = a->ydim - b->ydim) != 0) return x;
|
|
|
|
return 0;
|
|
}
|
|
void getvalidmodes(void)
|
|
{
|
|
static int defaultres[][2] =
|
|
{
|
|
{1280,1024},{1280,960},{1152,864},{1024,768},{800,600},{640,480},
|
|
{640,400},{512,384},{480,360},{400,300},{320,240},{320,200},{0,0}
|
|
};
|
|
int cdepths[2] = { 8, 0 };
|
|
int i, j, maxx=0, maxy=0;
|
|
HRESULT result;
|
|
|
|
#if defined(USE_OPENGL) && defined(POLYMOST)
|
|
if (desktopbpp > 8) cdepths[1] = desktopbpp;
|
|
#endif
|
|
|
|
if (modeschecked) return;
|
|
|
|
validmodecnt=0;
|
|
initprintf("Detecting video modes:\n");
|
|
|
|
if (bDDrawInited)
|
|
{
|
|
// if DirectDraw initialization didn't fail enumerate fullscreen modes
|
|
|
|
result = IDirectDraw_EnumDisplayModes(lpDD, 0, NULL, 0, getvalidmodes_enum);
|
|
if (result != DD_OK)
|
|
{
|
|
initprintf("Unable to enumerate fullscreen modes. Using default list.\n");
|
|
for (j=0; j < 2; j++)
|
|
{
|
|
if (cdepths[j] == 0) continue;
|
|
for (i=0; defaultres[i][0]; i++)
|
|
ADDMODE(defaultres[i][0],defaultres[i][1],cdepths[j],1,-1)
|
|
}
|
|
}
|
|
}
|
|
#if defined(USE_OPENGL) && defined(POLYMOST)
|
|
cdsenummodes();
|
|
#endif
|
|
|
|
// windowed modes cant be bigger than the current desktop resolution
|
|
maxx = desktopxdim-1;
|
|
maxy = desktopydim-1;
|
|
|
|
// add windowed modes next
|
|
for (j=0; j < 2; j++)
|
|
{
|
|
if (cdepths[j] == 0) continue;
|
|
for (i=0; defaultres[i][0]; i++)
|
|
CHECK(defaultres[i][0],defaultres[i][1])
|
|
ADDMODE(defaultres[i][0],defaultres[i][1],cdepths[j],0,-1)
|
|
}
|
|
|
|
qsort((void*)validmode, validmodecnt, sizeof(struct validmode_t), (int(*)(const void*,const void*))sortmodes);
|
|
|
|
modeschecked=1;
|
|
}
|
|
|
|
#undef CHECK
|
|
#undef ADDMODE
|
|
|
|
|
|
//
|
|
// resetvideomode() -- resets the video system
|
|
//
|
|
void resetvideomode(void)
|
|
{
|
|
videomodereset = 1;
|
|
modeschecked = 0;
|
|
}
|
|
|
|
|
|
//
|
|
// begindrawing() -- locks the framebuffer for drawing
|
|
//
|
|
void begindrawing(void)
|
|
{
|
|
int i,j;
|
|
|
|
if (bpp > 8)
|
|
{
|
|
if (offscreenrendering) return;
|
|
frameplace = 0;
|
|
bytesperline = 0;
|
|
imageSize = 0;
|
|
modechange = 0;
|
|
return;
|
|
}
|
|
|
|
if (lockcount++ > 0)
|
|
return; // already locked
|
|
|
|
if (offscreenrendering) return;
|
|
|
|
if (!fullscreen)
|
|
{
|
|
frameplace = (intptr_t)lpPixels;
|
|
}
|
|
else
|
|
{
|
|
frameplace = (intptr_t)lpOffscreen;
|
|
}
|
|
|
|
if (!modechange) return;
|
|
|
|
if (!fullscreen)
|
|
{
|
|
bytesperline = xres|4;
|
|
}
|
|
else
|
|
{
|
|
bytesperline = xres|1;
|
|
}
|
|
|
|
imageSize = bytesperline*yres;
|
|
setvlinebpl(bytesperline);
|
|
|
|
j = 0;
|
|
for (i=0;i<=ydim;i++) ylookup[i] = j, j += bytesperline;
|
|
modechange=0;
|
|
}
|
|
|
|
|
|
//
|
|
// enddrawing() -- unlocks the framebuffer
|
|
//
|
|
void enddrawing(void)
|
|
{
|
|
if (bpp > 8)
|
|
{
|
|
if (!offscreenrendering) frameplace = 0;
|
|
return;
|
|
}
|
|
|
|
if (!frameplace) return;
|
|
if (lockcount > 1) { lockcount--; return; }
|
|
if (!offscreenrendering) frameplace = 0;
|
|
lockcount = 0;
|
|
}
|
|
|
|
|
|
//
|
|
// showframe() -- update the display
|
|
//
|
|
void showframe(int w)
|
|
{
|
|
HRESULT result;
|
|
DDSURFACEDESC ddsd;
|
|
char *p,*q;
|
|
int i,j;
|
|
|
|
#if defined(USE_OPENGL) && defined(POLYMOST)
|
|
if (bpp > 8)
|
|
{
|
|
if (palfadedelta)
|
|
{
|
|
bglMatrixMode(GL_PROJECTION);
|
|
bglPushMatrix();
|
|
bglLoadIdentity();
|
|
bglMatrixMode(GL_MODELVIEW);
|
|
bglPushMatrix();
|
|
bglLoadIdentity();
|
|
|
|
bglDisable(GL_DEPTH_TEST);
|
|
bglDisable(GL_ALPHA_TEST);
|
|
bglDisable(GL_TEXTURE_2D);
|
|
|
|
bglEnable(GL_BLEND);
|
|
bglColor4ub(palfadergb.r, palfadergb.g, palfadergb.b, palfadedelta);
|
|
|
|
bglBegin(GL_QUADS);
|
|
bglVertex2i(-1, -1);
|
|
bglVertex2i(1, -1);
|
|
bglVertex2i(1, 1);
|
|
bglVertex2i(-1, 1);
|
|
bglEnd();
|
|
|
|
bglMatrixMode(GL_MODELVIEW);
|
|
bglPopMatrix();
|
|
bglMatrixMode(GL_PROJECTION);
|
|
bglPopMatrix();
|
|
}
|
|
|
|
bwglSwapBuffers(hDC);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
w = 1; // wait regardless. ken thinks it's better to do so.
|
|
|
|
if (offscreenrendering) return;
|
|
|
|
if (lockcount)
|
|
{
|
|
initprintf("Frame still locked %d times when showframe() called.\n", lockcount);
|
|
while (lockcount) enddrawing();
|
|
}
|
|
|
|
if (!fullscreen)
|
|
{
|
|
BitBlt(hDC, 0, 0, xres, yres, hDCSection, 0, 0, SRCCOPY);
|
|
}
|
|
else
|
|
{
|
|
if (!w)
|
|
{
|
|
if ((result = IDirectDrawSurface_GetBltStatus(lpDDSBack, DDGBS_CANBLT)) == DDERR_WASSTILLDRAWING)
|
|
return;
|
|
|
|
if ((result = IDirectDrawSurface_GetFlipStatus(lpDDSPrimary, DDGFS_CANFLIP)) == DDERR_WASSTILLDRAWING)
|
|
return;
|
|
}
|
|
|
|
// lock the backbuffer surface
|
|
memset(&ddsd, 0, sizeof(ddsd));
|
|
ddsd.dwSize = sizeof(ddsd);
|
|
|
|
result = IDirectDrawSurface_Lock(lpDDSBack, NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_NOSYSLOCK | DDLOCK_WAIT, NULL);
|
|
if (result == DDERR_SURFACELOST)
|
|
{
|
|
if (!appactive)
|
|
return; // not in a position to restore display anyway
|
|
|
|
IDirectDrawSurface_Restore(lpDDSPrimary);
|
|
result = IDirectDrawSurface_Lock(lpDDSBack, NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_NOSYSLOCK | DDLOCK_WAIT, NULL);
|
|
}
|
|
if (result != DD_OK)
|
|
{
|
|
if (result != DDERR_WASSTILLDRAWING)
|
|
initprintf("Failed locking back-buffer surface: %s\n", GetDDrawError(result));
|
|
return;
|
|
}
|
|
|
|
// copy each scanline
|
|
p = (char *)ddsd.lpSurface;
|
|
q = (char *)lpOffscreen;
|
|
j = xres >> 2;
|
|
|
|
for (i=0; i<yres; i++, p+=ddsd.lPitch, q+=bytesperline)
|
|
copybuf(q,p,j);
|
|
|
|
// unlock the backbuffer surface
|
|
result = IDirectDrawSurface_Unlock(lpDDSBack, NULL);
|
|
if (result != DD_OK)
|
|
{
|
|
initprintf("Failed unlocking back-buffer surface: %s\n", GetDDrawError(result));
|
|
return;
|
|
}
|
|
|
|
// flip the chain
|
|
result = IDirectDrawSurface_Flip(lpDDSPrimary, NULL, w?DDFLIP_WAIT:0);
|
|
if (result == DDERR_SURFACELOST)
|
|
{
|
|
if (!appactive)
|
|
return; // not in a position to restore display anyway
|
|
IDirectDrawSurface_Restore(lpDDSPrimary);
|
|
result = IDirectDrawSurface_Flip(lpDDSPrimary, NULL, w?DDFLIP_WAIT:0);
|
|
}
|
|
if (result != DD_OK)
|
|
{
|
|
if (result != DDERR_WASSTILLDRAWING)
|
|
initprintf("IDirectDrawSurface_Flip(): %s\n", GetDDrawError(result));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// setpalette() -- set palette values
|
|
// New behaviour: curpalettefaded is the live palette, and any changes this function
|
|
// makes are done to it and not the base palette.
|
|
//
|
|
int setpalette(int start, int num, char *dapal)
|
|
{
|
|
int i, n;
|
|
HRESULT result;
|
|
RGBQUAD *rgb;
|
|
//HPALETTE hPalPrev;
|
|
|
|
struct logpal
|
|
{
|
|
WORD palVersion;
|
|
WORD palNumEntries;
|
|
PALETTEENTRY palPalEntry[256];
|
|
} lpal;
|
|
|
|
UNREFERENCED_PARAMETER(dapal);
|
|
|
|
copybuf(curpalettefaded, lpal.palPalEntry, 256);
|
|
|
|
for (i=start, n=num; n>0; i++, n--)
|
|
{
|
|
/*
|
|
lpal.palPalEntry[i].peBlue = dapal[0] << 2;
|
|
lpal.palPalEntry[i].peGreen = dapal[1] << 2;
|
|
lpal.palPalEntry[i].peRed = dapal[2] << 2;
|
|
*/
|
|
curpalettefaded[i].f = lpal.palPalEntry[i].peFlags = PC_RESERVED | PC_NOCOLLAPSE;
|
|
//dapal += 4;
|
|
}
|
|
|
|
|
|
if (bpp > 8) return 0; // no palette in opengl
|
|
|
|
if (!fullscreen)
|
|
{
|
|
if (num > 0)
|
|
{
|
|
rgb = (RGBQUAD *)Bmalloc(sizeof(RGBQUAD)*num);
|
|
for (i=start, n=0; n<num; i++, n++)
|
|
{
|
|
rgb[n].rgbBlue = lpal.palPalEntry[i].peBlue;
|
|
rgb[n].rgbGreen = lpal.palPalEntry[i].peGreen;
|
|
rgb[n].rgbRed = lpal.palPalEntry[i].peRed;
|
|
rgb[n].rgbReserved = 0;
|
|
}
|
|
|
|
SetDIBColorTable(hDCSection, start, num, rgb);
|
|
free(rgb);
|
|
}
|
|
|
|
if (desktopbpp > 8) return 0; // only if an 8bit desktop do we do what follows
|
|
|
|
// set 0 and 255 to black and white
|
|
lpal.palVersion = 0x300;
|
|
lpal.palNumEntries = 256;
|
|
lpal.palPalEntry[0].peBlue = 0;
|
|
lpal.palPalEntry[0].peGreen = 0;
|
|
lpal.palPalEntry[0].peRed = 0;
|
|
lpal.palPalEntry[0].peFlags = 0;
|
|
lpal.palPalEntry[255].peBlue = 255;
|
|
lpal.palPalEntry[255].peGreen = 255;
|
|
lpal.palPalEntry[255].peRed = 255;
|
|
lpal.palPalEntry[255].peFlags = 0;
|
|
|
|
if (SetSystemPaletteUse(hDC, SYSPAL_NOSTATIC) == SYSPAL_ERROR)
|
|
{
|
|
initprintf("Problem setting system palette use.\n");
|
|
return -1;
|
|
}
|
|
|
|
if (hPalette)
|
|
{
|
|
if (num == 0) { start = 0; num = 256; } // refreshing the palette only
|
|
SetPaletteEntries(hPalette, start, num, lpal.palPalEntry+start);
|
|
}
|
|
else
|
|
{
|
|
hPalette = CreatePalette((LOGPALETTE *)lpal.palPalEntry);
|
|
if (!hPalette)
|
|
{
|
|
initprintf("Problem creating palette.\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (SelectPalette(hDC, hPalette, FALSE) == NULL)
|
|
{
|
|
initprintf("Problem selecting palette.\n");
|
|
return -1;
|
|
}
|
|
|
|
if (RealizePalette(hDC) == GDI_ERROR)
|
|
{
|
|
initprintf("Failure realizing palette.\n");
|
|
return -1;
|
|
}
|
|
|
|
SetBWSystemColours();
|
|
|
|
}
|
|
else
|
|
{
|
|
if (!lpDDPalette) return -1;
|
|
result = IDirectDrawPalette_SetEntries(lpDDPalette, 0, start, num, (PALETTEENTRY*)&lpal.palPalEntry[start]);
|
|
if (result != DD_OK)
|
|
{
|
|
initprintf("Palette set failed: %s\n", GetDDrawError(result));
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// getpalette() -- get palette values
|
|
//
|
|
/*
|
|
int getpalette(int start, int num, char *dapal)
|
|
{
|
|
int i;
|
|
|
|
for (i=num; i>0; i--, start++) {
|
|
dapal[0] = curpalette[start].b >> 2;
|
|
dapal[1] = curpalette[start].g >> 2;
|
|
dapal[2] = curpalette[start].r >> 2;
|
|
dapal += 4;
|
|
}
|
|
|
|
return 0;
|
|
}*/
|
|
|
|
|
|
//
|
|
// setgamma
|
|
//
|
|
static int setgammaramp(WORD gt[3][256])
|
|
{
|
|
if (!fullscreen || bpp > 8)
|
|
{
|
|
// GL and windowed mode use DIB method
|
|
int i;
|
|
HDC hDC = GetDC(hWindow);
|
|
i = SetDeviceGammaRamp(hDC, gt) ? 0 : -1;
|
|
ReleaseDC(hWindow, hDC);
|
|
return i;
|
|
}
|
|
else
|
|
{
|
|
// fullscreen uses DirectX
|
|
LPDIRECTDRAWGAMMACONTROL gam;
|
|
HRESULT hr;
|
|
|
|
if (!(DDdwCaps2 & DDCAPS2_PRIMARYGAMMA)) return -1;
|
|
|
|
hr = IDirectDrawSurface_QueryInterface(lpDDSPrimary, &IID_IDirectDrawGammaControl, (LPVOID)&gam);
|
|
if (hr != DD_OK)
|
|
{
|
|
ShowDDrawErrorBox("Error querying gamma control", hr);
|
|
return -1;
|
|
}
|
|
|
|
hr = IDirectDrawGammaControl_SetGammaRamp(gam, 0, (LPDDGAMMARAMP)gt);
|
|
if (hr != DD_OK)
|
|
{
|
|
IDirectDrawGammaControl_Release(gam);
|
|
ShowDDrawErrorBox("Error setting gamma ramp", hr);
|
|
return -1;
|
|
}
|
|
|
|
IDirectDrawGammaControl_Release(gam);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int setgamma(float ro, float go, float bo)
|
|
{
|
|
int i;
|
|
WORD gt[3][256];
|
|
|
|
if (!hWindow) return -1;
|
|
|
|
ro = 1.0 / ro; go = 1.0 / go; bo = 1.0 / bo;
|
|
for (i=0;i<256;i++)
|
|
{
|
|
gt[0][i] = (WORD)min(65535, max(0, (int)(pow((double)i / 256.0, ro) * 65535.0 + 0.5)));
|
|
gt[1][i] = (WORD)min(65535, max(0, (int)(pow((double)i / 256.0, go) * 65535.0 + 0.5)));
|
|
gt[2][i] = (WORD)min(65535, max(0, (int)(pow((double)i / 256.0, go) * 65535.0 + 0.5)));
|
|
}
|
|
|
|
return setgammaramp(gt);
|
|
}
|
|
|
|
static int getgammaramp(WORD gt[3][256])
|
|
{
|
|
if (!hWindow) return -1;
|
|
if (!fullscreen || bpp > 8)
|
|
{
|
|
int i;
|
|
HDC hDC = GetDC(hWindow);
|
|
i = GetDeviceGammaRamp(hDC, gt) ? 0 : -1;
|
|
ReleaseDC(hWindow, hDC);
|
|
return i;
|
|
}
|
|
else
|
|
{
|
|
LPDIRECTDRAWGAMMACONTROL gam;
|
|
HRESULT hr;
|
|
|
|
if (!(DDdwCaps2 & DDCAPS2_PRIMARYGAMMA)) return -1;
|
|
|
|
hr = IDirectDrawSurface_QueryInterface(lpDDSPrimary, &IID_IDirectDrawGammaControl, (LPVOID)&gam);
|
|
if (hr != DD_OK)
|
|
{
|
|
ShowDDrawErrorBox("Error querying gamma control", hr);
|
|
return -1;
|
|
}
|
|
|
|
hr = IDirectDrawGammaControl_GetGammaRamp(gam, 0, (LPDDGAMMARAMP)gt);
|
|
if (hr != DD_OK)
|
|
{
|
|
IDirectDrawGammaControl_Release(gam);
|
|
ShowDDrawErrorBox("Error getting gamma ramp", hr);
|
|
return -1;
|
|
}
|
|
|
|
IDirectDrawGammaControl_Release(gam);
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// InitDirectDraw() -- get DirectDraw started
|
|
//
|
|
|
|
// device enumerator
|
|
static BOOL WINAPI InitDirectDraw_enum(GUID *lpGUID, LPSTR lpDesc, LPSTR lpName, LPVOID lpContext)
|
|
{
|
|
UNREFERENCED_PARAMETER(lpGUID);
|
|
UNREFERENCED_PARAMETER(lpName);
|
|
UNREFERENCED_PARAMETER(lpContext);
|
|
initprintf(" * %s\n", lpDesc);
|
|
return 1;
|
|
}
|
|
|
|
static BOOL InitDirectDraw(void)
|
|
{
|
|
HRESULT result;
|
|
HRESULT(WINAPI *aDirectDrawCreate)(GUID *, LPDIRECTDRAW *, IUnknown *);
|
|
HRESULT(WINAPI *aDirectDrawEnumerate)(LPDDENUMCALLBACK, LPVOID);
|
|
DDCAPS ddcaps;
|
|
|
|
if (bDDrawInited) return FALSE;
|
|
|
|
initprintf("Initializing DirectDraw...\n");
|
|
|
|
// load up the DirectDraw DLL
|
|
if (!hDDrawDLL)
|
|
{
|
|
initprintf(" - Loading DDRAW.DLL\n");
|
|
hDDrawDLL = LoadLibrary("DDRAW.DLL");
|
|
if (!hDDrawDLL)
|
|
{
|
|
ShowErrorBox("Error loading DDRAW.DLL");
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// get the pointer to DirectDrawEnumerate
|
|
aDirectDrawEnumerate = (void *)GetProcAddress(hDDrawDLL, "DirectDrawEnumerateA");
|
|
if (!aDirectDrawEnumerate)
|
|
{
|
|
ShowErrorBox("Error fetching DirectDrawEnumerate()");
|
|
UninitDirectDraw();
|
|
return TRUE;
|
|
}
|
|
|
|
// enumerate the devices to make us look fancy
|
|
initprintf(" - Enumerating display devices\n");
|
|
aDirectDrawEnumerate(InitDirectDraw_enum, NULL);
|
|
|
|
// get the pointer to DirectDrawCreate
|
|
aDirectDrawCreate = (void *)GetProcAddress(hDDrawDLL, "DirectDrawCreate");
|
|
if (!aDirectDrawCreate)
|
|
{
|
|
ShowErrorBox("Error fetching DirectDrawCreate()");
|
|
UninitDirectDraw();
|
|
return TRUE;
|
|
}
|
|
|
|
// create a new DirectDraw object
|
|
initprintf(" - Creating DirectDraw object\n");
|
|
result = aDirectDrawCreate(NULL, &lpDD, NULL);
|
|
if (result != DD_OK)
|
|
{
|
|
ShowDDrawErrorBox("DirectDrawCreate() failed", result);
|
|
UninitDirectDraw();
|
|
return TRUE;
|
|
}
|
|
|
|
// fetch capabilities
|
|
initprintf(" - Checking capabilities\n");
|
|
ddcaps.dwSize = sizeof(DDCAPS);
|
|
result = IDirectDraw_GetCaps(lpDD, &ddcaps, NULL);
|
|
if (result != DD_OK)
|
|
{
|
|
initprintf(" Unable to get capabilities.\n");
|
|
}
|
|
else
|
|
{
|
|
DDdwCaps = ddcaps.dwCaps;
|
|
DDdwCaps2 = ddcaps.dwCaps2;
|
|
}
|
|
|
|
bDDrawInited = TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// UninitDirectDraw() -- clean up DirectDraw
|
|
//
|
|
static void UninitDirectDraw(void)
|
|
{
|
|
if (bDDrawInited) initprintf("Uninitializing DirectDraw...\n");
|
|
|
|
ReleaseDirectDrawSurfaces();
|
|
|
|
RestoreDirectDrawMode();
|
|
|
|
if (lpDD)
|
|
{
|
|
initprintf(" - Releasing DirectDraw object\n");
|
|
IDirectDraw_Release(lpDD);
|
|
lpDD = NULL;
|
|
}
|
|
|
|
if (hDDrawDLL)
|
|
{
|
|
initprintf(" - Unloading DDRAW.DLL\n");
|
|
FreeLibrary(hDDrawDLL);
|
|
hDDrawDLL = NULL;
|
|
}
|
|
|
|
bDDrawInited = FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// RestoreDirectDrawMode() -- resets the screen mode
|
|
//
|
|
static int RestoreDirectDrawMode(void)
|
|
{
|
|
HRESULT result;
|
|
|
|
if (fullscreen == 0 || /*bpp > 8 ||*/ !bDDrawInited) return FALSE;
|
|
|
|
if (modesetusing == 1) ChangeDisplaySettings(NULL,0);
|
|
else if (modesetusing == 0)
|
|
{
|
|
// restore previous display mode and set to normal cooperative level
|
|
result = IDirectDraw_RestoreDisplayMode(lpDD);
|
|
if (result != DD_OK)
|
|
{
|
|
ShowDDrawErrorBox("Error restoring display mode", result);
|
|
UninitDirectDraw();
|
|
return TRUE;
|
|
}
|
|
|
|
result = IDirectDraw_SetCooperativeLevel(lpDD, hWindow, DDSCL_NORMAL);
|
|
if (result != DD_OK)
|
|
{
|
|
ShowDDrawErrorBox("Error setting cooperative level", result);
|
|
UninitDirectDraw();
|
|
return TRUE;
|
|
}
|
|
}
|
|
modesetusing = -1;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// ReleaseDirectDrawSurfaces() -- release the front and back buffers
|
|
//
|
|
static void ReleaseDirectDrawSurfaces(void)
|
|
{
|
|
if (lpDDPalette)
|
|
{
|
|
initprintf(" - Releasing palette\n");
|
|
IDirectDrawPalette_Release(lpDDPalette);
|
|
lpDDPalette = NULL;
|
|
}
|
|
|
|
if (lpDDSBack)
|
|
{
|
|
initprintf(" - Releasing back-buffer surface\n");
|
|
IDirectDrawSurface_Release(lpDDSBack);
|
|
lpDDSBack = NULL;
|
|
}
|
|
|
|
if (lpDDSPrimary)
|
|
{
|
|
initprintf(" - Releasing primary surface\n");
|
|
IDirectDrawSurface_Release(lpDDSPrimary);
|
|
lpDDSPrimary = NULL;
|
|
}
|
|
|
|
if (lpOffscreen)
|
|
{
|
|
initprintf(" - Freeing offscreen buffer\n");
|
|
free(lpOffscreen);
|
|
lpOffscreen = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// SetupDirectDraw() -- sets up DirectDraw rendering
|
|
//
|
|
static int SetupDirectDraw(int width, int height)
|
|
{
|
|
HRESULT result;
|
|
DDSURFACEDESC ddsd;
|
|
|
|
// now create the DirectDraw surfaces
|
|
ZeroMemory(&ddsd, sizeof(ddsd));
|
|
ddsd.dwSize = sizeof(ddsd);
|
|
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
|
|
ddsd.dwBackBufferCount = 2; // triple-buffer
|
|
|
|
initprintf(" - Creating primary surface\n");
|
|
result = IDirectDraw_CreateSurface(lpDD, &ddsd, &lpDDSPrimary, NULL);
|
|
if (result != DD_OK)
|
|
{
|
|
ShowDDrawErrorBox("Failure creating primary surface", result);
|
|
UninitDirectDraw();
|
|
return TRUE;
|
|
}
|
|
|
|
ZeroMemory(&ddsd.ddsCaps, sizeof(ddsd.ddsCaps));
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
|
|
numpages = 1; // KJS 20031225
|
|
|
|
initprintf(" - Getting back buffer\n");
|
|
result = IDirectDrawSurface_GetAttachedSurface(lpDDSPrimary, &ddsd.ddsCaps, &lpDDSBack);
|
|
if (result != DD_OK)
|
|
{
|
|
ShowDDrawErrorBox("Failure fetching back-buffer surface", result);
|
|
UninitDirectDraw();
|
|
return TRUE;
|
|
}
|
|
|
|
initprintf(" - Allocating offscreen buffer\n");
|
|
lpOffscreen = (char *)malloc((width|1)*height);
|
|
if (!lpOffscreen)
|
|
{
|
|
ShowErrorBox("Failure allocating offscreen buffer");
|
|
UninitDirectDraw();
|
|
return TRUE;
|
|
}
|
|
|
|
// attach a palette to the primary surface
|
|
initprintf(" - Creating palette\n");
|
|
result = IDirectDraw_CreatePalette(lpDD, DDPCAPS_8BIT | DDPCAPS_ALLOW256, (PALETTEENTRY*)curpalette, &lpDDPalette, NULL);
|
|
if (result != DD_OK)
|
|
{
|
|
ShowDDrawErrorBox("Failure creating palette", result);
|
|
UninitDirectDraw();
|
|
return TRUE;
|
|
}
|
|
|
|
result = IDirectDrawSurface_SetPalette(lpDDSPrimary, lpDDPalette);
|
|
if (result != DD_OK)
|
|
{
|
|
ShowDDrawErrorBox("Failure setting palette", result);
|
|
UninitDirectDraw();
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// UninitDIB() -- clean up the DIB renderer
|
|
//
|
|
static void UninitDIB(void)
|
|
{
|
|
if (desktopbpp <= 8)
|
|
RestoreSystemColours();
|
|
|
|
if (hPalette)
|
|
{
|
|
DeleteObject(hPalette);
|
|
hPalette = NULL;
|
|
}
|
|
|
|
if (hDCSection)
|
|
{
|
|
DeleteDC(hDCSection);
|
|
hDCSection = NULL;
|
|
}
|
|
|
|
if (hDIBSection)
|
|
{
|
|
DeleteObject(hDIBSection);
|
|
hDIBSection = NULL;
|
|
}
|
|
|
|
if (hDC)
|
|
{
|
|
ReleaseDC(hWindow, hDC);
|
|
hDC = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// SetupDIB() -- sets up DIB rendering
|
|
//
|
|
static int SetupDIB(int width, int height)
|
|
{
|
|
struct binfo
|
|
{
|
|
BITMAPINFOHEADER header;
|
|
RGBQUAD colours[256];
|
|
} dibsect;
|
|
int i;
|
|
|
|
if (!hDC)
|
|
{
|
|
hDC = GetDC(hWindow);
|
|
if (!hDC)
|
|
{
|
|
ShowErrorBox("Error getting device context");
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
if (hDCSection)
|
|
{
|
|
DeleteDC(hDCSection);
|
|
hDCSection = NULL;
|
|
}
|
|
|
|
// destroy the previous DIB section if it existed
|
|
if (hDIBSection)
|
|
{
|
|
DeleteObject(hDIBSection);
|
|
hDIBSection = NULL;
|
|
}
|
|
|
|
// create the new DIB section
|
|
memset(&dibsect, 0, sizeof(dibsect));
|
|
numpages = 1; // KJS 20031225
|
|
dibsect.header.biSize = sizeof(dibsect.header);
|
|
dibsect.header.biWidth = width|1; // Ken did this
|
|
dibsect.header.biHeight = -height;
|
|
dibsect.header.biPlanes = 1;
|
|
dibsect.header.biBitCount = 8;
|
|
dibsect.header.biCompression = BI_RGB;
|
|
dibsect.header.biClrUsed = 256;
|
|
dibsect.header.biClrImportant = 256;
|
|
for (i=0; i<256; i++)
|
|
{
|
|
dibsect.colours[i].rgbBlue = curpalette[i].b;
|
|
dibsect.colours[i].rgbGreen = curpalette[i].g;
|
|
dibsect.colours[i].rgbRed = curpalette[i].r;
|
|
}
|
|
|
|
hDIBSection = CreateDIBSection(hDC, (BITMAPINFO *)&dibsect, DIB_RGB_COLORS, &lpPixels, NULL, 0);
|
|
if (!hDIBSection)
|
|
{
|
|
ReleaseDC(hWindow, hDC);
|
|
hDC = NULL;
|
|
|
|
ShowErrorBox("Error creating DIB section");
|
|
return TRUE;
|
|
}
|
|
|
|
memset(lpPixels, 0, width*height);
|
|
|
|
// create a compatible memory DC
|
|
hDCSection = CreateCompatibleDC(hDC);
|
|
if (!hDCSection)
|
|
{
|
|
ReleaseDC(hWindow, hDC);
|
|
hDC = NULL;
|
|
|
|
ShowErrorBox("Error creating compatible DC");
|
|
return TRUE;
|
|
}
|
|
|
|
// select the DIB section into the memory DC
|
|
if (!SelectObject(hDCSection, hDIBSection))
|
|
{
|
|
ReleaseDC(hWindow, hDC);
|
|
hDC = NULL;
|
|
DeleteDC(hDCSection);
|
|
hDCSection = NULL;
|
|
|
|
ShowErrorBox("Error creating compatible DC");
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#if defined(USE_OPENGL) && defined(POLYMOST)
|
|
//
|
|
// ReleaseOpenGL() -- cleans up OpenGL rendering stuff
|
|
//
|
|
|
|
static HWND hGLWindow = NULL;
|
|
|
|
static void ReleaseOpenGL(void)
|
|
{
|
|
if (hGLRC)
|
|
{
|
|
polymost_glreset();
|
|
if (!bwglMakeCurrent(0,0)) { }
|
|
if (!bwglDeleteContext(hGLRC)) { }
|
|
hGLRC = NULL;
|
|
}
|
|
if (hGLWindow)
|
|
{
|
|
if (hDC)
|
|
{
|
|
ReleaseDC(hGLWindow, hDC);
|
|
hDC = NULL;
|
|
}
|
|
|
|
DestroyWindow(hGLWindow);
|
|
hGLWindow = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// UninitOpenGL() -- unitializes any openGL libraries
|
|
//
|
|
static void UninitOpenGL(void)
|
|
{
|
|
ReleaseOpenGL();
|
|
}
|
|
|
|
|
|
//
|
|
// SetupOpenGL() -- sets up opengl rendering
|
|
//
|
|
static int SetupOpenGL(int width, int height, int bitspp)
|
|
{
|
|
PIXELFORMATDESCRIPTOR pfd =
|
|
{
|
|
sizeof(PIXELFORMATDESCRIPTOR),
|
|
1, //Version Number
|
|
PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER, //Must Support these
|
|
PFD_TYPE_RGBA, //Request An RGBA Format
|
|
0, //Select Our Color Depth
|
|
0,0,0,0,0,0, //Color Bits Ignored
|
|
0, //No Alpha Buffer
|
|
0, //Shift Bit Ignored
|
|
0, //No Accumulation Buffer
|
|
0,0,0,0, //Accumulation Bits Ignored
|
|
32, //16/24/32 Z-Buffer depth
|
|
1, //No Stencil Buffer
|
|
0, //No Auxiliary Buffer
|
|
PFD_MAIN_PLANE, //Main Drawing Layer
|
|
0, //Reserved
|
|
0,0,0 //Layer Masks Ignored
|
|
};
|
|
GLuint PixelFormat;
|
|
int minidriver;
|
|
int err;
|
|
static int warnonce = 0;
|
|
pfd.cColorBits = bitspp;
|
|
|
|
hGLWindow = CreateWindow(
|
|
WindowClass,
|
|
"OpenGL Window",
|
|
WS_CHILD|WS_VISIBLE,
|
|
0,0,
|
|
width,height,
|
|
hWindow,
|
|
(HMENU)0,
|
|
hInstance,
|
|
NULL);
|
|
if (!hGLWindow)
|
|
{
|
|
ShowErrorBox("Error creating OpenGL child window.");
|
|
return TRUE;
|
|
}
|
|
|
|
hDC = GetDC(hGLWindow);
|
|
if (!hDC)
|
|
{
|
|
ReleaseOpenGL();
|
|
ShowErrorBox("Error getting device context");
|
|
return TRUE;
|
|
}
|
|
|
|
minidriver = Bstrcasecmp(gldriver,"opengl32.dll");
|
|
|
|
if (minidriver) PixelFormat = bwglChoosePixelFormat(hDC,&pfd);
|
|
else PixelFormat = ChoosePixelFormat(hDC,&pfd);
|
|
if (!PixelFormat)
|
|
{
|
|
ReleaseOpenGL();
|
|
ShowErrorBox("Can't choose pixel format");
|
|
return TRUE;
|
|
}
|
|
|
|
if (minidriver) err = bwglSetPixelFormat(hDC, PixelFormat, &pfd);
|
|
else err = SetPixelFormat(hDC, PixelFormat, &pfd);
|
|
if (!err)
|
|
{
|
|
ReleaseOpenGL();
|
|
ShowErrorBox("Can't set pixel format");
|
|
return TRUE;
|
|
}
|
|
|
|
hGLRC = bwglCreateContext(hDC);
|
|
if (!hGLRC)
|
|
{
|
|
ReleaseOpenGL();
|
|
ShowErrorBox("Can't create GL RC");
|
|
return TRUE;
|
|
}
|
|
|
|
if (!bwglMakeCurrent(hDC, hGLRC))
|
|
{
|
|
ReleaseOpenGL();
|
|
ShowErrorBox("Can't activate GL RC");
|
|
return TRUE;
|
|
}
|
|
|
|
polymost_glreset();
|
|
|
|
bglEnable(GL_TEXTURE_2D);
|
|
bglShadeModel(GL_SMOOTH); //GL_FLAT
|
|
bglClearColor(0,0,0,0.5); //Black Background
|
|
bglHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST); //Use FASTEST for ortho!
|
|
bglHint(GL_LINE_SMOOTH_HINT,GL_NICEST);
|
|
bglHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST);
|
|
bglDisable(GL_DITHER);
|
|
|
|
{
|
|
GLubyte *p,*p2,*p3;
|
|
|
|
glinfo.vendor = (char *)bglGetString(GL_VENDOR);
|
|
glinfo.renderer = (char *)bglGetString(GL_RENDERER);
|
|
glinfo.version = (char *)bglGetString(GL_VERSION);
|
|
glinfo.extensions = (char *)bglGetString(GL_EXTENSIONS);
|
|
|
|
glinfo.maxanisotropy = 1.0;
|
|
glinfo.bgra = 0;
|
|
glinfo.texcompr = 0;
|
|
|
|
// process the extensions string and flag stuff we recognize
|
|
p = (unsigned char *)Bstrdup(glinfo.extensions);
|
|
p3 = p;
|
|
while ((p2 = (unsigned char *)Bstrtoken(p3==p?(char *)p:NULL, " ", (char**)&p3, 1)) != NULL)
|
|
{
|
|
if (!Bstrcmp((char *)p2, "GL_EXT_texture_filter_anisotropic"))
|
|
{
|
|
// supports anisotropy. get the maximum anisotropy level
|
|
bglGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &glinfo.maxanisotropy);
|
|
}
|
|
else if (!Bstrcmp((char *)p2, "GL_EXT_texture_edge_clamp") ||
|
|
!Bstrcmp((char *)p2, "GL_SGIS_texture_edge_clamp"))
|
|
{
|
|
// supports GL_CLAMP_TO_EDGE or GL_CLAMP_TO_EDGE_SGIS
|
|
glinfo.clamptoedge = 1;
|
|
}
|
|
else if (!Bstrcmp((char *)p2, "GL_EXT_bgra"))
|
|
{
|
|
// support bgra textures
|
|
glinfo.bgra = 1;
|
|
}
|
|
else if (!Bstrcmp((char *)p2, "GL_ARB_texture_compression"))
|
|
{
|
|
// support texture compression
|
|
glinfo.texcompr = 1;
|
|
}
|
|
else if (!Bstrcmp((char *)p2, "GL_ARB_texture_non_power_of_two"))
|
|
{
|
|
// support non-power-of-two texture sizes
|
|
glinfo.texnpot = 1;
|
|
}
|
|
else if (!Bstrcmp((char *)p2, "WGL_3DFX_gamma_control"))
|
|
{
|
|
// 3dfx cards have issues with fog
|
|
nofog = 1;
|
|
if (!(warnonce&1)) initprintf("3dfx card detected: OpenGL fog disabled\n");
|
|
warnonce |= 1;
|
|
}
|
|
else if (!Bstrcmp((char *)p2, "GL_ARB_fragment_program"))
|
|
{
|
|
glinfo.arbfp = 1;
|
|
}
|
|
else if (!Bstrcmp((char *)p2, "GL_ARB_depth_texture"))
|
|
{
|
|
glinfo.depthtex = 1;
|
|
}
|
|
else if (!Bstrcmp((char *)p2, "GL_ARB_shadow"))
|
|
{
|
|
glinfo.shadow = 1;
|
|
}
|
|
else if (!Bstrcmp((char *)p2, "GL_EXT_framebuffer_object"))
|
|
{
|
|
glinfo.fbos = 1;
|
|
}
|
|
else if (!Bstrcmp((char *)p2, "GL_NV_texture_rectangle") ||
|
|
!Bstrcmp((char *)p2, "GL_EXT_texture_rectangle"))
|
|
{
|
|
glinfo.rect = 1;
|
|
}
|
|
else if (!Bstrcmp((char *)p2, "GL_ARB_multitexture"))
|
|
{
|
|
glinfo.multitex = 1;
|
|
}
|
|
else if (!Bstrcmp((char *)p2, "GL_ARB_texture_env_combine"))
|
|
{
|
|
glinfo.envcombine = 1;
|
|
}
|
|
else if (!Bstrcmp((char *)p2, "GL_ARB_vertex_buffer_object"))
|
|
{
|
|
glinfo.vbos = 1;
|
|
}
|
|
}
|
|
Bfree(p);
|
|
}
|
|
numpages = 2; // KJS 20031225: tell rotatesprite that it's double buffered!
|
|
|
|
if (!glinfo.dumped)
|
|
{
|
|
int oldbpp = bpp;
|
|
bpp = 32;
|
|
osdcmd_glinfo(NULL);
|
|
glinfo.dumped = TRUE;
|
|
bpp = oldbpp;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// CreateAppWindow() -- create the application window
|
|
//
|
|
static BOOL CreateAppWindow(int modenum)
|
|
{
|
|
RECT rect;
|
|
int w, h, x, y, stylebits = 0, stylebitsex = 0;
|
|
int width, height, fs, bitspp;
|
|
|
|
HRESULT result;
|
|
|
|
if (modenum == 0x7fffffff)
|
|
{
|
|
width = customxdim;
|
|
height = customydim;
|
|
fs = customfs;
|
|
bitspp = custombpp;
|
|
}
|
|
else
|
|
{
|
|
width = validmode[modenum].xdim;
|
|
height = validmode[modenum].ydim;
|
|
fs = validmode[modenum].fs;
|
|
bitspp = validmode[modenum].bpp;
|
|
}
|
|
|
|
if (width == xres && height == yres && fs == fullscreen && bitspp == bpp && !videomodereset) return FALSE;
|
|
|
|
if (hWindow)
|
|
{
|
|
if (bpp > 8)
|
|
{
|
|
#if defined(USE_OPENGL) && defined(POLYMOST)
|
|
ReleaseOpenGL(); // release opengl
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
ReleaseDirectDrawSurfaces(); // releases directdraw surfaces
|
|
}
|
|
|
|
if (!fs && fullscreen)
|
|
{
|
|
// restore previous display mode and set to normal cooperative level
|
|
RestoreDirectDrawMode();
|
|
#if defined(USE_OPENGL) && defined(POLYMOST)
|
|
}
|
|
else if (fs && fullscreen)
|
|
{
|
|
// using CDS for GL modes, so restore from DirectDraw
|
|
if (bpp != bitspp) RestoreDirectDrawMode();
|
|
#endif
|
|
}
|
|
|
|
|
|
ShowWindow(hWindow, SW_HIDE); // so Windows redraws what's behind if the window shrinks
|
|
}
|
|
|
|
if (fs)
|
|
{
|
|
stylebitsex = WS_EX_TOPMOST;
|
|
stylebits = WS_POPUP;
|
|
}
|
|
else
|
|
{
|
|
stylebitsex = 0;
|
|
stylebits = WINDOW_STYLE;
|
|
}
|
|
|
|
if (!hWindow)
|
|
{
|
|
hWindow = CreateWindowEx(
|
|
stylebitsex,
|
|
"buildapp",
|
|
apptitle,
|
|
stylebits,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
320,
|
|
200,
|
|
NULL,
|
|
NULL,
|
|
hInstance,
|
|
0);
|
|
if (!hWindow)
|
|
{
|
|
ShowErrorBox("Unable to create window");
|
|
return TRUE;
|
|
}
|
|
|
|
startwin_close();
|
|
}
|
|
else
|
|
{
|
|
SetWindowLong(hWindow,GWL_EXSTYLE,stylebitsex);
|
|
SetWindowLong(hWindow,GWL_STYLE,stylebits);
|
|
}
|
|
|
|
// resize the window
|
|
if (!fs)
|
|
{
|
|
rect.left = 0;
|
|
rect.top = 0;
|
|
rect.right = width-1;
|
|
rect.bottom = height-1;
|
|
AdjustWindowRect(&rect, stylebits, FALSE);
|
|
|
|
w = (rect.right - rect.left);
|
|
h = (rect.bottom - rect.top);
|
|
x = (desktopxdim - w) / 2;
|
|
y = (desktopydim - h) / 2;
|
|
}
|
|
else
|
|
{
|
|
x=y=0;
|
|
w=width;
|
|
h=height;
|
|
}
|
|
|
|
if (windowx == -1)
|
|
windowx = x;
|
|
|
|
if (windowy == -1)
|
|
windowy = y;
|
|
|
|
SetWindowText(hWindow, apptitle);
|
|
ShowWindow(hWindow, SW_SHOWNORMAL);
|
|
SetForegroundWindow(hWindow);
|
|
SetFocus(hWindow);
|
|
|
|
SetWindowPos(hWindow, HWND_TOP, windowpos?windowx:x, windowpos?windowy:y, w, h, 0);
|
|
|
|
// fullscreen?
|
|
if (!fs)
|
|
{
|
|
if (bitspp > 8)
|
|
{
|
|
#if defined(USE_OPENGL) && defined(POLYMOST)
|
|
// yes, start up opengl
|
|
if (SetupOpenGL(width,height,bitspp))
|
|
{
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
// no, use DIB section
|
|
if (SetupDIB(width,height))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
modesetusing = -1;
|
|
|
|
}
|
|
else
|
|
{
|
|
// yes, set up DirectDraw
|
|
|
|
// clean up after the DIB renderer if it was being used
|
|
UninitDIB();
|
|
|
|
if (!bDDrawInited)
|
|
{
|
|
DestroyWindow(hWindow);
|
|
hWindow = NULL;
|
|
return TRUE;
|
|
}
|
|
|
|
#if defined(USE_OPENGL) && defined(POLYMOST)
|
|
if (bitspp > 8)
|
|
{
|
|
DEVMODE dmScreenSettings;
|
|
|
|
ZeroMemory(&dmScreenSettings, sizeof(DEVMODE));
|
|
dmScreenSettings.dmSize = sizeof(DEVMODE);
|
|
dmScreenSettings.dmPelsWidth = width;
|
|
dmScreenSettings.dmPelsHeight = height;
|
|
dmScreenSettings.dmBitsPerPel = bitspp;
|
|
dmScreenSettings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
|
|
if (modenum != 0x7fffffff)
|
|
{
|
|
dmScreenSettings.dmDisplayFrequency = validmode[modenum].extra;
|
|
dmScreenSettings.dmFields |= DM_DISPLAYFREQUENCY;
|
|
}
|
|
|
|
if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
|
|
{
|
|
ShowErrorBox("Video mode not supported");
|
|
return TRUE;
|
|
}
|
|
|
|
ShowWindow(hWindow, SW_SHOWNORMAL);
|
|
SetForegroundWindow(hWindow);
|
|
SetFocus(hWindow);
|
|
|
|
modesetusing = 1;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
// set exclusive cooperative level
|
|
result = IDirectDraw_SetCooperativeLevel(lpDD, hWindow, DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN);
|
|
if (result != DD_OK)
|
|
{
|
|
ShowDDrawErrorBox("Error setting cooperative level", result);
|
|
UninitDirectDraw();
|
|
return TRUE;
|
|
}
|
|
|
|
result = IDirectDraw_SetDisplayMode(lpDD, width, height, bitspp);
|
|
if (result != DD_OK)
|
|
{
|
|
ShowDDrawErrorBox("Error setting display mode", result);
|
|
UninitDirectDraw();
|
|
return TRUE;
|
|
}
|
|
|
|
modesetusing = 0;
|
|
}
|
|
|
|
if (bitspp > 8)
|
|
{
|
|
#if defined(USE_OPENGL) && defined(POLYMOST)
|
|
// we want an opengl mode
|
|
if (SetupOpenGL(width,height,bitspp))
|
|
{
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
// we want software
|
|
if (SetupDirectDraw(width,height))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if defined(USE_OPENGL) && defined(POLYMOST)
|
|
if (bitspp > 8) loadglextensions();
|
|
#endif
|
|
|
|
xres = width;
|
|
yres = height;
|
|
bpp = bitspp;
|
|
fullscreen = fs;
|
|
curvidmode = modenum;
|
|
|
|
frameplace = 0;
|
|
lockcount = 0;
|
|
|
|
// bytesperline is set when framebuffer is locked
|
|
//bytesperline = width;
|
|
//imageSize = bytesperline*yres;
|
|
|
|
modechange = 1;
|
|
OSD_ResizeDisplay(xres,yres);
|
|
|
|
UpdateWindow(hWindow);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// DestroyAppWindow() -- destroys the application window
|
|
//
|
|
static void DestroyAppWindow(void)
|
|
{
|
|
if (hWindow && gammabrightness)
|
|
{
|
|
setgammaramp(sysgamma);
|
|
gammabrightness = 0;
|
|
}
|
|
|
|
#if defined(USE_OPENGL) && defined(POLYMOST)
|
|
UninitOpenGL();
|
|
#endif
|
|
UninitDirectDraw();
|
|
UninitDIB();
|
|
|
|
if (hWindow)
|
|
{
|
|
DestroyWindow(hWindow);
|
|
hWindow = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// SaveSystemColours() -- save the Windows-reserved colours
|
|
//
|
|
static void SaveSystemColours(void)
|
|
{
|
|
int i;
|
|
|
|
if (system_colours_saved) return;
|
|
|
|
for (i=0; i<NUM_SYS_COLOURS; i++)
|
|
syscolours[i] = GetSysColor(syscolouridx[i]);
|
|
|
|
system_colours_saved = 1;
|
|
}
|
|
|
|
|
|
//
|
|
// SetBWSystemColours() -- set system colours to a black-and-white scheme
|
|
//
|
|
static void SetBWSystemColours(void)
|
|
{
|
|
#define WHI RGB(255,255,255)
|
|
#define BLA RGB(0,0,0)
|
|
static COLORREF syscoloursbw[NUM_SYS_COLOURS] =
|
|
{
|
|
WHI, BLA, BLA, WHI, WHI, WHI, WHI, BLA, BLA, WHI,
|
|
WHI, WHI, WHI, BLA, WHI, WHI, BLA, BLA, BLA, BLA,
|
|
BLA, BLA, WHI, BLA, WHI
|
|
};
|
|
#undef WHI
|
|
#undef BLA
|
|
if (!system_colours_saved || bw_colours_set) return;
|
|
|
|
SetSysColors(NUM_SYS_COLOURS, syscolouridx, syscoloursbw);
|
|
bw_colours_set = 1;
|
|
}
|
|
|
|
|
|
//
|
|
// RestoreSystemColours() -- restore the Windows-reserved colours
|
|
//
|
|
static void RestoreSystemColours(void)
|
|
{
|
|
if (!system_colours_saved || !bw_colours_set) return;
|
|
|
|
SetSystemPaletteUse(hDC, SYSPAL_STATIC);
|
|
SetSysColors(NUM_SYS_COLOURS, syscolouridx, syscolours);
|
|
bw_colours_set = 0;
|
|
}
|
|
|
|
|
|
//
|
|
// ShowDDrawErrorBox() -- shows an error message box for a DirectDraw error
|
|
//
|
|
static void ShowDDrawErrorBox(const char *m, HRESULT r)
|
|
{
|
|
TCHAR msg[1024];
|
|
|
|
wsprintf(msg, "%s: %s", m, GetDDrawError(r));
|
|
MessageBox(0, msg, apptitle, MB_OK|MB_ICONSTOP);
|
|
}
|
|
|
|
|
|
//
|
|
// GetDDrawError() -- stinking huge list of error messages since MS didn't want to include
|
|
// them in the DLL
|
|
//
|
|
static const char * GetDDrawError(HRESULT code)
|
|
{
|
|
switch (code)
|
|
{
|
|
case DD_OK:
|
|
return "DD_OK";
|
|
case DDERR_ALREADYINITIALIZED:
|
|
return "DDERR_ALREADYINITIALIZED";
|
|
case DDERR_BLTFASTCANTCLIP:
|
|
return "DDERR_BLTFASTCANTCLIP";
|
|
case DDERR_CANNOTATTACHSURFACE:
|
|
return "DDERR_CANNOTATTACHSURFACE";
|
|
case DDERR_CANNOTDETACHSURFACE:
|
|
return "DDERR_CANNOTDETACHSURFACE";
|
|
case DDERR_CANTCREATEDC:
|
|
return "DDERR_CANTCREATEDC";
|
|
case DDERR_CANTDUPLICATE:
|
|
return "DDERR_CANTDUPLICATE";
|
|
case DDERR_CANTLOCKSURFACE:
|
|
return "DDERR_CANTLOCKSURFACE";
|
|
case DDERR_CANTPAGELOCK:
|
|
return "DDERR_CANTPAGELOCK";
|
|
case DDERR_CANTPAGEUNLOCK:
|
|
return "DDERR_CANTPAGEUNLOCK";
|
|
case DDERR_CLIPPERISUSINGHWND:
|
|
return "DDERR_CLIPPERISUSINGHWND";
|
|
case DDERR_COLORKEYNOTSET:
|
|
return "DDERR_COLORKEYNOTSET";
|
|
case DDERR_CURRENTLYNOTAVAIL:
|
|
return "DDERR_CURRENTLYNOTAVAIL";
|
|
case DDERR_DCALREADYCREATED:
|
|
return "DDERR_DCALREADYCREATED";
|
|
case DDERR_DEVICEDOESNTOWNSURFACE:
|
|
return "DDERR_DEVICEDOESNTOWNSURFACE";
|
|
case DDERR_DIRECTDRAWALREADYCREATED:
|
|
return "DDERR_DIRECTDRAWALREADYCREATED";
|
|
case DDERR_EXCEPTION:
|
|
return "DDERR_EXCEPTION";
|
|
case DDERR_EXCLUSIVEMODEALREADYSET:
|
|
return "DDERR_EXCLUSIVEMODEALREADYSET";
|
|
case DDERR_EXPIRED:
|
|
return "DDERR_EXPIRED";
|
|
case DDERR_GENERIC:
|
|
return "DDERR_GENERIC";
|
|
case DDERR_HEIGHTALIGN:
|
|
return "DDERR_HEIGHTALIGN";
|
|
case DDERR_HWNDALREADYSET:
|
|
return "DDERR_HWNDALREADYSET";
|
|
case DDERR_HWNDSUBCLASSED:
|
|
return "DDERR_HWNDSUBCLASSED";
|
|
case DDERR_IMPLICITLYCREATED:
|
|
return "DDERR_IMPLICITLYCREATED";
|
|
case DDERR_INCOMPATIBLEPRIMARY:
|
|
return "DDERR_INCOMPATIBLEPRIMARY";
|
|
case DDERR_INVALIDCAPS:
|
|
return "DDERR_INVALIDCAPS";
|
|
case DDERR_INVALIDCLIPLIST:
|
|
return "DDERR_INVALIDCLIPLIST";
|
|
case DDERR_INVALIDDIRECTDRAWGUID:
|
|
return "DDERR_INVALIDDIRECTDRAWGUID";
|
|
case DDERR_INVALIDMODE:
|
|
return "DDERR_INVALIDMODE";
|
|
case DDERR_INVALIDOBJECT:
|
|
return "DDERR_INVALIDOBJECT";
|
|
case DDERR_INVALIDPARAMS:
|
|
return "DDERR_INVALIDPARAMS";
|
|
case DDERR_INVALIDPIXELFORMAT:
|
|
return "DDERR_INVALIDPIXELFORMAT";
|
|
case DDERR_INVALIDPOSITION:
|
|
return "DDERR_INVALIDPOSITION";
|
|
case DDERR_INVALIDRECT:
|
|
return "DDERR_INVALIDRECT";
|
|
case DDERR_INVALIDSTREAM:
|
|
return "DDERR_INVALIDSTREAM";
|
|
case DDERR_INVALIDSURFACETYPE:
|
|
return "DDERR_INVALIDSURFACETYPE";
|
|
case DDERR_LOCKEDSURFACES:
|
|
return "DDERR_LOCKEDSURFACES";
|
|
case DDERR_MOREDATA:
|
|
return "DDERR_MOREDATA";
|
|
case DDERR_NO3D:
|
|
return "DDERR_NO3D";
|
|
case DDERR_NOALPHAHW:
|
|
return "DDERR_NOALPHAHW";
|
|
case DDERR_NOBLTHW:
|
|
return "DDERR_NOBLTHW";
|
|
case DDERR_NOCLIPLIST:
|
|
return "DDERR_NOCLIPLIST";
|
|
case DDERR_NOCLIPPERATTACHED:
|
|
return "DDERR_NOCLIPPERATTACHED";
|
|
case DDERR_NOCOLORCONVHW:
|
|
return "DDERR_NOCOLORCONVHW";
|
|
case DDERR_NOCOLORKEY:
|
|
return "DDERR_NOCOLORKEY";
|
|
case DDERR_NOCOLORKEYHW:
|
|
return "DDERR_NOCOLORKEYHW";
|
|
case DDERR_NOCOOPERATIVELEVELSET:
|
|
return "DDERR_NOCOOPERATIVELEVELSET";
|
|
case DDERR_NODC:
|
|
return "DDERR_NODC";
|
|
case DDERR_NODDROPSHW:
|
|
return "DDERR_NODDROPSHW";
|
|
case DDERR_NODIRECTDRAWHW:
|
|
return "DDERR_NODIRECTDRAWHW";
|
|
case DDERR_NODIRECTDRAWSUPPORT:
|
|
return "DDERR_NODIRECTDRAWSUPPORT";
|
|
case DDERR_NOEMULATION:
|
|
return "DDERR_NOEMULATION";
|
|
case DDERR_NOEXCLUSIVEMODE:
|
|
return "DDERR_NOEXCLUSIVEMODE";
|
|
case DDERR_NOFLIPHW:
|
|
return "DDERR_NOFLIPHW";
|
|
case DDERR_NOFOCUSWINDOW:
|
|
return "DDERR_NOFOCUSWINDOW";
|
|
case DDERR_NOGDI:
|
|
return "DDERR_NOGDI";
|
|
case DDERR_NOHWND:
|
|
return "DDERR_NOHWND";
|
|
case DDERR_NOMIPMAPHW:
|
|
return "DDERR_NOMIPMAPHW";
|
|
case DDERR_NOMIRRORHW:
|
|
return "DDERR_NOMIRRORHW";
|
|
case DDERR_NONONLOCALVIDMEM:
|
|
return "DDERR_NONONLOCALVIDMEM";
|
|
case DDERR_NOOPTIMIZEHW:
|
|
return "DDERR_NOOPTIMIZEHW";
|
|
case DDERR_NOOVERLAYDEST:
|
|
return "DDERR_NOOVERLAYDEST";
|
|
case DDERR_NOOVERLAYHW:
|
|
return "DDERR_NOOVERLAYHW";
|
|
case DDERR_NOPALETTEATTACHED:
|
|
return "DDERR_NOPALETTEATTACHED";
|
|
case DDERR_NOPALETTEHW:
|
|
return "DDERR_NOPALETTEHW";
|
|
case DDERR_NORASTEROPHW:
|
|
return "DDERR_NORASTEROPHW";
|
|
case DDERR_NOROTATIONHW:
|
|
return "DDERR_NOROTATIONHW";
|
|
case DDERR_NOSTRETCHHW:
|
|
return "DDERR_NOSTRETCHHW";
|
|
case DDERR_NOT4BITCOLOR:
|
|
return "DDERR_NOT4BITCOLOR";
|
|
case DDERR_NOT4BITCOLORINDEX:
|
|
return "DDERR_NOT4BITCOLORINDEX";
|
|
case DDERR_NOT8BITCOLOR:
|
|
return "DDERR_NOT8BITCOLOR";
|
|
case DDERR_NOTAOVERLAYSURFACE:
|
|
return "DDERR_NOTAOVERLAYSURFACE";
|
|
case DDERR_NOTEXTUREHW:
|
|
return "DDERR_NOTEXTUREHW";
|
|
case DDERR_NOTFLIPPABLE:
|
|
return "DDERR_NOTFLIPPABLE";
|
|
case DDERR_NOTFOUND:
|
|
return "DDERR_NOTFOUND";
|
|
case DDERR_NOTINITIALIZED:
|
|
return "DDERR_NOTINITIALIZED";
|
|
case DDERR_NOTLOADED:
|
|
return "DDERR_NOTLOADED";
|
|
case DDERR_NOTLOCKED:
|
|
return "DDERR_NOTLOCKED";
|
|
case DDERR_NOTPAGELOCKED:
|
|
return "DDERR_NOTPAGELOCKED";
|
|
case DDERR_NOTPALETTIZED:
|
|
return "DDERR_NOTPALETTIZED";
|
|
case DDERR_NOVSYNCHW:
|
|
return "DDERR_NOVSYNCHW";
|
|
case DDERR_NOZBUFFERHW:
|
|
return "DDERR_NOZBUFFERHW";
|
|
case DDERR_NOZOVERLAYHW:
|
|
return "DDERR_NOZOVERLAYHW";
|
|
case DDERR_OUTOFCAPS:
|
|
return "DDERR_OUTOFCAPS";
|
|
case DDERR_OUTOFMEMORY:
|
|
return "DDERR_OUTOFMEMORY";
|
|
case DDERR_OUTOFVIDEOMEMORY:
|
|
return "DDERR_OUTOFVIDEOMEMORY";
|
|
case DDERR_OVERLAPPINGRECTS:
|
|
return "DDERR_OVERLAPPINGRECTS";
|
|
case DDERR_OVERLAYCANTCLIP:
|
|
return "DDERR_OVERLAYCANTCLIP";
|
|
case DDERR_OVERLAYCOLORKEYONLYONEACTIVE:
|
|
return "DDERR_OVERLAYCOLORKEYONLYONEACTIVE";
|
|
case DDERR_OVERLAYNOTVISIBLE:
|
|
return "DDERR_OVERLAYNOTVISIBLE";
|
|
case DDERR_PALETTEBUSY:
|
|
return "DDERR_PALETTEBUSY";
|
|
case DDERR_PRIMARYSURFACEALREADYEXISTS:
|
|
return "DDERR_PRIMARYSURFACEALREADYEXISTS";
|
|
case DDERR_REGIONTOOSMALL:
|
|
return "DDERR_REGIONTOOSMALL";
|
|
case DDERR_SURFACEALREADYATTACHED:
|
|
return "DDERR_SURFACEALREADYATTACHED";
|
|
case DDERR_SURFACEALREADYDEPENDENT:
|
|
return "DDERR_SURFACEALREADYDEPENDENT";
|
|
case DDERR_SURFACEBUSY:
|
|
return "DDERR_SURFACEBUSY";
|
|
case DDERR_SURFACEISOBSCURED:
|
|
return "DDERR_SURFACEISOBSCURED";
|
|
case DDERR_SURFACELOST:
|
|
return "DDERR_SURFACELOST";
|
|
case DDERR_SURFACENOTATTACHED:
|
|
return "DDERR_SURFACENOTATTACHED";
|
|
case DDERR_TOOBIGHEIGHT:
|
|
return "DDERR_TOOBIGHEIGHT";
|
|
case DDERR_TOOBIGSIZE:
|
|
return "DDERR_TOOBIGSIZE";
|
|
case DDERR_TOOBIGWIDTH:
|
|
return "DDERR_TOOBIGWIDTH";
|
|
case DDERR_UNSUPPORTED:
|
|
return "DDERR_UNSUPPORTED";
|
|
case DDERR_UNSUPPORTEDFORMAT:
|
|
return "DDERR_UNSUPPORTEDFORMAT";
|
|
case DDERR_UNSUPPORTEDMASK:
|
|
return "DDERR_UNSUPPORTEDMASK";
|
|
case DDERR_UNSUPPORTEDMODE:
|
|
return "DDERR_UNSUPPORTEDMODE";
|
|
case DDERR_VERTICALBLANKINPROGRESS:
|
|
return "DDERR_VERTICALBLANKINPROGRESS";
|
|
case DDERR_VIDEONOTACTIVE:
|
|
return "DDERR_VIDEONOTACTIVE";
|
|
case DDERR_WASSTILLDRAWING:
|
|
return "DDERR_WASSTILLDRAWING";
|
|
case DDERR_WRONGMODE:
|
|
return "DDERR_WRONGMODE";
|
|
case DDERR_XALIGN:
|
|
return "DDERR_XALIGN";
|
|
default:
|
|
break;
|
|
}
|
|
return "Unknown error";
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
// MOSTLY STATIC INTERNAL WINDOWS THINGS
|
|
//=================================================================================================
|
|
|
|
//
|
|
// ShowErrorBox() -- shows an error message box
|
|
//
|
|
static void ShowErrorBox(const char *m)
|
|
{
|
|
TCHAR msg[1024];
|
|
|
|
wsprintf(msg, "%s: %s", m, GetWindowsErrorMsg(GetLastError()));
|
|
MessageBox(0, msg, apptitle, MB_OK|MB_ICONSTOP);
|
|
}
|
|
|
|
|
|
//
|
|
// CheckWinVersion() -- check to see what version of Windows we happen to be running under
|
|
//
|
|
static BOOL CheckWinVersion(void)
|
|
{
|
|
OSVERSIONINFO osv;
|
|
|
|
ZeroMemory(&osv, sizeof(osv));
|
|
osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
if (!GetVersionEx(&osv)) return TRUE;
|
|
|
|
// haha, yeah, like it will work on Win32s
|
|
if (osv.dwPlatformId == VER_PLATFORM_WIN32s) return TRUE;
|
|
|
|
// we don't like NT 3.51
|
|
if (osv.dwMajorVersion < 4) return TRUE;
|
|
|
|
// nor do we like NT 4
|
|
if (osv.dwPlatformId == VER_PLATFORM_WIN32_NT &&
|
|
osv.dwMajorVersion == 4) return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// WndProcCallback() -- the Windows window callback
|
|
//
|
|
static LRESULT CALLBACK WndProcCallback(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
/* RECT rect;
|
|
POINT pt;
|
|
HRESULT result; */
|
|
|
|
#if defined(POLYMOST) && defined(USE_OPENGL)
|
|
if (hWnd == hGLWindow) return DefWindowProc(hWnd,uMsg,wParam,lParam);
|
|
#endif
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_SYSCOMMAND:
|
|
// don't let the monitor fall asleep or let the screensaver activate
|
|
if (wParam == SC_SCREENSAVE || wParam == SC_MONITORPOWER) return 0;
|
|
|
|
// Since DirectInput won't let me set an exclusive-foreground
|
|
// keyboard for some unknown reason I just have to tell Windows to
|
|
// rack off with its keyboard accelerators.
|
|
if (wParam == SC_KEYMENU || wParam == SC_HOTKEY) return 0;
|
|
break;
|
|
|
|
case WM_ACTIVATEAPP:
|
|
{
|
|
appactive = wParam;
|
|
#if defined(POLYMOST) && defined(USE_OPENGL)
|
|
if (hGLWindow)
|
|
{
|
|
if (!appactive && fullscreen)
|
|
{
|
|
realfs = fullscreen;
|
|
setgamemode(!fullscreen,xdim,ydim,bpp);
|
|
ShowWindow(hWindow, SW_MINIMIZE);
|
|
}
|
|
else if (appactive && realfs)
|
|
{
|
|
ShowWindow(hWindow, SW_SHOWNORMAL);
|
|
SetForegroundWindow(hWindow);
|
|
SetFocus(hWindow);
|
|
setgamemode(realfs,xdim,ydim,bpp);
|
|
realfs = 0;
|
|
}
|
|
}
|
|
#endif
|
|
if (backgroundidle)
|
|
SetPriorityClass(GetCurrentProcess(),
|
|
appactive ? NORMAL_PRIORITY_CLASS : IDLE_PRIORITY_CLASS);
|
|
break;
|
|
}
|
|
case WM_ACTIVATE:
|
|
if (desktopbpp <= 8)
|
|
{
|
|
if (appactive)
|
|
{
|
|
setpalette(0,0,0);
|
|
SetBWSystemColours();
|
|
// initprintf("Resetting palette.\n");
|
|
}
|
|
else
|
|
{
|
|
RestoreSystemColours();
|
|
// initprintf("Resetting system colours.\n");
|
|
}
|
|
}
|
|
|
|
AcquireInputDevices(appactive,-1);
|
|
break;
|
|
|
|
case WM_SIZE:
|
|
if (wParam == SIZE_MAXHIDE || wParam == SIZE_MINIMIZED) appactive = 0;
|
|
else appactive = 1;
|
|
AcquireInputDevices(appactive,-1);
|
|
break;
|
|
|
|
case WM_PALETTECHANGED:
|
|
// someone stole the palette so try and steal it back
|
|
if (appactive && (HWND)wParam != hWindow) setpalette(0,0,0);
|
|
break;
|
|
|
|
case WM_DISPLAYCHANGE:
|
|
// desktop settings changed so adjust our world-view accordingly
|
|
desktopxdim = LOWORD(lParam);
|
|
desktopydim = HIWORD(lParam);
|
|
desktopbpp = wParam;
|
|
getvalidmodes();
|
|
break;
|
|
|
|
case WM_PAINT:
|
|
repaintneeded=1;
|
|
break;
|
|
|
|
// don't draw the frame if fullscreen
|
|
//case WM_NCPAINT:
|
|
//if (!fullscreen) break;
|
|
//return 0;
|
|
|
|
case WM_ERASEBKGND:
|
|
return TRUE;
|
|
|
|
case WM_MOVE:
|
|
// windowx = LOWORD(lParam);
|
|
// windowy = HIWORD(lParam);
|
|
return 0;
|
|
|
|
case WM_MOVING:
|
|
{
|
|
RECT *RECTYMcRECT = (LPRECT)lParam;
|
|
|
|
windowx = RECTYMcRECT->left;
|
|
windowy = RECTYMcRECT->top;
|
|
return 0;
|
|
}
|
|
case WM_CLOSE:
|
|
quitevent = 1;
|
|
return 0;
|
|
|
|
case WM_KEYDOWN:
|
|
case WM_KEYUP:
|
|
// pause sucks. I read that apparently it doesn't work the same everwhere
|
|
// with DirectInput but it does with Windows messages. Oh well.
|
|
if (wParam == VK_PAUSE && (lParam & 0x80000000l))
|
|
{
|
|
SetKey(0x59, 1);
|
|
|
|
if (keypresscallback)
|
|
keypresscallback(0x59, 1);
|
|
}
|
|
break;
|
|
|
|
// JBF 20040115: Alt-F4 upsets us, so drop all system keys on their asses
|
|
case WM_SYSKEYDOWN:
|
|
case WM_SYSKEYUP:
|
|
return 0;
|
|
|
|
case WM_CHAR:
|
|
if (((keyasciififoend+1)&(KEYFIFOSIZ-1)) == keyasciififoplc) return 0;
|
|
if ((keyasciififoend - keyasciififoplc) > 0) return 0;
|
|
keyasciififo[keyasciififoend] = (unsigned char)wParam;
|
|
keyasciififoend = ((keyasciififoend+1)&(KEYFIFOSIZ-1));
|
|
//OSD_Printf("WM_CHAR %d, %d-%d\n",wParam,keyasciififoplc,keyasciififoend);
|
|
return 0;
|
|
|
|
case WM_HOTKEY:
|
|
return 0;
|
|
|
|
case WM_ENTERMENULOOP:
|
|
case WM_ENTERSIZEMOVE:
|
|
AcquireInputDevices(0,-1);
|
|
return 0;
|
|
case WM_EXITMENULOOP:
|
|
case WM_EXITSIZEMOVE:
|
|
AcquireInputDevices(1,-1);
|
|
return 0;
|
|
|
|
case WM_DESTROY:
|
|
hWindow = 0;
|
|
//PostQuitMessage(0); // JBF 20040115: not anymore
|
|
return 0;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
|
|
//
|
|
// RegisterWindowClass() -- register the window class
|
|
//
|
|
static BOOL RegisterWindowClass(void)
|
|
{
|
|
WNDCLASSEX wcx;
|
|
|
|
if (window_class_registered) return FALSE;
|
|
|
|
//initprintf("Registering window class\n");
|
|
|
|
wcx.cbSize = sizeof(wcx);
|
|
wcx.style = CS_OWNDC;
|
|
wcx.lpfnWndProc = WndProcCallback;
|
|
wcx.cbClsExtra = 0;
|
|
wcx.cbWndExtra = 0;
|
|
wcx.hInstance = hInstance;
|
|
wcx.hIcon = LoadImage(hInstance, MAKEINTRESOURCE(100), IMAGE_ICON,
|
|
GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR);
|
|
wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wcx.hbrBackground = (HBRUSH)COLOR_GRAYTEXT;
|
|
wcx.lpszMenuName = NULL;
|
|
wcx.lpszClassName = WindowClass;
|
|
wcx.hIconSm = LoadImage(hInstance, MAKEINTRESOURCE(100), IMAGE_ICON,
|
|
GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR);
|
|
if (!RegisterClassEx(&wcx))
|
|
{
|
|
ShowErrorBox("Failed to register window class");
|
|
return TRUE;
|
|
}
|
|
|
|
window_class_registered = TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// GetWindowsErrorMsg() -- gives a pointer to a static buffer containing the Windows error message
|
|
//
|
|
static LPTSTR GetWindowsErrorMsg(DWORD code)
|
|
{
|
|
static TCHAR lpMsgBuf[1024];
|
|
|
|
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
NULL, code,
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
(LPTSTR)lpMsgBuf, 1024, NULL);
|
|
|
|
return lpMsgBuf;
|
|
}
|
|
|
|
//
|
|
// makeasmwriteable() -- removes write protection from the self-modifying assembly code
|
|
//
|
|
void makeasmwriteable(void)
|
|
{
|
|
#ifndef ENGINE_USING_A_C
|
|
extern int dep_begin, dep_end;
|
|
DWORD oldprot;
|
|
|
|
if (!VirtualProtect((LPVOID)&dep_begin, (SIZE_T)&dep_end - (SIZE_T)&dep_begin, PAGE_EXECUTE_READWRITE, &oldprot))
|
|
{
|
|
ShowErrorBox("Problem making code writeable");
|
|
}
|
|
#endif
|
|
}
|
|
|