2012-01-12 15:32:27 -08:00
|
|
|
/* Copyright (c) 2012 Wildfire Games
|
2009-04-18 10:00:33 -07:00
|
|
|
*
|
2010-02-08 08:23:39 -08:00
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining
|
|
|
|
|
* a copy of this software and associated documentation files (the
|
|
|
|
|
* "Software"), to deal in the Software without restriction, including
|
|
|
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
|
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
|
|
|
* the following conditions:
|
|
|
|
|
*
|
|
|
|
|
* The above copyright notice and this permission notice shall be included
|
|
|
|
|
* in all copies or substantial portions of the Software.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
|
|
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
|
|
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
|
|
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
|
|
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
2009-04-18 10:00:33 -07:00
|
|
|
*/
|
|
|
|
|
|
2009-04-18 10:51:05 -07:00
|
|
|
/*
|
|
|
|
|
* emulate SDL on Windows.
|
2006-04-11 16:59:08 -07:00
|
|
|
*/
|
|
|
|
|
|
2004-05-07 18:11:51 -07:00
|
|
|
#include "precompiled.h"
|
2012-01-12 15:32:27 -08:00
|
|
|
#include "lib/external_libraries/libsdl.h"
|
2004-03-02 15:56:51 -08:00
|
|
|
|
2008-01-19 03:33:11 -08:00
|
|
|
#if CONFIG2_WSDL
|
2007-12-29 08:45:22 -08:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <math.h>
|
2006-04-18 22:30:02 -07:00
|
|
|
#include <queue>
|
2006-09-11 15:35:44 -07:00
|
|
|
#include <algorithm>
|
2005-11-02 11:10:44 -08:00
|
|
|
|
2010-03-01 06:52:58 -08:00
|
|
|
#include "lib/sysdep/os/win/win.h"
|
2005-11-02 11:10:44 -08:00
|
|
|
#include <process.h> // _beginthreadex
|
|
|
|
|
#include <WindowsX.h> // message crackers
|
2004-03-02 15:56:51 -08:00
|
|
|
|
2007-05-28 08:08:33 -07:00
|
|
|
#include "lib/module_init.h"
|
2011-03-21 10:53:13 -07:00
|
|
|
#include "lib/posix/posix_pthread.h"
|
2011-03-23 09:14:47 -07:00
|
|
|
#include "lib/sysdep/sysdep.h"
|
2010-03-01 06:52:58 -08:00
|
|
|
#include "lib/sysdep/os/win/wutil.h"
|
|
|
|
|
#include "lib/sysdep/os/win/winit.h"
|
2008-06-30 10:34:18 -07:00
|
|
|
#include "lib/sysdep/os/win/wmi.h" // for SDL_GetVideoInfo
|
2005-01-23 10:05:33 -08:00
|
|
|
|
2005-08-09 09:23:19 -07:00
|
|
|
#if MSC_VERSION
|
2004-03-02 15:56:51 -08:00
|
|
|
#pragma comment(lib, "user32.lib")
|
|
|
|
|
#pragma comment(lib, "gdi32.lib")
|
|
|
|
|
#endif
|
|
|
|
|
|
2008-01-14 13:04:55 -08:00
|
|
|
#include "lib/ogl.h" // needed to pull in the delay-loaded opengl32.dll
|
|
|
|
|
|
2010-06-14 05:09:49 -07:00
|
|
|
|
2007-06-15 14:58:24 -07:00
|
|
|
WINIT_REGISTER_LATE_INIT(wsdl_Init);
|
|
|
|
|
WINIT_REGISTER_EARLY_SHUTDOWN(wsdl_Shutdown);
|
|
|
|
|
|
2005-10-30 17:15:49 -08:00
|
|
|
// in fullscreen mode, i.e. not windowed.
|
|
|
|
|
// video mode will be restored when app is deactivated.
|
2004-07-28 01:31:13 -07:00
|
|
|
static bool fullscreen;
|
2004-03-02 15:56:51 -08:00
|
|
|
|
2005-10-30 17:15:49 -08:00
|
|
|
// the app is shutting down.
|
|
|
|
|
// if set, ignore further Windows messages for clean shutdown.
|
2007-05-29 09:28:34 -07:00
|
|
|
static bool is_quitting;
|
2004-06-09 08:43:59 -07:00
|
|
|
|
2007-12-29 08:45:22 -08:00
|
|
|
static HWND g_hWnd = (HWND)INVALID_HANDLE_VALUE;
|
2010-12-09 03:16:21 -08:00
|
|
|
|
|
|
|
|
// usable at any time (required by SDL_SetGamma); this is made
|
|
|
|
|
// mostly safe via CS_OWNDC.
|
|
|
|
|
static HDC g_hDC = (HDC)INVALID_HANDLE_VALUE;
|
2005-10-30 17:15:49 -08:00
|
|
|
|
|
|
|
|
|
2005-10-11 21:27:55 -07:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
// gamma
|
2004-05-31 05:21:14 -07:00
|
|
|
|
2008-06-21 11:24:07 -07:00
|
|
|
class GammaRamp
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
GammaRamp()
|
|
|
|
|
: m_hasChanged(false)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-09 03:16:21 -08:00
|
|
|
bool Change(HDC hDC, float gamma_r, float gamma_g, float gamma_b)
|
2008-06-21 11:24:07 -07:00
|
|
|
{
|
|
|
|
|
// get current ramp (once) so we can later restore it.
|
|
|
|
|
if(!m_hasChanged)
|
|
|
|
|
{
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(wutil_IsValidHandle(hDC));
|
2010-12-09 03:16:21 -08:00
|
|
|
if(!GetDeviceGammaRamp(hDC, m_original))
|
2008-06-21 11:24:07 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
2005-10-11 21:27:55 -07:00
|
|
|
|
2008-06-21 11:24:07 -07:00
|
|
|
Compute(gamma_r, m_changed+0*256);
|
|
|
|
|
Compute(gamma_g, m_changed+1*256);
|
|
|
|
|
Compute(gamma_b, m_changed+2*256);
|
|
|
|
|
if(!Upload(m_changed))
|
|
|
|
|
return false;
|
2005-10-11 21:27:55 -07:00
|
|
|
|
2008-06-21 11:24:07 -07:00
|
|
|
m_hasChanged = true;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2005-10-11 21:27:55 -07:00
|
|
|
|
2008-06-21 11:24:07 -07:00
|
|
|
void Latch()
|
2005-10-11 21:27:55 -07:00
|
|
|
{
|
2008-06-21 11:24:07 -07:00
|
|
|
if(m_hasChanged)
|
2011-09-21 13:38:09 -07:00
|
|
|
{
|
|
|
|
|
if(!Upload(m_changed))
|
|
|
|
|
m_hasChanged = false;
|
|
|
|
|
}
|
|
|
|
|
|
2005-10-11 21:27:55 -07:00
|
|
|
}
|
|
|
|
|
|
2008-06-21 11:24:07 -07:00
|
|
|
void RestoreOriginal()
|
2005-10-11 21:27:55 -07:00
|
|
|
{
|
2008-06-21 11:24:07 -07:00
|
|
|
if(m_hasChanged)
|
2011-09-21 13:38:09 -07:00
|
|
|
{
|
|
|
|
|
if(!Upload(m_original))
|
|
|
|
|
m_hasChanged = false;
|
|
|
|
|
}
|
2005-10-11 21:27:55 -07:00
|
|
|
}
|
|
|
|
|
|
2008-06-21 11:24:07 -07:00
|
|
|
private:
|
|
|
|
|
static void Compute(float gamma, u16* ramp)
|
|
|
|
|
{
|
|
|
|
|
// assume identity if invalid
|
|
|
|
|
if(gamma <= 0.0f)
|
|
|
|
|
gamma = 1.0f;
|
2005-10-11 21:27:55 -07:00
|
|
|
|
2008-06-21 11:24:07 -07:00
|
|
|
// identity: special-case to make sure we get exact values
|
|
|
|
|
if(gamma == 1.0f)
|
|
|
|
|
{
|
|
|
|
|
for(u16 i = 0; i < 256; i++)
|
2008-12-17 08:32:46 -08:00
|
|
|
ramp[i] = u16(i << 8);
|
2008-06-21 11:24:07 -07:00
|
|
|
return;
|
|
|
|
|
}
|
2005-10-11 21:27:55 -07:00
|
|
|
|
2008-06-21 11:24:07 -07:00
|
|
|
for(int i = 0; i < 256; i++)
|
|
|
|
|
{
|
2008-08-10 04:02:25 -07:00
|
|
|
const double val = pow(i/255.0, (double)gamma);
|
2008-06-21 11:24:07 -07:00
|
|
|
const double clamped = std::max(0.0, std::min(val, 1.0-DBL_EPSILON));
|
|
|
|
|
ramp[i] = u16_from_double(clamped);
|
|
|
|
|
}
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(ramp[0] == 0);
|
|
|
|
|
ENSURE(ramp[255] == 0xFFFF);
|
2008-06-21 11:24:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Upload(u16* ramps)
|
2005-10-11 21:27:55 -07:00
|
|
|
{
|
2008-06-21 11:24:07 -07:00
|
|
|
WinScopedPreserveLastError s;
|
|
|
|
|
SetLastError(0);
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(wutil_IsValidHandle(g_hDC));
|
2010-03-31 15:26:08 -07:00
|
|
|
BOOL ok = SetDeviceGammaRamp(g_hDC, ramps);
|
|
|
|
|
// on multi-monitor NVidia systems, the first call after a reboot
|
|
|
|
|
// fails, but subsequent ones succeed.
|
|
|
|
|
// see http://icculus.org/pipermail/quake3-bugzilla/2009-October/001316.html
|
|
|
|
|
if(ok == FALSE)
|
|
|
|
|
{
|
|
|
|
|
ok = SetDeviceGammaRamp(g_hDC, ramps);
|
2011-09-21 13:38:09 -07:00
|
|
|
// at least one 32-bit XP system STILL fails here,
|
|
|
|
|
// so don't raise an error dialog.
|
|
|
|
|
if(!ok)
|
|
|
|
|
debug_printf(L"SetDeviceGammaRamp failed twice. Oh well.\n");
|
2010-03-31 15:26:08 -07:00
|
|
|
}
|
|
|
|
|
return (ok == TRUE);
|
2005-10-11 21:27:55 -07:00
|
|
|
}
|
|
|
|
|
|
2008-06-21 11:24:07 -07:00
|
|
|
bool m_hasChanged;
|
2005-10-11 21:27:55 -07:00
|
|
|
|
2008-06-21 11:24:07 -07:00
|
|
|
// values are 8.8 fixed point
|
|
|
|
|
u16 m_original[3*256];
|
|
|
|
|
u16 m_changed[3*256];
|
|
|
|
|
};
|
2005-10-11 21:27:55 -07:00
|
|
|
|
2008-06-21 11:24:07 -07:00
|
|
|
static GammaRamp gammaRamp;
|
2005-10-11 21:27:55 -07:00
|
|
|
|
|
|
|
|
|
2008-06-21 11:24:07 -07:00
|
|
|
// note: any component gamma = 0 is assumed to be identity.
|
|
|
|
|
int SDL_SetGamma(float r, float g, float b)
|
|
|
|
|
{
|
2010-12-09 03:16:21 -08:00
|
|
|
return gammaRamp.Change(g_hDC, r, g, b)? 0 : -1;
|
2005-10-11 21:27:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
//----------------------------------------------------------------------------
|
2010-06-05 11:52:39 -07:00
|
|
|
// window
|
2005-10-11 21:27:55 -07:00
|
|
|
//----------------------------------------------------------------------------
|
2004-05-31 05:21:14 -07:00
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
static DWORD wnd_ChooseWindowStyle(bool fullscreen, HWND previousWindow = (HWND)INVALID_HANDLE_VALUE)
|
2005-12-22 16:27:29 -08:00
|
|
|
{
|
2010-06-05 11:52:39 -07:00
|
|
|
DWORD windowStyle = fullscreen? WS_POPUP : WS_POPUPWINDOW|WS_CAPTION|WS_MINIMIZEBOX;
|
|
|
|
|
windowStyle |= WS_VISIBLE;
|
|
|
|
|
windowStyle |= WS_CLIPCHILDREN|WS_CLIPSIBLINGS; // MSDN SetPixelFormat says this is required
|
2005-12-22 16:27:29 -08:00
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
if(!fullscreen) // windowed
|
|
|
|
|
{
|
|
|
|
|
// support resizing
|
|
|
|
|
windowStyle |= WS_SIZEBOX|WS_MAXIMIZEBOX;
|
2005-12-22 16:27:29 -08:00
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
// remember the previous maximized state
|
|
|
|
|
// (else subsequent attempts to maximize will fail)
|
|
|
|
|
if(wutil_IsValidHandle(previousWindow))
|
|
|
|
|
{
|
|
|
|
|
const DWORD previousWindowState = GetWindowLongW(previousWindow, GWL_STYLE);
|
|
|
|
|
windowStyle |= (previousWindowState & WS_MAXIMIZE);
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-03-29 05:21:42 -08:00
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
return windowStyle;
|
2005-11-02 11:10:44 -08:00
|
|
|
}
|
2004-05-07 18:11:51 -07:00
|
|
|
|
|
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
// @param w,h value-return (in: desired, out: actual pixel count)
|
|
|
|
|
static void wnd_UpdateWindowDimensions(DWORD windowStyle, int& w, int& h)
|
2005-11-02 11:10:44 -08:00
|
|
|
{
|
2010-06-03 14:15:45 -07:00
|
|
|
// Calculate the size of the outer window, so that the client area has
|
|
|
|
|
// the desired dimensions.
|
|
|
|
|
RECT r;
|
|
|
|
|
r.left = r.top = 0;
|
2010-06-05 11:52:39 -07:00
|
|
|
r.right = w; r.bottom = h;
|
2011-12-29 01:01:09 -08:00
|
|
|
if(AdjustWindowRectEx(&r, windowStyle, FALSE, 0))
|
2010-06-03 14:15:45 -07:00
|
|
|
{
|
2010-06-05 11:52:39 -07:00
|
|
|
w = r.right - r.left;
|
|
|
|
|
h = r.bottom - r.top;
|
2010-06-03 14:15:45 -07:00
|
|
|
}
|
|
|
|
|
}
|
2004-03-29 05:21:42 -08:00
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
|
2010-12-09 03:16:21 -08:00
|
|
|
static LRESULT CALLBACK OnMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
2004-03-29 05:21:42 -08:00
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
static HWND wnd_CreateWindow(int w, int h)
|
2005-11-02 11:10:44 -08:00
|
|
|
{
|
2007-12-29 08:45:22 -08:00
|
|
|
// (create new window every time (instead of once at startup), because
|
|
|
|
|
// pixel format isn't supposed to be changed more than once)
|
2005-10-13 11:05:55 -07:00
|
|
|
|
2008-06-21 11:24:07 -07:00
|
|
|
// app instance.
|
2010-06-05 11:52:39 -07:00
|
|
|
// returned by GetModuleHandle and used in keyboard hook and window creation.
|
2008-06-21 11:24:07 -07:00
|
|
|
const HINSTANCE hInst = GetModuleHandle(0);
|
|
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
// register window class
|
2010-04-03 03:46:28 -07:00
|
|
|
WNDCLASSW wc;
|
2005-11-02 11:10:44 -08:00
|
|
|
memset(&wc, 0, sizeof(wc));
|
2010-12-09 03:16:21 -08:00
|
|
|
// no CS_VREDRAW and CS_HREDRAW - avoids redrawing when resized.
|
|
|
|
|
wc.style = CS_OWNDC; // (see g_hDC definition)
|
|
|
|
|
wc.lpfnWndProc = OnMessage;
|
2011-12-29 01:01:09 -08:00
|
|
|
wc.lpszClassName = L"WSDL{55752F43-0241-492C-8648-C7243397FCE4}";
|
2005-11-02 11:10:44 -08:00
|
|
|
wc.hInstance = hInst;
|
2010-04-03 03:46:28 -07:00
|
|
|
ATOM class_atom = RegisterClassW(&wc);
|
2005-11-02 11:10:44 -08:00
|
|
|
if(!class_atom)
|
|
|
|
|
{
|
2011-05-04 05:10:17 -07:00
|
|
|
DEBUG_WARN_ERR(ERR::LOGIC); // RegisterClassW failed
|
2005-11-02 11:10:44 -08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2005-10-13 11:05:55 -07:00
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
const DWORD windowStyle = wnd_ChooseWindowStyle(fullscreen);
|
|
|
|
|
wnd_UpdateWindowDimensions(windowStyle, w, h);
|
2005-10-31 08:26:51 -08:00
|
|
|
|
2011-12-29 01:01:09 -08:00
|
|
|
// note: you can override the hard-coded window name via SDL_WM_SetCaption.
|
|
|
|
|
HWND hWnd = CreateWindowExW(WS_EX_APPWINDOW, (LPCWSTR)(uintptr_t)class_atom, L"wsdl", windowStyle, 0, 0, w, h, 0, 0, hInst, 0);
|
|
|
|
|
if(!wutil_IsValidHandle(hWnd))
|
|
|
|
|
DEBUG_WARN_ERR(ERR::FAIL);
|
|
|
|
|
return hWnd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static RECT ClientRect(HWND hWnd)
|
|
|
|
|
{
|
|
|
|
|
RECT rect;
|
|
|
|
|
ENSURE(wutil_IsValidHandle(hWnd));
|
|
|
|
|
WARN_IF_FALSE(GetClientRect(hWnd, &rect));
|
|
|
|
|
return rect;
|
2007-12-29 08:45:22 -08:00
|
|
|
}
|
2005-10-31 10:36:36 -08:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
// video
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
static DEVMODE dm; // current video mode
|
|
|
|
|
static HGLRC hGLRC = (HGLRC)INVALID_HANDLE_VALUE;
|
|
|
|
|
|
2010-10-17 01:55:47 -07:00
|
|
|
// set via SDL_GL_SetAttribute:
|
|
|
|
|
static int depthBufferBits = 24;
|
2011-03-18 11:07:18 -07:00
|
|
|
static int stencilBufferBits = 0;
|
2010-10-17 01:55:47 -07:00
|
|
|
static int vsyncEnabled = 1;
|
|
|
|
|
|
|
|
|
|
int SDL_GL_SetAttribute(SDL_GLattr attr, int value)
|
|
|
|
|
{
|
|
|
|
|
switch(attr)
|
|
|
|
|
{
|
|
|
|
|
case SDL_GL_DEPTH_SIZE:
|
|
|
|
|
depthBufferBits = value;
|
|
|
|
|
break;
|
|
|
|
|
|
2011-03-18 11:07:18 -07:00
|
|
|
case SDL_GL_STENCIL_SIZE:
|
|
|
|
|
stencilBufferBits = value;
|
|
|
|
|
break;
|
|
|
|
|
|
2010-10-17 01:55:47 -07:00
|
|
|
case SDL_GL_SWAP_CONTROL:
|
|
|
|
|
vsyncEnabled = value;
|
|
|
|
|
break;
|
2010-12-09 03:16:21 -08:00
|
|
|
|
|
|
|
|
case SDL_GL_DOUBLEBUFFER:
|
|
|
|
|
// (always enabled)
|
|
|
|
|
break;
|
2010-10-17 01:55:47 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
|
|
|
|
|
// check if resolution needs to be changed
|
|
|
|
|
static bool video_NeedsChange(int w, int h, int cur_w, int cur_h, bool fullscreen)
|
|
|
|
|
{
|
|
|
|
|
// invalid: keep current settings
|
|
|
|
|
if(w <= 0 || h <= 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// higher resolution mode needed
|
|
|
|
|
if(w > cur_w || h > cur_h)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
// fullscreen requested and not exact same mode set
|
|
|
|
|
if(fullscreen && (w != cur_w || h != cur_h))
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-12-28 18:06:09 -08:00
|
|
|
static void video_SetPixelFormat(HDC hDC, int bpp)
|
2007-12-29 08:45:22 -08:00
|
|
|
{
|
2005-11-02 11:10:44 -08:00
|
|
|
const DWORD dwFlags = PFD_SUPPORT_OPENGL|PFD_DRAW_TO_WINDOW|PFD_DOUBLEBUFFER;
|
|
|
|
|
BYTE cColourBits = (BYTE)bpp;
|
|
|
|
|
BYTE cAlphaBits = 0;
|
|
|
|
|
if(bpp == 32)
|
|
|
|
|
{
|
|
|
|
|
cColourBits = 24;
|
|
|
|
|
cAlphaBits = 8;
|
|
|
|
|
}
|
|
|
|
|
const BYTE cAccumBits = 0;
|
2010-10-17 01:55:47 -07:00
|
|
|
const BYTE cDepthBits = (BYTE)depthBufferBits;
|
2011-03-18 11:07:18 -07:00
|
|
|
const BYTE cStencilBits = (BYTE)stencilBufferBits;
|
2005-11-02 11:10:44 -08:00
|
|
|
const BYTE cAuxBuffers = 0;
|
2005-10-31 10:36:36 -08:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
PIXELFORMATDESCRIPTOR pfd =
|
|
|
|
|
{
|
|
|
|
|
sizeof(PIXELFORMATDESCRIPTOR),
|
2007-12-29 08:45:22 -08:00
|
|
|
1, // version
|
|
|
|
|
dwFlags,
|
|
|
|
|
PFD_TYPE_RGBA,
|
|
|
|
|
cColourBits, 0, 0, 0, 0, 0, 0, // c*Bits, c*Shift are unused
|
|
|
|
|
cAlphaBits, 0, // cAlphaShift is unused
|
|
|
|
|
cAccumBits, 0, 0, 0, 0, // cAccum*Bits are unused
|
|
|
|
|
cDepthBits,
|
|
|
|
|
cStencilBits,
|
|
|
|
|
cAuxBuffers,
|
|
|
|
|
PFD_MAIN_PLANE,
|
|
|
|
|
0, 0, 0, 0 // bReserved, dw*Mask are unused
|
2005-11-02 11:10:44 -08:00
|
|
|
};
|
2005-10-31 10:36:36 -08:00
|
|
|
|
2008-01-14 13:04:55 -08:00
|
|
|
// note: the GDI pixel format functions require opengl32.dll to be loaded.
|
|
|
|
|
// a deadlock on the next line is probably due to VLD's LdrLoadDll hook.
|
2005-10-31 08:26:51 -08:00
|
|
|
|
2011-12-28 18:06:09 -08:00
|
|
|
const int pf = ChoosePixelFormat(hDC, &pfd);
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(pf >= 1);
|
2011-12-28 18:06:09 -08:00
|
|
|
WARN_IF_FALSE(SetPixelFormat(hDC, pf, &pfd));
|
2007-12-29 08:45:22 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
// set video mode width x height : bpp (or leave unchanged if already adequate).
|
2007-12-29 08:45:22 -08:00
|
|
|
// w = h = bpp = 0 => no change.
|
2010-09-04 07:49:12 -07:00
|
|
|
SDL_Surface* SDL_SetVideoMode(int w, int h, int bpp, Uint32 flags)
|
2007-12-29 08:45:22 -08:00
|
|
|
{
|
|
|
|
|
WinScopedPreserveLastError s; // OpenGL and GDI
|
|
|
|
|
|
|
|
|
|
fullscreen = (flags & SDL_FULLSCREEN) != 0;
|
|
|
|
|
|
|
|
|
|
// get current mode settings
|
|
|
|
|
memset(&dm, 0, sizeof(dm));
|
|
|
|
|
dm.dmSize = sizeof(dm);
|
2011-12-29 01:01:09 -08:00
|
|
|
WARN_IF_FALSE(EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &dm));
|
2007-12-29 08:45:22 -08:00
|
|
|
const int cur_w = (int)dm.dmPelsWidth, cur_h = (int)dm.dmPelsHeight;
|
|
|
|
|
|
|
|
|
|
// independent of resolution; app must always get bpp it wants
|
|
|
|
|
dm.dmBitsPerPel = bpp;
|
|
|
|
|
dm.dmFields = DM_BITSPERPEL;
|
|
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
if(video_NeedsChange(w,h, cur_w,cur_h, fullscreen))
|
2007-12-29 08:45:22 -08:00
|
|
|
{
|
|
|
|
|
dm.dmPelsWidth = (DWORD)w;
|
|
|
|
|
dm.dmPelsHeight = (DWORD)h;
|
|
|
|
|
dm.dmFields |= DM_PELSWIDTH|DM_PELSHEIGHT;
|
|
|
|
|
}
|
|
|
|
|
// the (possibly changed) mode will be (re)set at next WM_ACTIVATE
|
|
|
|
|
|
2011-12-29 01:01:09 -08:00
|
|
|
if(!wutil_IsValidHandle(g_hWnd))
|
2010-06-03 14:15:45 -07:00
|
|
|
{
|
2010-06-05 11:52:39 -07:00
|
|
|
g_hWnd = wnd_CreateWindow(w, h);
|
2010-06-03 14:15:45 -07:00
|
|
|
if(!wutil_IsValidHandle(g_hWnd))
|
|
|
|
|
return 0;
|
2008-01-14 13:04:55 -08:00
|
|
|
|
2010-06-03 14:15:45 -07:00
|
|
|
g_hDC = GetDC(g_hWnd);
|
2005-11-02 11:10:44 -08:00
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
video_SetPixelFormat(g_hDC, bpp);
|
2007-12-29 08:45:22 -08:00
|
|
|
|
2010-06-03 14:15:45 -07:00
|
|
|
hGLRC = wglCreateContext(g_hDC);
|
|
|
|
|
if(!hGLRC)
|
|
|
|
|
return 0;
|
2005-11-02 11:10:44 -08:00
|
|
|
|
2010-06-03 14:15:45 -07:00
|
|
|
if(!wglMakeCurrent(g_hDC, hGLRC))
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2010-06-05 11:52:39 -07:00
|
|
|
else // update the existing window
|
2010-06-03 14:15:45 -07:00
|
|
|
{
|
2010-06-05 11:52:39 -07:00
|
|
|
const DWORD windowStyle = wnd_ChooseWindowStyle(fullscreen, g_hWnd);
|
|
|
|
|
wnd_UpdateWindowDimensions(windowStyle, w, h);
|
2010-06-03 14:15:45 -07:00
|
|
|
|
2010-06-14 05:09:49 -07:00
|
|
|
UINT swp_flags = SWP_FRAMECHANGED|SWP_NOZORDER|SWP_NOACTIVATE;
|
2010-06-05 11:52:39 -07:00
|
|
|
if(!fullscreen) // windowed: preserve the top-left corner
|
2010-06-14 05:09:49 -07:00
|
|
|
swp_flags |= SWP_NOMOVE;
|
2010-06-03 14:15:45 -07:00
|
|
|
|
|
|
|
|
WARN_IF_FALSE(SetWindowLongW(g_hWnd, GWL_STYLE, windowStyle));
|
2010-06-14 05:09:49 -07:00
|
|
|
WARN_IF_FALSE(SetWindowPos(g_hWnd, 0, 0, 0, w, h, swp_flags));
|
2010-06-03 14:15:45 -07:00
|
|
|
|
2011-12-29 01:01:09 -08:00
|
|
|
LONG status;
|
2010-06-03 14:15:45 -07:00
|
|
|
if(fullscreen)
|
2010-06-05 11:52:39 -07:00
|
|
|
{
|
|
|
|
|
ShowWindow(g_hWnd, SW_RESTORE);
|
2011-12-29 01:01:09 -08:00
|
|
|
status = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
|
2010-06-05 11:52:39 -07:00
|
|
|
}
|
2010-06-03 14:15:45 -07:00
|
|
|
else
|
2010-06-05 11:52:39 -07:00
|
|
|
{
|
2011-12-29 01:01:09 -08:00
|
|
|
status = ChangeDisplaySettings(0, 0);
|
2010-06-05 11:52:39 -07:00
|
|
|
// don't ShowWindow with SW_MINIMIZE (we just want to update)
|
|
|
|
|
}
|
2011-12-29 01:01:09 -08:00
|
|
|
ENSURE(status == DISP_CHANGE_SUCCESSFUL);
|
2010-06-03 14:15:45 -07:00
|
|
|
}
|
2005-11-02 11:10:44 -08:00
|
|
|
|
2010-10-17 01:55:47 -07:00
|
|
|
// (required for ogl_HaveExtension, but callers should also invoke
|
|
|
|
|
// ogl_Init in case the real SDL is being used.)
|
|
|
|
|
ogl_Init();
|
|
|
|
|
if(ogl_HaveExtension("WGL_EXT_swap_control") && pwglSwapIntervalEXT)
|
|
|
|
|
pwglSwapIntervalEXT(vsyncEnabled);
|
|
|
|
|
|
2011-12-29 01:01:09 -08:00
|
|
|
const RECT rect = ClientRect(g_hWnd); // updated window size
|
|
|
|
|
|
|
|
|
|
static SDL_PixelFormat format;
|
|
|
|
|
format.BitsPerPixel = bpp;
|
|
|
|
|
|
|
|
|
|
static SDL_Surface screen;
|
|
|
|
|
screen.w = rect.right;
|
|
|
|
|
screen.h = rect.bottom;
|
|
|
|
|
screen.format = &format;
|
2010-09-04 07:49:12 -07:00
|
|
|
return &screen;
|
2005-11-02 11:10:44 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
static void video_Shutdown()
|
2005-10-13 11:05:55 -07:00
|
|
|
{
|
2005-11-02 11:10:44 -08:00
|
|
|
if(fullscreen)
|
2007-12-20 12:09:19 -08:00
|
|
|
{
|
|
|
|
|
LONG status = ChangeDisplaySettings(0, 0);
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(status == DISP_CHANGE_SUCCESSFUL);
|
2007-12-20 12:09:19 -08:00
|
|
|
}
|
2005-10-13 11:05:55 -07:00
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
if(wutil_IsValidHandle(hGLRC))
|
2005-10-13 11:05:55 -07:00
|
|
|
{
|
2005-11-02 11:10:44 -08:00
|
|
|
WARN_IF_FALSE(wglMakeCurrent(0, 0));
|
|
|
|
|
WARN_IF_FALSE(wglDeleteContext(hGLRC));
|
|
|
|
|
hGLRC = (HGLRC)INVALID_HANDLE_VALUE;
|
|
|
|
|
}
|
2010-07-07 15:23:18 -07:00
|
|
|
|
|
|
|
|
g_hWnd = (HWND)INVALID_HANDLE_VALUE;
|
|
|
|
|
g_hDC = (HDC)INVALID_HANDLE_VALUE;
|
2005-11-02 11:10:44 -08:00
|
|
|
}
|
2005-10-13 11:05:55 -07:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
|
|
|
|
|
void SDL_GL_SwapBuffers()
|
|
|
|
|
{
|
2011-12-29 01:01:09 -08:00
|
|
|
WARN_IF_FALSE(SwapBuffers(g_hDC));
|
2005-11-02 11:10:44 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SDL_VideoInfo* SDL_GetVideoInfo()
|
|
|
|
|
{
|
|
|
|
|
static SDL_VideoInfo video_info;
|
|
|
|
|
|
2007-12-29 08:45:22 -08:00
|
|
|
if(video_info.video_mem == 0)
|
2005-11-02 11:10:44 -08:00
|
|
|
{
|
2011-10-13 11:53:59 -07:00
|
|
|
WmiInstances instances;
|
|
|
|
|
if(wmi_GetClassInstances(L"Win32_VideoController", instances) == INFO::OK)
|
2009-08-03 14:24:00 -07:00
|
|
|
{
|
2011-10-13 11:53:59 -07:00
|
|
|
for(WmiInstances::iterator it = instances.begin(); it != instances.end(); ++it)
|
|
|
|
|
{
|
|
|
|
|
if((*it)[L"Availability"].intVal != 8) // not offline
|
|
|
|
|
{
|
2011-12-06 01:17:39 -08:00
|
|
|
video_info.video_mem = std::max<Uint32>(video_info.video_mem, (*it)[L"AdapterRAM"].lVal / KiB);
|
2011-10-13 11:53:59 -07:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-08-03 14:24:00 -07:00
|
|
|
}
|
2005-11-02 11:10:44 -08:00
|
|
|
}
|
2005-10-30 17:15:49 -08:00
|
|
|
|
2007-12-29 08:45:22 -08:00
|
|
|
return &video_info;
|
2005-11-02 11:10:44 -08:00
|
|
|
}
|
2005-10-13 11:05:55 -07:00
|
|
|
|
|
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
SDL_Surface* SDL_GetVideoSurface()
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2005-10-13 11:05:55 -07:00
|
|
|
|
|
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
// event queue
|
|
|
|
|
|
2007-12-29 08:45:22 -08:00
|
|
|
// note: we only use winit to redirect stdout; this queue won't be used
|
|
|
|
|
// before _cinit.
|
2005-11-02 11:10:44 -08:00
|
|
|
typedef std::queue<SDL_Event> Queue;
|
2010-06-05 11:52:39 -07:00
|
|
|
static Queue g_queue;
|
2005-11-02 11:10:44 -08:00
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
static void QueueEvent(const SDL_Event& ev)
|
2005-11-02 11:10:44 -08:00
|
|
|
{
|
2010-06-05 11:52:39 -07:00
|
|
|
g_queue.push(ev);
|
2005-11-02 11:10:44 -08:00
|
|
|
}
|
|
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
static bool DequeueEvent(SDL_Event& ev)
|
2005-11-02 11:10:44 -08:00
|
|
|
{
|
2010-06-05 11:52:39 -07:00
|
|
|
if(g_queue.empty())
|
2005-11-02 11:10:44 -08:00
|
|
|
return false;
|
2010-06-05 11:52:39 -07:00
|
|
|
ev = g_queue.front();
|
|
|
|
|
g_queue.pop();
|
2005-11-02 11:10:44 -08:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2005-12-22 16:27:29 -08:00
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
// keyboard
|
|
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
// note: keysym.unicode is only returned for SDL_KEYDOWN, and is otherwise 0.
|
2010-06-05 11:52:39 -07:00
|
|
|
static void QueueKeyEvent(Uint8 type, SDLKey sdlk, WCHAR unicode_char)
|
2005-11-02 11:10:44 -08:00
|
|
|
{
|
|
|
|
|
SDL_Event ev;
|
|
|
|
|
ev.type = type;
|
2010-06-05 11:52:39 -07:00
|
|
|
ev.key.keysym.sym = sdlk;
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 11:48:32 -07:00
|
|
|
ev.key.keysym.unicode = (Uint16)unicode_char;
|
2010-06-05 11:52:39 -07:00
|
|
|
QueueEvent(ev);
|
2005-11-02 11:10:44 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static Uint8 keys[SDLK_LAST];
|
|
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
static SDLKey g_SDLKeyForVK[256]; // g_SDLKeyForVK[vk] == SDLK
|
2006-06-23 10:41:55 -07:00
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
static void key_Init()
|
2005-11-02 11:10:44 -08:00
|
|
|
{
|
|
|
|
|
// Map the VK keysyms
|
2010-10-28 05:22:11 -07:00
|
|
|
for(size_t i = 0; i < ARRAY_SIZE(g_SDLKeyForVK); i++)
|
2010-06-05 11:52:39 -07:00
|
|
|
g_SDLKeyForVK[i] = SDLK_UNKNOWN;
|
|
|
|
|
|
|
|
|
|
g_SDLKeyForVK[VK_BACK] = SDLK_BACKSPACE;
|
|
|
|
|
g_SDLKeyForVK[VK_TAB] = SDLK_TAB;
|
|
|
|
|
g_SDLKeyForVK[VK_CLEAR] = SDLK_CLEAR;
|
|
|
|
|
g_SDLKeyForVK[VK_RETURN] = SDLK_RETURN;
|
|
|
|
|
g_SDLKeyForVK[VK_PAUSE] = SDLK_PAUSE;
|
|
|
|
|
g_SDLKeyForVK[VK_ESCAPE] = SDLK_ESCAPE;
|
|
|
|
|
g_SDLKeyForVK[VK_SPACE] = SDLK_SPACE;
|
|
|
|
|
g_SDLKeyForVK[VK_OEM_7] = SDLK_QUOTE;
|
|
|
|
|
g_SDLKeyForVK[VK_OEM_COMMA] = SDLK_COMMA;
|
|
|
|
|
g_SDLKeyForVK[VK_OEM_MINUS] = SDLK_MINUS;
|
|
|
|
|
g_SDLKeyForVK[VK_OEM_PERIOD] = SDLK_PERIOD;
|
|
|
|
|
g_SDLKeyForVK[VK_OEM_2] = SDLK_SLASH;
|
|
|
|
|
g_SDLKeyForVK[VK_OEM_1] = SDLK_SEMICOLON;
|
|
|
|
|
g_SDLKeyForVK[VK_OEM_PLUS] = SDLK_EQUALS;
|
|
|
|
|
g_SDLKeyForVK[VK_OEM_4] = SDLK_LEFTBRACKET;
|
|
|
|
|
g_SDLKeyForVK[VK_OEM_5] = SDLK_BACKSLASH;
|
|
|
|
|
g_SDLKeyForVK[VK_OEM_6] = SDLK_RIGHTBRACKET;
|
|
|
|
|
g_SDLKeyForVK[VK_OEM_3] = SDLK_BACKQUOTE;
|
|
|
|
|
g_SDLKeyForVK[VK_OEM_8] = SDLK_BACKQUOTE;
|
|
|
|
|
|
|
|
|
|
// winuser.h guarantees A..Z and 0..9 match their ASCII values:
|
|
|
|
|
const int VK_0 = '0';
|
|
|
|
|
for(int i = 0; i < 10; i++)
|
|
|
|
|
g_SDLKeyForVK[VK_0+i] = (SDLKey)(SDLK_0+i);
|
|
|
|
|
const int VK_A = 'A';
|
|
|
|
|
for(int i = 0; i < 26; i++)
|
|
|
|
|
g_SDLKeyForVK[VK_A+i] = (SDLKey)(SDLK_a+i);
|
|
|
|
|
|
|
|
|
|
g_SDLKeyForVK[VK_DELETE] = SDLK_DELETE;
|
|
|
|
|
|
|
|
|
|
for(int i = 0; i < 10; i++)
|
|
|
|
|
g_SDLKeyForVK[VK_NUMPAD0+i] = (SDLKey)(SDLK_KP0+i);
|
|
|
|
|
|
|
|
|
|
g_SDLKeyForVK[VK_DECIMAL] = SDLK_KP_PERIOD;
|
|
|
|
|
g_SDLKeyForVK[VK_DIVIDE] = SDLK_KP_DIVIDE;
|
|
|
|
|
g_SDLKeyForVK[VK_MULTIPLY] = SDLK_KP_MULTIPLY;
|
|
|
|
|
g_SDLKeyForVK[VK_SUBTRACT] = SDLK_KP_MINUS;
|
|
|
|
|
g_SDLKeyForVK[VK_ADD] = SDLK_KP_PLUS;
|
|
|
|
|
|
|
|
|
|
g_SDLKeyForVK[VK_UP] = SDLK_UP;
|
|
|
|
|
g_SDLKeyForVK[VK_DOWN] = SDLK_DOWN;
|
|
|
|
|
g_SDLKeyForVK[VK_RIGHT] = SDLK_RIGHT;
|
|
|
|
|
g_SDLKeyForVK[VK_LEFT] = SDLK_LEFT;
|
|
|
|
|
g_SDLKeyForVK[VK_INSERT] = SDLK_INSERT;
|
|
|
|
|
g_SDLKeyForVK[VK_HOME] = SDLK_HOME;
|
|
|
|
|
g_SDLKeyForVK[VK_END] = SDLK_END;
|
|
|
|
|
g_SDLKeyForVK[VK_PRIOR] = SDLK_PAGEUP;
|
|
|
|
|
g_SDLKeyForVK[VK_NEXT] = SDLK_PAGEDOWN;
|
|
|
|
|
|
|
|
|
|
for(int i = 0; i < 12; i++)
|
|
|
|
|
g_SDLKeyForVK[VK_F1+i] = (SDLKey)(SDLK_F1+i);
|
|
|
|
|
|
|
|
|
|
g_SDLKeyForVK[VK_NUMLOCK] = SDLK_NUMLOCK;
|
|
|
|
|
g_SDLKeyForVK[VK_CAPITAL] = SDLK_CAPSLOCK;
|
|
|
|
|
g_SDLKeyForVK[VK_SCROLL] = SDLK_SCROLLOCK;
|
|
|
|
|
g_SDLKeyForVK[VK_RSHIFT] = SDLK_RSHIFT;
|
|
|
|
|
g_SDLKeyForVK[VK_LSHIFT] = SDLK_LSHIFT;
|
|
|
|
|
g_SDLKeyForVK[VK_SHIFT] = SDLK_LSHIFT; // XXX: Not quite
|
|
|
|
|
g_SDLKeyForVK[VK_RCONTROL] = SDLK_RCTRL;
|
|
|
|
|
g_SDLKeyForVK[VK_LCONTROL] = SDLK_LCTRL;
|
|
|
|
|
g_SDLKeyForVK[VK_CONTROL] = SDLK_LCTRL; // XXX: Not quite
|
|
|
|
|
g_SDLKeyForVK[VK_RMENU] = SDLK_RALT;
|
|
|
|
|
g_SDLKeyForVK[VK_LMENU] = SDLK_LALT;
|
|
|
|
|
g_SDLKeyForVK[VK_MENU] = SDLK_LALT; // XXX: Not quite
|
|
|
|
|
g_SDLKeyForVK[VK_RWIN] = SDLK_RSUPER;
|
|
|
|
|
g_SDLKeyForVK[VK_LWIN] = SDLK_LSUPER;
|
|
|
|
|
|
|
|
|
|
g_SDLKeyForVK[VK_HELP] = SDLK_HELP;
|
2005-11-02 11:10:44 -08:00
|
|
|
#ifdef VK_PRINT
|
2010-06-05 11:52:39 -07:00
|
|
|
g_SDLKeyForVK[VK_PRINT] = SDLK_PRINT;
|
2005-11-02 11:10:44 -08:00
|
|
|
#endif
|
2010-06-05 11:52:39 -07:00
|
|
|
g_SDLKeyForVK[VK_SNAPSHOT] = SDLK_PRINT;
|
|
|
|
|
g_SDLKeyForVK[VK_CANCEL] = SDLK_BREAK;
|
|
|
|
|
g_SDLKeyForVK[VK_APPS] = SDLK_MENU;
|
2005-11-02 11:10:44 -08:00
|
|
|
}
|
2005-10-31 10:36:36 -08:00
|
|
|
|
2005-10-13 11:05:55 -07:00
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
static inline SDLKey SDLKeyFromVK(int vk)
|
|
|
|
|
{
|
2005-11-02 11:10:44 -08:00
|
|
|
if(!(0 <= vk && vk < 256))
|
|
|
|
|
{
|
2011-05-04 05:10:17 -07:00
|
|
|
DEBUG_WARN_ERR(ERR::LOGIC); // invalid vk
|
2005-11-02 11:10:44 -08:00
|
|
|
return SDLK_UNKNOWN;
|
2005-10-13 11:05:55 -07:00
|
|
|
}
|
2010-06-05 11:52:39 -07:00
|
|
|
return g_SDLKeyForVK[vk];
|
2005-10-13 11:05:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
static void key_ResetAll()
|
2005-10-13 11:05:55 -07:00
|
|
|
{
|
2005-11-02 11:10:44 -08:00
|
|
|
SDL_Event spoofed_up_event;
|
|
|
|
|
spoofed_up_event.type = SDL_KEYUP;
|
|
|
|
|
spoofed_up_event.key.keysym.unicode = 0;
|
2005-10-13 11:05:55 -07:00
|
|
|
|
2010-10-28 05:22:11 -07:00
|
|
|
for(size_t i = 0; i < ARRAY_SIZE(keys); i++)
|
2010-06-05 11:52:39 -07:00
|
|
|
{
|
2005-11-02 11:10:44 -08:00
|
|
|
if(keys[i])
|
|
|
|
|
{
|
|
|
|
|
spoofed_up_event.key.keysym.sym = (SDLKey)i;
|
2010-06-05 11:52:39 -07:00
|
|
|
QueueEvent(spoofed_up_event);
|
2005-11-02 11:10:44 -08:00
|
|
|
}
|
2010-06-05 11:52:39 -07:00
|
|
|
}
|
2005-01-06 17:25:10 -08:00
|
|
|
}
|
|
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
|
|
|
|
|
static LRESULT OnKey(HWND UNUSED(hWnd), UINT vk, BOOL fDown, int UNUSED(cRepeat), UINT flags)
|
2004-03-02 15:56:51 -08:00
|
|
|
{
|
2005-11-02 11:10:44 -08:00
|
|
|
// TODO Mappings for left/right modifier keys
|
|
|
|
|
// TODO Modifier statekeeping
|
2004-03-02 15:56:51 -08:00
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
const SDLKey sdlk = SDLKeyFromVK(vk);
|
2005-11-02 11:10:44 -08:00
|
|
|
if(sdlk != SDLK_UNKNOWN)
|
|
|
|
|
keys[sdlk] = (Uint8)fDown;
|
2004-03-02 15:56:51 -08:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
if(!fDown)
|
2010-06-05 11:52:39 -07:00
|
|
|
QueueKeyEvent(SDL_KEYUP, sdlk, 0);
|
2005-11-02 11:10:44 -08:00
|
|
|
else
|
2004-03-02 15:56:51 -08:00
|
|
|
{
|
2005-11-02 11:10:44 -08:00
|
|
|
// note: flags is HIWORD(lParam) from WM_KEYDOWN, which includes
|
|
|
|
|
// scancode. ToUnicode also uses its bit 15 to determine if the
|
|
|
|
|
// key is currently pressed.
|
|
|
|
|
const UINT scancode = flags;
|
|
|
|
|
u8 key_states[256];
|
2011-12-29 01:01:09 -08:00
|
|
|
WARN_IF_FALSE(GetKeyboardState(key_states));
|
2005-11-02 11:10:44 -08:00
|
|
|
WCHAR wchars[8];
|
|
|
|
|
int output_count = ToUnicode(vk, scancode, key_states, wchars, ARRAY_SIZE(wchars), 0);
|
|
|
|
|
// translation succeeded; queue each produced character
|
|
|
|
|
if(output_count > 0)
|
2004-03-02 15:56:51 -08:00
|
|
|
{
|
2005-11-02 11:10:44 -08:00
|
|
|
for(int i = 0; i < output_count; i++)
|
2010-06-05 11:52:39 -07:00
|
|
|
QueueKeyEvent(SDL_KEYDOWN, sdlk, wchars[i]);
|
2004-03-02 15:56:51 -08:00
|
|
|
}
|
2005-11-02 11:10:44 -08:00
|
|
|
// dead-char; do nothing
|
|
|
|
|
else if(output_count == -1)
|
2004-03-02 15:56:51 -08:00
|
|
|
{
|
|
|
|
|
}
|
2005-11-02 11:10:44 -08:00
|
|
|
// translation failed; just generate a regular (non-unicode) event
|
|
|
|
|
else if(output_count == 0)
|
2010-06-05 11:52:39 -07:00
|
|
|
QueueKeyEvent(SDL_KEYDOWN, sdlk, 0);
|
2005-11-02 11:10:44 -08:00
|
|
|
else
|
|
|
|
|
UNREACHABLE;
|
2004-03-02 15:56:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
|
|
|
|
|
Uint8* SDL_GetKeyState(int* num_keys)
|
2004-07-21 09:34:07 -07:00
|
|
|
{
|
2005-11-02 11:10:44 -08:00
|
|
|
if(num_keys)
|
|
|
|
|
*num_keys = SDLK_LAST;
|
|
|
|
|
return keys;
|
2004-07-21 09:34:07 -07:00
|
|
|
}
|
2004-03-02 15:56:51 -08:00
|
|
|
|
|
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
// always on (we don't care about the extra overhead)
|
|
|
|
|
int SDL_EnableUNICODE(int UNUSED(enable))
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
2004-03-02 15:56:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-12-30 11:45:13 -08:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
// joystick
|
|
|
|
|
|
|
|
|
|
int SDL_NumJoysticks()
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int SDL_JoystickEventState(int UNUSED(state))
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-30 12:10:04 -08:00
|
|
|
const char* SDL_JoystickName(int UNUSED(device_index))
|
|
|
|
|
{
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-30 11:45:13 -08:00
|
|
|
SDL_Joystick* SDL_JoystickOpen(int UNUSED(device_index))
|
|
|
|
|
{
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int SDL_JoystickNumAxes(SDL_Joystick* UNUSED(joystick))
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Sint16 SDL_JoystickGetAxis(SDL_Joystick* UNUSED(joystick), int UNUSED(axis))
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
// app activation
|
|
|
|
|
|
|
|
|
|
enum SdlActivationType { LOSE = 0, GAIN = 1 };
|
|
|
|
|
|
|
|
|
|
static inline void QueueActiveEvent(SdlActivationType type, size_t changed_app_state)
|
|
|
|
|
{
|
|
|
|
|
// SDL says this event is not generated when the window is created,
|
|
|
|
|
// but skipping the first event may confuse things.
|
|
|
|
|
|
|
|
|
|
SDL_Event ev;
|
|
|
|
|
ev.type = SDL_ACTIVEEVENT;
|
|
|
|
|
ev.active.state = (u8)changed_app_state;
|
|
|
|
|
ev.active.gain = (u8)((type == GAIN)? 1 : 0);
|
|
|
|
|
QueueEvent(ev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// SDL_APP* bitflags indicating whether we are active.
|
|
|
|
|
// note: responsibility for yielding lies with SDL apps -
|
|
|
|
|
// they control the main loop.
|
|
|
|
|
static Uint8 app_state;
|
|
|
|
|
|
|
|
|
|
static void active_ChangeState(SdlActivationType type, Uint8 changed_app_state)
|
|
|
|
|
{
|
|
|
|
|
Uint8 old_app_state = app_state;
|
|
|
|
|
|
|
|
|
|
if(type == GAIN)
|
|
|
|
|
app_state = Uint8(app_state | changed_app_state);
|
|
|
|
|
else
|
|
|
|
|
app_state = Uint8(app_state & ~changed_app_state);
|
|
|
|
|
|
|
|
|
|
// generate an event - but only if the given state flags actually changed.
|
|
|
|
|
if((old_app_state & changed_app_state) != (app_state & changed_app_state))
|
|
|
|
|
QueueActiveEvent(type, changed_app_state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static LRESULT OnActivate(HWND hWnd, UINT state, HWND UNUSED(hWndActDeact), BOOL fMinimized)
|
|
|
|
|
{
|
|
|
|
|
SdlActivationType type;
|
|
|
|
|
Uint8 changed_app_state;
|
|
|
|
|
|
|
|
|
|
// went active and not minimized
|
|
|
|
|
if(state != WA_INACTIVE && !fMinimized)
|
|
|
|
|
{
|
|
|
|
|
type = GAIN;
|
|
|
|
|
changed_app_state = SDL_APPINPUTFOCUS|SDL_APPACTIVE;
|
|
|
|
|
|
|
|
|
|
// grab keyboard focus (we previously had DefWindowProc do this).
|
|
|
|
|
SetFocus(hWnd);
|
|
|
|
|
|
|
|
|
|
gammaRamp.Latch();
|
|
|
|
|
if(fullscreen)
|
|
|
|
|
{
|
|
|
|
|
ShowWindow(g_hWnd, SW_RESTORE);
|
2011-12-29 01:01:09 -08:00
|
|
|
const LONG ret = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
|
|
|
|
|
ENSURE(ret == DISP_CHANGE_SUCCESSFUL);
|
2010-06-05 11:52:39 -07:00
|
|
|
}
|
2010-10-21 14:09:41 -07:00
|
|
|
|
|
|
|
|
// re-assert mouse grab state
|
|
|
|
|
SDL_WM_GrabInput(SDL_WM_GrabInput(SDL_GRAB_QUERY));
|
2010-06-05 11:52:39 -07:00
|
|
|
}
|
|
|
|
|
// deactivated (Alt+Tab out) or minimized
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
type = LOSE;
|
|
|
|
|
changed_app_state = SDL_APPINPUTFOCUS;
|
|
|
|
|
if(fMinimized)
|
|
|
|
|
changed_app_state |= SDL_APPACTIVE;
|
|
|
|
|
|
|
|
|
|
key_ResetAll();
|
|
|
|
|
|
|
|
|
|
gammaRamp.RestoreOriginal();
|
|
|
|
|
if(fullscreen)
|
|
|
|
|
{
|
2011-12-29 01:01:09 -08:00
|
|
|
const LONG ret = ChangeDisplaySettings(0, 0);
|
|
|
|
|
ENSURE(ret == DISP_CHANGE_SUCCESSFUL);
|
|
|
|
|
WARN_IF_FALSE(ShowWindow(g_hWnd, SW_MINIMIZE));
|
2010-06-05 11:52:39 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
active_ChangeState(type, changed_app_state);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Uint8 SDL_GetAppState()
|
|
|
|
|
{
|
|
|
|
|
return app_state;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void QueueQuitEvent()
|
|
|
|
|
{
|
|
|
|
|
SDL_Event ev;
|
|
|
|
|
ev.type = SDL_QUIT;
|
|
|
|
|
QueueEvent(ev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
// mouse
|
2004-07-08 08:11:42 -07:00
|
|
|
|
2006-09-11 16:30:23 -07:00
|
|
|
// background: there are several types of coordinates.
|
|
|
|
|
// - screen coords are relative to the primary desktop and may therefore be
|
|
|
|
|
// negative on multi-monitor systems (e.g. if secondary monitor is left of
|
|
|
|
|
// primary). they are prefixed with screen_*.
|
|
|
|
|
// - "client" coords are simply relative to the parent window's origin and
|
|
|
|
|
// can also be negative (e.g. in the window's NC area).
|
|
|
|
|
// these are prefixed with client_*.
|
2008-06-22 04:11:59 -07:00
|
|
|
// - "idealized" coords are what the app sees. these range from 0 to
|
2010-06-05 11:52:39 -07:00
|
|
|
// windowDimensions-1. they are returned by mouse_GetCoords and have no prefix.
|
2006-08-27 03:33:22 -07:00
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
static void QueueMouseEvent(int x, int y)
|
2005-12-22 16:27:29 -08:00
|
|
|
{
|
|
|
|
|
SDL_Event ev;
|
|
|
|
|
ev.type = SDL_MOUSEMOTION;
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(unsigned(x|y) <= USHRT_MAX);
|
2006-09-11 16:30:23 -07:00
|
|
|
ev.motion.x = (Uint16)x;
|
|
|
|
|
ev.motion.y = (Uint16)y;
|
2010-06-05 11:52:39 -07:00
|
|
|
QueueEvent(ev);
|
2005-12-22 16:27:29 -08:00
|
|
|
}
|
|
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
static void QueueButtonEvent(int button, int state, int x, int y)
|
2005-12-22 16:27:29 -08:00
|
|
|
{
|
|
|
|
|
SDL_Event ev;
|
2009-07-16 16:53:46 -07:00
|
|
|
ev.type = Uint8((state == SDL_PRESSED)? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP);
|
2005-12-22 16:27:29 -08:00
|
|
|
ev.button.button = (u8)button;
|
|
|
|
|
ev.button.state = (u8)state;
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(unsigned(x|y) <= USHRT_MAX);
|
2006-09-11 16:30:23 -07:00
|
|
|
ev.button.x = (Uint16)x;
|
|
|
|
|
ev.button.y = (Uint16)y;
|
2010-06-05 11:52:39 -07:00
|
|
|
QueueEvent(ev);
|
2005-12-22 16:27:29 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 11:48:32 -07:00
|
|
|
static int mouse_x, mouse_y;
|
2005-12-22 16:27:29 -08:00
|
|
|
|
|
|
|
|
// generate a mouse move message and update our notion of the mouse position.
|
2006-09-08 13:09:26 -07:00
|
|
|
// x, y are client pixel coordinates.
|
2005-12-22 16:27:29 -08:00
|
|
|
// notes:
|
|
|
|
|
// - does not actually move the OS cursor;
|
2010-06-05 11:52:39 -07:00
|
|
|
// - called from mouse_Update and SDL_WarpMouse.
|
|
|
|
|
static void mouse_UpdatePosition(int x, int y)
|
2005-12-22 16:27:29 -08:00
|
|
|
{
|
2006-09-08 13:09:26 -07:00
|
|
|
// nothing to do if it hasn't changed since last time
|
|
|
|
|
if(mouse_x == x && mouse_y == y)
|
|
|
|
|
return;
|
2006-08-27 03:33:22 -07:00
|
|
|
|
|
|
|
|
mouse_x = x;
|
|
|
|
|
mouse_y = y;
|
2010-06-05 11:52:39 -07:00
|
|
|
QueueMouseEvent(x, y);
|
2005-12-22 16:27:29 -08:00
|
|
|
}
|
|
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
static POINT mouse_ScreenFromClient(int client_x, int client_y)
|
2005-12-22 16:27:29 -08:00
|
|
|
{
|
2008-06-21 11:24:07 -07:00
|
|
|
POINT screen_pt;
|
|
|
|
|
screen_pt.x = (LONG)client_x;
|
|
|
|
|
screen_pt.y = (LONG)client_y;
|
|
|
|
|
WARN_IF_FALSE(ClientToScreen(g_hWnd, &screen_pt));
|
|
|
|
|
return screen_pt;
|
2006-09-11 16:30:23 -07:00
|
|
|
}
|
|
|
|
|
|
2008-06-21 11:24:07 -07:00
|
|
|
// get idealized client coordinates or return false if outside our window.
|
2010-06-05 11:52:39 -07:00
|
|
|
static bool mouse_GetCoords(int screen_x, int screen_y, int& x, int& y)
|
2006-09-11 16:30:23 -07:00
|
|
|
{
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(wutil_IsValidHandle(g_hWnd));
|
2008-06-22 04:11:59 -07:00
|
|
|
|
2008-06-21 11:24:07 -07:00
|
|
|
POINT screen_pt;
|
|
|
|
|
screen_pt.x = (LONG)screen_x;
|
|
|
|
|
screen_pt.y = (LONG)screen_y;
|
|
|
|
|
|
|
|
|
|
POINT client_pt;
|
|
|
|
|
{
|
2008-06-22 04:11:59 -07:00
|
|
|
// note: MapWindowPoints has a really stupid interface, returning 0
|
|
|
|
|
// on failure or if no shift was needed (i.e. window is fullscreen).
|
|
|
|
|
// we must use GetLastError to detect error conditions.
|
|
|
|
|
WinScopedPreserveLastError s;
|
|
|
|
|
SetLastError(0);
|
2008-06-21 11:24:07 -07:00
|
|
|
client_pt = screen_pt; // translated below
|
2008-06-22 04:11:59 -07:00
|
|
|
const int ret = MapWindowPoints(HWND_DESKTOP, g_hWnd, &client_pt, 1);
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(ret != 0 || GetLastError() == 0);
|
2008-06-21 11:24:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
2011-12-29 01:01:09 -08:00
|
|
|
const RECT client_rect = ClientRect(g_hWnd);
|
2008-06-21 11:24:07 -07:00
|
|
|
if(!PtInRect(&client_rect, client_pt))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(WindowFromPoint(screen_pt) != g_hWnd)
|
2006-09-11 16:30:23 -07:00
|
|
|
return false;
|
|
|
|
|
|
2008-06-21 11:24:07 -07:00
|
|
|
x = client_pt.x;
|
|
|
|
|
y = client_pt.y;
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(x >= 0 && y >= 0);
|
2006-09-11 16:30:23 -07:00
|
|
|
return true;
|
2006-08-27 03:33:22 -07:00
|
|
|
}
|
|
|
|
|
|
2006-09-08 13:09:26 -07:00
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
static void mouse_Update()
|
2006-08-27 03:33:22 -07:00
|
|
|
{
|
2006-01-23 00:02:08 -08:00
|
|
|
// window not created yet or already shut down. no sense reporting
|
|
|
|
|
// mouse position, and bail now to avoid ScreenToClient failing.
|
2008-06-22 04:11:59 -07:00
|
|
|
if(!wutil_IsValidHandle(g_hWnd))
|
2006-01-23 00:02:08 -08:00
|
|
|
return;
|
|
|
|
|
|
2006-09-08 13:09:26 -07:00
|
|
|
// don't use DirectInput, because we want to respect the user's mouse
|
2011-12-29 01:01:09 -08:00
|
|
|
// sensitivity settings. Windows messages are prone to lag,
|
|
|
|
|
// so query current position directly.
|
2009-01-03 10:40:48 -08:00
|
|
|
// note: GetCursorPos fails if the desktop is switched (e.g. after
|
|
|
|
|
// pressing Ctrl+Alt+Del), which can be ignored.
|
2006-09-08 13:09:26 -07:00
|
|
|
POINT screen_pt;
|
2009-01-03 10:40:48 -08:00
|
|
|
if(!GetCursorPos(&screen_pt))
|
|
|
|
|
return;
|
2008-06-21 11:24:07 -07:00
|
|
|
int x, y;
|
2010-06-05 11:52:39 -07:00
|
|
|
if(mouse_GetCoords(screen_pt.x, screen_pt.y, x, y))
|
2005-12-22 16:27:29 -08:00
|
|
|
{
|
2010-06-05 11:52:39 -07:00
|
|
|
active_ChangeState(GAIN, SDL_APPMOUSEFOCUS);
|
|
|
|
|
mouse_UpdatePosition(x, y);
|
2005-12-22 16:27:29 -08:00
|
|
|
}
|
|
|
|
|
// moved outside of window
|
|
|
|
|
else
|
2010-06-05 11:52:39 -07:00
|
|
|
active_ChangeState(LOSE, SDL_APPMOUSEFOCUS);
|
2005-12-22 16:27:29 -08:00
|
|
|
}
|
|
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
|
2010-01-01 07:33:07 -08:00
|
|
|
static unsigned mouse_buttons;
|
2004-07-08 08:11:42 -07:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
// (we define a new function signature since the windowsx.h message crackers
|
|
|
|
|
// don't provide for passing uMsg)
|
2010-11-13 11:51:15 -08:00
|
|
|
static LRESULT OnMouseButton(HWND UNUSED(hWnd), UINT uMsg, int client_x, int client_y, UINT flags)
|
2004-07-08 08:11:42 -07:00
|
|
|
{
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 11:48:32 -07:00
|
|
|
int button;
|
|
|
|
|
int state;
|
2005-11-02 11:10:44 -08:00
|
|
|
switch(uMsg)
|
2004-07-08 08:11:42 -07:00
|
|
|
{
|
2005-11-02 11:10:44 -08:00
|
|
|
case WM_LBUTTONDOWN:
|
|
|
|
|
button = SDL_BUTTON_LEFT;
|
|
|
|
|
state = SDL_PRESSED;
|
|
|
|
|
break;
|
|
|
|
|
case WM_LBUTTONUP:
|
|
|
|
|
button = SDL_BUTTON_LEFT;
|
|
|
|
|
state = SDL_RELEASED;
|
|
|
|
|
break;
|
|
|
|
|
case WM_RBUTTONDOWN:
|
|
|
|
|
button = SDL_BUTTON_RIGHT;
|
|
|
|
|
state = SDL_PRESSED;
|
|
|
|
|
break;
|
|
|
|
|
case WM_RBUTTONUP:
|
|
|
|
|
button = SDL_BUTTON_RIGHT;
|
|
|
|
|
state = SDL_RELEASED;
|
|
|
|
|
break;
|
|
|
|
|
case WM_MBUTTONDOWN:
|
|
|
|
|
button = SDL_BUTTON_MIDDLE;
|
|
|
|
|
state = SDL_PRESSED;
|
|
|
|
|
break;
|
|
|
|
|
case WM_MBUTTONUP:
|
|
|
|
|
button = SDL_BUTTON_MIDDLE;
|
|
|
|
|
state = SDL_RELEASED;
|
2005-11-07 13:52:27 -08:00
|
|
|
break;
|
2010-11-13 11:51:15 -08:00
|
|
|
case WM_XBUTTONDOWN:
|
|
|
|
|
button = SDL_BUTTON_X1 + GET_XBUTTON_WPARAM(flags) - 1;
|
|
|
|
|
state = SDL_PRESSED;
|
|
|
|
|
break;
|
|
|
|
|
case WM_XBUTTONUP:
|
|
|
|
|
button = SDL_BUTTON_X1 + GET_XBUTTON_WPARAM(flags) - 1;
|
|
|
|
|
state = SDL_RELEASED;
|
|
|
|
|
break;
|
2006-04-09 23:44:54 -07:00
|
|
|
NODEFAULT;
|
2004-07-08 08:11:42 -07:00
|
|
|
}
|
|
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
// mouse capture
|
|
|
|
|
static int outstanding_press_events;
|
|
|
|
|
if(state == SDL_PRESSED)
|
2004-07-08 08:11:42 -07:00
|
|
|
{
|
2005-11-02 11:10:44 -08:00
|
|
|
// grab mouse to ensure we get up events
|
|
|
|
|
if(++outstanding_press_events > 0)
|
2011-12-29 01:01:09 -08:00
|
|
|
(void)SetCapture(g_hWnd); // (returns previous window)
|
2004-07-08 08:11:42 -07:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2005-11-02 11:10:44 -08:00
|
|
|
// release after all up events received
|
|
|
|
|
if(--outstanding_press_events <= 0)
|
|
|
|
|
{
|
2011-12-29 01:01:09 -08:00
|
|
|
WARN_IF_FALSE(ReleaseCapture());
|
2005-11-02 11:10:44 -08:00
|
|
|
outstanding_press_events = 0;
|
|
|
|
|
}
|
2004-07-08 08:11:42 -07:00
|
|
|
}
|
|
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
// update button bitfield
|
|
|
|
|
if(state == SDL_PRESSED)
|
|
|
|
|
mouse_buttons |= SDL_BUTTON(button);
|
|
|
|
|
else
|
|
|
|
|
mouse_buttons &= ~SDL_BUTTON(button);
|
2004-07-08 08:11:42 -07:00
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
const POINT screen_pt = mouse_ScreenFromClient(client_x, client_y);
|
2008-06-21 11:24:07 -07:00
|
|
|
int x, y;
|
2010-06-05 11:52:39 -07:00
|
|
|
if(mouse_GetCoords(screen_pt.x, screen_pt.y, x, y))
|
|
|
|
|
QueueButtonEvent(button, state, x, y);
|
2010-11-13 11:51:15 -08:00
|
|
|
|
|
|
|
|
// Per MSDN, return TRUE for XBUTTON events
|
|
|
|
|
if (uMsg == WM_XBUTTONDOWN || uMsg == WM_XBUTTONUP)
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2004-07-08 08:11:42 -07:00
|
|
|
|
|
|
|
|
|
2008-06-21 11:24:07 -07:00
|
|
|
// (note: this message is sent even if the cursor is outside our window)
|
2006-09-08 13:09:26 -07:00
|
|
|
static LRESULT OnMouseWheel(HWND UNUSED(hWnd), int screen_x, int screen_y, int zDelta, UINT UNUSED(fwKeys))
|
2004-05-15 20:31:29 -07:00
|
|
|
{
|
2008-06-21 11:24:07 -07:00
|
|
|
int x, y;
|
2010-06-05 11:52:39 -07:00
|
|
|
if(mouse_GetCoords(screen_x, screen_y, x, y))
|
2006-09-11 16:30:23 -07:00
|
|
|
{
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 11:48:32 -07:00
|
|
|
int button = (zDelta < 0)? SDL_BUTTON_WHEELDOWN : SDL_BUTTON_WHEELUP;
|
2006-09-11 16:30:23 -07:00
|
|
|
// SDL says this sends a down message followed by up.
|
2010-06-05 11:52:39 -07:00
|
|
|
QueueButtonEvent(button, SDL_PRESSED, x, y);
|
|
|
|
|
QueueButtonEvent(button, SDL_RELEASED, x, y);
|
2006-09-11 16:30:23 -07:00
|
|
|
}
|
2008-06-21 11:24:07 -07:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
return 0; // handled
|
|
|
|
|
}
|
2004-07-08 08:16:31 -07:00
|
|
|
|
2005-10-12 16:48:44 -07:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
Uint8 SDL_GetMouseState(int* x, int* y)
|
|
|
|
|
{
|
|
|
|
|
if(x)
|
2006-09-08 13:09:26 -07:00
|
|
|
*x = (int)mouse_x;
|
2005-11-02 11:10:44 -08:00
|
|
|
if(y)
|
2006-09-08 13:09:26 -07:00
|
|
|
*y = (int)mouse_y;
|
2005-11-02 11:10:44 -08:00
|
|
|
return (Uint8)mouse_buttons;
|
|
|
|
|
}
|
2004-07-08 08:16:31 -07:00
|
|
|
|
2005-10-11 21:27:55 -07:00
|
|
|
|
2010-06-14 05:09:49 -07:00
|
|
|
void SDL_WarpMouse(int x, int y)
|
2005-11-02 11:10:44 -08:00
|
|
|
{
|
2006-09-11 16:30:23 -07:00
|
|
|
// SDL interface provides for int, but the values should be
|
|
|
|
|
// idealized client coords (>= 0)
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(x >= 0 && y >= 0);
|
2010-06-05 11:52:39 -07:00
|
|
|
mouse_UpdatePosition(x, y);
|
2006-09-08 13:09:26 -07:00
|
|
|
|
2008-06-21 11:24:07 -07:00
|
|
|
const int client_x = x, client_y = y;
|
2010-06-05 11:52:39 -07:00
|
|
|
const POINT screen_pt = mouse_ScreenFromClient(client_x, client_y);
|
2006-09-08 13:09:26 -07:00
|
|
|
WARN_IF_FALSE(SetCursorPos(screen_pt.x, screen_pt.y));
|
2004-05-27 10:30:06 -07:00
|
|
|
}
|
2004-05-15 20:31:29 -07:00
|
|
|
|
2004-05-27 10:30:06 -07:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
int SDL_ShowCursor(int toggle)
|
2004-05-27 10:30:06 -07:00
|
|
|
{
|
2005-11-02 11:10:44 -08:00
|
|
|
static int cursor_visible = SDL_ENABLE;
|
|
|
|
|
if(toggle != SDL_QUERY)
|
|
|
|
|
{
|
|
|
|
|
// only call Windows ShowCursor if changing the visibility -
|
|
|
|
|
// it maintains a counter.
|
|
|
|
|
if(cursor_visible != toggle)
|
|
|
|
|
{
|
2011-12-29 01:01:09 -08:00
|
|
|
(void)ShowCursor(toggle); // (returns display counter)
|
2005-11-02 11:10:44 -08:00
|
|
|
cursor_visible = toggle;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return cursor_visible;
|
|
|
|
|
}
|
2004-06-09 08:43:59 -07:00
|
|
|
|
|
|
|
|
|
2010-07-04 03:15:53 -07:00
|
|
|
SDL_GrabMode SDL_WM_GrabInput(SDL_GrabMode mode)
|
|
|
|
|
{
|
|
|
|
|
static SDL_GrabMode prevMode;
|
|
|
|
|
if(mode == SDL_GRAB_QUERY)
|
|
|
|
|
return prevMode;
|
|
|
|
|
prevMode = mode;
|
|
|
|
|
|
|
|
|
|
if(mode == SDL_GRAB_OFF)
|
2011-12-29 01:01:09 -08:00
|
|
|
WARN_IF_FALSE(ClipCursor(0));
|
2010-07-04 03:15:53 -07:00
|
|
|
else
|
|
|
|
|
{
|
2011-12-29 01:01:09 -08:00
|
|
|
const RECT clientRect = ClientRect(g_hWnd);
|
2010-07-04 03:15:53 -07:00
|
|
|
POINT upperLeft = { clientRect.left, clientRect.top };
|
|
|
|
|
WARN_IF_FALSE(ClientToScreen(g_hWnd, &upperLeft));
|
|
|
|
|
POINT lowerRight = { clientRect.right, clientRect.bottom };
|
|
|
|
|
WARN_IF_FALSE(ClientToScreen(g_hWnd, &lowerRight));
|
|
|
|
|
const RECT screenRect = { upperLeft.x, upperLeft.y, lowerRight.x, lowerRight.y };
|
|
|
|
|
WARN_IF_FALSE(ClipCursor(&screenRect));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return mode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-06-03 14:15:45 -07:00
|
|
|
//----------------------------------------------------------------------------
|
2010-06-21 13:22:26 -07:00
|
|
|
// video resizing/expose
|
|
|
|
|
|
2010-07-04 04:12:50 -07:00
|
|
|
static bool ResizeEventEnabled(int clientWidth, int clientHeight)
|
|
|
|
|
{
|
2010-11-01 02:04:55 -07:00
|
|
|
// when the app receives a resize event, it must call SDL_SetVideoMode.
|
|
|
|
|
// avoid that if the size hasn't actually changed. this also
|
|
|
|
|
// prevents infinite recursion, since SDL_SetVideoMode might
|
|
|
|
|
// trigger resize events. note that this logic is safer than a
|
|
|
|
|
// skipResize flag, because that would remain set if SDL_SetVideoMode
|
|
|
|
|
// doesn't trigger a resize, and we would miss an actual resize.
|
|
|
|
|
static int lastClientWidth, lastClientHeight;
|
|
|
|
|
if(lastClientWidth == clientWidth && lastClientHeight == clientHeight)
|
2010-07-04 04:12:50 -07:00
|
|
|
return false;
|
2010-11-01 02:04:55 -07:00
|
|
|
lastClientWidth = clientWidth;
|
|
|
|
|
lastClientHeight = clientHeight;
|
2010-07-04 04:12:50 -07:00
|
|
|
|
|
|
|
|
// if fullscreen, interaction with other topmost windows causes
|
|
|
|
|
// minimization and a spurious resize. however, the app only
|
|
|
|
|
// expects resizing events if !fullscreen.
|
|
|
|
|
if(fullscreen)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// this happens during minimization, which results in an
|
|
|
|
|
// app-active event anyway, and the app might have
|
|
|
|
|
// trouble with size=0.
|
|
|
|
|
if(clientWidth == 0 && clientHeight == 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-21 13:22:26 -07:00
|
|
|
// note: this is called continuously during resizing. since SDL doesn't
|
|
|
|
|
// discard any SDL_VIDEORESIZE events, the application must deal with
|
|
|
|
|
// the flood (and only call SDL_SetVideoMode once a frame or similar).
|
|
|
|
|
// note: SDL uses WM_WINDOWPOSCHANGING, which requires calling
|
|
|
|
|
// GetClientRect and suffers from false alarms.
|
2010-06-30 16:40:51 -07:00
|
|
|
static void OnSize(HWND UNUSED(hWnd), UINT UNUSED(state), int clientWidth, int clientHeight)
|
2010-06-03 14:15:45 -07:00
|
|
|
{
|
2010-07-04 04:12:50 -07:00
|
|
|
if(!ResizeEventEnabled(clientWidth, clientHeight))
|
2010-06-21 13:22:26 -07:00
|
|
|
return;
|
|
|
|
|
|
2010-06-03 14:15:45 -07:00
|
|
|
SDL_Event ev;
|
|
|
|
|
ev.type = SDL_VIDEORESIZE;
|
2010-06-21 13:22:26 -07:00
|
|
|
ev.resize.w = clientWidth;
|
|
|
|
|
ev.resize.h = clientHeight;
|
2010-06-05 11:52:39 -07:00
|
|
|
QueueEvent(ev);
|
2010-06-03 14:15:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-06-21 13:22:26 -07:00
|
|
|
static BOOL OnEraseBkgnd(HWND UNUSED(hWnd), HDC UNUSED(hDC))
|
|
|
|
|
{
|
|
|
|
|
SDL_Event ev;
|
|
|
|
|
ev.type = SDL_VIDEOEXPOSE;
|
|
|
|
|
QueueEvent(ev);
|
2010-06-03 14:15:45 -07:00
|
|
|
|
2010-12-09 03:16:21 -08:00
|
|
|
// prevent GDI from erasing the background by claiming we did so.
|
|
|
|
|
// PAINTSTRUCT.fErase will later be FALSE.
|
2010-06-21 13:22:26 -07:00
|
|
|
return TRUE;
|
2010-06-03 14:15:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
2010-11-01 02:04:55 -07:00
|
|
|
static LRESULT OnPaint(HWND hWnd)
|
|
|
|
|
{
|
2010-12-09 03:16:21 -08:00
|
|
|
// BeginPaint/EndPaint is unnecessary (see http://opengl.czweb.org/ch04/082-084.html)
|
|
|
|
|
// however, we at least need to validate the window to prevent
|
|
|
|
|
// continuous WM_PAINT messages.
|
2011-12-29 01:01:09 -08:00
|
|
|
WARN_IF_FALSE(ValidateRect(hWnd, 0));
|
2010-11-01 02:04:55 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2008-06-01 03:19:17 -07:00
|
|
|
static LRESULT OnDestroy(HWND hWnd)
|
|
|
|
|
{
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(hWnd == g_hWnd);
|
2008-06-01 03:19:17 -07:00
|
|
|
WARN_IF_FALSE(ReleaseDC(g_hWnd, g_hDC));
|
|
|
|
|
g_hDC = (HDC)INVALID_HANDLE_VALUE;
|
|
|
|
|
g_hWnd = (HWND)INVALID_HANDLE_VALUE;
|
2010-06-05 11:52:39 -07:00
|
|
|
QueueQuitEvent();
|
2008-06-01 03:19:17 -07:00
|
|
|
|
2008-12-17 08:32:46 -08:00
|
|
|
#ifdef _DEBUG
|
2008-06-01 03:19:17 -07:00
|
|
|
// see http://www.adrianmccarthy.com/blog/?p=51
|
|
|
|
|
// with WM_QUIT in the message queue, MessageBox will immediately
|
|
|
|
|
// return IDABORT. to ensure any subsequent CRT error reports are
|
|
|
|
|
// at least somewhat visible, we redirect them to debug output.
|
|
|
|
|
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
|
2008-12-17 08:32:46 -08:00
|
|
|
#endif
|
2008-06-01 03:19:17 -07:00
|
|
|
|
2010-11-01 02:04:55 -07:00
|
|
|
PostQuitMessage(0);
|
2008-06-01 03:19:17 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-11-01 02:04:55 -07:00
|
|
|
enum DefWindowProcDisposition
|
|
|
|
|
{
|
|
|
|
|
kSkipDefWindowProc,
|
|
|
|
|
kRunDefWindowProc
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static DefWindowProcDisposition OnSysCommand(WPARAM wParam)
|
|
|
|
|
{
|
|
|
|
|
switch(wParam)
|
|
|
|
|
{
|
|
|
|
|
case SC_SCREENSAVE:
|
|
|
|
|
// disable screen-saver in fullscreen mode (other applications
|
2011-12-29 01:01:09 -08:00
|
|
|
// may interfere with us, and we have set the system-wide gamma)
|
2010-11-01 02:04:55 -07:00
|
|
|
if(fullscreen)
|
|
|
|
|
return kSkipDefWindowProc;
|
|
|
|
|
break;
|
|
|
|
|
|
2011-12-29 01:01:09 -08:00
|
|
|
// Alt+F4 or system menu double-click / exit
|
2010-11-01 02:04:55 -07:00
|
|
|
case SC_CLOSE:
|
|
|
|
|
QueueQuitEvent();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return kRunDefWindowProc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-12-09 03:16:21 -08:00
|
|
|
static LRESULT CALLBACK OnMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
2004-07-08 08:11:42 -07:00
|
|
|
{
|
2007-05-29 09:28:34 -07:00
|
|
|
if(is_quitting)
|
2010-04-06 05:32:17 -07:00
|
|
|
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
|
2004-07-08 08:11:42 -07:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
switch(uMsg)
|
|
|
|
|
{
|
|
|
|
|
case WM_PAINT:
|
2010-11-01 02:04:55 -07:00
|
|
|
return OnPaint(hWnd);
|
2004-07-08 08:11:42 -07:00
|
|
|
|
2010-06-21 13:22:26 -07:00
|
|
|
HANDLE_MSG(hWnd, WM_ERASEBKGND, OnEraseBkgnd);
|
2004-07-08 08:11:42 -07:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
// prevent selecting menu in fullscreen mode
|
|
|
|
|
case WM_NCHITTEST:
|
|
|
|
|
if(fullscreen)
|
|
|
|
|
return HTCLIENT;
|
|
|
|
|
break;
|
2004-07-08 08:11:42 -07:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
HANDLE_MSG(hWnd, WM_ACTIVATE, OnActivate);
|
2008-06-01 03:19:17 -07:00
|
|
|
HANDLE_MSG(hWnd, WM_DESTROY, OnDestroy);
|
2004-03-02 15:56:51 -08:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
case WM_SYSCOMMAND:
|
2010-11-01 02:04:55 -07:00
|
|
|
if(OnSysCommand(wParam) == kSkipDefWindowProc)
|
|
|
|
|
return 0;
|
2005-11-02 11:10:44 -08:00
|
|
|
break;
|
2004-03-02 15:56:51 -08:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
HANDLE_MSG(hWnd, WM_SYSKEYUP , OnKey);
|
|
|
|
|
HANDLE_MSG(hWnd, WM_KEYUP , OnKey);
|
|
|
|
|
HANDLE_MSG(hWnd, WM_SYSKEYDOWN, OnKey);
|
|
|
|
|
HANDLE_MSG(hWnd, WM_KEYDOWN , OnKey);
|
2004-03-02 15:56:51 -08:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
HANDLE_MSG(hWnd, WM_MOUSEWHEEL, OnMouseWheel);
|
2004-03-02 15:56:51 -08:00
|
|
|
|
2010-06-21 13:22:26 -07:00
|
|
|
HANDLE_MSG(hWnd, WM_SIZE, OnSize);
|
|
|
|
|
|
2005-12-22 16:27:29 -08:00
|
|
|
// (can't use message crackers: they do not provide for passing uMsg)
|
2005-11-02 11:10:44 -08:00
|
|
|
case WM_LBUTTONDOWN:
|
|
|
|
|
case WM_LBUTTONUP:
|
|
|
|
|
case WM_RBUTTONDOWN:
|
|
|
|
|
case WM_RBUTTONUP:
|
|
|
|
|
case WM_MBUTTONDOWN:
|
|
|
|
|
case WM_MBUTTONUP:
|
2010-11-13 11:51:15 -08:00
|
|
|
case WM_XBUTTONDOWN:
|
|
|
|
|
case WM_XBUTTONUP:
|
2006-08-27 03:33:22 -07:00
|
|
|
return OnMouseButton(hWnd, uMsg, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), (UINT)wParam);
|
2005-11-02 11:10:44 -08:00
|
|
|
|
|
|
|
|
default:
|
2010-11-01 02:04:55 -07:00
|
|
|
// (DefWindowProc must be called outside the switch because some
|
|
|
|
|
// messages are only conditionally 'grabbed', e.g. NCHITTEST)
|
2005-11-02 11:10:44 -08:00
|
|
|
break;
|
2005-01-23 10:05:33 -08:00
|
|
|
}
|
2004-03-02 15:56:51 -08:00
|
|
|
|
2010-04-06 05:32:17 -07:00
|
|
|
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
|
2005-11-02 11:10:44 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-11-03 13:46:35 -08:00
|
|
|
void SDL_PumpEvents()
|
2005-11-02 11:10:44 -08:00
|
|
|
{
|
2005-12-06 19:38:39 -08:00
|
|
|
// rationale: we would like to reduce CPU usage automatically if
|
|
|
|
|
// possible. blocking here until a message arrives would accomplish
|
|
|
|
|
// that, but might potentially freeze the app too long.
|
|
|
|
|
// instead, they should check active state and call SDL_Delay etc.
|
|
|
|
|
// if our window is minimized.
|
|
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
mouse_Update(); // polled
|
2005-12-22 16:27:29 -08:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
MSG msg;
|
|
|
|
|
while(PeekMessageW(&msg, 0, 0, 0, PM_REMOVE))
|
2005-08-09 14:26:40 -07:00
|
|
|
{
|
2011-12-29 01:01:09 -08:00
|
|
|
(void)DispatchMessageW(&msg); // (returns window procedure's return value)
|
2005-08-09 14:26:40 -07:00
|
|
|
}
|
2005-11-02 11:10:44 -08:00
|
|
|
}
|
2005-08-09 14:26:40 -07:00
|
|
|
|
2004-03-02 15:56:51 -08:00
|
|
|
|
2005-12-22 16:27:29 -08:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
int SDL_PollEvent(SDL_Event* ev)
|
|
|
|
|
{
|
|
|
|
|
SDL_PumpEvents();
|
2004-03-02 15:56:51 -08:00
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
if(DequeueEvent(*ev))
|
2005-11-02 11:10:44 -08:00
|
|
|
return 1;
|
2005-01-06 17:25:10 -08:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2004-03-02 15:56:51 -08:00
|
|
|
|
2004-06-09 08:43:59 -07:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
int SDL_PushEvent(SDL_Event* ev)
|
|
|
|
|
{
|
2010-06-05 11:52:39 -07:00
|
|
|
QueueEvent(*ev);
|
2005-11-02 11:10:44 -08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2004-03-02 15:56:51 -08:00
|
|
|
|
|
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// byte swapping
|
2004-05-31 05:21:14 -07:00
|
|
|
|
|
|
|
|
// implement only if the header hasn't mapped SDL_Swap* to intrinsics
|
|
|
|
|
|
|
|
|
|
#ifndef SDL_Swap16
|
|
|
|
|
u16 SDL_Swap16(const u16 x)
|
|
|
|
|
{
|
|
|
|
|
return (u16)(((x & 0xff) << 8) | (x >> 8));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifndef SDL_Swap32
|
|
|
|
|
u32 SDL_Swap32(const u32 x)
|
|
|
|
|
{
|
|
|
|
|
return (x << 24) |
|
|
|
|
|
(x >> 24) |
|
|
|
|
|
((x << 8) & 0x00ff0000) |
|
|
|
|
|
((x >> 8) & 0x0000ff00);
|
2004-05-24 13:25:48 -07:00
|
|
|
}
|
2004-05-31 05:21:14 -07:00
|
|
|
#endif
|
2004-03-02 15:56:51 -08:00
|
|
|
|
2004-05-31 05:21:14 -07:00
|
|
|
#ifndef SDL_Swap64
|
|
|
|
|
u64 SDL_Swap64(const u64 x)
|
|
|
|
|
{
|
2007-01-01 13:25:47 -08:00
|
|
|
const u32 lo = (u32)(x & 0xFFFFFFFF);
|
2004-05-31 05:21:14 -07:00
|
|
|
const u32 hi = (u32)(x >> 32);
|
|
|
|
|
u64 ret = SDL_Swap32(lo);
|
|
|
|
|
ret <<= 32;
|
|
|
|
|
// careful: must shift var of type u64, not u32
|
|
|
|
|
ret |= SDL_Swap32(hi);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2005-03-18 14:09:44 -08:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// multithread support
|
2005-03-18 14:09:44 -08:00
|
|
|
|
|
|
|
|
// semaphores
|
|
|
|
|
// note: implementing these in terms of pthread sem_t doesn't help;
|
|
|
|
|
// this wrapper is very close to the Win32 routines.
|
|
|
|
|
|
2007-12-29 08:45:22 -08:00
|
|
|
static HANDLE HANDLE_from_sem(SDL_sem* s)
|
2005-03-18 14:09:44 -08:00
|
|
|
{
|
2007-12-29 08:45:22 -08:00
|
|
|
return (HANDLE)s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static SDL_sem* sem_from_HANDLE(HANDLE h)
|
|
|
|
|
{
|
|
|
|
|
return (SDL_sem*)h;
|
|
|
|
|
}
|
2005-03-18 14:09:44 -08:00
|
|
|
|
2004-03-02 15:56:51 -08:00
|
|
|
SDL_sem* SDL_CreateSemaphore(int cnt)
|
|
|
|
|
{
|
2010-06-05 11:52:39 -07:00
|
|
|
HANDLE h = CreateSemaphore(0, cnt, std::numeric_limits<LONG>::max(), 0);
|
2007-12-29 08:45:22 -08:00
|
|
|
return sem_from_HANDLE(h);
|
2004-03-02 15:56:51 -08:00
|
|
|
}
|
|
|
|
|
|
2010-06-14 05:09:49 -07:00
|
|
|
void SDL_DestroySemaphore(SDL_sem* sem)
|
2004-03-02 15:56:51 -08:00
|
|
|
{
|
2007-12-29 08:45:22 -08:00
|
|
|
HANDLE h = HANDLE_from_sem(sem);
|
2011-12-29 01:01:09 -08:00
|
|
|
WARN_IF_FALSE(CloseHandle(h));
|
2004-03-02 15:56:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int SDL_SemPost(SDL_sem* sem)
|
|
|
|
|
{
|
2007-12-29 08:45:22 -08:00
|
|
|
HANDLE h = HANDLE_from_sem(sem);
|
|
|
|
|
return ReleaseSemaphore(h, 1, 0);
|
2004-03-02 15:56:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int SDL_SemWait(SDL_sem* sem)
|
|
|
|
|
{
|
2007-12-29 08:45:22 -08:00
|
|
|
HANDLE h = HANDLE_from_sem(sem);
|
|
|
|
|
return WaitForSingleObject(h, INFINITE);
|
2004-03-02 15:56:51 -08:00
|
|
|
}
|
|
|
|
|
|
2005-03-18 14:09:44 -08:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// misc API
|
|
|
|
|
|
|
|
|
|
void SDL_WM_SetCaption(const char* title, const char* icon)
|
|
|
|
|
{
|
2010-04-03 03:46:28 -07:00
|
|
|
WARN_IF_FALSE(SetWindowTextA(g_hWnd, title));
|
2005-11-02 11:10:44 -08:00
|
|
|
|
2005-12-09 23:04:31 -08:00
|
|
|
// real SDL ignores this parameter, so we will follow suit.
|
|
|
|
|
UNUSED2(icon);
|
2005-11-02 11:10:44 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-06-14 05:09:49 -07:00
|
|
|
u32 SDL_GetTicks()
|
2005-11-02 11:10:44 -08:00
|
|
|
{
|
|
|
|
|
return GetTickCount();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-06-14 05:09:49 -07:00
|
|
|
void SDL_Delay(Uint32 ms)
|
2005-11-02 11:10:44 -08:00
|
|
|
{
|
|
|
|
|
Sleep(ms);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-06-14 05:09:49 -07:00
|
|
|
void* SDL_GL_GetProcAddress(const char* name)
|
2005-11-02 11:10:44 -08:00
|
|
|
{
|
|
|
|
|
return wglGetProcAddress(name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// init/shutdown
|
|
|
|
|
|
2007-05-28 08:08:33 -07:00
|
|
|
// defend against calling SDL_Quit twice (GameSetup does this to work
|
|
|
|
|
// around ATI driver breakage)
|
|
|
|
|
static ModuleInitState initState;
|
|
|
|
|
|
2011-05-03 05:38:42 -07:00
|
|
|
static Status Init()
|
2005-11-02 11:10:44 -08:00
|
|
|
{
|
2010-06-05 11:52:39 -07:00
|
|
|
key_Init();
|
2010-07-12 05:57:58 -07:00
|
|
|
return INFO::OK;
|
2007-06-15 14:58:24 -07:00
|
|
|
}
|
|
|
|
|
|
2010-07-12 05:57:58 -07:00
|
|
|
static void Shutdown()
|
2007-06-15 14:58:24 -07:00
|
|
|
{
|
|
|
|
|
is_quitting = true;
|
|
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
if(wutil_IsValidHandle(g_hDC))
|
2008-06-21 11:24:07 -07:00
|
|
|
gammaRamp.RestoreOriginal();
|
2007-06-15 14:58:24 -07:00
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
if(wutil_IsValidHandle(g_hWnd))
|
2007-12-29 08:45:22 -08:00
|
|
|
WARN_IF_FALSE(DestroyWindow(g_hWnd));
|
2007-06-15 14:58:24 -07:00
|
|
|
|
2010-06-05 11:52:39 -07:00
|
|
|
video_Shutdown();
|
2007-06-15 14:58:24 -07:00
|
|
|
}
|
|
|
|
|
|
2010-07-12 05:57:58 -07:00
|
|
|
int SDL_Init(Uint32 UNUSED(flags))
|
|
|
|
|
{
|
|
|
|
|
return (ModuleInit(&initState, Init) < 0)? -1 : 0;
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-30 12:10:04 -08:00
|
|
|
int SDL_InitSubSystem(Uint32 UNUSED(flags))
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-12 05:57:58 -07:00
|
|
|
void SDL_Quit()
|
|
|
|
|
{
|
|
|
|
|
ModuleShutdown(&initState, Shutdown);
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-14 05:09:49 -07:00
|
|
|
|
2010-07-14 00:29:35 -07:00
|
|
|
static void RedirectStdout()
|
|
|
|
|
{
|
|
|
|
|
// this process is apparently attached to a console, and users might be
|
|
|
|
|
// surprised to find that we redirected the output to a file, so don't.
|
|
|
|
|
if(wutil_IsValidHandle(GetStdHandle(STD_OUTPUT_HANDLE)))
|
|
|
|
|
return;
|
|
|
|
|
|
2011-05-03 06:46:35 -07:00
|
|
|
WinScopedPreserveLastError s; // ChangeExtension
|
|
|
|
|
|
2011-03-23 09:14:47 -07:00
|
|
|
// this code may be included in multiple executables sharing the same
|
|
|
|
|
// directory, so include the executable's name in the filename. use its
|
|
|
|
|
// full path since the current directory is unreliable.
|
|
|
|
|
const OsPath pathname = sys_ExecutablePathname().ChangeExtension(L"_stdout.txt");
|
2010-07-14 00:29:35 -07:00
|
|
|
|
2010-04-03 03:46:28 -07:00
|
|
|
// ignore BoundsChecker warnings here. subsystem is set to "Windows"
|
2010-07-14 00:29:35 -07:00
|
|
|
// to prevent the OS from opening a console on startup (ugly).
|
|
|
|
|
// that means stdout isn't associated with a lowio handle; _close is
|
|
|
|
|
// called with fd = -1. oh well, there's nothing we can do.
|
2011-08-22 01:54:56 -07:00
|
|
|
FILE* f = 0;
|
|
|
|
|
// ignore return value - it might indicate 'file already exists' even
|
|
|
|
|
// if f is valid, which is what actually counts.
|
|
|
|
|
(void)_wfreopen_s(&f, OsString(pathname).c_str(), L"wt", stdout);
|
2011-05-03 06:46:35 -07:00
|
|
|
if(GetLastError() == ERROR_ALREADY_EXISTS)
|
|
|
|
|
SetLastError(0);
|
2010-07-14 00:29:35 -07:00
|
|
|
// executable directory (probably Program Files) is read-only for
|
|
|
|
|
// non-Administrators. we can't pick another directory because
|
2010-07-14 05:23:53 -07:00
|
|
|
// ah_log_dir might not be valid until the app's init has run,
|
|
|
|
|
// nor should we pollute the (root) wutil_AppdataPath directory.
|
2010-07-14 00:29:35 -07:00
|
|
|
// since stdout usually isn't critical and is seen if launching the
|
|
|
|
|
// app from a console, just skip the redirection in this case.
|
|
|
|
|
if(f == 0)
|
|
|
|
|
return;
|
2010-07-14 05:23:53 -07:00
|
|
|
|
2011-05-03 05:38:42 -07:00
|
|
|
#if CONFIG_ENABLE_CHECKS
|
2005-11-02 11:10:44 -08:00
|
|
|
// disable buffering, so that no writes are lost even if the program
|
2010-04-03 03:46:28 -07:00
|
|
|
// crashes. only enabled in full debug mode because this is really slow!
|
|
|
|
|
setvbuf(stdout, 0, _IONBF, 0);
|
|
|
|
|
#endif
|
2005-11-02 11:10:44 -08:00
|
|
|
}
|
2010-06-14 05:09:49 -07:00
|
|
|
|
2011-05-03 05:38:42 -07:00
|
|
|
static Status wsdl_Init()
|
2010-04-03 03:46:28 -07:00
|
|
|
{
|
|
|
|
|
// note: SDL does this in its WinMain hook. doing so in SDL_Init would be
|
|
|
|
|
// too late (we might miss some output), so we use winit.
|
|
|
|
|
// (this is possible because _cinit has already been called)
|
|
|
|
|
RedirectStdout();
|
2005-11-02 11:10:44 -08:00
|
|
|
|
2010-04-03 03:46:28 -07:00
|
|
|
return INFO::OK;
|
|
|
|
|
}
|
2005-11-02 11:10:44 -08:00
|
|
|
|
2011-05-03 05:38:42 -07:00
|
|
|
static Status wsdl_Shutdown()
|
2007-06-15 14:58:24 -07:00
|
|
|
{
|
|
|
|
|
// was redirected to stdout.txt; closing avoids a BoundsChecker warning.
|
2005-11-02 11:10:44 -08:00
|
|
|
fclose(stdout);
|
|
|
|
|
|
2007-06-15 14:58:24 -07:00
|
|
|
return INFO::OK;
|
2005-11-02 11:10:44 -08:00
|
|
|
}
|
2007-12-29 08:45:22 -08:00
|
|
|
|
2008-01-19 03:33:11 -08:00
|
|
|
#endif // #if CONFIG2_WSDL
|