2010-02-08 08:23:39 -08:00
|
|
|
/* Copyright (c) 2010 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"
|
2007-05-04 10:30:32 -07:00
|
|
|
#include "lib/external_libraries/sdl.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-01-01 13:25:47 -08:00
|
|
|
#include "lib/posix/posix_pthread.h"
|
2007-05-28 08:08:33 -07:00
|
|
|
#include "lib/module_init.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
|
|
|
|
|
|
2007-06-15 14:58:24 -07:00
|
|
|
WINIT_REGISTER_LATE_INIT(wsdl_Init);
|
|
|
|
|
WINIT_REGISTER_EARLY_SHUTDOWN(wsdl_Shutdown);
|
|
|
|
|
|
2004-03-02 15:56:51 -08:00
|
|
|
|
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;
|
|
|
|
|
static HDC g_hDC = (HDC)INVALID_HANDLE_VALUE; // needed by gamma code
|
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)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Change(float gamma_r, float gamma_g, float gamma_b)
|
|
|
|
|
{
|
|
|
|
|
// get current ramp (once) so we can later restore it.
|
|
|
|
|
if(!m_hasChanged)
|
|
|
|
|
{
|
2008-06-22 04:11:59 -07:00
|
|
|
debug_assert(wutil_IsValidHandle(g_hDC));
|
2008-06-21 11:24:07 -07:00
|
|
|
if(!GetDeviceGammaRamp(g_hDC, m_original))
|
|
|
|
|
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)
|
|
|
|
|
Upload(m_changed);
|
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)
|
|
|
|
|
Upload(m_original);
|
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);
|
|
|
|
|
}
|
2008-08-10 04:02:25 -07:00
|
|
|
debug_assert(ramp[0] == 0);
|
|
|
|
|
debug_assert(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);
|
2008-06-22 04:11:59 -07:00
|
|
|
debug_assert(wutil_IsValidHandle(g_hDC));
|
2008-06-21 11:24:07 -07:00
|
|
|
const BOOL ok = SetDeviceGammaRamp(g_hDC, ramps);
|
|
|
|
|
debug_assert(ok);
|
|
|
|
|
return !!ok;
|
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)
|
|
|
|
|
{
|
|
|
|
|
return gammaRamp.Change(r, g, b)? 0 : -1;
|
2005-10-11 21:27:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
// video
|
2005-10-11 21:27:55 -07:00
|
|
|
//----------------------------------------------------------------------------
|
2004-05-31 05:21:14 -07:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
static DEVMODE dm; // current video mode
|
|
|
|
|
static HGLRC hGLRC = (HGLRC)INVALID_HANDLE_VALUE;
|
2005-10-30 17:15:49 -08:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
static int depth_bits = 24; // depth buffer size; set via SDL_GL_SetAttribute
|
2004-03-29 05:21:42 -08:00
|
|
|
|
2005-12-22 16:27:29 -08:00
|
|
|
// check if resolution needs to be changed
|
|
|
|
|
static bool video_need_change(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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
static inline void video_enter_game_mode()
|
|
|
|
|
{
|
2007-12-29 08:45:22 -08:00
|
|
|
ShowWindow(g_hWnd, SW_RESTORE);
|
2005-11-02 11:10:44 -08:00
|
|
|
ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
|
|
|
|
|
}
|
2004-03-29 05:21:42 -08:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
static inline void video_leave_game_mode()
|
|
|
|
|
{
|
|
|
|
|
ChangeDisplaySettings(0, 0);
|
2007-12-29 08:45:22 -08:00
|
|
|
ShowWindow(g_hWnd, SW_MINIMIZE);
|
2005-11-02 11:10:44 -08:00
|
|
|
}
|
2004-05-07 18:11:51 -07:00
|
|
|
|
|
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
int SDL_GL_SetAttribute(SDL_GLattr attr, int value)
|
|
|
|
|
{
|
|
|
|
|
if(attr == SDL_GL_DEPTH_SIZE)
|
|
|
|
|
depth_bits = value;
|
2004-03-29 05:21:42 -08:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2004-05-07 18:11:51 -07:00
|
|
|
|
2004-03-29 05:21:42 -08:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
static LRESULT CALLBACK wndproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
2004-03-29 05:21:42 -08:00
|
|
|
|
2007-12-29 08:45:22 -08:00
|
|
|
static HWND wsdl_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.
|
|
|
|
|
// returned by GetModuleHandle and used in kbd hook and window creation.
|
|
|
|
|
const HINSTANCE hInst = GetModuleHandle(0);
|
|
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
// register window class
|
|
|
|
|
WNDCLASS wc;
|
|
|
|
|
memset(&wc, 0, sizeof(wc));
|
2007-12-29 08:45:22 -08:00
|
|
|
wc.style = 0;
|
2005-11-02 11:10:44 -08:00
|
|
|
wc.lpfnWndProc = wndproc;
|
|
|
|
|
wc.lpszClassName = "WSDL";
|
|
|
|
|
wc.hInstance = hInst;
|
|
|
|
|
ATOM class_atom = RegisterClass(&wc);
|
|
|
|
|
if(!class_atom)
|
|
|
|
|
{
|
2007-12-20 12:09:19 -08:00
|
|
|
debug_assert(0); // SDL_SetVideoMode: RegisterClass failed
|
2005-11-02 11:10:44 -08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2005-10-13 11:05:55 -07:00
|
|
|
|
2008-01-14 13:04:55 -08: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-10-31 08:26:51 -08:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
// Calculate the size of the outer window, so that the client area has
|
|
|
|
|
// the desired dimensions.
|
|
|
|
|
RECT r;
|
|
|
|
|
r.left = r.top = 0;
|
|
|
|
|
r.right = w; r.bottom = h;
|
|
|
|
|
if (AdjustWindowRectEx(&r, windowStyle, FALSE, 0))
|
|
|
|
|
{
|
|
|
|
|
w = r.right - r.left;
|
|
|
|
|
h = r.bottom - r.top;
|
|
|
|
|
}
|
2005-10-31 08:26:51 -08:00
|
|
|
|
2005-11-08 17:20:33 -08:00
|
|
|
// note: you can override the hardcoded window name via SDL_WM_SetCaption.
|
2008-05-01 08:41:42 -07:00
|
|
|
return CreateWindowEx(WS_EX_APPWINDOW, (LPCSTR)(uintptr_t)class_atom, "wsdl", windowStyle, 0, 0, w, h, 0, 0, hInst, 0);
|
2007-12-29 08:45:22 -08:00
|
|
|
}
|
2005-10-31 10:36:36 -08:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
|
2007-12-29 08:45:22 -08:00
|
|
|
static void SetPixelFormat(HDC g_hDC, int bpp)
|
|
|
|
|
{
|
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;
|
|
|
|
|
const BYTE cDepthBits = (BYTE)depth_bits;
|
|
|
|
|
const BYTE cStencilBits = 0;
|
|
|
|
|
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
|
|
|
|
2007-12-29 08:45:22 -08:00
|
|
|
const int pf = ChoosePixelFormat(g_hDC, &pfd);
|
2008-01-14 13:04:55 -08:00
|
|
|
debug_assert(pf >= 1);
|
2007-12-29 08:45:22 -08:00
|
|
|
WARN_IF_FALSE(SetPixelFormat(g_hDC, pf, &pfd));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// set video mode wxh:bpp if necessary.
|
|
|
|
|
// w = h = bpp = 0 => no change.
|
|
|
|
|
int SDL_SetVideoMode(int w, int h, int bpp, unsigned long flags)
|
|
|
|
|
{
|
|
|
|
|
WinScopedPreserveLastError s; // OpenGL and GDI
|
|
|
|
|
|
|
|
|
|
fullscreen = (flags & SDL_FULLSCREEN) != 0;
|
|
|
|
|
|
|
|
|
|
// get current mode settings
|
|
|
|
|
memset(&dm, 0, sizeof(dm));
|
|
|
|
|
dm.dmSize = sizeof(dm);
|
|
|
|
|
EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &dm);
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
if(video_need_change(w,h, cur_w,cur_h, fullscreen))
|
|
|
|
|
{
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
g_hWnd = wsdl_CreateWindow(w, h);
|
2008-06-22 04:11:59 -07:00
|
|
|
if(!wutil_IsValidHandle(g_hWnd))
|
2007-12-23 04:20:37 -08:00
|
|
|
return 0;
|
2008-01-14 13:04:55 -08:00
|
|
|
|
2007-12-29 08:45:22 -08:00
|
|
|
g_hDC = GetDC(g_hWnd);
|
2005-11-02 11:10:44 -08:00
|
|
|
|
2007-12-29 08:45:22 -08:00
|
|
|
SetPixelFormat(g_hDC, bpp);
|
|
|
|
|
|
|
|
|
|
hGLRC = wglCreateContext(g_hDC);
|
2005-11-02 11:10:44 -08:00
|
|
|
if(!hGLRC)
|
2007-12-23 04:20:37 -08:00
|
|
|
return 0;
|
2005-11-02 11:10:44 -08:00
|
|
|
|
2007-12-29 08:45:22 -08:00
|
|
|
if(!wglMakeCurrent(g_hDC, hGLRC))
|
2007-12-23 04:20:37 -08:00
|
|
|
return 0;
|
2005-11-02 11:10:44 -08:00
|
|
|
|
2007-12-23 04:20:37 -08:00
|
|
|
return 1;
|
2005-11-02 11:10:44 -08: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);
|
|
|
|
|
debug_assert(status == DISP_CHANGE_SUCCESSFUL);
|
|
|
|
|
}
|
2005-10-13 11:05:55 -07:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
if(hGLRC != INVALID_HANDLE_VALUE)
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-10-13 11:05:55 -07:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
|
|
|
|
|
void SDL_GL_SwapBuffers()
|
|
|
|
|
{
|
2007-12-29 08:45:22 -08:00
|
|
|
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
|
|
|
{
|
2007-12-29 08:45:22 -08:00
|
|
|
WmiMap videoAdapter;
|
2009-11-03 13:46:35 -08:00
|
|
|
if(wmi_GetClass(L"Win32_VideoController", videoAdapter) == INFO::OK)
|
2009-08-03 14:24:00 -07:00
|
|
|
{
|
|
|
|
|
VARIANT vTotalMemory = videoAdapter[L"AdapterRAM"];
|
|
|
|
|
video_info.video_mem = vTotalMemory.lVal;
|
|
|
|
|
}
|
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;
|
|
|
|
|
static Queue queue;
|
|
|
|
|
|
|
|
|
|
static void queue_event(const SDL_Event& ev)
|
|
|
|
|
{
|
2007-05-29 09:28:34 -07:00
|
|
|
debug_assert(!is_quitting);
|
|
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
queue.push(ev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool dequeue_event(SDL_Event* ev)
|
|
|
|
|
{
|
2007-05-29 09:28:34 -07:00
|
|
|
debug_assert(!is_quitting);
|
|
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
if(queue.empty())
|
|
|
|
|
return false;
|
|
|
|
|
*ev = queue.front();
|
|
|
|
|
queue.pop();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2005-12-22 16:27:29 -08:00
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
// app activation
|
|
|
|
|
|
|
|
|
|
enum SdlActivationType { LOSE = 0, GAIN = 1 };
|
|
|
|
|
|
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 inline void queue_active_event(SdlActivationType type, size_t changed_app_state)
|
2005-11-02 11:10:44 -08:00
|
|
|
{
|
|
|
|
|
// 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;
|
2008-12-17 08:32:46 -08:00
|
|
|
ev.active.gain = (u8)((type == GAIN)? 1 : 0);
|
2005-11-02 11:10:44 -08:00
|
|
|
queue_event(ev);
|
|
|
|
|
}
|
|
|
|
|
|
2005-12-22 16:27:29 -08:00
|
|
|
|
|
|
|
|
// SDL_APP* bitflags indicating whether we are active.
|
|
|
|
|
// note: responsibility for yielding lies with SDL apps -
|
|
|
|
|
// they control the main loop.
|
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 Uint8 app_state;
|
2005-12-22 16:27:29 -08:00
|
|
|
|
2008-12-17 08:32:46 -08:00
|
|
|
static void active_change_state(SdlActivationType type, Uint8 changed_app_state)
|
2005-11-02 11:10:44 -08:00
|
|
|
{
|
2008-12-17 08:32:46 -08:00
|
|
|
Uint8 old_app_state = app_state;
|
2005-12-22 16:27:29 -08:00
|
|
|
|
|
|
|
|
if(type == GAIN)
|
2009-07-16 16:53:46 -07:00
|
|
|
app_state = Uint8(app_state | changed_app_state);
|
2005-12-22 16:27:29 -08:00
|
|
|
else
|
2009-07-16 16:53:46 -07:00
|
|
|
app_state = Uint8(app_state & ~changed_app_state);
|
2005-12-22 16:27:29 -08:00
|
|
|
|
|
|
|
|
// generate an event - but only if the given state flags actually changed.
|
|
|
|
|
if((old_app_state & changed_app_state) != (app_state & changed_app_state))
|
|
|
|
|
queue_active_event(type, changed_app_state);
|
2005-11-02 11:10:44 -08:00
|
|
|
}
|
|
|
|
|
|
2005-12-22 16:27:29 -08:00
|
|
|
static void reset_all_keys();
|
|
|
|
|
|
|
|
|
|
static LRESULT OnActivate(HWND hWnd, UINT state, HWND UNUSED(hWndActDeact), BOOL fMinimized)
|
|
|
|
|
{
|
|
|
|
|
SdlActivationType type;
|
2008-12-17 08:32:46 -08:00
|
|
|
Uint8 changed_app_state;
|
2005-12-22 16:27:29 -08:00
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
2008-06-21 11:24:07 -07:00
|
|
|
gammaRamp.Latch();
|
2005-12-22 16:27:29 -08:00
|
|
|
if(fullscreen)
|
|
|
|
|
video_enter_game_mode();
|
|
|
|
|
}
|
|
|
|
|
// deactivated (Alt+Tab out) or minimized
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
type = LOSE;
|
|
|
|
|
changed_app_state = SDL_APPINPUTFOCUS;
|
|
|
|
|
if(fMinimized)
|
|
|
|
|
changed_app_state |= SDL_APPACTIVE;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
reset_all_keys();
|
|
|
|
|
|
2008-06-21 11:24:07 -07:00
|
|
|
gammaRamp.RestoreOriginal();
|
2005-12-22 16:27:29 -08:00
|
|
|
if(fullscreen)
|
|
|
|
|
video_leave_game_mode();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
active_change_state(type, changed_app_state);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Uint8 SDL_GetAppState()
|
|
|
|
|
{
|
|
|
|
|
return app_state;
|
|
|
|
|
}
|
|
|
|
|
|
2007-05-29 09:28:34 -07:00
|
|
|
|
|
|
|
|
static void queue_quit_event()
|
|
|
|
|
{
|
|
|
|
|
SDL_Event ev;
|
|
|
|
|
ev.type = SDL_QUIT;
|
|
|
|
|
queue_event(ev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
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.
|
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 void queue_key_event(Uint8 type, SDLKey sdlk, WCHAR unicode_char)
|
2005-11-02 11:10:44 -08:00
|
|
|
{
|
|
|
|
|
SDL_Event ev;
|
|
|
|
|
ev.type = type;
|
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.sym = sdlk;
|
|
|
|
|
ev.key.keysym.unicode = (Uint16)unicode_char;
|
2005-11-02 11:10:44 -08:00
|
|
|
queue_event(ev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static Uint8 keys[SDLK_LAST];
|
|
|
|
|
|
2007-05-29 09:28:34 -07:00
|
|
|
// winuser.h promises VK_0..9 and VK_A..Z etc. match ASCII value.
|
2006-06-23 10:41:55 -07:00
|
|
|
#define VK_0 '0'
|
|
|
|
|
#define VK_A 'A'
|
|
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
static void init_vkmap(SDLKey (&VK_keymap)[256])
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
// Map the VK keysyms
|
|
|
|
|
for ( i=0; i<sizeof(VK_keymap)/sizeof(VK_keymap[0]); ++i )
|
|
|
|
|
VK_keymap[i] = SDLK_UNKNOWN;
|
|
|
|
|
|
|
|
|
|
VK_keymap[VK_BACK] = SDLK_BACKSPACE;
|
|
|
|
|
VK_keymap[VK_TAB] = SDLK_TAB;
|
|
|
|
|
VK_keymap[VK_CLEAR] = SDLK_CLEAR;
|
|
|
|
|
VK_keymap[VK_RETURN] = SDLK_RETURN;
|
|
|
|
|
VK_keymap[VK_PAUSE] = SDLK_PAUSE;
|
|
|
|
|
VK_keymap[VK_ESCAPE] = SDLK_ESCAPE;
|
|
|
|
|
VK_keymap[VK_SPACE] = SDLK_SPACE;
|
|
|
|
|
VK_keymap[VK_OEM_7] = SDLK_QUOTE;
|
|
|
|
|
VK_keymap[VK_OEM_COMMA] = SDLK_COMMA;
|
|
|
|
|
VK_keymap[VK_OEM_MINUS] = SDLK_MINUS;
|
|
|
|
|
VK_keymap[VK_OEM_PERIOD] = SDLK_PERIOD;
|
|
|
|
|
VK_keymap[VK_OEM_2] = SDLK_SLASH;
|
|
|
|
|
for(i = 0; i < 10; i++)
|
|
|
|
|
VK_keymap[VK_0+i] = (SDLKey)(SDLK_0+i);
|
|
|
|
|
VK_keymap[VK_OEM_1] = SDLK_SEMICOLON;
|
|
|
|
|
VK_keymap[VK_OEM_PLUS] = SDLK_EQUALS;
|
|
|
|
|
VK_keymap[VK_OEM_4] = SDLK_LEFTBRACKET;
|
|
|
|
|
VK_keymap[VK_OEM_5] = SDLK_BACKSLASH;
|
|
|
|
|
VK_keymap[VK_OEM_6] = SDLK_RIGHTBRACKET;
|
|
|
|
|
VK_keymap[VK_OEM_3] = SDLK_BACKQUOTE;
|
|
|
|
|
VK_keymap[VK_OEM_8] = SDLK_BACKQUOTE;
|
|
|
|
|
|
|
|
|
|
for(i = 0; i < 26; i++)
|
|
|
|
|
VK_keymap[VK_A+i] = (SDLKey)(SDLK_a+i);
|
2005-10-13 11:05:55 -07:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
VK_keymap[VK_DELETE] = SDLK_DELETE;
|
2005-10-13 11:05:55 -07:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
for(i = 0; i < 10; i++)
|
|
|
|
|
VK_keymap[VK_NUMPAD0+i] = (SDLKey)(SDLK_KP0+i);
|
2005-10-30 17:15:49 -08:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
VK_keymap[VK_DECIMAL] = SDLK_KP_PERIOD;
|
|
|
|
|
VK_keymap[VK_DIVIDE] = SDLK_KP_DIVIDE;
|
|
|
|
|
VK_keymap[VK_MULTIPLY] = SDLK_KP_MULTIPLY;
|
|
|
|
|
VK_keymap[VK_SUBTRACT] = SDLK_KP_MINUS;
|
|
|
|
|
VK_keymap[VK_ADD] = SDLK_KP_PLUS;
|
2005-10-13 11:05:55 -07:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
VK_keymap[VK_UP] = SDLK_UP;
|
|
|
|
|
VK_keymap[VK_DOWN] = SDLK_DOWN;
|
|
|
|
|
VK_keymap[VK_RIGHT] = SDLK_RIGHT;
|
|
|
|
|
VK_keymap[VK_LEFT] = SDLK_LEFT;
|
|
|
|
|
VK_keymap[VK_INSERT] = SDLK_INSERT;
|
|
|
|
|
VK_keymap[VK_HOME] = SDLK_HOME;
|
|
|
|
|
VK_keymap[VK_END] = SDLK_END;
|
|
|
|
|
VK_keymap[VK_PRIOR] = SDLK_PAGEUP;
|
|
|
|
|
VK_keymap[VK_NEXT] = SDLK_PAGEDOWN;
|
2005-10-30 17:15:49 -08:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
for(i = 0; i < 12; i++)
|
|
|
|
|
VK_keymap[VK_F1+i] = (SDLKey)(SDLK_F1+i);
|
2005-10-30 17:15:49 -08:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
VK_keymap[VK_NUMLOCK] = SDLK_NUMLOCK;
|
|
|
|
|
VK_keymap[VK_CAPITAL] = SDLK_CAPSLOCK;
|
|
|
|
|
VK_keymap[VK_SCROLL] = SDLK_SCROLLOCK;
|
|
|
|
|
VK_keymap[VK_RSHIFT] = SDLK_RSHIFT;
|
|
|
|
|
VK_keymap[VK_LSHIFT] = SDLK_LSHIFT;
|
|
|
|
|
VK_keymap[VK_SHIFT] = SDLK_LSHIFT; // XXX: Not quite
|
|
|
|
|
VK_keymap[VK_RCONTROL] = SDLK_RCTRL;
|
|
|
|
|
VK_keymap[VK_LCONTROL] = SDLK_LCTRL;
|
|
|
|
|
VK_keymap[VK_CONTROL] = SDLK_LCTRL; // XXX: Not quite
|
|
|
|
|
VK_keymap[VK_RMENU] = SDLK_RALT;
|
|
|
|
|
VK_keymap[VK_LMENU] = SDLK_LALT;
|
|
|
|
|
VK_keymap[VK_MENU] = SDLK_LALT; // XXX: Not quite
|
|
|
|
|
VK_keymap[VK_RWIN] = SDLK_RSUPER;
|
|
|
|
|
VK_keymap[VK_LWIN] = SDLK_LSUPER;
|
2005-10-30 17:15:49 -08:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
VK_keymap[VK_HELP] = SDLK_HELP;
|
|
|
|
|
#ifdef VK_PRINT
|
|
|
|
|
VK_keymap[VK_PRINT] = SDLK_PRINT;
|
|
|
|
|
#endif
|
|
|
|
|
VK_keymap[VK_SNAPSHOT] = SDLK_PRINT;
|
|
|
|
|
VK_keymap[VK_CANCEL] = SDLK_BREAK;
|
|
|
|
|
VK_keymap[VK_APPS] = SDLK_MENU;
|
|
|
|
|
}
|
2005-10-31 10:36:36 -08:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
inline SDLKey vkmap(int vk)
|
|
|
|
|
{
|
|
|
|
|
static SDLKey VK_SDLKMap[256]; // VK_SDLKMap[vk] == SDLK
|
|
|
|
|
ONCE( init_vkmap(VK_SDLKMap); );
|
2005-10-13 11:05:55 -07:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
if(!(0 <= vk && vk < 256))
|
|
|
|
|
{
|
2007-12-20 12:09:19 -08:00
|
|
|
debug_assert(0); // invalid vk
|
2005-11-02 11:10:44 -08:00
|
|
|
return SDLK_UNKNOWN;
|
2005-10-13 11:05:55 -07:00
|
|
|
}
|
2005-11-02 11:10:44 -08:00
|
|
|
return VK_SDLKMap[vk];
|
2005-10-13 11:05:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
static void reset_all_keys()
|
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
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
for(int i = 0; i < ARRAY_SIZE(keys); i++)
|
|
|
|
|
if(keys[i])
|
|
|
|
|
{
|
|
|
|
|
spoofed_up_event.key.keysym.sym = (SDLKey)i;
|
|
|
|
|
queue_event(spoofed_up_event);
|
|
|
|
|
}
|
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
|
|
|
|
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
|
|
|
const SDLKey sdlk = vkmap(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)
|
|
|
|
|
queue_key_event(SDL_KEYUP, sdlk, 0);
|
|
|
|
|
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];
|
|
|
|
|
GetKeyboardState(key_states);
|
|
|
|
|
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++)
|
|
|
|
|
queue_key_event(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)
|
|
|
|
|
queue_key_event(SDL_KEYDOWN, sdlk, 0);
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
// windowDimensions-1. they are returned by GetCoords and have no prefix.
|
2006-08-27 03:33:22 -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
|
|
|
static void queue_mouse_event(int x, int y)
|
2005-12-22 16:27:29 -08:00
|
|
|
{
|
|
|
|
|
SDL_Event ev;
|
|
|
|
|
ev.type = SDL_MOUSEMOTION;
|
2008-06-21 11:24:07 -07:00
|
|
|
debug_assert(unsigned(x|y) <= USHRT_MAX);
|
2006-09-11 16:30:23 -07:00
|
|
|
ev.motion.x = (Uint16)x;
|
|
|
|
|
ev.motion.y = (Uint16)y;
|
2005-12-22 16:27:29 -08:00
|
|
|
queue_event(ev);
|
|
|
|
|
}
|
|
|
|
|
|
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 void queue_button_event(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;
|
2008-06-21 11:24:07 -07:00
|
|
|
debug_assert(unsigned(x|y) <= USHRT_MAX);
|
2006-09-11 16:30:23 -07:00
|
|
|
ev.button.x = (Uint16)x;
|
|
|
|
|
ev.button.y = (Uint16)y;
|
2005-12-22 16:27:29 -08:00
|
|
|
queue_event(ev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
// - called from mouse_update and SDL_WarpMouse.
|
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 void mouse_moved(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;
|
|
|
|
|
queue_mouse_event(x, y);
|
2005-12-22 16:27:29 -08:00
|
|
|
}
|
|
|
|
|
|
2008-06-21 11:24:07 -07:00
|
|
|
static POINT 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.
|
|
|
|
|
static bool GetCoords(int screen_x, int screen_y, int& x, int& y)
|
2006-09-11 16:30:23 -07:00
|
|
|
{
|
2008-06-22 04:11:59 -07:00
|
|
|
debug_assert(wutil_IsValidHandle(g_hWnd));
|
|
|
|
|
|
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);
|
|
|
|
|
debug_assert(ret != 0 || GetLastError() == 0);
|
2008-06-21 11:24:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
RECT client_rect;
|
|
|
|
|
WARN_IF_FALSE(GetClientRect(g_hWnd, &client_rect));
|
|
|
|
|
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;
|
|
|
|
|
debug_assert(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
|
|
|
|
2006-08-27 03:33:22 -07:00
|
|
|
static void mouse_update()
|
|
|
|
|
{
|
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
|
|
|
|
|
// sensitivity settings. Windows messages are laggy, 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;
|
|
|
|
|
if(GetCoords(screen_pt.x, screen_pt.y, x, y))
|
2005-12-22 16:27:29 -08:00
|
|
|
{
|
|
|
|
|
active_change_state(GAIN, SDL_APPMOUSEFOCUS);
|
2006-08-27 03:33:22 -07:00
|
|
|
mouse_moved(x, y);
|
2005-12-22 16:27:29 -08:00
|
|
|
}
|
|
|
|
|
// moved outside of window
|
|
|
|
|
else
|
2006-03-13 23:20:12 -08:00
|
|
|
active_change_state(LOSE, SDL_APPMOUSEFOCUS);
|
2005-12-22 16:27:29 -08: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)
|
2008-06-21 11:24:07 -07:00
|
|
|
static LRESULT OnMouseButton(HWND UNUSED(hWnd), UINT uMsg, int client_x, int client_y, UINT UNUSED(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;
|
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)
|
2007-12-29 08:45:22 -08:00
|
|
|
SetCapture(g_hWnd);
|
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)
|
|
|
|
|
{
|
|
|
|
|
ReleaseCapture();
|
|
|
|
|
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
|
|
|
|
2008-06-21 11:24:07 -07:00
|
|
|
const POINT screen_pt = ScreenFromClient(client_x, client_y);
|
|
|
|
|
int x, y;
|
|
|
|
|
if(GetCoords(screen_pt.x, screen_pt.y, x, y))
|
|
|
|
|
queue_button_event(button, state, x, y);
|
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;
|
|
|
|
|
if(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.
|
2008-06-21 11:24:07 -07:00
|
|
|
queue_button_event(button, SDL_PRESSED, x, y);
|
2006-09-11 16:30:23 -07:00
|
|
|
queue_button_event(button, SDL_RELEASED, x, y);
|
|
|
|
|
}
|
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
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
inline void SDL_WarpMouse(int x, int y)
|
|
|
|
|
{
|
2006-09-11 16:30:23 -07:00
|
|
|
// SDL interface provides for int, but the values should be
|
|
|
|
|
// idealized client coords (>= 0)
|
|
|
|
|
debug_assert(x >= 0 && y >= 0);
|
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
|
|
|
mouse_moved(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;
|
|
|
|
|
const POINT screen_pt = 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)
|
|
|
|
|
{
|
|
|
|
|
ShowCursor(toggle);
|
|
|
|
|
cursor_visible = toggle;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return cursor_visible;
|
|
|
|
|
}
|
2004-06-09 08:43:59 -07:00
|
|
|
|
|
|
|
|
|
2004-05-15 20:31:29 -07:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
2008-06-01 03:19:17 -07:00
|
|
|
static LRESULT OnDestroy(HWND hWnd)
|
|
|
|
|
{
|
|
|
|
|
debug_assert(hWnd == g_hWnd);
|
|
|
|
|
WARN_IF_FALSE(ReleaseDC(g_hWnd, g_hDC));
|
|
|
|
|
g_hDC = (HDC)INVALID_HANDLE_VALUE;
|
|
|
|
|
g_hWnd = (HWND)INVALID_HANDLE_VALUE;
|
|
|
|
|
queue_quit_event();
|
|
|
|
|
PostQuitMessage(0);
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
static LRESULT CALLBACK wndproc(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)
|
2005-11-02 11:10:44 -08:00
|
|
|
return DefWindowProc(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:
|
|
|
|
|
PAINTSTRUCT ps;
|
|
|
|
|
BeginPaint(hWnd, &ps);
|
|
|
|
|
EndPaint(hWnd, &ps);
|
|
|
|
|
return 0;
|
2004-07-08 08:11:42 -07:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
case WM_ERASEBKGND:
|
|
|
|
|
// this indicates we allegedly erased the background;
|
|
|
|
|
// PAINTSTRUCT.fErase is then FALSE.
|
|
|
|
|
return 1;
|
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:
|
|
|
|
|
switch(wParam)
|
|
|
|
|
{
|
|
|
|
|
// prevent moving, sizing, screensaver, and power-off in fullscreen mode
|
|
|
|
|
case SC_MOVE:
|
|
|
|
|
case SC_SIZE:
|
|
|
|
|
case SC_MAXIMIZE:
|
|
|
|
|
case SC_MONITORPOWER:
|
|
|
|
|
if(fullscreen)
|
|
|
|
|
return 1;
|
|
|
|
|
break;
|
2004-03-02 15:56:51 -08:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
// Alt+F4 or system menu doubleclick/exit
|
|
|
|
|
case SC_CLOSE:
|
|
|
|
|
queue_quit_event();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
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:
|
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:
|
|
|
|
|
// can't call DefWindowProc here: some messages
|
|
|
|
|
// are only conditionally 'grabbed' (e.g. NCHITTEST)
|
|
|
|
|
break;
|
2005-01-23 10:05:33 -08:00
|
|
|
}
|
2004-03-02 15:56:51 -08:00
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
2005-12-22 16:27:29 -08:00
|
|
|
mouse_update(); // polled
|
|
|
|
|
|
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
|
|
|
{
|
2005-11-02 11:10:44 -08:00
|
|
|
DispatchMessageW(&msg);
|
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
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
if(dequeue_event(ev))
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
queue_event(*ev);
|
|
|
|
|
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)
|
|
|
|
|
{
|
2007-12-29 08:45:22 -08:00
|
|
|
HANDLE h = CreateSemaphore(0, cnt, 0x7fffffff, 0);
|
|
|
|
|
return sem_from_HANDLE(h);
|
2004-03-02 15:56:51 -08:00
|
|
|
}
|
|
|
|
|
|
2005-01-06 17:25:10 -08:00
|
|
|
inline 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);
|
|
|
|
|
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
|
|
|
|
|
|
|
|
// threads
|
2005-01-06 17:25:10 -08:00
|
|
|
// users don't need to allocate SDL_Thread variables, so type = void
|
|
|
|
|
// API returns SDL_Thread*, which is the HANDLE value itself.
|
2005-07-04 10:09:28 -07:00
|
|
|
//
|
|
|
|
|
// we go through hoops to avoid type cast warnings;
|
|
|
|
|
// a simple union { pthread_t; SDL_Thread* } yields "uninitialized"
|
|
|
|
|
// warnings in VC2005, so we coerce values directly.
|
|
|
|
|
cassert(sizeof(pthread_t) == sizeof(SDL_Thread*));
|
2005-01-06 17:25:10 -08:00
|
|
|
|
2005-12-11 14:23:55 -08:00
|
|
|
SDL_Thread* SDL_CreateThread(int (*func)(void*), void* param)
|
2004-03-02 15:56:51 -08:00
|
|
|
{
|
2005-07-04 10:09:28 -07:00
|
|
|
pthread_t thread = 0;
|
2005-12-11 14:23:55 -08:00
|
|
|
if(pthread_create(&thread, 0, (void* (*)(void*))func, param) < 0)
|
2005-01-06 17:25:10 -08:00
|
|
|
return 0;
|
2005-07-04 10:09:28 -07:00
|
|
|
return *(SDL_Thread**)&thread;
|
2004-03-02 15:56:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int SDL_KillThread(SDL_Thread* thread)
|
|
|
|
|
{
|
2005-07-04 10:09:28 -07:00
|
|
|
pthread_cancel(*(pthread_t*)&thread);
|
2005-01-06 17:25:10 -08:00
|
|
|
return 0;
|
2004-03-02 15:56:51 -08:00
|
|
|
}
|
|
|
|
|
|
2005-11-02 11:10:44 -08:00
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// misc API
|
|
|
|
|
|
|
|
|
|
void SDL_WM_SetCaption(const char* title, const char* icon)
|
|
|
|
|
{
|
2007-12-29 08:45:22 -08:00
|
|
|
WARN_IF_FALSE(SetWindowText(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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inline u32 SDL_GetTicks()
|
|
|
|
|
{
|
|
|
|
|
return GetTickCount();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inline void SDL_Delay(Uint32 ms)
|
|
|
|
|
{
|
|
|
|
|
Sleep(ms);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inline void* SDL_GL_GetProcAddress(const char* name)
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
int SDL_Init(Uint32 UNUSED(flags))
|
2005-11-02 11:10:44 -08:00
|
|
|
{
|
2007-05-28 08:08:33 -07:00
|
|
|
if(!ModuleShouldInitialize(&initState))
|
|
|
|
|
return 0;
|
|
|
|
|
|
2007-06-15 14:58:24 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SDL_Quit()
|
|
|
|
|
{
|
|
|
|
|
if(!ModuleShouldShutdown(&initState))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
is_quitting = true;
|
|
|
|
|
|
2008-06-21 11:24:07 -07:00
|
|
|
if(g_hDC != INVALID_HANDLE_VALUE)
|
|
|
|
|
gammaRamp.RestoreOriginal();
|
2007-06-15 14:58:24 -07:00
|
|
|
|
2007-12-29 08:45:22 -08:00
|
|
|
if(g_hWnd != INVALID_HANDLE_VALUE)
|
|
|
|
|
WARN_IF_FALSE(DestroyWindow(g_hWnd));
|
2007-06-15 14:58:24 -07:00
|
|
|
|
2007-12-29 08:45:22 -08:00
|
|
|
video_shutdown();
|
2007-06-15 14:58:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// note: we go to the trouble of hooking stdout via winit because SDL_Init
|
|
|
|
|
// is called fairly late (or even not at all in the case of Atlas) and
|
|
|
|
|
// we would otherwise lose some printfs.
|
|
|
|
|
// this is possible because wstartup calls winit after _cinit.
|
|
|
|
|
|
|
|
|
|
static LibError wsdl_Init()
|
|
|
|
|
{
|
2005-11-02 11:10:44 -08:00
|
|
|
// redirect stdout to file (otherwise it's simply ignored on Win32).
|
|
|
|
|
// notes:
|
|
|
|
|
// - use full path for safety (works even if someone does chdir)
|
2007-06-15 14:58:24 -07:00
|
|
|
// - the real SDL does this in its WinMain hook
|
2009-11-03 13:46:35 -08:00
|
|
|
fs::wpath path = wutil_ExecutablePath()/L"stdout.txt";
|
2005-11-02 11:10:44 -08:00
|
|
|
// ignore BoundsChecker warnings here. subsystem is set to "Windows"
|
|
|
|
|
// to avoid the OS opening a console on startup (ugly). that means
|
|
|
|
|
// stdout isn't associated with a lowio handle; _close ends up
|
|
|
|
|
// getting called with fd = -1. oh well, nothing we can do.
|
2010-01-01 07:33:07 -08:00
|
|
|
FILE* f = 0;
|
|
|
|
|
errno_t ret = _wfreopen_s(&f, path.string().c_str(), L"wt", stdout);
|
|
|
|
|
debug_assert(ret == 0);
|
2007-05-28 08:08:33 -07:00
|
|
|
debug_assert(f);
|
2005-11-02 11:10:44 -08:00
|
|
|
|
|
|
|
|
#if CONFIG_PARANOIA
|
|
|
|
|
// disable buffering, so that no writes are lost even if the program
|
|
|
|
|
// crashes. only enabled in full debug mode because this is really slow!
|
|
|
|
|
setvbuf(stdout, 0, _IONBF, 0);
|
|
|
|
|
#endif
|
|
|
|
|
|
2007-06-15 14:58:24 -07:00
|
|
|
return INFO::OK;
|
2005-11-02 11:10:44 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2007-06-15 14:58:24 -07:00
|
|
|
static LibError wsdl_Shutdown()
|
|
|
|
|
{
|
|
|
|
|
// 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
|