mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-25 21:21:14 +00:00
517 lines
12 KiB
C
517 lines
12 KiB
C
/*
|
|
vid_win.c
|
|
|
|
Win32 vid component
|
|
|
|
Copyright (C) 1996-1997 Id Software, Inc.
|
|
|
|
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.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to:
|
|
|
|
Free Software Foundation, Inc.
|
|
59 Temple Place - Suite 330
|
|
Boston, MA 02111-1307, USA
|
|
|
|
*/
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include "winquake.h"
|
|
#include <ddraw.h>
|
|
|
|
#include "QF/cmd.h"
|
|
#include "QF/cvar.h"
|
|
#include "QF/input.h"
|
|
#include "QF/qargs.h"
|
|
#include "QF/sys.h"
|
|
#include "QF/va.h"
|
|
#include "QF/vid.h"
|
|
|
|
#include "context_win.h"
|
|
#include "r_shared.h"
|
|
#include "in_win.h"
|
|
#include "vid_internal.h"
|
|
#include "vid_sw.h"
|
|
|
|
HWND win_mainwindow;
|
|
HDC win_maindc;
|
|
HCURSOR win_arrow;
|
|
bool win_cursor_visible;
|
|
int win_palettized;
|
|
bool win_minimized;
|
|
bool win_focused;
|
|
bool win_canalttab;
|
|
sw_ctx_t *win_sw_context;
|
|
|
|
#define MODE_WINDOWED 0
|
|
#define MODE_SETTABLE_WINDOW 2
|
|
#define NO_MODE (MODE_WINDOWED - 1)
|
|
#define MODE_FULLSCREEN_DEFAULT (MODE_WINDOWED + 3)
|
|
|
|
#define WINDOW_CLASS PACKAGE_NAME "WindowClass"
|
|
|
|
int vid_ddraw;
|
|
static cvar_t vid_ddraw_cvar = {
|
|
.name = "vid_ddraw",
|
|
.description =
|
|
"",
|
|
.default_value = "1",
|
|
.flags = CVAR_NONE,
|
|
.value = { .type = &cexpr_int, .value = &vid_ddraw },
|
|
};
|
|
|
|
// Note that 0 is MODE_WINDOWED
|
|
static int vid_mode;
|
|
static cvar_t vid_mode_cvar = {
|
|
.name = "vid_mode",
|
|
.description =
|
|
"",
|
|
.default_value = "0",
|
|
.flags = CVAR_NONE,
|
|
.value = { .type = &cexpr_int, .value = &vid_mode },
|
|
};
|
|
|
|
// Note that 0 is MODE_WINDOWED
|
|
int _vid_default_mode;
|
|
static cvar_t _vid_default_mode_cvar = {
|
|
.name = "_vid_default_mode",
|
|
.description =
|
|
"",
|
|
.default_value = "0",
|
|
.flags = CVAR_ARCHIVE,
|
|
.value = { .type = &cexpr_int, .value = &_vid_default_mode },
|
|
};
|
|
|
|
// Note that 3 is MODE_FULLSCREEN_DEFAULT
|
|
static int _vid_default_mode_win;
|
|
static cvar_t _vid_default_mode_win_cvar = {
|
|
.name = "_vid_default_mode_win",
|
|
.description =
|
|
"",
|
|
.default_value = "3",
|
|
.flags = CVAR_ARCHIVE,
|
|
.value = { .type = &cexpr_int, .value = &_vid_default_mode_win },
|
|
};
|
|
int vid_wait;
|
|
static cvar_t vid_wait_cvar = {
|
|
.name = "vid_wait",
|
|
.description =
|
|
"",
|
|
.default_value = "0",
|
|
.flags = CVAR_NONE,
|
|
.value = { .type = &cexpr_int, .value = &vid_wait },
|
|
};
|
|
int vid_nopageflip;
|
|
static cvar_t vid_nopageflip_cvar = {
|
|
.name = "vid_nopageflip",
|
|
.description =
|
|
"",
|
|
.default_value = "0",
|
|
.flags = CVAR_ARCHIVE,
|
|
.value = { .type = &cexpr_int, .value = &vid_nopageflip },
|
|
};
|
|
int _vid_wait_override;
|
|
static cvar_t _vid_wait_override_cvar = {
|
|
.name = "_vid_wait_override",
|
|
.description =
|
|
"",
|
|
.default_value = "0",
|
|
.flags = CVAR_ARCHIVE,
|
|
.value = { .type = &cexpr_int, .value = &_vid_wait_override },
|
|
};
|
|
int vid_config_x;
|
|
static cvar_t vid_config_x_cvar = {
|
|
.name = "vid_config_x",
|
|
.description =
|
|
"",
|
|
.default_value = "800",
|
|
.flags = CVAR_ARCHIVE,
|
|
.value = { .type = &cexpr_int, .value = &vid_config_x },
|
|
};
|
|
int vid_config_y;
|
|
static cvar_t vid_config_y_cvar = {
|
|
.name = "vid_config_y",
|
|
.description =
|
|
"",
|
|
.default_value = "600",
|
|
.flags = CVAR_ARCHIVE,
|
|
.value = { .type = &cexpr_int, .value = &vid_config_y },
|
|
};
|
|
int vid_stretch_by_2;
|
|
static cvar_t vid_stretch_by_2_cvar = {
|
|
.name = "vid_stretch_by_2",
|
|
.description =
|
|
"",
|
|
.default_value = "1",
|
|
.flags = CVAR_ARCHIVE,
|
|
.value = { .type = &cexpr_int, .value = &vid_stretch_by_2 },
|
|
};
|
|
static int _windowed_mouse;
|
|
static cvar_t _windowed_mouse_cvar = {
|
|
.name = "_windowed_mouse",
|
|
.description =
|
|
"",
|
|
.default_value = "0",
|
|
.flags = CVAR_ARCHIVE,
|
|
.value = { .type = &cexpr_int, .value = &_windowed_mouse },
|
|
};
|
|
static int vid_fullscreen_mode;
|
|
static cvar_t vid_fullscreen_mode_cvar = {
|
|
.name = "vid_fullscreen_mode",
|
|
.description =
|
|
"",
|
|
.default_value = "3",
|
|
.flags = CVAR_ARCHIVE,
|
|
.value = { .type = &cexpr_int, .value = &vid_fullscreen_mode },
|
|
};
|
|
static int vid_windowed_mode;
|
|
static cvar_t vid_windowed_mode_cvar = {
|
|
.name = "vid_windowed_mode",
|
|
.description =
|
|
"",
|
|
.default_value = "0",
|
|
.flags = CVAR_ARCHIVE,
|
|
.value = { .type = &cexpr_int, .value = &vid_windowed_mode },
|
|
};
|
|
int block_switch;
|
|
static cvar_t block_switch_cvar = {
|
|
.name = "block_switch",
|
|
.description =
|
|
"",
|
|
.default_value = "0",
|
|
.flags = CVAR_ARCHIVE,
|
|
.value = { .type = &cexpr_int, .value = &block_switch },
|
|
};
|
|
static int vid_window_x;
|
|
static cvar_t vid_window_x_cvar = {
|
|
.name = "vid_window_x",
|
|
.description =
|
|
"",
|
|
.default_value = "0",
|
|
.flags = CVAR_ARCHIVE,
|
|
.value = { .type = &cexpr_int, .value = &vid_window_x },
|
|
};
|
|
static int vid_window_y;
|
|
static cvar_t vid_window_y_cvar = {
|
|
.name = "vid_window_y",
|
|
.description =
|
|
"",
|
|
.default_value = "0",
|
|
.flags = CVAR_ARCHIVE,
|
|
.value = { .type = &cexpr_int, .value = &vid_window_y },
|
|
};
|
|
|
|
//FIXME?int yeahimconsoled;
|
|
|
|
#define MAX_MODE_LIST 36
|
|
#define VID_ROW_SIZE 3
|
|
|
|
static DWORD WindowStyle, ExWindowStyle;
|
|
|
|
int win_center_x, win_center_y;
|
|
int win_pos_x, win_pos_y;
|
|
int win_len_x, win_len_y;
|
|
RECT win_rect;
|
|
|
|
DEVMODE win_gdevmode;
|
|
|
|
int vid_modenum = NO_MODE;
|
|
int vid_testingmode, vid_realmode;
|
|
double vid_testendtime;
|
|
int vid_default = MODE_WINDOWED;
|
|
|
|
modestate_t modestate = MS_UNINIT;
|
|
|
|
byte vid_curpal[256 * 3];
|
|
|
|
int mode;
|
|
|
|
int aPage; // Current active display page
|
|
int vPage; // Current visible display page
|
|
int waitVRT = true; // True to wait for retrace on flip
|
|
|
|
static LONG (*event_handlers[WM_USER])(HWND, UINT, WPARAM, LPARAM);
|
|
|
|
bool
|
|
Win_AddEvent (UINT event, LONG (*event_handler)(HWND, UINT, WPARAM, LPARAM))
|
|
{
|
|
if (event >= WM_USER) {
|
|
Sys_MaskPrintf (SYS_vid, "event: %d, WM_USER: %d\n", event, WM_USER);
|
|
return false;
|
|
}
|
|
|
|
if (event_handlers[event]) {
|
|
return false;
|
|
}
|
|
|
|
event_handlers[event] = event_handler;
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
Win_RemoveEvent (UINT event)
|
|
{
|
|
if (event >= WM_USER) {
|
|
Sys_MaskPrintf (SYS_vid, "event: %d, WM_USER: %d\n", event, WM_USER);
|
|
return false;
|
|
}
|
|
event_handlers[event] = 0;
|
|
return true;
|
|
}
|
|
|
|
static LONG WINAPI
|
|
Win_EventHandler (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (uMsg < WM_USER && event_handlers[uMsg]) {
|
|
return event_handlers[uMsg] (hWnd, uMsg, wParam, lParam);
|
|
}
|
|
return DefWindowProc (hWnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
static void
|
|
Win_UpdateWindowStatus ()
|
|
{
|
|
win_rect.left = win_pos_x;
|
|
win_rect.top = win_pos_y;
|
|
win_rect.right = win_pos_x + win_len_x;
|
|
win_rect.bottom = win_pos_y + win_len_y;
|
|
win_center_x = (win_rect.left + win_rect.right) / 2;
|
|
win_center_y = (win_rect.top + win_rect.bottom) / 2;
|
|
VID_SetWindow (win_pos_x, win_pos_y, win_len_x, win_len_y);
|
|
IN_UpdateClipCursor ();
|
|
}
|
|
|
|
static void
|
|
VID_InitModes (HINSTANCE hInstance)
|
|
{
|
|
WNDCLASS wc = {
|
|
.style = CS_OWNDC,
|
|
.lpfnWndProc = (WNDPROC) Win_EventHandler,
|
|
.hInstance = hInstance,
|
|
.lpszClassName = WINDOW_CLASS,
|
|
};
|
|
|
|
win_arrow = LoadCursor (NULL, IDC_ARROW);
|
|
|
|
//FIXME hIcon = LoadIcon (hInstance, MAKEINTRESOURCE (IDI_ICON2));
|
|
|
|
/* Register the frame class */
|
|
|
|
if (!RegisterClass (&wc))
|
|
Sys_Error ("Couldn't register window class");
|
|
}
|
|
|
|
void
|
|
Win_OpenDisplay (void)
|
|
{
|
|
global_hInstance = GetModuleHandle (0);
|
|
VID_InitModes (global_hInstance);
|
|
}
|
|
|
|
void
|
|
Win_CloseDisplay (void)
|
|
{
|
|
if (viddef.initialized) {
|
|
PostMessage (HWND_BROADCAST, WM_PALETTECHANGED, (WPARAM) win_mainwindow,
|
|
(LPARAM) 0);
|
|
PostMessage (HWND_BROADCAST, WM_SYSCOLORCHANGE, (WPARAM) 0, (LPARAM) 0);
|
|
|
|
vid_testingmode = 0;
|
|
viddef.initialized = false;
|
|
}
|
|
}
|
|
|
|
static RECT window_rect;
|
|
void
|
|
Win_UpdateFullscreen (int fullscreen)
|
|
{
|
|
if (fullscreen) {
|
|
GetWindowRect (win_mainwindow, &window_rect);
|
|
SetWindowLongW (win_mainwindow, GWL_STYLE, 0);
|
|
HMONITOR monitor = MonitorFromWindow (win_mainwindow, MONITOR_DEFAULTTONEAREST);
|
|
MONITORINFO info = {
|
|
.cbSize = sizeof (info),
|
|
};
|
|
GetMonitorInfoW (monitor, &info);
|
|
SetWindowPos (win_mainwindow, HWND_TOP,
|
|
info.rcMonitor.left,
|
|
info.rcMonitor.top,
|
|
info.rcMonitor.right - info.rcMonitor.left,
|
|
info.rcMonitor.bottom - info.rcMonitor.top,
|
|
SWP_FRAMECHANGED | SWP_NOACTIVATE);
|
|
ShowWindow (win_mainwindow, SW_MAXIMIZE);
|
|
} else {
|
|
SetWindowLongW (win_mainwindow, GWL_STYLE, WindowStyle);
|
|
SetWindowPos (win_mainwindow, HWND_NOTOPMOST,
|
|
window_rect.left,
|
|
window_rect.top,
|
|
window_rect.right - window_rect.left,
|
|
window_rect.bottom - window_rect.top,
|
|
SWP_FRAMECHANGED | SWP_NOACTIVATE);
|
|
ShowWindow (win_mainwindow, SW_NORMAL);
|
|
}
|
|
}
|
|
|
|
static long
|
|
notify_create (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static long
|
|
notify_destroy (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (win_mainwindow) {
|
|
DestroyWindow (win_mainwindow);
|
|
win_mainwindow = 0;
|
|
}
|
|
PostQuitMessage (0);
|
|
return 1;
|
|
}
|
|
|
|
static long
|
|
notify_move (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
win_pos_x = (short) LOWORD (lParam);
|
|
win_pos_y = (short) HIWORD (lParam);
|
|
Sys_MaskPrintf (SYS_vid, "notify_move: %d %d\n", win_pos_x, win_pos_y);
|
|
Win_UpdateWindowStatus ();
|
|
return 1;
|
|
}
|
|
|
|
static long
|
|
notify_size (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
win_len_x = (short) LOWORD (lParam);
|
|
win_len_y = (short) HIWORD (lParam);
|
|
Sys_MaskPrintf (SYS_vid, "notify_size: %d %d\n", win_pos_x, win_pos_y);
|
|
Win_UpdateWindowStatus ();
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
Win_CreateWindow (int width, int height)
|
|
{
|
|
IN_Win_Preinit ();
|
|
|
|
Win_AddEvent (WM_CREATE, notify_create);
|
|
Win_AddEvent (WM_DESTROY, notify_destroy);
|
|
Win_AddEvent (WM_MOVE, notify_move);
|
|
Win_AddEvent (WM_SIZE, notify_size);
|
|
|
|
|
|
RECT rect = {
|
|
.top = win_pos_x = 0,
|
|
.left = win_pos_y = 0,
|
|
.right = win_len_x = width,
|
|
.bottom = win_len_y = height,
|
|
};
|
|
WindowStyle = WS_OVERLAPPEDWINDOW | WS_CAPTION | WS_SYSMENU | WS_SIZEBOX |
|
|
WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
|
|
AdjustWindowRectEx (&rect, WindowStyle, FALSE, 0);
|
|
// sound initialization has to go here, preceded by a windowed mode set,
|
|
// so there's a window for DirectSound to work with but we're not yet
|
|
// fullscreen so the "hardware already in use" dialog is visible if it
|
|
// gets displayed
|
|
// keep the window minimized until we're ready for the first real mode set
|
|
win_mainwindow = CreateWindowExA (ExWindowStyle,
|
|
WINDOW_CLASS,
|
|
PACKAGE_STRING,
|
|
WindowStyle,
|
|
0, 0,
|
|
rect.right - rect.left,
|
|
rect.bottom - rect.top,
|
|
NULL, NULL, global_hInstance, NULL);
|
|
|
|
if (!win_mainwindow)
|
|
Sys_Error ("Couldn't create window");
|
|
|
|
// done
|
|
Win_UpdateWindowStatus ();
|
|
|
|
HDC hdc = GetDC (NULL);
|
|
if (GetDeviceCaps (hdc, RASTERCAPS) & RC_PALETTE) {
|
|
win_palettized = true;
|
|
} else {
|
|
win_palettized = false;
|
|
}
|
|
ReleaseDC (NULL, hdc);
|
|
|
|
MSG msg;
|
|
while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) {
|
|
TranslateMessage (&msg);
|
|
DispatchMessage (&msg);
|
|
}
|
|
|
|
Sleep (100);
|
|
|
|
SetWindowPos (win_mainwindow, HWND_TOP, 0, 0, 0, 0,
|
|
SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW |
|
|
SWP_NOCOPYBITS);
|
|
SetForegroundWindow (win_mainwindow);
|
|
|
|
viddef.recalc_refdef = 1;
|
|
}
|
|
|
|
void
|
|
Win_SetCaption (const char *text)
|
|
{
|
|
if (win_mainwindow) {
|
|
SetWindowTextA (win_mainwindow, text);
|
|
}
|
|
}
|
|
|
|
//static WORD systemgammaramps[3][256];
|
|
static WORD currentgammaramps[3][256];
|
|
|
|
bool
|
|
Win_SetGamma (double gamma)
|
|
{
|
|
int i;
|
|
HDC hdc = GetDC (NULL);
|
|
|
|
for (i = 0; i < 256; i++) {
|
|
currentgammaramps[2][i] = currentgammaramps[1][i] =
|
|
currentgammaramps[0][i] = viddef.gammatable[i] * 256;
|
|
}
|
|
|
|
i = SetDeviceGammaRamp (hdc, ¤tgammaramps[0][0]);
|
|
ReleaseDC (NULL, hdc);
|
|
return i;
|
|
}
|
|
|
|
void
|
|
Win_Init_Cvars (void)
|
|
{
|
|
Cvar_Register (&vid_ddraw_cvar, 0, 0);
|
|
Cvar_Register (&vid_mode_cvar, 0, 0);
|
|
Cvar_Register (&vid_wait_cvar, 0, 0);
|
|
Cvar_Register (&vid_nopageflip_cvar, 0, 0);
|
|
Cvar_Register (&_vid_wait_override_cvar, 0, 0);
|
|
Cvar_Register (&_vid_default_mode_cvar, 0, 0);
|
|
Cvar_Register (&_vid_default_mode_win_cvar, 0, 0);
|
|
Cvar_Register (&vid_config_x_cvar, 0, 0);
|
|
Cvar_Register (&vid_config_y_cvar, 0, 0);
|
|
Cvar_Register (&vid_stretch_by_2_cvar, 0, 0);
|
|
Cvar_Register (&_windowed_mouse_cvar, 0, 0);
|
|
Cvar_Register (&vid_fullscreen_mode_cvar, 0, 0);
|
|
Cvar_Register (&vid_windowed_mode_cvar, 0, 0);
|
|
Cvar_Register (&block_switch_cvar, 0, 0);
|
|
Cvar_Register (&vid_window_x_cvar, 0, 0);
|
|
Cvar_Register (&vid_window_y_cvar, 0, 0);
|
|
}
|
|
|
|
extern int win_force_link;
|
|
static __attribute__((used)) int *context_win_force_link = &win_force_link;
|