raze-gles/polymer/eduke32/build/src/winlayer.c
helixhorned 35a151d2cd Workaround (two, actually) for the hardware gamma bug in 8-bit fullscreen with
ATI cards.
From the time of OpenGL initialization, gamma lookup in classic/fullscreen
will be done in software. Before that, always do a setgamma() after setting the
palette, since this is what resets the HW gamma. However, this may lead to
unappealing artifacts with portions of the scene being sent to the screen with
different gammas.

git-svn-id: https://svn.eduke32.com/eduke32@2085 1a8010ca-5511-0410-912e-c29ae57300e0
2011-10-27 13:14:22 +00:00

3832 lines
99 KiB
C

// Windows DIB/DirectDraw interface layer for the Build Engine
// Originally by Jonathon Fowler (jonof@edgenetwk.com)
#define DIRECTINPUT_VERSION 0x0700
#define DIRECTDRAW_VERSION 0x0600
#define _WIN32_WINNT 0x0501
#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>
#ifdef _MSC_VER
#include <crtdbg.h>
#endif
#include "dxdidf.h" // comment this out if c_dfDI* is being reported as multiply defined
#include <stdlib.h>
#include <signal.h>
#include <stdarg.h>
#ifdef USE_OPENGL
#include "glbuild.h"
#endif
#include "compat.h"
#include "winlayer.h"
#include "pragmas.h"
#include "build.h"
#include "a.h"
#include "osd.h"
#include "rawinput.h"
#include "nedmalloc.h"
#include "mutex.h"
// undefine to restrict windowed resolutions to conventional sizes
#define ANY_WINDOWED_SIZE
static mutex_t m_initprintf;
static int32_t winlayer_uselastgamma = -1;
static int32_t winlayer_have_ATI = 0;
int32_t _buildargc = 0;
const char **_buildargv = NULL;
static char *argvbuf = NULL;
extern int32_t app_main(int32_t 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;
int32_t backgroundidle = 1;
static WORD sysgamma[3][256];
extern int32_t curbrightness, gammabrightness;
#ifdef USE_OPENGL
// OpenGL stuff
static HGLRC hGLRC = 0;
char nofog=0;
char nogl=0;
char forcegl=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 inline BOOL CheckWinVersion(void);
static LRESULT CALLBACK WndProcCallback(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static BOOL InitDirectDraw(void);
static void UninitDirectDraw(void);
static int32_t RestoreDirectDrawMode(void);
static void ReleaseDirectDrawSurfaces(void);
static BOOL InitDirectInput(void);
static void UninitDirectInput(void);
static void GetKeyNames(void);
static void AcquireInputDevices(char acquire);
static inline void DI_PollJoysticks(void);
static int32_t SetupDirectDraw(int32_t width, int32_t height);
static void UninitDIB(void);
static int32_t SetupDIB(int32_t width, int32_t height);
static void ReleaseOpenGL(void);
static void UninitOpenGL(void);
static int32_t SetupOpenGL(int32_t width, int32_t height, int32_t bitspp);
static BOOL RegisterWindowClass(void);
static BOOL CreateAppWindow(int32_t modenum);
static void DestroyAppWindow(void);
// video
static int32_t desktopxdim=0;
static int32_t desktopydim=0;
static int32_t desktopbpp=0;
static int32_t modesetusing=-1;
static int32_t curvidmode = -1;
static int32_t customxdim = 640;
static int32_t customydim = 480;
static int32_t custombpp = 8;
static int32_t customfs = 0;
static uint32_t modeschecked=0;
int32_t xres=-1;
int32_t yres=-1;
int32_t fullscreen=0;
int32_t bpp=0;
int32_t bytesperline=0;
int32_t lockcount=0;
int32_t glcolourdepth=32;
int32_t vsync=0;
uint32_t maxrefreshfreq=60;
intptr_t frameplace=0;
char modechange=1;
char repaintneeded=0;
char offscreenrendering=0;
char videomodereset = 0;
char silentvideomodeswitch = 0;
// input and events
char quitevent=0;
char appactive=1;
char realfs=0;
char regrabmouse=0;
uint32_t mousewheel[2] = { 0,0 };
static char taskswitching=1;
static OSVERSIONINFOEX osv;
#ifdef NEDMALLOC
extern int32_t largepagesavailable;
#else
static HMODULE nedhandle = NULL;
#endif
//-------------------------------------------------------------------------------------------------
// DINPUT (JOYSTICK)
//=================================================================================================
#define JOYSTICK 0
static HMODULE hDInputDLL = NULL;
static LPDIRECTINPUT7A lpDI = NULL;
static LPDIRECTINPUTDEVICE7A lpDID = NULL;
#define INPUT_BUFFER_SIZE 32
static GUID guidDevs;
char di_disabled = 0;
static char di_devacquired;
static HANDLE di_inputevt = 0;
static int32_t joyblast=0;
static struct
{
char *name;
LPDIRECTINPUTDEVICE7A *did;
const DIDATAFORMAT *df;
} devicedef = { "joystick", &lpDID, &c_dfDIJoystick };
static struct _joydef
{
const char *name;
uint32_t ofs; // directinput 'dwOfs' value
} *axisdefs = NULL, *buttondefs = NULL, *hatdefs = NULL;
//-------------------------------------------------------------------------------------------------
// MAIN CRAP
//=================================================================================================
//
// win_gethwnd() -- gets the window handle
//
int32_t win_gethwnd(void)
{
return (int32_t)hWindow;
}
//
// win_gethinstance() -- gets the application instance
//
int32_t win_gethinstance(void)
{
return (int32_t)hInstance;
}
//
// win_allowtaskswitching() -- captures/releases alt+tab hotkeys
//
void win_allowtaskswitching(int32_t 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
//
int32_t win_checkinstance(void)
{
if (!instanceflag) return 0;
return (WaitForSingleObject(instanceflag,0) == WAIT_TIMEOUT);
}
//
// wm_msgbox/wm_ynbox() -- window-manager-provided message boxes
//
int32_t 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;
}
int32_t wm_ynbox(char *name, char *fmt, ...)
{
char buf[2048];
va_list va;
int32_t r;
va_start(va,fmt);
vsprintf(buf,fmt,va);
va_end(va);
r = MessageBox((HWND)win_gethwnd(),buf,name,MB_YESNO|MB_ICONQUESTION|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);
}
static int32_t setgammaramp(WORD gt[3][256]);
//
// SignalHandler() -- called when we've sprung a leak
//
static void SignalHandler(int32_t signum)
{
switch (signum)
{
case SIGSEGV:
OSD_Printf("Fatal Signal caught: SIGSEGV. Bailing out.\n");
if (gammabrightness)
setgammaramp(sysgamma);
gammabrightness = 0;
app_crashhandler();
uninitsystem();
if (stdout) fclose(stdout);
break;
default:
break;
}
}
//
// WinMain() -- main Windows entry point
//
int32_t WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int32_t nCmdShow)
{
int32_t r;
char *argp;
FILE *fp;
HDC hdc;
UNREFERENCED_PARAMETER(lpCmdLine);
UNREFERENCED_PARAMETER(nCmdShow);
hInstance = hInst;
#ifdef _MSC_VER
_CrtSetDbgFlag(_CRTDBG_CHECK_ALWAYS_DF);
#endif
if (!CheckWinVersion() || hPrevInst)
{
MessageBox(0, "This application requires Windows XP or better to run.",
apptitle, MB_OK|MB_ICONSTOP);
return -1;
}
#ifdef NEDMALLOC
/* Attempt to enable SeLockMemoryPrivilege, 2003/Vista/7 only */
if (Bgetenv("BUILD_NOLARGEPAGES") == NULL &&
(osv.dwMajorVersion >= 6 || (osv.dwMajorVersion == 5 && osv.dwMinorVersion == 2)))
{
HANDLE token;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token))
{
TOKEN_PRIVILEGES privs;
privs.PrivilegeCount = 1;
if (LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME, &privs.Privileges[0].Luid))
{
privs.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(token, FALSE, &privs, 0, NULL, NULL) || GetLastError() != S_OK)
{
// failure...
largepagesavailable = 0;
}
}
CloseHandle(token);
}
}
nedcreatepool(SYSTEM_POOL_SIZE, -1);
// atexit(neddestroysyspool);
#else
// don't want to mix msvcrt with msvcrtd!
#ifndef DEBUGGINGAIDS
if ((nedhandle = LoadLibrary("nedmalloc.dll")))
{
nedpool *(WINAPI *nedcreatepool)(size_t, int);
if ((nedcreatepool = (void *)GetProcAddress(nedhandle, "nedcreatepool")))
nedcreatepool(SYSTEM_POOL_SIZE, -1);
}
#endif
#endif
#ifdef DEBUGGINGAIDS
LoadLibraryA("ebacktrace1.dll");
/*
wm_msgbox("boo","didn't load backtrace DLL (code %d)\n", (int)GetLastError());
else
wm_msgbox("yay","loaded backtrace DLL\n");
*/
#endif
hdc = GetDC(NULL);
r = GetDeviceCaps(hdc, BITSPIXEL);
ReleaseDC(NULL, hdc);
if (r < 8)
{
MessageBox(0, "This application requires a desktop color depth of 256-colors or better.",
apptitle, MB_OK|MB_ICONSTOP);
return -1;
}
// carve up the commandline into more recognizable pieces
argvbuf = Bstrdup(GetCommandLine());
_buildargc = 0;
if (argvbuf)
{
char quoted = 0, instring = 0, swallownext = 0;
char *p,*wp; int32_t 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 **)Bmalloc(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;
}
#ifdef USE_OPENGL
if ((argp = Bgetenv("BUILD_NOFOG")) != NULL)
nofog = Batol(argp);
if (Bgetenv("BUILD_FORCEGL") != NULL)
forcegl = 1;
#endif
// install signal handlers
#if !defined(_MSC_VER) || !defined(DEBUGGINGAIDS)
signal(SIGSEGV, SignalHandler);
#endif
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);
if (r) Sleep(3000);
startwin_close();
if (instanceflag) CloseHandle(instanceflag);
if (argvbuf) Bfree(argvbuf);
return r;
}
static int32_t set_maxrefreshfreq(const osdfuncparm_t *parm)
{
int32_t 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 int32_t 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 win_printversion(void)
{
const char *ver = "";
switch (osv.dwPlatformId)
{
case VER_PLATFORM_WIN32_NT:
if (osv.dwMajorVersion == 5)
{
switch (osv.dwMinorVersion)
{
case 1:
ver = "XP";
break;
case 2:
ver = osv.wProductType == VER_NT_WORKSTATION ? "XP x64" : "Server 2003";
break;
}
break;
}
if (osv.dwMajorVersion == 6)
{
switch (osv.dwMinorVersion)
{
case 0:
ver = osv.wProductType == VER_NT_WORKSTATION ? "Vista" : "Server 2008";
break;
case 1:
ver = osv.wProductType == VER_NT_WORKSTATION ? "7" : "Server 2008 R2";
break;
}
break;
}
break;
}
initprintf("Windows %s (build %lu.%lu.%lu) %s", ver,
osv.dwMajorVersion, osv.dwMinorVersion, osv.dwBuildNumber, osv.szCSDVersion);
#ifdef NEDMALLOC
initprintf("\n");
if (largepagesavailable)
initprintf("Large page support available\n");
#else
initprintf(nedhandle ? "\nInitialized nedmalloc\n" : "\n");
#endif
}
int32_t initsystem(void)
{
DEVMODE desktopmode;
// initprintf("Initializing Windows DirectX/GDI system interface\n");
mutex_init(&m_initprintf);
// 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;
memset(curpalette, 0, sizeof(palette_t) * 256);
atexit(uninitsystem);
frameplace=0;
lockcount=0;
win_printversion();
#ifdef USE_OPENGL
if (loadgldriver(getenv("BUILD_GLDRV")))
{
initprintf("Failure loading OpenGL. GL modes are 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);
#ifdef USE_OPENGL
unloadgldriver();
#endif
#ifndef NEDMALLOC
// if (nedhandle) FreeLibrary(nedhandle), nedhandle = NULL;
#endif
}
//
// initprintf() -- prints a string to the intitialization window
//
void initprintf(const char *f, ...)
{
va_list va;
char buf[2048];
static char dabuf[2048];
va_start(va, f);
Bvsnprintf(buf, sizeof(buf), f, va);
va_end(va);
OSD_Printf(buf);
mutex_lock(&m_initprintf);
if ((Bstrlen(dabuf) + Bstrlen(buf) + 2) > sizeof(dabuf))
{
startwin_puts(dabuf);
Bmemset(dabuf, 0, sizeof(dabuf));
}
Bstrcat(dabuf,buf);
if (flushlogwindow || Bstrlen(dabuf) > 768)
{
startwin_puts(dabuf);
handleevents();
Bmemset(dabuf, 0, sizeof(dabuf));
}
mutex_unlock(&m_initprintf);
}
//
// debugprintf() -- sends a debug string to the debugger
//
void debugprintf(const char *f, ...)
{
#if 0 // def 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)
//
int32_t handleevents(void)
{
int32_t rv=0;
MSG msg;
//if (frameplace && fullscreen) printf("Offscreen buffer is locked!\n");
RI_PollDevices(TRUE);
if (hDInputDLL)
DI_PollJoysticks();
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
switch (msg.message)
{
case WM_QUIT:
quitevent = 1;
continue;
case WM_INPUT:
// this call to RI_PollDevices() probably isn't necessary
// RI_PollDevices(FALSE);
RI_ProcessMessage(&msg);
continue;
}
if (startwin_idle((void *)&msg) > 0) continue;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (!appactive || quitevent) rv = -1;
sampletimer();
if (after_handleevents_hook)
after_handleevents_hook();
return rv;
}
//
// initinput() -- init input system
//
int32_t initinput(void)
{
int32_t i;
char layoutname[KL_NAMELENGTH];
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 = 1|2;
joyisgamepad = joynumaxes = joynumbuttons = joynumhats=0;
// 00000409 is "American English"
GetKeyboardLayoutName(layoutname);
if (Bstrcmp(layoutname, "00000409"))
{
initprintf("Switching kb layout from %s ",layoutname);
LoadKeyboardLayout("00000409", KLF_ACTIVATE|KLF_SETFORPROCESS|KLF_SUBSTITUTE_OK);
GetKeyboardLayoutName(layoutname);
initprintf("to %s\n",layoutname);
}
GetKeyNames();
InitDirectInput();
return 0;
}
//
// uninitinput() -- uninit input system
//
void uninitinput(void)
{
uninitmouse();
UninitDirectInput();
}
inline void idle_waitevent_timeout(uint32_t timeout)
{
// timeout becomes a completion deadline
timeout += getticks();
do
{
MSG msg;
if (PeekMessage(&msg, 0, WM_INPUT, WM_INPUT, PM_QS_INPUT))
{
RI_PollDevices(TRUE);
return;
}
Sleep(10);
}
while (timeout > (getticks() + 10));
}
inline void idle_waitevent(void)
{
idle_waitevent_timeout(100);
}
inline void idle(void)
{
idle_waitevent();
}
//
// setjoydeadzone() -- sets the dead and saturation zones for the joystick
//
void setjoydeadzone(int32_t axis, uint16_t dead, uint16_t satur)
{
DIPROPDWORD dipdw;
HRESULT result;
if (!lpDID) 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 = IDirectInputDevice7_SetProperty(lpDID, 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 = IDirectInputDevice7_SetProperty(lpDID, 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(int32_t axis, uint16_t *dead, uint16_t *satur)
{
DIPROPDWORD dipdw;
HRESULT result;
if (!dead || !satur) return;
if (!lpDID) { *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 = IDirectInputDevice7_GetProperty(lpDID, 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 = IDirectInputDevice7_GetProperty(lpDID, 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)
{
int32_t 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_HandleScanCode(i, 0);
SetKey(i, 0);
if (keypresscallback) keypresscallback(i, 0);
//}
}
}
//
// InitDirectInput() -- get DirectInput started
//
// device enumerator
static BOOL CALLBACK InitDirectInput_enum(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef)
{
const char *d;
UNREFERENCED_PARAMETER(pvRef);
if ((lpddi->dwDevType&0xff) != DIDEVTYPE_JOYSTICK)
return DIENUM_CONTINUE;
inputdevices |= 4;
joyisgamepad = ((lpddi->dwDevType & (DIDEVTYPEJOYSTICK_GAMEPAD<<8)) != 0);
d = joyisgamepad ? "GAMEPAD" : "JOYSTICK";
Bmemcpy(&guidDevs, &lpddi->guidInstance, sizeof(GUID));
initprintf(" * %s: %s\n", d, lpddi->tszProductName);
return DIENUM_CONTINUE;
}
static BOOL CALLBACK InitDirectInput_enumobjects(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef)
{
int32_t *typecounts = (int32_t *)pvRef;
if (lpddoi->dwType & DIDFT_AXIS)
{
//initprintf(" Axis: %s (dwOfs=%d)\n", lpddoi->tszName, lpddoi->dwOfs);
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 = 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 = 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, LPDIRECTINPUT7A *, LPUNKNOWN);
DIPROPDWORD dipdw;
LPDIRECTINPUTDEVICE7A dev;
LPDIRECTINPUTDEVICE7A dev2;
DIDEVCAPS didc;
if (hDInputDLL || di_disabled) return FALSE;
initprintf("Initializing DirectInput...\n");
if (!hDInputDLL)
{
// initprintf(" - Loading DINPUT.DLL\n");
hDInputDLL = LoadLibrary("DINPUT.DLL");
if (!hDInputDLL)
{
ShowErrorBox("Error loading DINPUT.DLL");
return TRUE;
}
}
aDirectInputCreateA = (void *)GetProcAddress(hDInputDLL, "DirectInputCreateA");
if (!aDirectInputCreateA) ShowErrorBox("Error fetching DirectInputCreateA()");
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));
initprintf(" - Enumerating attached game controllers\n");
inputdevices = 1|2;
result = IDirectInput7_EnumDevices(lpDI, DIDEVTYPE_JOYSTICK, InitDirectInput_enum, NULL, DIEDFL_ATTACHEDONLY);
if (FAILED(result)) { HorribleDInputDeath("Failed enumerating attached game controllers", result); }
else if (result != DI_OK) initprintf(" Enumerated game controllers with warning: %s\n",GetDInputError(result));
if (inputdevices == (1|2))
{
initprintf(" - No game controllers found\n");
UninitDirectInput();
return TRUE;
}
*devicedef.did = NULL;
// initprintf(" - Creating %s device\n", devicedef.name);
result = IDirectInput7_CreateDeviceEx(lpDI, &guidDevs, &IID_IDirectInputDevice7, (void *)&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 = IDirectInputDevice7_QueryInterface(dev, &IID_IDirectInputDevice7, (LPVOID *)&dev2);
IDirectInputDevice7_Release(dev);
if (FAILED(result)) { HorribleDInputDeath("Failed querying DirectInput7 interface for device", result); }
else if (result != DI_OK) initprintf(" Queried IDirectInputDevice7 interface with warning: %s\n",GetDInputError(result));
result = IDirectInputDevice7_SetDataFormat(dev2, devicedef.df);
if (FAILED(result)) { IDirectInputDevice7_Release(dev2); HorribleDInputDeath("Failed setting data format", result); }
else if (result != DI_OK) initprintf(" Set data format with warning: %s\n",GetDInputError(result));
di_inputevt = CreateEvent(NULL, FALSE, FALSE, NULL);
if (di_inputevt == NULL)
{
IDirectInputDevice7_Release(dev2);
ShowErrorBox("Couldn't create event object");
UninitDirectInput();
return TRUE;
}
result = IDirectInputDevice7_SetEventNotification(dev2, di_inputevt);
if (FAILED(result)) { IDirectInputDevice7_Release(dev2); HorribleDInputDeath("Failed setting event object", result); }
else if (result != DI_OK) initprintf(" Set event object with warning: %s\n",GetDInputError(result));
IDirectInputDevice7_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 = IDirectInputDevice7_SetProperty(dev2, DIPROP_BUFFERSIZE, &dipdw.diph);
if (FAILED(result)) { IDirectInputDevice7_Release(dev2); HorribleDInputDeath("Failed setting buffering", result); }
else if (result != DI_OK) initprintf(" Set buffering with warning: %s\n",GetDInputError(result));
// set up device
{
int32_t typecounts[3] = {0,0,0};
memset(&didc, 0, sizeof(didc));
didc.dwSize = sizeof(didc);
result = IDirectInputDevice7_GetCapabilities(dev2, &didc);
if (FAILED(result)) { IDirectInputDevice7_Release(dev2); HorribleDInputDeath("Failed getting controller capabilities", result); }
else if (result != DI_OK) initprintf(" Fetched controller capabilities with warning: %s\n",GetDInputError(result));
joynumaxes = (uint8_t)didc.dwAxes;
joynumbuttons = min(32,(uint8_t)didc.dwButtons);
joynumhats = (uint8_t)didc.dwPOVs;
initprintf("Controller 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 = (int32_t *)Bcalloc(didc.dwAxes, sizeof(int32_t));
joyhat = (int32_t *)Bcalloc(didc.dwPOVs, sizeof(int32_t));
result = IDirectInputDevice7_EnumObjects(dev2, InitDirectInput_enumobjects, (LPVOID)typecounts, DIDFT_ALL);
if (FAILED(result)) { IDirectInputDevice7_Release(dev2); HorribleDInputDeath("Failed getting controller features", result); }
else if (result != DI_OK) initprintf(" Fetched controller features with warning: %s\n",GetDInputError(result));
}
*devicedef.did = dev2;
di_devacquired = 0;
return FALSE;
}
//
// UninitDirectInput() -- clean up DirectInput
//
static void UninitDirectInput(void)
{
int32_t i;
if (hDInputDLL) initprintf("Uninitializing DirectInput...\n");
AcquireInputDevices(0);
if (axisdefs)
{
for (i=joynumaxes-1; i>=0; i--) if (axisdefs[i].name) Bfree((void *)axisdefs[i].name);
Bfree(axisdefs); axisdefs = NULL;
}
if (buttondefs)
{
for (i=joynumbuttons-1; i>=0; i--) if (buttondefs[i].name) Bfree((void *)buttondefs[i].name);
Bfree(buttondefs); buttondefs = NULL;
}
if (hatdefs)
{
for (i=joynumhats-1; i>=0; i--) if (hatdefs[i].name) Bfree((void *)hatdefs[i].name);
Bfree(hatdefs); hatdefs = NULL;
}
if (di_inputevt)
{
CloseHandle(di_inputevt);
di_inputevt = NULL;
}
if (*devicedef.did)
{
IDirectInputDevice7_Release(*devicedef.did);
*devicedef.did = NULL;
}
if (lpDI)
{
IDirectInput7_Release(lpDI);
lpDI = NULL;
}
if (hDInputDLL)
{
FreeLibrary(hDInputDLL);
hDInputDLL = NULL;
}
}
//
// GetKeyNames() -- retrieves the names for all the keys on the keyboard
//
static void GetKeyNames(void)
{
int32_t i;
char tbuf[MAX_PATH], *cp;
memset(key_names,0,sizeof(key_names));
for (i=0; i<256; i++)
{
tbuf[0] = 0;
GetKeyNameText((i>128?(i+128):i)<<16, tbuf, sizeof(key_names[i])-1);
Bstrncpy(&key_names[i][0], tbuf, sizeof(key_names[i])-1);
for (cp=key_names[i]; *cp; cp++)
if (!(*cp>=32 && *cp<127))
*cp = '?';
}
}
const char *getjoyname(int32_t what, int32_t num)
{
switch (what)
{
case 0: // axis
return ((unsigned)num > (unsigned)joynumaxes) ? NULL : (char *)axisdefs[num].name;
case 1: // button
return ((unsigned)num > (unsigned)joynumbuttons) ? NULL : (char *)buttondefs[num].name;
case 2: // hat
return ((unsigned)num > (unsigned)joynumhats) ? NULL : (char *)hatdefs[num].name;
default:
return NULL;
}
}
//
// AcquireInputDevices() -- (un)acquires the input devices
//
static void AcquireInputDevices(char acquire)
{
DWORD flags;
HRESULT result;
if (!hDInputDLL) return;
if (!hWindow) return;
if (acquire)
{
// if (!appactive) return; // why acquire when inactive?
if (! *devicedef.did) return;
IDirectInputDevice7_Unacquire(*devicedef.did);
flags = DISCL_FOREGROUND|DISCL_NONEXCLUSIVE;
result = IDirectInputDevice7_SetCooperativeLevel(*devicedef.did, hWindow, flags);
if (FAILED(result))
initprintf("IDirectInputDevice7_SetCooperativeLevel(%s): %s\n",
devicedef.name, GetDInputError(result));
if (SUCCEEDED(IDirectInputDevice7_Acquire(*devicedef.did)))
di_devacquired = 1;
else
di_devacquired = 0;
return;
}
di_devacquired = 0;
releaseallbuttons();
if (! *devicedef.did) return;
IDirectInputDevice7_Unacquire(*devicedef.did);
result = IDirectInputDevice7_SetCooperativeLevel(*devicedef.did, hWindow, DISCL_FOREGROUND|DISCL_NONEXCLUSIVE);
if (FAILED(result))
initprintf("IDirectInputDevice7_SetCooperativeLevel(%s): %s\n",
devicedef.name, GetDInputError(result));
}
//
// ProcessInputDevices() -- processes the input devices
//
static inline void DI_PollJoysticks(void)
{
DWORD dwElements = INPUT_BUFFER_SIZE;
HRESULT result;
DIDEVICEOBJECTDATA didod[INPUT_BUFFER_SIZE];
int32_t i, ev;
if (*devicedef.did)
{
result = IDirectInputDevice7_Poll(*devicedef.did);
if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED)
{
if (SUCCEEDED(IDirectInputDevice7_Acquire(*devicedef.did)))
{
di_devacquired = 1;
IDirectInputDevice7_Poll(*devicedef.did);
}
else di_devacquired = 0;
}
if (di_devacquired)
{
// use event objects so that we can quickly get indication of when data is ready
// to be read and input events processed
ev = WaitForSingleObject(di_inputevt, 0);
if (ev != WAIT_OBJECT_0 || !lpDID)
return;
result = IDirectInputDevice7_GetDeviceData(lpDID, sizeof(DIDEVICEOBJECTDATA),
(LPDIDEVICEOBJECTDATA)&didod, &dwElements, 0);
if (result != DI_OK || !dwElements) return;
for (i=dwElements-1; i>=0; i--)
{
int32_t j;
// 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;
}
}
}
}
}
//
// 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_t timerfreq=0;
static int32_t timerlastsample=0;
int32_t 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
//
int32_t inittimer(int32_t tickspersecond)
{
int64_t 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 = (int32_t)(t*timerticspersec / timerfreq);
usertimercallback = NULL;
return 0;
}
//
// uninittimer() -- shut down timer
//
void uninittimer(void)
{
if (!timerfreq) return;
timerfreq=0;
timerticspersec = 0;
}
//
// sampletimer() -- update totalclock
//
inline void sampletimer(void)
{
int64_t i;
int32_t n;
if (!timerfreq) return;
QueryPerformanceCounter((LARGE_INTEGER *)&i);
n = (int32_t)((i*timerticspersec / timerfreq) - timerlastsample);
if (n <= 0) return;
totalclock += n;
timerlastsample += n;
if (usertimercallback) for (; n>0; n--) usertimercallback();
}
//
// getticks() -- returns the windows ticks count
//
uint32_t getticks(void)
{
int64_t i;
if (timerfreq == 0) return 0;
QueryPerformanceCounter((LARGE_INTEGER *)&i);
return (uint32_t)(i*longlong(1000)/timerfreq);
}
// high-resolution timers for profiling
uint64_t gethiticks(void)
{
uint64_t i;
if (timerfreq == 0) return 0;
QueryPerformanceCounter((LARGE_INTEGER *)&i);
return i;
}
uint64_t gethitickspersec(void)
{
return timerfreq;
}
//
// gettimerfreq() -- returns the number of ticks per second the timer is configured to generate
//
int32_t 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;
static int32_t setgammaramp(WORD gt[3][256]);
static int32_t getgammaramp(WORD gt[3][256]);
static void ToggleDesktopComposition(BOOL compEnable)
{
static HMODULE hDWMApiDLL = NULL;
static HRESULT(WINAPI *aDwmEnableComposition)(UINT);
if (!hDWMApiDLL && (hDWMApiDLL = LoadLibrary("DWMAPI.DLL")))
aDwmEnableComposition = (void *)GetProcAddress(hDWMApiDLL, "DwmEnableComposition");
if (aDwmEnableComposition)
{
aDwmEnableComposition(compEnable);
if (!silentvideomodeswitch)
initprintf("%sabling desktop composition...\n", (compEnable) ? "En" : "Dis");
}
}
//
// checkvideomode() -- makes sure the video mode passed is legal
//
int32_t checkvideomode(int32_t *x, int32_t *y, int32_t c, int32_t fs, int32_t forced)
{
int32_t 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
//
#ifdef USE_OPENGL
static HWND hGLWindow = NULL;
#endif
int32_t setvideomode(int32_t x, int32_t y, int32_t c, int32_t fs)
{
char inp;
int32_t 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;
}
inp = di_devacquired;
AcquireInputDevices(0);
if (hWindow && gammabrightness)
{
setgammaramp(sysgamma);
gammabrightness = 0;
}
if (osv.dwMajorVersion >= 6)
ToggleDesktopComposition(c < 16);
if (!silentvideomodeswitch)
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() < 0) gammabrightness = 0;
}
#ifdef USE_OPENGL
if (hGLWindow && glinfo.vsync) bwglSwapIntervalEXT(vsync);
#endif
if (inp) AcquireInputDevices(1);
modechange=1;
videomodereset = 0;
OSD_ResizeDisplay(xres,yres);
//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))
#ifdef USE_OPENGL
void setvsync(int32_t sync)
{
if (!glinfo.vsync)
{
vsync = 0;
return;
}
vsync = sync;
bwglSwapIntervalEXT(sync);
}
static void cdsenummodes(void)
{
DEVMODE dm;
int32_t i = 0, j = 0;
struct { uint32_t x,y,bpp,freq; } modes[MAXVALIDMODES];
int32_t nmodes=0;
uint32_t 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)
{
uint32_t 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 int32_t sortmodes(const struct validmode_t *a, const struct validmode_t *b)
{
int32_t 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)
{
int32_t cdepths[2] = { 8, 0 };
int32_t i, j, maxx=0, maxy=0;
HRESULT result;
#ifdef USE_OPENGL
if (desktopbpp > 8 && !nogl) cdepths[1] = desktopbpp;
else cdepths[1] = 0;
#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)
}
}
}
#ifdef USE_OPENGL
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), (int32_t( *)(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)
{
if (bpp > 8)
{
if (offscreenrendering) return;
frameplace = 0;
bytesperline = 0;
modechange = 0;
return;
}
if (lockcount++ > 0)
return; // already locked
if (offscreenrendering) return;
frameplace = fullscreen ? (intptr_t)lpOffscreen : (intptr_t)lpPixels;
if (!modechange) return;
modechange=0;
if (!fullscreen)
{
bytesperline = xres|4;
}
else
{
bytesperline = xres|1;
}
setvlinebpl(bytesperline);
{
int32_t i = 0, j = 0;
for (; i<=ydim; i++)
ylookup[i] = j, j += bytesperline;
}
}
//
// 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(int32_t w)
{
HRESULT result;
DDSURFACEDESC ddsd;
char *p,*q;
int32_t i,j;
#ifdef USE_OPENGL
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_TRIANGLES);
bglVertex2f(-2.5f, 1.f);
bglVertex2f(2.5f, 1.f);
bglVertex2f(.0f, -2.5f);
bglEnd();
bglDisable(GL_BLEND);
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);
return;
}
if (!w && (IDirectDrawSurface_GetBltStatus(lpDDSBack, DDGBS_CANBLT) == DDERR_WASSTILLDRAWING ||
IDirectDrawSurface_GetFlipStatus(lpDDSPrimary, DDGFS_CANFLIP) == DDERR_WASSTILLDRAWING))
return;
// lock the backbuffer surface
Bmemset(&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.
//
int32_t setpalette(int32_t start, int32_t num)
{
int32_t i, n;
HRESULT result;
RGBQUAD *rgb;
//HPALETTE hPalPrev;
static struct logpal
{
WORD palVersion;
WORD palNumEntries;
PALETTEENTRY palPalEntry[256];
} lpal;
if (bpp > 8) return 0; // no palette in opengl
Bmemcpy(lpal.palPalEntry, curpalettefaded, sizeof(lpal.palPalEntry));
for (i=start, n=num-1; n>0; i++, n--)
curpalettefaded[i].f = lpal.palPalEntry[i].peFlags = PC_NOCOLLAPSE;
if (fullscreen)
{
if (!lpDDPalette) return -1;
result = IDirectDrawPalette_SetEntries(lpDDPalette, 0, 0, 256, (LPPALETTEENTRY)lpal.palPalEntry);
if (result != DD_OK)
{
initprintf("Palette set failed: %s\n", GetDDrawError(result));
return -1;
}
if (winlayer_have_ATI)
{
winlayer_uselastgamma = (winlayer_uselastgamma!=-1);
setgamma();
winlayer_uselastgamma = 0;
}
return 0;
}
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);
Bfree(rgb);
}
return 0;
}
//
// getpalette() -- get palette values
//
/*
int32_t getpalette(int32_t start, int32_t num, char *dapal)
{
int32_t 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 int32_t setgammaramp(WORD gt[3][256])
{
if (!fullscreen || bpp > 8)
{
// GL and windowed mode use DIB method
int32_t i;
HDC hDC = GetDC(hWindow);
i = SetDeviceGammaRamp(hDC, gt) ? 0 : -1;
ReleaseDC(hWindow, hDC);
return i;
}
else if (appactive)
{
// 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);
initprintf("Error querying gamma control: %s\n",GetDDrawError(hr));
return -1;
}
hr = IDirectDrawGammaControl_SetGammaRamp(gam, 0, (LPDDGAMMARAMP)gt);
if (hr != DD_OK)
{
IDirectDrawGammaControl_Release(gam);
initprintf("Error setting gamma ramp: %s\n",GetDDrawError(hr));
// ShowDDrawErrorBox("Error setting gamma ramp", hr);
return -1;
}
IDirectDrawGammaControl_Release(gam);
return 0;
}
return 0;
}
int32_t setgamma(void)
{
int32_t i;
static WORD gammaTable[3][256];
float gamma = max(0.1f,min(4.f,vid_gamma));
float contrast = max(0.1f,min(3.f,vid_contrast));
float bright = max(-0.8f,min(0.8f,vid_brightness));
double invgamma = 1 / gamma;
double norm = pow(255., invgamma - 1);
if (!hWindow) return -1;
if (winlayer_have_ATI && bpp==8 && fullscreen)
return -1;
// This formula is taken from Doomsday
if (!winlayer_uselastgamma)
for (i = 0; i < 256; i++)
{
double val = i * contrast - (contrast - 1) * 127;
if (gamma != 1) val = pow(val, invgamma) / norm;
val += bright * 128;
gammaTable[0][i] = gammaTable[1][i] = gammaTable[2][i] = (WORD)max(0.f,(double)min(0xffff,val*256));
}
return setgammaramp(gammaTable);
}
static int32_t getgammaramp(WORD gt[3][256])
{
if (!hWindow) return -1;
if (!fullscreen || bpp > 8)
{
int32_t 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);
UNREFERENCED_PARAMETER(lpDesc);
// 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 int32_t 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");
Bfree(lpOffscreen);
lpOffscreen = NULL;
}
}
//
// SetupDirectDraw() -- sets up DirectDraw rendering
//
static int32_t SetupDirectDraw(int32_t width, int32_t height)
{
HRESULT result;
DDSURFACEDESC ddsd;
int32_t i;
// 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 *)Bmalloc((width|1)*height);
if (!lpOffscreen)
{
ShowErrorBox("Failure allocating offscreen buffer");
UninitDirectDraw();
return TRUE;
}
// attach a palette to the primary surface
// initprintf(" - Creating palette\n");
for (i=0; i<256; i++)
curpalettefaded[i].f = PC_NOCOLLAPSE;
result = IDirectDraw_CreatePalette(lpDD, DDPCAPS_8BIT | DDPCAPS_ALLOW256, (LPPALETTEENTRY)curpalettefaded, &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 (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 int32_t SetupDIB(int32_t width, int32_t height)
{
struct binfo
{
BITMAPINFOHEADER header;
RGBQUAD colours[256];
} dibsect;
int32_t 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;
}
#ifdef USE_OPENGL
//
// ReleaseOpenGL() -- cleans up OpenGL rendering stuff
//
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 int32_t SetupOpenGL(int32_t width, int32_t height, int32_t 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;
int32_t minidriver;
int32_t err;
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;
}
loadglextensions();
// We should really be checking for the new WGL extension string instead
// Enable this to leverage ARB_debug_output
if (bwglCreateContextAttribsARB && 0) {
HGLRC debuggingContext = hGLRC;
// This corresponds to WGL_CONTEXT_FLAGS_ARB set to WGL_CONTEXT_DEBUG_BIT_ARB
// I'm too lazy to get a new wglext.h
int attribs[] = {
0x2094, 0x1,
0
};
debuggingContext = bwglCreateContextAttribsARB(hDC, NULL, attribs);
if (debuggingContext) {
bwglDeleteContext(hGLRC);
bwglMakeCurrent(hDC, debuggingContext);
hGLRC = debuggingContext;
// This should be able to get the ARB_debug_output symbols
loadglextensions();
}
}
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;
int32_t err = 0;
glinfo.vendor = (char *)bglGetString(GL_VENDOR);
glinfo.renderer = (char *)bglGetString(GL_RENDERER);
glinfo.version = (char *)bglGetString(GL_VERSION);
glinfo.extensions = (char *)bglGetString(GL_EXTENSIONS);
// GL driver blacklist
if (!Bstrcmp(glinfo.vendor,"Microsoft Corporation")) err = 1;
else if (!Bstrcmp(glinfo.vendor,"SiS")) err = 1;
else if (!Bstrcmp(glinfo.vendor,"3Dfx Interactive Inc.")) err = 1;
else if (!Bstrcmp(glinfo.vendor,"Intel"))
{
if (!Bstrncmp(glinfo.renderer,"Intel 8", 7)) // 845G and 865G confirmed to work
err = 0;
else if (!Bstrncmp(glinfo.renderer,"Intel 9", 7)) // 915G, 945GM, 965/963 GMA confirmed to work
err = 0;
else if (!Bstrcmp(glinfo.renderer,"Intel Cantiga"))
err = 0;
else if (!Bstrcmp(glinfo.renderer,"Mobile Intel(R) 4 Series Express Chipset Family"))
err = 0;
else if (!Bstrcmp(glinfo.renderer,"Intel Brookdale-G"))
err = 0;
else err = 1;
}
else
{
if (!Bstrcmp(glinfo.vendor,"ATI Technologies Inc."))
{
winlayer_have_ATI = 1;
#ifdef POLYMER
pr_ati_fboworkaround = 1;
initprintf("Enabling ATI FBO color attachment workaround.\n");
#endif
if (Bstrstr(glinfo.renderer,"Radeon X1"))
{
r_vbos = 0;
#ifdef POLYMER
pr_ati_nodepthoffset = 1;
initprintf("Enabling ATI R520 polygon offset workaround.\n");
#endif
}
#ifdef POLYMER
else
pr_ati_nodepthoffset = 0;
#endif
}
#ifdef POLYMER
else
pr_ati_fboworkaround = 0;
#endif
}
if (!forcegl && err)
{
OSD_Printf("Unsupported OpenGL driver detected. GL modes will be unavailable. Use -forcegl to override.\n");
wm_msgbox("Unsupported OpenGL driver", "Unsupported OpenGL driver detected. GL modes will be unavailable.");
ReleaseOpenGL();
unloadgldriver();
nogl = 1;
modeschecked = 0;
getvalidmodes();
return TRUE;
}
glinfo.maxanisotropy = 1.0;
glinfo.bgra = 0;
glinfo.texcompr = 0;
// process the extensions string and flag stuff we recognize
p = (GLubyte *)Bstrdup(glinfo.extensions);
p3 = p;
while ((p2 = (GLubyte *)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") && Bstrcmp(glinfo.vendor,"ATI Technologies Inc."))
{
// 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, "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;
}
else if (!Bstrcmp((char *)p2, "WGL_EXT_swap_control"))
{
glinfo.vsync = 1;
}
else if (!Bstrcmp((char *)p2, "GL_EXT_gpu_shader4"))
{
glinfo.sm4 = 1;
}
else if (!Bstrcmp((char *)p2, "GL_ARB_occlusion_query"))
{
glinfo.occlusionqueries = 1;
}
else if (!Bstrcmp((char *)p2, "GL_ARB_shader_objects"))
{
glinfo.glsl = 1;
}
else if (!Bstrcmp((char *)p2, "GL_ARB_debug_output"))
{
glinfo.debugoutput = 1;
}
}
Bfree(p);
}
numpages = 2; // KJS 20031225: tell rotatesprite that it's double buffered!
if (!glinfo.dumped)
{
int32_t oldbpp = bpp;
bpp = 32;
osdcmd_glinfo(NULL);
glinfo.dumped = TRUE;
bpp = oldbpp;
}
return FALSE;
}
#endif
//
// CreateAppWindow() -- create the application window
//
static BOOL CreateAppWindow(int32_t modenum)
{
RECT rect;
int32_t w, h, x, y, stylebits = 0, stylebitsex = 0;
int32_t 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)
{
#ifdef USE_OPENGL
ReleaseOpenGL();
#endif
}
else
{
ReleaseDirectDrawSurfaces();
}
if (!fs && fullscreen)
{
// restore previous display mode and set to normal cooperative level
RestoreDirectDrawMode();
#ifdef USE_OPENGL
}
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,
WindowClass,
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)
{
#ifdef USE_OPENGL
// yes, start up opengl
if (SetupOpenGL(width,height,bitspp))
return TRUE;
#endif
}
else if (SetupDIB(width,height)) // use DIB section
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;
}
#ifdef USE_OPENGL
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_ALLOWMODEX|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)
{
#ifdef USE_OPENGL
// we want an opengl mode
if (SetupOpenGL(width,height,bitspp))
{
return TRUE;
}
#endif
}
else
{
// we want software
if (SetupDirectDraw(width,height))
{
return TRUE;
}
}
}
xres = width;
yres = height;
bpp = bitspp;
fullscreen = fs;
curvidmode = modenum;
frameplace = 0;
lockcount = 0;
// bytesperline is set when framebuffer is locked
//bytesperline = width;
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;
}
#ifdef USE_OPENGL
UninitOpenGL();
#endif
UninitDirectDraw();
UninitDIB();
if (hWindow)
{
DestroyWindow(hWindow);
hWindow = NULL;
}
}
//
// 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 inline BOOL CheckWinVersion(void)
{
ZeroMemory(&osv, sizeof(osv));
osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
// we don't like anything older than Windows XP
if (!GetVersionEx((LPOSVERSIONINFOA)&osv)) return FALSE;
if (osv.dwMajorVersion >= 6) return TRUE;
if (osv.dwMajorVersion == 5 && osv.dwMinorVersion >= 1) 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; */
#ifdef 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 != 0);
#ifdef USE_OPENGL
if (hGLWindow)
{
if (!appactive && fullscreen)
{
if (mousegrab)
{
grabmouse(0);
regrabmouse = 1;
}
realfs = fullscreen;
silentvideomodeswitch = 1;
setgamemode(!fullscreen,xdim,ydim,bpp);
ShowWindow(hWindow, SW_MINIMIZE);
}
else if (appactive && realfs)
{
if (regrabmouse)
{
grabmouse(1);
regrabmouse = 0;
}
ShowWindow(hWindow, SW_RESTORE);
SetForegroundWindow(hWindow);
SetFocus(hWindow);
setgamemode(realfs,xdim,ydim,bpp);
silentvideomodeswitch = 0;
realfs = 0;
}
}
#endif
if (backgroundidle)
SetPriorityClass(GetCurrentProcess(),
appactive ? NORMAL_PRIORITY_CLASS : IDLE_PRIORITY_CLASS);
if (appactive)
{
SetForegroundWindow(hWindow);
SetFocus(hWindow);
}
Bmemset(keystatus, 0, sizeof(keystatus));
AcquireInputDevices(appactive);
break;
}
case WM_ACTIVATE:
appactive = (wParam != WA_INACTIVE);
if (appactive)
{
SetForegroundWindow(hWindow);
SetFocus(hWindow);
}
Bmemset(keystatus, 0, sizeof(keystatus));
AcquireInputDevices(appactive);
break;
case WM_SIZE:
if (wParam == SIZE_MAXHIDE || wParam == SIZE_MINIMIZED) appactive = 0;
else appactive = 1;
AcquireInputDevices(appactive);
break;
case WM_PALETTECHANGED:
// someone stole the palette so try and steal it back
if (bDDrawInited && bpp == 8 && fullscreen)
{
int32_t result = IDirectDrawSurface_SetPalette(lpDDSPrimary, lpDDPalette);
if (result != DD_OK)
{
initprintf("Palette set failed: %s\n", GetDDrawError(result));
break;
}
setpalette(0,256);
break;
}
if (appactive && (HWND)wParam != hWindow) setpalette(0,256);
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_ENTERMENULOOP:
case WM_ENTERSIZEMOVE:
AcquireInputDevices(0);
return 0;
case WM_EXITMENULOOP:
case WM_EXITSIZEMOVE:
AcquireInputDevices(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;
}