2005-01-23 19:05:33 +01:00
|
|
|
// emulation of a subset of SDL and GLUT for Win32
|
|
|
|
//
|
|
|
|
// Copyright (c) 2003 Jan Wassenberg
|
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU General Public License as
|
|
|
|
// published by the Free Software Foundation; either version 2 of the
|
|
|
|
// License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful, but
|
|
|
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
// General Public License for more details.
|
|
|
|
//
|
|
|
|
// Contact info:
|
|
|
|
// Jan.Wassenberg@stud.uni-karlsruhe.de
|
|
|
|
// http://www.stud.uni-karlsruhe.de/~urkt/
|
|
|
|
|
2004-05-08 03:11:51 +02:00
|
|
|
|
|
|
|
// TODO: should use GetMessage when not active to reduce CPU load.
|
|
|
|
// where to do this?
|
|
|
|
// - force the app to check for SDL's activation messages, and call
|
|
|
|
// sdl-wait-message?
|
|
|
|
// - do it here, just make SDL_PollEvent block until message received?
|
2004-07-28 10:31:13 +02:00
|
|
|
// - have the app use another free-the-cpu method, since it controls the main loop.
|
|
|
|
// this is what's currently happening.
|
2004-03-03 00:56:51 +01:00
|
|
|
|
2004-05-08 03:11:51 +02:00
|
|
|
#include "precompiled.h"
|
2004-03-03 00:56:51 +01:00
|
|
|
|
|
|
|
#include <process.h>
|
|
|
|
|
|
|
|
#include "sdl.h"
|
|
|
|
#include "lib.h"
|
2005-03-18 23:44:55 +01:00
|
|
|
#include "posix.h"
|
2004-03-03 00:56:51 +01:00
|
|
|
#include "win_internal.h"
|
2004-05-08 03:11:51 +02:00
|
|
|
|
2005-01-23 19:05:33 +01:00
|
|
|
#include "ogl.h" // needed to pull in the delay-loaded opengl32.dll
|
|
|
|
|
2004-06-19 16:29:40 +02:00
|
|
|
#include "SDL_vkeys.h"
|
2005-01-07 02:25:10 +01:00
|
|
|
/*/*#include "ps/Hotkey.h"*/
|
2004-03-03 00:56:51 +01:00
|
|
|
|
2005-01-23 19:05:33 +01:00
|
|
|
|
|
|
|
#include <ddraw.h>
|
2005-01-07 02:25:10 +01:00
|
|
|
#include <process.h> // _beginthreadex
|
2005-06-28 06:06:25 +02:00
|
|
|
|
2004-06-04 14:41:53 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <math.h>
|
|
|
|
|
2005-01-23 19:05:33 +01:00
|
|
|
// for easy removal of DirectDraw dependency (used to query total video mem)
|
|
|
|
#define DDRAW
|
|
|
|
|
2005-08-09 18:23:19 +02:00
|
|
|
#if MSC_VERSION
|
2004-03-03 00:56:51 +01:00
|
|
|
#pragma comment(lib, "user32.lib")
|
|
|
|
#pragma comment(lib, "gdi32.lib")
|
2005-01-23 19:05:33 +01:00
|
|
|
|
|
|
|
// don't bother with dynamic linking -
|
|
|
|
// DirectX is present in all Windows versions since Win95.
|
|
|
|
#ifdef DDRAW
|
|
|
|
# pragma comment(lib, "ddraw.lib")
|
|
|
|
#endif
|
|
|
|
|
2004-03-03 00:56:51 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2005-06-21 18:31:55 +02:00
|
|
|
#pragma data_seg(WIN_CALLBACK_PRE_MAIN(b))
|
2004-06-13 18:06:23 +02:00
|
|
|
WIN_REGISTER_FUNC(wsdl_init);
|
2005-06-21 18:31:55 +02:00
|
|
|
#pragma data_seg(WIN_CALLBACK_POST_ATEXIT(d))
|
2004-06-13 18:06:23 +02:00
|
|
|
WIN_REGISTER_FUNC(wsdl_shutdown);
|
|
|
|
#pragma data_seg()
|
|
|
|
|
|
|
|
|
2004-07-28 10:31:13 +02:00
|
|
|
static bool app_active;
|
|
|
|
// window is active and visible.
|
|
|
|
// used to send SDL_ACTIVEEVENT messages and in the msgproc.
|
|
|
|
// note: responsibility for yielding lies with SDL apps -
|
2004-06-21 15:59:58 +02:00
|
|
|
// they control the main loop.
|
|
|
|
|
2004-07-28 10:31:13 +02:00
|
|
|
static bool fullscreen;
|
|
|
|
// in fullscreen mode, i.e. not windowed.
|
|
|
|
// video mode must be restored when app is deactivated.
|
2004-03-03 00:56:51 +01:00
|
|
|
|
2004-06-09 17:43:59 +02:00
|
|
|
static bool is_shutdown;
|
2004-07-28 10:31:13 +02:00
|
|
|
// the app is shutting down.
|
|
|
|
// if set, ignore further Windows messages for clean shutdown.
|
|
|
|
|
2004-06-09 17:43:59 +02:00
|
|
|
|
2004-07-08 17:11:42 +02:00
|
|
|
static HINSTANCE hInst = 0;
|
2004-07-28 10:31:13 +02:00
|
|
|
// app instance.
|
|
|
|
// returned by GetModuleHandle and used in kbd hook and window creation.
|
2004-07-08 17:11:42 +02:00
|
|
|
|
2004-08-03 01:14:54 +02:00
|
|
|
|
2005-01-23 19:05:33 +01:00
|
|
|
HWND hWnd = (HWND)INVALID_HANDLE_VALUE;
|
|
|
|
|
2004-03-03 00:56:51 +01:00
|
|
|
|
2005-01-23 19:05:33 +01:00
|
|
|
static DEVMODE dm; // current video mode
|
2004-03-03 00:56:51 +01:00
|
|
|
static HDC hDC;
|
|
|
|
static HGLRC hGLRC;
|
|
|
|
|
2005-01-23 19:05:33 +01:00
|
|
|
static int depth_bits = 24; // depth buffer size; set via SDL_GL_SetAttribute
|
2004-03-03 00:56:51 +01:00
|
|
|
|
|
|
|
static u16 mouse_x, mouse_y;
|
|
|
|
|
2004-05-31 14:21:14 +02:00
|
|
|
|
|
|
|
static void gamma_swap(bool restore_org);
|
|
|
|
|
|
|
|
|
2005-01-23 19:05:33 +01:00
|
|
|
// shared msg handler
|
|
|
|
// SDL and GLUT have separate pumps; messages are handled there
|
|
|
|
|
2004-03-03 00:56:51 +01:00
|
|
|
static LRESULT CALLBACK wndproc(HWND hWnd, unsigned int uMsg, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
2004-06-09 17:43:59 +02:00
|
|
|
if(is_shutdown)
|
|
|
|
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
|
|
|
|
2004-03-03 00:56:51 +01:00
|
|
|
switch(uMsg)
|
|
|
|
{
|
|
|
|
case WM_PAINT:
|
|
|
|
PAINTSTRUCT ps;
|
|
|
|
BeginPaint(hWnd, &ps);
|
|
|
|
EndPaint(hWnd, &ps);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case WM_ERASEBKGND:
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case WM_ACTIVATE:
|
|
|
|
app_active = (wParam & 0xffff) != 0;
|
|
|
|
|
2004-05-31 14:21:14 +02:00
|
|
|
gamma_swap(!app_active);
|
2005-01-09 15:23:59 +01:00
|
|
|
|
2004-03-03 00:56:51 +01:00
|
|
|
if(fullscreen)
|
2005-01-09 15:23:59 +01:00
|
|
|
// (re)activating
|
2004-03-03 00:56:51 +01:00
|
|
|
if(app_active)
|
2005-01-09 15:23:59 +01:00
|
|
|
{
|
2004-03-03 00:56:51 +01:00
|
|
|
ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
|
2005-01-09 15:23:59 +01:00
|
|
|
ShowWindow(hWnd, SW_RESTORE);
|
|
|
|
}
|
|
|
|
// deactivating
|
2004-03-03 00:56:51 +01:00
|
|
|
else
|
2005-01-09 15:23:59 +01:00
|
|
|
{
|
2004-03-03 00:56:51 +01:00
|
|
|
ChangeDisplaySettings(0, 0);
|
2005-01-09 15:23:59 +01:00
|
|
|
ShowWindow(hWnd, SW_MINIMIZE);
|
|
|
|
}
|
2004-03-03 00:56:51 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_CLOSE:
|
|
|
|
exit(0);
|
2005-01-23 19:05:33 +01:00
|
|
|
break;
|
2004-05-08 03:11:51 +02:00
|
|
|
|
|
|
|
// prevent moving, sizing, screensaver, and power-off in fullscreen mode
|
|
|
|
case WM_SYSCOMMAND:
|
|
|
|
switch(wParam)
|
|
|
|
{
|
|
|
|
case SC_MOVE:
|
|
|
|
case SC_SIZE:
|
|
|
|
case SC_MAXIMIZE:
|
|
|
|
case SC_MONITORPOWER:
|
|
|
|
if(fullscreen)
|
|
|
|
return 1;
|
2005-01-23 19:05:33 +01:00
|
|
|
default:;
|
2004-05-08 03:11:51 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
// prevent selecting menu in fullscreen mode
|
|
|
|
case WM_NCHITTEST:
|
|
|
|
if(fullscreen)
|
|
|
|
return HTCLIENT;
|
2005-01-23 19:05:33 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:;
|
|
|
|
// can't call DefWindowProc here: some messages
|
|
|
|
// are only conditionally 'grabbed' (e.g. NCHITTEST)
|
2004-03-03 00:56:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-09 18:23:19 +02:00
|
|
|
// always on (we don't care about the extra overhead)
|
|
|
|
int SDL_EnableUNICODE(int UNUSED(enable))
|
2004-03-03 00:56:51 +01:00
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2004-03-29 15:21:42 +02:00
|
|
|
// Translate Windows VK's into our SDLK's for keys that must be translated
|
|
|
|
static void init_vkmap(SDLKey (&VK_keymap)[256])
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2005-01-23 19:05:33 +01:00
|
|
|
// Map the VK keysyms
|
2004-03-29 15:21:42 +02:00
|
|
|
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;
|
2004-05-08 03:11:51 +02:00
|
|
|
for(i = 0; i < 10; i++)
|
|
|
|
VK_keymap[VK_0+i] = (SDLKey)(SDLK_0+i);
|
2004-03-29 15:21:42 +02:00
|
|
|
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;
|
2004-05-08 03:11:51 +02:00
|
|
|
|
|
|
|
for(i = 0; i < 26; i++)
|
|
|
|
VK_keymap[VK_A+i] = (SDLKey)(SDLK_a+i);
|
|
|
|
|
2004-03-29 15:21:42 +02:00
|
|
|
VK_keymap[VK_DELETE] = SDLK_DELETE;
|
|
|
|
|
2004-05-08 03:11:51 +02:00
|
|
|
for(i = 0; i < 10; i++)
|
|
|
|
VK_keymap[VK_NUMPAD0+i] = (SDLKey)(SDLK_KP0+i);
|
|
|
|
|
2004-03-29 15:21:42 +02: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;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2004-05-08 03:11:51 +02:00
|
|
|
for(i = 0; i < 12; i++)
|
|
|
|
VK_keymap[VK_F1+i] = (SDLKey)(SDLK_F1+i);
|
2004-03-29 15:21:42 +02: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;
|
2004-06-10 11:57:03 +02:00
|
|
|
VK_keymap[VK_SHIFT] = SDLK_LSHIFT; // XXX: Not quite
|
2004-03-29 15:21:42 +02:00
|
|
|
VK_keymap[VK_RCONTROL] = SDLK_RCTRL;
|
|
|
|
VK_keymap[VK_LCONTROL] = SDLK_LCTRL;
|
2004-06-10 11:57:03 +02:00
|
|
|
VK_keymap[VK_CONTROL] = SDLK_LCTRL; // XXX: Not quite
|
2004-03-29 15:21:42 +02:00
|
|
|
VK_keymap[VK_RMENU] = SDLK_RALT;
|
|
|
|
VK_keymap[VK_LMENU] = SDLK_LALT;
|
2004-06-10 11:57:03 +02:00
|
|
|
VK_keymap[VK_MENU] = SDLK_LALT; // XXX: Not quite
|
2004-03-29 15:21:42 +02:00
|
|
|
VK_keymap[VK_RWIN] = SDLK_RSUPER;
|
|
|
|
VK_keymap[VK_LWIN] = SDLK_LSUPER;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline SDLKey vkmap(int vk)
|
|
|
|
{
|
2005-01-23 19:05:33 +01:00
|
|
|
static SDLKey VK_SDLKMap[256]; // VK_SDLKMap[vk] == SDLK
|
2004-05-06 19:14:30 +02:00
|
|
|
ONCE( init_vkmap(VK_SDLKMap); );
|
2004-03-29 15:21:42 +02:00
|
|
|
|
2005-07-04 19:09:28 +02:00
|
|
|
if(!(0 <= vk && vk < 256))
|
|
|
|
{
|
|
|
|
debug_warn("vkmap: invalid vk");
|
|
|
|
return SDLK_UNKNOWN;
|
|
|
|
}
|
2004-03-29 15:21:42 +02:00
|
|
|
return VK_SDLKMap[vk];
|
|
|
|
}
|
|
|
|
|
2004-06-21 15:59:58 +02:00
|
|
|
|
2005-01-07 02:25:10 +01:00
|
|
|
int SDL_WaitEvent(SDL_Event* ev)
|
|
|
|
{
|
2005-06-28 06:06:25 +02:00
|
|
|
debug_assert(ev == 0 && "can't store event, since wsdl doesn't have a real queue");
|
2005-01-07 02:25:10 +01:00
|
|
|
WaitMessage();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-03-03 00:56:51 +01:00
|
|
|
// note: keysym.unicode is only returned for SDL_KEYDOWN, and is otherwise 0.
|
|
|
|
int SDL_PollEvent(SDL_Event* ev)
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// buffer for unicode support / dead char
|
|
|
|
//
|
|
|
|
|
|
|
|
const int CHAR_BUF_SIZE = 8;
|
|
|
|
static wchar_t char_buf[CHAR_BUF_SIZE];
|
2004-03-29 15:21:42 +02:00
|
|
|
static uint next_char_idx=0;
|
|
|
|
static int num_chars=0;
|
|
|
|
static SDLKey translated_keysym=SDLK_UNKNOWN;
|
2004-03-03 00:56:51 +01:00
|
|
|
|
|
|
|
// input is waiting in buffer
|
|
|
|
return_char:
|
2005-06-28 06:06:25 +02:00
|
|
|
debug_assert(num_chars <= CHAR_BUF_SIZE);
|
2004-03-29 15:21:42 +02:00
|
|
|
if(num_chars > 0)
|
2004-03-03 00:56:51 +01:00
|
|
|
{
|
|
|
|
num_chars--;
|
|
|
|
if(next_char_idx < CHAR_BUF_SIZE)
|
|
|
|
{
|
2004-03-29 15:21:42 +02:00
|
|
|
wchar_t c = char_buf[next_char_idx];
|
2004-03-03 00:56:51 +01:00
|
|
|
next_char_idx++;
|
|
|
|
|
|
|
|
ev->type = SDL_KEYDOWN;
|
2004-06-13 21:42:48 +02:00
|
|
|
ev->key.keysym.sym = (SDLKey)translated_keysym;
|
|
|
|
//ev->key.keysym.sym = (SDLKey)((c < 256)? c : 0);
|
2004-03-03 00:56:51 +01:00
|
|
|
ev->key.keysym.unicode = c;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else
|
2004-05-08 03:11:51 +02:00
|
|
|
debug_warn("SDL_PollEvent: next_char_idx invalid");
|
2004-03-03 00:56:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// events that trigger messages (mouse done below)
|
|
|
|
MSG msg;
|
|
|
|
while(PeekMessageW(&msg, 0, 0, 0, PM_REMOVE))
|
|
|
|
{
|
|
|
|
DispatchMessageW(&msg);
|
|
|
|
|
|
|
|
int sdl_btn = -1;
|
|
|
|
|
|
|
|
|
|
|
|
switch(msg.message)
|
|
|
|
{
|
|
|
|
|
|
|
|
case WM_SYSKEYDOWN:
|
|
|
|
case WM_KEYDOWN:
|
2004-03-29 15:21:42 +02:00
|
|
|
{
|
2004-03-03 00:56:51 +01:00
|
|
|
UINT vk = (UINT)msg.wParam;
|
2004-03-29 15:21:42 +02:00
|
|
|
UINT scancode = (UINT)((msg.lParam >> 16) & 0xff);
|
|
|
|
u8 key_states[256];
|
|
|
|
GetKeyboardState(key_states);
|
2004-06-10 11:57:03 +02:00
|
|
|
|
2004-03-29 15:21:42 +02:00
|
|
|
num_chars = ToUnicode(vk, scancode, key_states, char_buf, CHAR_BUF_SIZE, 0);
|
|
|
|
next_char_idx = 0;
|
|
|
|
if(num_chars > 0)
|
|
|
|
{
|
|
|
|
// Translation complete: Produce one or more Unicode chars
|
|
|
|
char_buf[num_chars]=0;
|
2004-06-13 21:42:48 +02:00
|
|
|
translated_keysym=vkmap(vk);
|
2004-03-29 15:21:42 +02:00
|
|
|
//wprintf(L"ToUnicode: Translated %02x to [%s], %d chars, SDLK %02x. Extended flag %d, scancode %d\n", vk, char_buf, num_chars, translated_keysym, msg.lParam & 0x01000000, scancode);
|
|
|
|
goto return_char;
|
|
|
|
}
|
|
|
|
else if (num_chars == -1)
|
2004-03-03 00:56:51 +01:00
|
|
|
{
|
2004-03-29 15:21:42 +02:00
|
|
|
// Dead Key: Don't produce an event for this one
|
|
|
|
//printf("ToUnicode: Dead Key %02x [%c] [%c] SDLK %02x\n", vk, vk, char_buf[0], vkmap(vk));
|
|
|
|
num_chars = 0;
|
|
|
|
break;
|
2004-05-06 19:14:30 +02:00
|
|
|
// leave the switch statement; get next message.
|
2004-03-03 00:56:51 +01:00
|
|
|
}
|
2004-03-29 15:21:42 +02:00
|
|
|
// num_chars == 0: No translation: Just produce a plain KEYDOWN event
|
2004-06-10 11:57:03 +02:00
|
|
|
|
2004-03-29 15:21:42 +02:00
|
|
|
// TODO Mappings for left/right modifier keys
|
|
|
|
// TODO Modifier statekeeping
|
2004-03-03 00:56:51 +01:00
|
|
|
|
|
|
|
ev->type = SDL_KEYDOWN;
|
2004-03-29 15:21:42 +02:00
|
|
|
ev->key.keysym.sym = vkmap(vk);
|
2004-03-03 00:56:51 +01:00
|
|
|
ev->key.keysym.unicode = 0;
|
2004-03-29 15:21:42 +02:00
|
|
|
|
|
|
|
//printf("ToUnicode: No translation for %02x, extended flag %d, scancode %d, SDLK %02x [%c]\n", vk, msg.lParam & 0x01000000, scancode, ev->key.keysym.sym, ev->key.keysym.sym);
|
|
|
|
|
2004-03-03 00:56:51 +01:00
|
|
|
return 1;
|
2004-03-29 15:21:42 +02:00
|
|
|
}
|
2004-03-03 00:56:51 +01:00
|
|
|
|
|
|
|
case WM_SYSKEYUP:
|
|
|
|
case WM_KEYUP:
|
2004-03-29 15:21:42 +02:00
|
|
|
// TODO Mappings for left/right modifier keys
|
|
|
|
// TODO Modifier statekeeping
|
|
|
|
|
2004-03-03 00:56:51 +01:00
|
|
|
ev->type = SDL_KEYUP;
|
2004-05-06 19:14:30 +02:00
|
|
|
ev->key.keysym.sym = vkmap((int)msg.wParam);
|
2004-03-03 00:56:51 +01:00
|
|
|
ev->key.keysym.unicode = 0;
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
case WM_MOUSEWHEEL:
|
|
|
|
sdl_btn = (msg.wParam & BIT(31))? SDL_BUTTON_WHEELUP : SDL_BUTTON_WHEELDOWN;
|
|
|
|
break; // event filled in mouse code below
|
2004-07-21 18:34:07 +02:00
|
|
|
default:
|
2004-08-03 01:14:54 +02:00
|
|
|
if( ( msg.message >= WM_APP ) && ( msg.message < 0xC000 ) ) // 0xC000 = maximum application message
|
2004-07-21 18:34:07 +02:00
|
|
|
{
|
2005-06-28 06:06:25 +02:00
|
|
|
debug_assert( SDL_USEREVENT+(msg.message-WM_APP) <= 0xff && "Message too far above WM_APP");
|
2004-07-24 16:04:40 +02:00
|
|
|
ev->type = (u8)(SDL_USEREVENT+(msg.message-WM_APP));
|
2004-07-21 18:34:07 +02:00
|
|
|
ev->user.code = (int)msg.wParam;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
break;
|
2004-03-03 00:56:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// mouse button
|
|
|
|
// map Win L(up,down,double),R(),M() to L,R,M with up flag
|
|
|
|
uint btn = msg.message-0x201; // 0..8 if it's a valid button;
|
|
|
|
if(btn < 9 && btn%3 != 2) // every third msg is dblclick
|
|
|
|
sdl_btn = SDL_BUTTON_LEFT + btn/3; // assumes L,R,M
|
|
|
|
if(sdl_btn != -1)
|
|
|
|
{
|
2004-05-06 19:14:30 +02:00
|
|
|
ev->type = (u8)(SDL_MOUSEBUTTONDOWN + btn%3);
|
2004-03-03 00:56:51 +01:00
|
|
|
ev->button.button = (u8)sdl_btn;
|
|
|
|
ev->button.x = (u16)(msg.lParam & 0xffff);
|
|
|
|
ev->button.y = (u16)((msg.lParam >> 16) & 0xffff);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// mouse motion
|
|
|
|
//
|
|
|
|
// don't use DirectInput, because we want to respect the user's mouse
|
|
|
|
// sensitivity settings. Windows messages are laggy, so poll instead.
|
|
|
|
POINT p;
|
|
|
|
GetCursorPos(&p);
|
2005-08-09 23:26:40 +02:00
|
|
|
ScreenToClient(hWnd, &p);
|
2004-03-03 00:56:51 +01:00
|
|
|
if(mouse_x != p.x || mouse_y != p.y)
|
|
|
|
{
|
|
|
|
ev->type = SDL_MOUSEMOTION;
|
|
|
|
ev->motion.x = mouse_x = (u16)p.x;
|
|
|
|
ev->motion.y = mouse_y = (u16)p.y;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2004-06-21 15:59:58 +02:00
|
|
|
// app activate
|
|
|
|
// WM_ACTIVATE is only sent to the wndproc, apparently,
|
|
|
|
// so we have to poll here.
|
|
|
|
static bool last_app_active = true;
|
|
|
|
// true => suppress first event (as documented by SDL)
|
|
|
|
if(app_active != last_app_active)
|
|
|
|
{
|
|
|
|
last_app_active = app_active;
|
|
|
|
|
2004-07-10 23:50:35 +02:00
|
|
|
ev->type = SDL_ACTIVEEVENT;
|
2004-06-21 15:59:58 +02:00
|
|
|
ev->active.state = SDL_APPACTIVE;
|
|
|
|
ev->active.gain = (u8)app_active;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2004-03-03 00:56:51 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-07-21 18:34:07 +02:00
|
|
|
int SDL_PushEvent(SDL_Event* ev)
|
|
|
|
{
|
|
|
|
if( ev->type < SDL_USEREVENT )
|
|
|
|
return -1;
|
|
|
|
// Use Windows app-global user events.
|
|
|
|
PostMessage(NULL, WM_APP + ( ev->type - SDL_USEREVENT ), ev->user.code, 0);
|
|
|
|
return 0;
|
|
|
|
}
|
2004-03-03 00:56:51 +01:00
|
|
|
|
|
|
|
int SDL_GL_SetAttribute(SDL_GLattr attr, int value)
|
|
|
|
{
|
|
|
|
if(attr == SDL_GL_DEPTH_SIZE)
|
2005-01-07 02:25:10 +01:00
|
|
|
depth_bits = value;
|
2004-03-03 00:56:51 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-07-08 17:11:42 +02:00
|
|
|
//
|
|
|
|
// keyboard hook - used to intercept PrintScreen and system keys (e.g. Alt+Tab)
|
|
|
|
//
|
|
|
|
|
|
|
|
// note: the LowLevel hooks are global, but a DLL isn't actually required
|
|
|
|
// as stated in the docs. Windows apparently calls the handler in its original
|
|
|
|
// context. see http://www.gamedev.net/community/forums/topic.asp?topic_id=255399 .
|
|
|
|
|
|
|
|
static HHOOK hKeyboard_LL_Hook = (HHOOK)0;
|
|
|
|
|
2005-03-20 16:45:52 +01:00
|
|
|
static LRESULT CALLBACK keyboard_ll_hook(int nCode, WPARAM wParam, LPARAM lParam)
|
2004-07-08 17:11:42 +02:00
|
|
|
{
|
|
|
|
if(nCode == HC_ACTION)
|
|
|
|
{
|
|
|
|
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
|
|
|
|
DWORD vk = p->vkCode;
|
2005-08-09 18:23:19 +02:00
|
|
|
UNUSED2(vk);
|
2004-07-08 17:11:42 +02:00
|
|
|
|
2005-08-09 18:23:19 +02:00
|
|
|
// disabled - we want the normal Windows printscreen handling to
|
|
|
|
// remain so as not to confuse artists.
|
|
|
|
/*
|
2004-07-08 17:11:42 +02:00
|
|
|
// replace Windows PrintScreen handler
|
|
|
|
if(vk == VK_SNAPSHOT)
|
|
|
|
{
|
2004-08-09 22:58:32 +02:00
|
|
|
// check whether PrintScreen should be taking screenshots -- if
|
|
|
|
// not, allow the standard Windows clipboard to work
|
2005-08-09 18:23:19 +02:00
|
|
|
if(app_active)
|
2004-08-09 22:58:32 +02:00
|
|
|
{
|
|
|
|
// send to wndproc
|
|
|
|
UINT msg = (UINT)wParam;
|
|
|
|
PostMessage(hWnd, msg, vk, 0);
|
|
|
|
// specify hWnd to be safe.
|
|
|
|
// if window not yet created, it's INVALID_HANDLE_VALUE.
|
2004-07-08 17:11:42 +02:00
|
|
|
|
2004-08-09 22:58:32 +02:00
|
|
|
// don't pass it on to other handlers
|
|
|
|
return 1;
|
|
|
|
}
|
2004-07-08 17:11:42 +02:00
|
|
|
}
|
2005-08-09 18:23:19 +02:00
|
|
|
*/
|
2004-07-08 17:11:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// pass it on to other hook handlers
|
|
|
|
return CallNextHookEx(hKeyboard_LL_Hook, nCode, wParam, lParam);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-03-20 16:45:52 +01:00
|
|
|
static void enable_kbd_hook(bool enable)
|
2004-07-08 17:11:42 +02:00
|
|
|
{
|
|
|
|
if(enable)
|
|
|
|
{
|
2005-06-28 06:06:25 +02:00
|
|
|
debug_assert(hKeyboard_LL_Hook == 0);
|
2004-07-08 17:11:42 +02:00
|
|
|
hKeyboard_LL_Hook = SetWindowsHookEx(WH_KEYBOARD_LL, keyboard_ll_hook, hInst, 0);
|
2005-06-28 06:06:25 +02:00
|
|
|
debug_assert(hKeyboard_LL_Hook != 0);
|
2004-07-08 17:11:42 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-06-28 06:06:25 +02:00
|
|
|
debug_assert(hKeyboard_LL_Hook != 0);
|
2004-07-08 17:11:42 +02:00
|
|
|
UnhookWindowsHookEx(hKeyboard_LL_Hook);
|
|
|
|
hKeyboard_LL_Hook = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-27 19:30:06 +02:00
|
|
|
// SDL redirects stdout.txt in its WinMain hook. we need to do this
|
|
|
|
// here (before main is called), instead of in SDL_Init,
|
|
|
|
// to completely emulate SDL; bonus: we don't miss output before SDL_Init.
|
|
|
|
|
|
|
|
static int wsdl_init()
|
2004-05-16 05:31:29 +02:00
|
|
|
{
|
2004-07-08 17:16:31 +02:00
|
|
|
hInst = GetModuleHandle(0);
|
|
|
|
|
2004-05-31 14:21:14 +02: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.
|
2004-12-10 00:12:02 +01:00
|
|
|
FILE* ret = freopen("stdout.txt", "w", stdout);
|
2004-05-16 05:31:29 +02:00
|
|
|
if(!ret)
|
2004-05-27 19:30:06 +02:00
|
|
|
debug_warn("stdout freopen failed");
|
2004-05-29 14:04:42 +02:00
|
|
|
setvbuf(stdout, 0, _IONBF, 0);
|
2004-07-08 17:16:31 +02:00
|
|
|
|
2004-05-27 19:30:06 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2004-05-16 05:31:29 +02:00
|
|
|
|
2004-05-27 19:30:06 +02:00
|
|
|
|
|
|
|
static int wsdl_shutdown()
|
|
|
|
{
|
2004-06-09 17:43:59 +02:00
|
|
|
is_shutdown = true;
|
|
|
|
|
2004-05-27 19:30:06 +02:00
|
|
|
// redirected to stdout.txt in SDL_Init;
|
|
|
|
// close to avoid BoundsChecker warning.
|
|
|
|
fclose(stdout);
|
2004-06-09 17:43:59 +02:00
|
|
|
|
|
|
|
gamma_swap(true);
|
|
|
|
|
2004-08-12 19:18:54 +02:00
|
|
|
if(fullscreen)
|
|
|
|
ChangeDisplaySettings(0, 0);
|
|
|
|
|
|
|
|
if(hGLRC != INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
wglMakeCurrent(0, 0);
|
|
|
|
wglDeleteContext(hGLRC);
|
|
|
|
hGLRC = (HGLRC)INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
|
2004-06-09 17:43:59 +02:00
|
|
|
if(hDC != INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
ReleaseDC(hWnd, hDC);
|
|
|
|
hDC = (HDC)INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(hWnd != INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
DestroyWindow(hWnd);
|
|
|
|
hWnd = (HWND)INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-05-27 19:30:06 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-09 18:23:19 +02:00
|
|
|
int SDL_Init(Uint32 UNUSED(flags))
|
2004-05-27 19:30:06 +02:00
|
|
|
{
|
2004-07-08 17:11:42 +02:00
|
|
|
enable_kbd_hook(true);
|
|
|
|
|
2004-05-16 05:31:29 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-07-08 17:11:42 +02:00
|
|
|
void SDL_Quit()
|
|
|
|
{
|
|
|
|
enable_kbd_hook(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2005-01-23 19:05:33 +01:00
|
|
|
// set video mode wxh:bpp if necessary.
|
|
|
|
// w = h = bpp = 0 => no change.
|
2004-03-03 00:56:51 +01:00
|
|
|
int SDL_SetVideoMode(int w, int h, int bpp, unsigned long flags)
|
|
|
|
{
|
2004-07-12 16:25:39 +02:00
|
|
|
int ret = 0; // assume failure
|
|
|
|
WIN_SAVE_LAST_ERROR; // OpenGL and GDI
|
|
|
|
|
2004-07-08 17:11:42 +02:00
|
|
|
fullscreen = (flags & SDL_FULLSCREEN) != 0;
|
2004-03-03 00:56:51 +01:00
|
|
|
|
2005-01-23 19:05:33 +01:00
|
|
|
// get current mode settings
|
2005-01-07 02:25:10 +01:00
|
|
|
memset(&dm, 0, sizeof(dm));
|
|
|
|
dm.dmSize = sizeof(dm);
|
2004-03-03 00:56:51 +01:00
|
|
|
EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &dm);
|
2005-01-23 19:05:33 +01:00
|
|
|
int cur_w = (int)dm.dmPelsWidth, cur_h = (int)dm.dmPelsHeight;
|
2004-03-03 00:56:51 +01:00
|
|
|
|
2005-01-23 19:05:33 +01:00
|
|
|
// independent of resolution; app must always get bpp it wants
|
2004-03-03 00:56:51 +01:00
|
|
|
dm.dmBitsPerPel = bpp;
|
|
|
|
dm.dmFields = DM_BITSPERPEL;
|
|
|
|
|
2005-01-23 19:05:33 +01:00
|
|
|
// check if resolution needs to be changed
|
|
|
|
// .. invalid: keep current settings
|
|
|
|
if(w <= 0 || h <= 0 || bpp <= 0)
|
|
|
|
goto keep;
|
|
|
|
// .. higher resolution mode needed
|
|
|
|
if(w > cur_w || h > cur_h)
|
|
|
|
goto change;
|
|
|
|
// .. fullscreen requested and not exact same mode set
|
|
|
|
if(fullscreen && (w != cur_w || h != cur_h))
|
2004-03-03 00:56:51 +01:00
|
|
|
{
|
2005-01-23 19:05:33 +01:00
|
|
|
change:
|
|
|
|
dm.dmPelsWidth = (DWORD)w;
|
|
|
|
dm.dmPelsHeight = (DWORD)h;
|
2004-03-03 00:56:51 +01:00
|
|
|
dm.dmFields |= DM_PELSWIDTH|DM_PELSHEIGHT;
|
|
|
|
}
|
2005-01-23 19:05:33 +01:00
|
|
|
keep:
|
2004-03-03 00:56:51 +01:00
|
|
|
|
2005-01-23 19:05:33 +01:00
|
|
|
// the (possibly changed) mode will be (re)set at next WM_ACTIVATE
|
2004-03-03 00:56:51 +01:00
|
|
|
|
2005-01-23 19:05:33 +01:00
|
|
|
//
|
|
|
|
// window init
|
|
|
|
// create new window every time (instead of once at startup), because
|
|
|
|
// pixel format isn't supposed to be changed more than once
|
|
|
|
//
|
|
|
|
|
|
|
|
// register window class
|
2005-01-07 02:25:10 +01:00
|
|
|
WNDCLASS wc;
|
|
|
|
memset(&wc, 0, sizeof(wc));
|
2004-03-03 00:56:51 +01:00
|
|
|
wc.lpfnWndProc = wndproc;
|
2005-01-23 19:05:33 +01:00
|
|
|
wc.lpszClassName = "WSDL";
|
2004-03-03 00:56:51 +01:00
|
|
|
wc.hInstance = hInst;
|
2005-01-23 19:05:33 +01:00
|
|
|
ATOM class_atom = RegisterClass(&wc);
|
|
|
|
if(!class_atom)
|
|
|
|
{
|
|
|
|
debug_warn("SDL_SetVideoMode: RegisterClass failed");
|
|
|
|
return 0;
|
|
|
|
}
|
2004-03-03 00:56:51 +01:00
|
|
|
|
2005-08-08 05:59:50 +02:00
|
|
|
DWORD windowStyle = fullscreen ? (WS_POPUP|WS_VISIBLE) : (WS_CAPTION | WS_POPUPWINDOW | WS_VISIBLE);
|
|
|
|
|
2005-08-09 23:26:40 +02: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-08-08 05:59:50 +02:00
|
|
|
hWnd = CreateWindowEx(0, (LPCSTR)class_atom, APP_NAME, windowStyle, 0, 0, w, h, 0, 0, hInst, 0);
|
2004-03-03 00:56:51 +01:00
|
|
|
if(!hWnd)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
hDC = GetDC(hWnd);
|
|
|
|
|
2005-01-07 02:25:10 +01:00
|
|
|
|
|
|
|
//
|
|
|
|
// pixel format
|
|
|
|
//
|
|
|
|
|
|
|
|
const DWORD dwFlags = PFD_SUPPORT_OPENGL|PFD_DRAW_TO_WINDOW|PFD_DOUBLEBUFFER;
|
2005-08-10 02:33:15 +02:00
|
|
|
BYTE cColourBits = (BYTE)bpp;
|
2005-01-07 02:25:10 +01:00
|
|
|
BYTE cAlphaBits = 0;
|
|
|
|
if(bpp == 32)
|
|
|
|
{
|
2005-08-10 02:33:15 +02:00
|
|
|
cColourBits = 24;
|
2005-01-07 02:25:10 +01:00
|
|
|
cAlphaBits = 8;
|
|
|
|
}
|
|
|
|
const BYTE cAccumBits = 0;
|
|
|
|
const BYTE cDepthBits = (BYTE)depth_bits;
|
|
|
|
const BYTE cStencilBits = 0;
|
|
|
|
const BYTE cAuxBuffers = 0;
|
|
|
|
|
|
|
|
PIXELFORMATDESCRIPTOR pfd =
|
2004-03-03 00:56:51 +01:00
|
|
|
{
|
|
|
|
sizeof(PIXELFORMATDESCRIPTOR),
|
2005-01-07 02:25:10 +01:00
|
|
|
1, // version
|
|
|
|
dwFlags,
|
2004-03-03 00:56:51 +01:00
|
|
|
PFD_TYPE_RGBA,
|
2005-08-10 02:33:15 +02:00
|
|
|
cColourBits, 0, 0, 0, 0, 0, 0, // c*Bits, c*Shift are unused
|
2005-01-07 02:25:10 +01:00
|
|
|
cAlphaBits, 0, // cAlphaShift is unused
|
|
|
|
cAccumBits, 0, 0, 0, 0, // cAccum*Bits are unused
|
|
|
|
cDepthBits,
|
|
|
|
cStencilBits,
|
|
|
|
cAuxBuffers,
|
2004-03-03 00:56:51 +01:00
|
|
|
PFD_MAIN_PLANE,
|
2005-01-07 02:25:10 +01:00
|
|
|
0, 0, 0, 0 // bReserved, dw*Mask are unused
|
2004-03-03 00:56:51 +01:00
|
|
|
};
|
|
|
|
|
2004-06-09 17:43:59 +02:00
|
|
|
// GDI pixel format functions apparently require opengl to be loaded
|
|
|
|
// (may not have been done yet, if delay-loaded). call a gl function
|
|
|
|
// (no-op) to make sure.
|
2005-01-23 19:05:33 +01:00
|
|
|
(void)glGetError();
|
2004-06-09 17:43:59 +02:00
|
|
|
|
2004-03-03 00:56:51 +01:00
|
|
|
int pf = ChoosePixelFormat(hDC, &pfd);
|
|
|
|
if(!SetPixelFormat(hDC, pf, &pfd))
|
2004-07-12 16:25:39 +02:00
|
|
|
goto fail;
|
2004-03-03 00:56:51 +01:00
|
|
|
|
|
|
|
hGLRC = wglCreateContext(hDC);
|
|
|
|
if(!hGLRC)
|
2004-07-12 16:25:39 +02:00
|
|
|
goto fail;
|
2004-03-03 00:56:51 +01:00
|
|
|
|
|
|
|
if(!wglMakeCurrent(hDC, hGLRC))
|
2004-07-12 16:25:39 +02:00
|
|
|
goto fail;
|
2004-03-03 00:56:51 +01:00
|
|
|
|
2004-07-12 16:25:39 +02:00
|
|
|
ret = 1;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
WIN_RESTORE_LAST_ERROR;
|
|
|
|
return ret;
|
2004-03-03 00:56:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-01-23 19:05:33 +01:00
|
|
|
void SDL_GL_SwapBuffers()
|
2004-03-03 00:56:51 +01:00
|
|
|
{
|
|
|
|
SwapBuffers(hDC);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-05-31 14:21:14 +02:00
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
static bool gamma_changed;
|
|
|
|
static u16 org_ramp[3][256];
|
|
|
|
static u16 cur_ramp[3][256];
|
|
|
|
|
|
|
|
|
2005-01-07 02:25:10 +01:00
|
|
|
// ramp: 8.8 fixed point
|
2004-05-27 02:29:54 +02:00
|
|
|
static int calc_gamma_ramp(float gamma, u16* ramp)
|
2004-05-24 22:25:48 +02:00
|
|
|
{
|
2005-01-07 02:25:10 +01:00
|
|
|
// assume identity if invalid
|
2004-05-24 22:25:48 +02:00
|
|
|
if(gamma <= 0.0f)
|
2005-01-07 02:25:10 +01:00
|
|
|
gamma = 1.0f;
|
2004-05-24 22:25:48 +02:00
|
|
|
|
2005-01-07 02:25:10 +01:00
|
|
|
// identity: special-case to make sure we get exact values
|
2004-05-24 22:25:48 +02:00
|
|
|
if(gamma == 1.0f)
|
|
|
|
{
|
|
|
|
for(u16 i = 0; i < 256; i++)
|
|
|
|
ramp[i] = (i << 8);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const double inv_gamma = 1.0 / gamma;
|
|
|
|
for(int i = 0; i < 256; i++)
|
|
|
|
{
|
|
|
|
const double frac = i / 256.0;
|
2005-01-07 02:25:10 +01:00
|
|
|
// don't add 1/256 - this isn't time-critical and
|
|
|
|
// accuracy is more important.
|
|
|
|
// need a temp variable to disambiguate pow() argument type.
|
2004-05-24 22:25:48 +02:00
|
|
|
ramp[i] = fp_to_u16(pow(frac, inv_gamma));
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-05-31 14:21:14 +02:00
|
|
|
static void gamma_swap(bool restore_org)
|
|
|
|
{
|
|
|
|
if(gamma_changed)
|
|
|
|
{
|
|
|
|
void* ramp = (restore_org)? org_ramp : cur_ramp;
|
|
|
|
SetDeviceGammaRamp(hDC, ramp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-01-07 02:25:10 +01:00
|
|
|
// note: any component gamma = 0 is assumed to be identity.
|
2004-05-24 22:25:48 +02:00
|
|
|
int SDL_SetGamma(float r, float g, float b)
|
|
|
|
{
|
2005-01-07 02:25:10 +01:00
|
|
|
// if we haven't successfully changed gamma yet,
|
|
|
|
// get current ramp so we can later restore it.
|
2004-05-31 14:21:14 +02:00
|
|
|
if(!gamma_changed)
|
|
|
|
if(!GetDeviceGammaRamp(hDC, org_ramp))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
CHECK_ERR(calc_gamma_ramp(r, cur_ramp[0]));
|
|
|
|
CHECK_ERR(calc_gamma_ramp(g, cur_ramp[1]));
|
|
|
|
CHECK_ERR(calc_gamma_ramp(b, cur_ramp[2]));
|
|
|
|
|
|
|
|
if(!SetDeviceGammaRamp(hDC, cur_ramp))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
gamma_changed = true;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
// 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 22:25:48 +02:00
|
|
|
}
|
2004-05-31 14:21:14 +02:00
|
|
|
#endif
|
2004-03-03 00:56:51 +01:00
|
|
|
|
2004-05-31 14:21:14 +02:00
|
|
|
#ifndef SDL_Swap64
|
|
|
|
u64 SDL_Swap64(const u64 x)
|
|
|
|
{
|
|
|
|
const u32 lo = (u32)(x & 0xffffffff);
|
|
|
|
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
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
2004-03-03 00:56:51 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-06 19:14:30 +02:00
|
|
|
void SDL_WM_SetCaption(const char* title, const char* icon)
|
2004-03-03 00:56:51 +01:00
|
|
|
{
|
|
|
|
SetWindowText(hWnd, title);
|
2004-05-06 19:14:30 +02:00
|
|
|
|
2005-08-09 18:23:19 +02:00
|
|
|
UNUSED2(icon); // TODO: implement
|
2004-03-03 00:56:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SDL_VideoInfo* SDL_GetVideoInfo()
|
|
|
|
{
|
|
|
|
static SDL_VideoInfo video_info;
|
|
|
|
|
|
|
|
#ifdef DDRAW
|
|
|
|
|
2004-07-12 16:25:39 +02:00
|
|
|
WIN_SAVE_LAST_ERROR; // DirectDraw
|
|
|
|
|
|
|
|
ONCE({
|
2004-03-03 00:56:51 +01:00
|
|
|
IDirectDraw* dd = 0;
|
|
|
|
HRESULT hr = DirectDrawCreate(0, &dd, 0);
|
|
|
|
if(SUCCEEDED(hr) && dd != 0)
|
|
|
|
{
|
2005-01-23 19:05:33 +01:00
|
|
|
DDCAPS caps;
|
|
|
|
memset(&caps, 0, sizeof(caps));
|
2004-03-03 00:56:51 +01:00
|
|
|
caps.dwSize = sizeof(caps);
|
|
|
|
hr = dd->GetCaps(&caps, 0);
|
|
|
|
if(SUCCEEDED(hr))
|
|
|
|
video_info.video_mem = caps.dwVidMemTotal;
|
|
|
|
dd->Release();
|
|
|
|
}
|
2004-07-12 16:25:39 +02:00
|
|
|
});
|
2004-03-03 00:56:51 +01:00
|
|
|
|
2004-07-12 16:25:39 +02:00
|
|
|
WIN_RESTORE_LAST_ERROR;
|
2004-03-03 00:56:51 +01:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return &video_info;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-08-14 13:21:29 +02:00
|
|
|
// For very [very] basic memory-usage information.
|
|
|
|
// Should be replaced by a decent memory profiler.
|
2005-07-16 19:49:38 +02:00
|
|
|
//
|
|
|
|
// copied from SDL_GetVideoInfo but cannot be implemented in terms of it:
|
|
|
|
// SDL_VideoInfo doesn't provide for returning "remaining video memory".
|
2004-08-14 13:21:29 +02:00
|
|
|
int GetVRAMInfo(int& remaining, int& total)
|
|
|
|
{
|
|
|
|
int ok = 0;
|
|
|
|
#ifdef DDRAW
|
|
|
|
|
|
|
|
WIN_SAVE_LAST_ERROR; // DirectDraw
|
|
|
|
|
|
|
|
IDirectDraw* dd = 0;
|
|
|
|
HRESULT hr = DirectDrawCreate(0, &dd, 0);
|
|
|
|
if(SUCCEEDED(hr) && dd != 0)
|
|
|
|
{
|
|
|
|
static DDCAPS caps;
|
|
|
|
caps.dwSize = sizeof(caps);
|
|
|
|
hr = dd->GetCaps(&caps, 0);
|
|
|
|
if(SUCCEEDED(hr))
|
|
|
|
{
|
|
|
|
ok = 1;
|
|
|
|
remaining = caps.dwVidMemFree;
|
|
|
|
total = caps.dwVidMemTotal;
|
|
|
|
}
|
|
|
|
dd->Release();
|
|
|
|
}
|
|
|
|
|
|
|
|
WIN_RESTORE_LAST_ERROR;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-03-03 00:56:51 +01:00
|
|
|
SDL_Surface* SDL_GetVideoSurface()
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-01-07 02:25:10 +01:00
|
|
|
inline u32 SDL_GetTicks()
|
2004-03-03 00:56:51 +01:00
|
|
|
{
|
2005-01-07 02:25:10 +01:00
|
|
|
return GetTickCount();
|
2004-03-03 00:56:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-01-07 02:25:10 +01:00
|
|
|
inline void SDL_Delay(Uint32 ms)
|
2004-06-21 15:59:58 +02:00
|
|
|
{
|
2005-01-07 02:25:10 +01:00
|
|
|
Sleep(ms);
|
2004-06-21 15:59:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2005-03-18 23:09:44 +01:00
|
|
|
inline int SDL_WarpMouse(int x, int y)
|
|
|
|
{
|
|
|
|
return SetCursorPos(x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int SDL_ShowCursor(int toggle)
|
|
|
|
{
|
|
|
|
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-03-03 00:56:51 +01:00
|
|
|
void* SDL_GL_GetProcAddress(const char* name)
|
|
|
|
{
|
|
|
|
return wglGetProcAddress(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-03-18 23:09:44 +01:00
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// semaphores
|
|
|
|
//
|
|
|
|
|
|
|
|
// note: implementing these in terms of pthread sem_t doesn't help;
|
|
|
|
// this wrapper is very close to the Win32 routines.
|
|
|
|
|
|
|
|
union HANDLE_sem
|
|
|
|
{
|
|
|
|
HANDLE h;
|
|
|
|
SDL_sem* s;
|
|
|
|
};
|
|
|
|
|
2004-03-03 00:56:51 +01:00
|
|
|
SDL_sem* SDL_CreateSemaphore(int cnt)
|
|
|
|
{
|
2005-03-18 23:09:44 +01:00
|
|
|
HANDLE_sem u;
|
|
|
|
u.h = CreateSemaphore(0, cnt, 0x7fffffff, 0);
|
|
|
|
return u.s;
|
2004-03-03 00:56:51 +01:00
|
|
|
}
|
|
|
|
|
2005-01-07 02:25:10 +01:00
|
|
|
inline void SDL_DestroySemaphore(SDL_sem* sem)
|
2004-03-03 00:56:51 +01:00
|
|
|
{
|
2005-03-18 23:09:44 +01:00
|
|
|
HANDLE_sem u;
|
|
|
|
u.s = sem;
|
|
|
|
CloseHandle(u.h);
|
2004-03-03 00:56:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int SDL_SemPost(SDL_sem* sem)
|
|
|
|
{
|
2005-03-18 23:09:44 +01:00
|
|
|
HANDLE_sem u;
|
|
|
|
u.s = sem;
|
|
|
|
return ReleaseSemaphore(u.h, 1, 0);
|
2004-03-03 00:56:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int SDL_SemWait(SDL_sem* sem)
|
|
|
|
{
|
2005-03-18 23:09:44 +01:00
|
|
|
HANDLE_sem u;
|
|
|
|
u.s = sem;
|
|
|
|
return WaitForSingleObject(u.h, INFINITE);
|
2004-03-03 00:56:51 +01:00
|
|
|
}
|
|
|
|
|
2005-03-18 23:09:44 +01:00
|
|
|
|
|
|
|
//
|
|
|
|
// threads
|
|
|
|
//
|
|
|
|
|
2005-01-07 02:25:10 +01: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 19:09:28 +02: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-07 02:25:10 +01:00
|
|
|
|
2004-03-03 00:56:51 +01:00
|
|
|
SDL_Thread* SDL_CreateThread(int(*func)(void*), void* param)
|
|
|
|
{
|
2005-07-04 19:09:28 +02:00
|
|
|
pthread_t thread = 0;
|
|
|
|
if(pthread_create(&thread, 0, (void*(*)(void*))func, param) < 0)
|
2005-01-07 02:25:10 +01:00
|
|
|
return 0;
|
2005-07-04 19:09:28 +02:00
|
|
|
return *(SDL_Thread**)&thread;
|
2004-03-03 00:56:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int SDL_KillThread(SDL_Thread* thread)
|
|
|
|
{
|
2005-07-04 19:09:28 +02:00
|
|
|
pthread_cancel(*(pthread_t*)&thread);
|
2005-01-07 02:25:10 +01:00
|
|
|
return 0;
|
2004-03-03 00:56:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-01-07 02:25:10 +01:00
|
|
|
|
|
|
|
|
2004-03-03 00:56:51 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2005-01-23 19:05:33 +01:00
|
|
|
static bool need_redisplay; // display callback should be called in next main loop iteration
|
2004-03-03 00:56:51 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
2005-01-23 19:05:33 +01:00
|
|
|
// glut callbacks
|
2004-03-03 00:56:51 +01:00
|
|
|
static void (*idle)();
|
|
|
|
static void (*display)();
|
|
|
|
static void (*key)(int, int, int);
|
|
|
|
static void (*special)(int, int, int);
|
|
|
|
static void (*mouse)(int, int, int, int);
|
|
|
|
|
|
|
|
void glutIdleFunc(void (*func)())
|
|
|
|
{ idle = func; }
|
|
|
|
|
|
|
|
void glutDisplayFunc(void (*func)())
|
|
|
|
{ display = func; }
|
|
|
|
|
|
|
|
void glutKeyboardFunc(void (*func)(int, int, int))
|
|
|
|
{ key = func; }
|
|
|
|
|
|
|
|
void glutSpecialFunc(void (*func)(int, int, int))
|
|
|
|
{ special = func; }
|
|
|
|
|
|
|
|
void glutMouseFunc(void (*func)(int, int, int, int))
|
|
|
|
{ mouse = func; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2005-08-09 18:23:19 +02:00
|
|
|
void glutInit(int* UNUSED(argc), char* UNUSED(argv)[])
|
2004-03-03 00:56:51 +01:00
|
|
|
{
|
|
|
|
SDL_Init(0);
|
|
|
|
atexit(SDL_Quit);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int glutGet(int arg)
|
|
|
|
{
|
|
|
|
if(arg == GLUT_ELAPSED_TIME)
|
|
|
|
return GetTickCount();
|
|
|
|
|
|
|
|
dm.dmSize = sizeof(DEVMODE);
|
|
|
|
EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &dm);
|
|
|
|
|
|
|
|
if(arg == GLUT_SCREEN_WIDTH)
|
|
|
|
return dm.dmPelsWidth;
|
|
|
|
if(arg == GLUT_SCREEN_HEIGHT)
|
|
|
|
return dm.dmPelsHeight;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int w, h, bpp, refresh;
|
|
|
|
|
|
|
|
int glutGameModeString(const char* str)
|
|
|
|
{
|
2005-01-23 19:05:33 +01:00
|
|
|
// default = "don't care", in case string doesn't specify all values
|
2004-03-03 00:56:51 +01:00
|
|
|
w = 0, h = 0, bpp = 0, refresh = 0;
|
|
|
|
|
|
|
|
sscanf(str, "%dx%d:%d@%d", &w, &h, &bpp, &refresh);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-01-23 19:05:33 +01:00
|
|
|
|
2004-03-03 00:56:51 +01:00
|
|
|
int glutEnterGameMode()
|
|
|
|
{
|
|
|
|
return SDL_SetVideoMode(w, h, bpp, SDL_OPENGL|SDL_FULLSCREEN);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inline void glutPostRedisplay()
|
|
|
|
{
|
|
|
|
need_redisplay = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void glutSetCursor(int cursor)
|
|
|
|
{
|
|
|
|
SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(cursor)));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2005-01-23 19:05:33 +01:00
|
|
|
|
|
|
|
// GLUT message handler
|
|
|
|
// message also goes to the shared wndproc
|
|
|
|
//
|
|
|
|
// not done in wndproc to separate GLUT and SDL;
|
|
|
|
// split out of glutMainLoop for clarity.
|
2004-03-03 00:56:51 +01:00
|
|
|
static void glut_process_msg(MSG* msg)
|
|
|
|
{
|
|
|
|
switch(msg->message)
|
|
|
|
{
|
|
|
|
case WM_PAINT:
|
|
|
|
need_redisplay = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_CHAR:
|
|
|
|
if(key)
|
|
|
|
key((int)msg->wParam, mouse_x, mouse_y);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_KEYDOWN:
|
|
|
|
if(special)
|
|
|
|
special((int)msg->wParam, mouse_x, mouse_y);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_LBUTTONDOWN:
|
2005-01-23 19:05:33 +01:00
|
|
|
case WM_RBUTTONDOWN: // FIXME: only left/right clicks, assume GLUT_LEFT|RIGHT_BUTTON == 0, 1
|
2004-03-03 00:56:51 +01:00
|
|
|
if(mouse)
|
|
|
|
mouse(msg->message == WM_RBUTTONDOWN, GLUT_DOWN, (int)(msg->lParam & 0xffff), (int)(msg->lParam >> 16));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_MOUSEWHEEL:
|
|
|
|
if(mouse)
|
|
|
|
mouse(GLUT_MIDDLE_BUTTON, ((short)(msg->wParam >> 16) > 0)? GLUT_UP : GLUT_DOWN, 0, 0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void glutMainLoop()
|
|
|
|
{
|
|
|
|
for(;;)
|
|
|
|
{
|
|
|
|
if(!app_active)
|
|
|
|
WaitMessage();
|
|
|
|
|
|
|
|
MSG msg;
|
|
|
|
if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
|
|
|
|
{
|
|
|
|
glut_process_msg(&msg);
|
|
|
|
|
|
|
|
TranslateMessage(&msg);
|
|
|
|
DispatchMessage(&msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(idle)
|
|
|
|
idle();
|
|
|
|
|
|
|
|
if(need_redisplay)
|
|
|
|
{
|
|
|
|
need_redisplay = false;
|
|
|
|
display();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|