/* | |
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 the Free Software | |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
*/ | |
// gl_vidnt.c -- NT GL vid component | |
#include "quakedef.h" | |
#include "winquake.h" | |
#include "resource.h" | |
#include <commctrl.h> | |
#define MAX_MODE_LIST 30 | |
#define VID_ROW_SIZE 3 | |
#define WARP_WIDTH 320 | |
#define WARP_HEIGHT 200 | |
#define MAXWIDTH 10000 | |
#define MAXHEIGHT 10000 | |
#define BASEWIDTH 320 | |
#define BASEHEIGHT 200 | |
#define MODE_WINDOWED 0 | |
#define NO_MODE (MODE_WINDOWED - 1) | |
#define MODE_FULLSCREEN_DEFAULT (MODE_WINDOWED + 1) | |
typedef struct { | |
modestate_t type; | |
int width; | |
int height; | |
int modenum; | |
int dib; | |
int fullscreen; | |
int bpp; | |
int halfscreen; | |
char modedesc[17]; | |
} vmode_t; | |
typedef struct { | |
int width; | |
int height; | |
} lmode_t; | |
lmode_t lowresmodes[] = { | |
{320, 200}, | |
{320, 240}, | |
{400, 300}, | |
{512, 384}, | |
}; | |
const char *gl_vendor; | |
const char *gl_renderer; | |
const char *gl_version; | |
const char *gl_extensions; | |
qboolean DDActive; | |
qboolean scr_skipupdate; | |
static vmode_t modelist[MAX_MODE_LIST]; | |
static int nummodes; | |
static vmode_t *pcurrentmode; | |
static vmode_t badmode; | |
static DEVMODE gdevmode; | |
static qboolean vid_initialized = false; | |
static qboolean windowed, leavecurrentmode; | |
static qboolean vid_canalttab = false; | |
static qboolean vid_wassuspended = false; | |
static int windowed_mouse; | |
extern qboolean mouseactive; // from in_win.c | |
static HICON hIcon; | |
int DIBWidth, DIBHeight; | |
RECT WindowRect; | |
DWORD WindowStyle, ExWindowStyle; | |
HWND mainwindow, dibwindow; | |
int vid_modenum = NO_MODE; | |
int vid_realmode; | |
int vid_default = MODE_WINDOWED; | |
static int windowed_default; | |
unsigned char vid_curpal[256*3]; | |
static qboolean fullsbardraw = false; | |
static float vid_gamma = 1.0; | |
HGLRC baseRC; | |
HDC maindc; | |
glvert_t glv; | |
cvar_t gl_ztrick = {"gl_ztrick","1"}; | |
HWND WINAPI InitializeWindow (HINSTANCE hInstance, int nCmdShow); | |
viddef_t vid; // global video state | |
unsigned short d_8to16table[256]; | |
unsigned d_8to24table[256]; | |
unsigned char d_15to8table[65536]; | |
float gldepthmin, gldepthmax; | |
modestate_t modestate = MS_UNINIT; | |
void VID_MenuDraw (void); | |
void VID_MenuKey (int key); | |
LONG WINAPI MainWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); | |
void AppActivate(BOOL fActive, BOOL minimize); | |
char *VID_GetModeDescription (int mode); | |
void ClearAllStates (void); | |
void VID_UpdateWindowStatus (void); | |
void GL_Init (void); | |
PROC glArrayElementEXT; | |
PROC glColorPointerEXT; | |
PROC glTexCoordPointerEXT; | |
PROC glVertexPointerEXT; | |
typedef void (APIENTRY *lp3DFXFUNC) (int, int, int, int, int, const void*); | |
lp3DFXFUNC glColorTableEXT; | |
qboolean is8bit = false; | |
qboolean isPermedia = false; | |
qboolean gl_mtexable = false; | |
//==================================== | |
cvar_t vid_mode = {"vid_mode","0", false}; | |
// Note that 0 is MODE_WINDOWED | |
cvar_t _vid_default_mode = {"_vid_default_mode","0", true}; | |
// Note that 3 is MODE_FULLSCREEN_DEFAULT | |
cvar_t _vid_default_mode_win = {"_vid_default_mode_win","3", true}; | |
cvar_t vid_wait = {"vid_wait","0"}; | |
cvar_t vid_nopageflip = {"vid_nopageflip","0", true}; | |
cvar_t _vid_wait_override = {"_vid_wait_override", "0", true}; | |
cvar_t vid_config_x = {"vid_config_x","800", true}; | |
cvar_t vid_config_y = {"vid_config_y","600", true}; | |
cvar_t vid_stretch_by_2 = {"vid_stretch_by_2","1", true}; | |
cvar_t _windowed_mouse = {"_windowed_mouse","1", true}; | |
int window_center_x, window_center_y, window_x, window_y, window_width, window_height; | |
RECT window_rect; | |
// direct draw software compatability stuff | |
void VID_HandlePause (qboolean pause) | |
{ | |
} | |
void VID_ForceLockState (int lk) | |
{ | |
} | |
void VID_LockBuffer (void) | |
{ | |
} | |
void VID_UnlockBuffer (void) | |
{ | |
} | |
int VID_ForceUnlockedAndReturnState (void) | |
{ | |
return 0; | |
} | |
void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height) | |
{ | |
} | |
void D_EndDirectRect (int x, int y, int width, int height) | |
{ | |
} | |
void CenterWindow(HWND hWndCenter, int width, int height, BOOL lefttopjustify) | |
{ | |
RECT rect; | |
int CenterX, CenterY; | |
CenterX = (GetSystemMetrics(SM_CXSCREEN) - width) / 2; | |
CenterY = (GetSystemMetrics(SM_CYSCREEN) - height) / 2; | |
if (CenterX > CenterY*2) | |
CenterX >>= 1; // dual screens | |
CenterX = (CenterX < 0) ? 0: CenterX; | |
CenterY = (CenterY < 0) ? 0: CenterY; | |
SetWindowPos (hWndCenter, NULL, CenterX, CenterY, 0, 0, | |
SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_DRAWFRAME); | |
} | |
qboolean VID_SetWindowedMode (int modenum) | |
{ | |
HDC hdc; | |
int lastmodestate, width, height; | |
RECT rect; | |
lastmodestate = modestate; | |
WindowRect.top = WindowRect.left = 0; | |
WindowRect.right = modelist[modenum].width; | |
WindowRect.bottom = modelist[modenum].height; | |
DIBWidth = modelist[modenum].width; | |
DIBHeight = modelist[modenum].height; | |
WindowStyle = WS_OVERLAPPED | WS_BORDER | WS_CAPTION | WS_SYSMENU | | |
WS_MINIMIZEBOX; | |
ExWindowStyle = 0; | |
rect = WindowRect; | |
AdjustWindowRectEx(&rect, WindowStyle, FALSE, 0); | |
width = rect.right - rect.left; | |
height = rect.bottom - rect.top; | |
// Create the DIB window | |
dibwindow = CreateWindowEx ( | |
ExWindowStyle, | |
"WinQuake", | |
"GLQuake", | |
WindowStyle, | |
rect.left, rect.top, | |
width, | |
height, | |
NULL, | |
NULL, | |
global_hInstance, | |
NULL); | |
if (!dibwindow) | |
Sys_Error ("Couldn't create DIB window"); | |
// Center and show the DIB window | |
CenterWindow(dibwindow, WindowRect.right - WindowRect.left, | |
WindowRect.bottom - WindowRect.top, false); | |
ShowWindow (dibwindow, SW_SHOWDEFAULT); | |
UpdateWindow (dibwindow); | |
modestate = MS_WINDOWED; | |
// because we have set the background brush for the window to NULL | |
// (to avoid flickering when re-sizing the window on the desktop), | |
// we clear the window to black when created, otherwise it will be | |
// empty while Quake starts up. | |
hdc = GetDC(dibwindow); | |
PatBlt(hdc,0,0,WindowRect.right,WindowRect.bottom,BLACKNESS); | |
ReleaseDC(dibwindow, hdc); | |
if (vid.conheight > modelist[modenum].height) | |
vid.conheight = modelist[modenum].height; | |
if (vid.conwidth > modelist[modenum].width) | |
vid.conwidth = modelist[modenum].width; | |
vid.width = vid.conwidth; | |
vid.height = vid.conheight; | |
vid.numpages = 2; | |
mainwindow = dibwindow; | |
SendMessage (mainwindow, WM_SETICON, (WPARAM)TRUE, (LPARAM)hIcon); | |
SendMessage (mainwindow, WM_SETICON, (WPARAM)FALSE, (LPARAM)hIcon); | |
return true; | |
} | |
qboolean VID_SetFullDIBMode (int modenum) | |
{ | |
HDC hdc; | |
int lastmodestate, width, height; | |
RECT rect; | |
if (!leavecurrentmode) | |
{ | |
gdevmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; | |
gdevmode.dmBitsPerPel = modelist[modenum].bpp; | |
gdevmode.dmPelsWidth = modelist[modenum].width << | |
modelist[modenum].halfscreen; | |
gdevmode.dmPelsHeight = modelist[modenum].height; | |
gdevmode.dmSize = sizeof (gdevmode); | |
if (ChangeDisplaySettings (&gdevmode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) | |
Sys_Error ("Couldn't set fullscreen DIB mode"); | |
} | |
lastmodestate = modestate; | |
modestate = MS_FULLDIB; | |
WindowRect.top = WindowRect.left = 0; | |
WindowRect.right = modelist[modenum].width; | |
WindowRect.bottom = modelist[modenum].height; | |
DIBWidth = modelist[modenum].width; | |
DIBHeight = modelist[modenum].height; | |
WindowStyle = WS_POPUP; | |
ExWindowStyle = 0; | |
rect = WindowRect; | |
AdjustWindowRectEx(&rect, WindowStyle, FALSE, 0); | |
width = rect.right - rect.left; | |
height = rect.bottom - rect.top; | |
// Create the DIB window | |
dibwindow = CreateWindowEx ( | |
ExWindowStyle, | |
"WinQuake", | |
"GLQuake", | |
WindowStyle, | |
rect.left, rect.top, | |
width, | |
height, | |
NULL, | |
NULL, | |
global_hInstance, | |
NULL); | |
if (!dibwindow) | |
Sys_Error ("Couldn't create DIB window"); | |
ShowWindow (dibwindow, SW_SHOWDEFAULT); | |
UpdateWindow (dibwindow); | |
// Because we have set the background brush for the window to NULL | |
// (to avoid flickering when re-sizing the window on the desktop), we | |
// clear the window to black when created, otherwise it will be | |
// empty while Quake starts up. | |
hdc = GetDC(dibwindow); | |
PatBlt(hdc,0,0,WindowRect.right,WindowRect.bottom,BLACKNESS); | |
ReleaseDC(dibwindow, hdc); | |
if (vid.conheight > modelist[modenum].height) | |
vid.conheight = modelist[modenum].height; | |
if (vid.conwidth > modelist[modenum].width) | |
vid.conwidth = modelist[modenum].width; | |
vid.width = vid.conwidth; | |
vid.height = vid.conheight; | |
vid.numpages = 2; | |
// needed because we're not getting WM_MOVE messages fullscreen on NT | |
window_x = 0; | |
window_y = 0; | |
mainwindow = dibwindow; | |
SendMessage (mainwindow, WM_SETICON, (WPARAM)TRUE, (LPARAM)hIcon); | |
SendMessage (mainwindow, WM_SETICON, (WPARAM)FALSE, (LPARAM)hIcon); | |
return true; | |
} | |
int VID_SetMode (int modenum, unsigned char *palette) | |
{ | |
int original_mode, temp; | |
qboolean stat; | |
MSG msg; | |
HDC hdc; | |
if ((windowed && (modenum != 0)) || | |
(!windowed && (modenum < 1)) || | |
(!windowed && (modenum >= nummodes))) | |
{ | |
Sys_Error ("Bad video mode\n"); | |
} | |
// so Con_Printfs don't mess us up by forcing vid and snd updates | |
temp = scr_disabled_for_loading; | |
scr_disabled_for_loading = true; | |
CDAudio_Pause (); | |
if (vid_modenum == NO_MODE) | |
original_mode = windowed_default; | |
else | |
original_mode = vid_modenum; | |
// Set either the fullscreen or windowed mode | |
if (modelist[modenum].type == MS_WINDOWED) | |
{ | |
if (_windowed_mouse.value && key_dest == key_game) | |
{ | |
stat = VID_SetWindowedMode(modenum); | |
IN_ActivateMouse (); | |
IN_HideMouse (); | |
} | |
else | |
{ | |
IN_DeactivateMouse (); | |
IN_ShowMouse (); | |
stat = VID_SetWindowedMode(modenum); | |
} | |
} | |
else if (modelist[modenum].type == MS_FULLDIB) | |
{ | |
stat = VID_SetFullDIBMode(modenum); | |
IN_ActivateMouse (); | |
IN_HideMouse (); | |
} | |
else | |
{ | |
Sys_Error ("VID_SetMode: Bad mode type in modelist"); | |
} | |
window_width = DIBWidth; | |
window_height = DIBHeight; | |
VID_UpdateWindowStatus (); | |
CDAudio_Resume (); | |
scr_disabled_for_loading = temp; | |
if (!stat) | |
{ | |
Sys_Error ("Couldn't set video mode"); | |
} | |
// now we try to make sure we get the focus on the mode switch, because | |
// sometimes in some systems we don't. We grab the foreground, then | |
// finish setting up, pump all our messages, and sleep for a little while | |
// to let messages finish bouncing around the system, then we put | |
// ourselves at the top of the z order, then grab the foreground again, | |
// Who knows if it helps, but it probably doesn't hurt | |
SetForegroundWindow (mainwindow); | |
VID_SetPalette (palette); | |
vid_modenum = modenum; | |
Cvar_SetValue ("vid_mode", (float)vid_modenum); | |
while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) | |
{ | |
TranslateMessage (&msg); | |
DispatchMessage (&msg); | |
} | |
Sleep (100); | |
SetWindowPos (mainwindow, HWND_TOP, 0, 0, 0, 0, | |
SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | | |
SWP_NOCOPYBITS); | |
SetForegroundWindow (mainwindow); | |
// fix the leftover Alt from any Alt-Tab or the like that switched us away | |
ClearAllStates (); | |
if (!msg_suppress_1) | |
Con_SafePrintf ("Video mode %s initialized.\n", VID_GetModeDescription (vid_modenum)); | |
VID_SetPalette (palette); | |
vid.recalc_refdef = 1; | |
return true; | |
} | |
/* | |
================ | |
VID_UpdateWindowStatus | |
================ | |
*/ | |
void VID_UpdateWindowStatus (void) | |
{ | |
window_rect.left = window_x; | |
window_rect.top = window_y; | |
window_rect.right = window_x + window_width; | |
window_rect.bottom = window_y + window_height; | |
window_center_x = (window_rect.left + window_rect.right) / 2; | |
window_center_y = (window_rect.top + window_rect.bottom) / 2; | |
IN_UpdateClipCursor (); | |
} | |
//==================================== | |
BINDTEXFUNCPTR bindTexFunc; | |
#define TEXTURE_EXT_STRING "GL_EXT_texture_object" | |
void CheckTextureExtensions (void) | |
{ | |
char *tmp; | |
qboolean texture_ext; | |
HINSTANCE hInstGL; | |
texture_ext = FALSE; | |
/* check for texture extension */ | |
tmp = (unsigned char *)glGetString(GL_EXTENSIONS); | |
while (*tmp) | |
{ | |
if (strncmp((const char*)tmp, TEXTURE_EXT_STRING, strlen(TEXTURE_EXT_STRING)) == 0) | |
texture_ext = TRUE; | |
tmp++; | |
} | |
if (!texture_ext || COM_CheckParm ("-gl11") ) | |
{ | |
hInstGL = LoadLibrary("opengl32.dll"); | |
if (hInstGL == NULL) | |
Sys_Error ("Couldn't load opengl32.dll\n"); | |
bindTexFunc = (void *)GetProcAddress(hInstGL,"glBindTexture"); | |
if (!bindTexFunc) | |
Sys_Error ("No texture objects!"); | |
return; | |
} | |
/* load library and get procedure adresses for texture extension API */ | |
if ((bindTexFunc = (BINDTEXFUNCPTR) | |
wglGetProcAddress((LPCSTR) "glBindTextureEXT")) == NULL) | |
{ | |
Sys_Error ("GetProcAddress for BindTextureEXT failed"); | |
return; | |
} | |
} | |
void CheckArrayExtensions (void) | |
{ | |
char *tmp; | |
/* check for texture extension */ | |
tmp = (unsigned char *)glGetString(GL_EXTENSIONS); | |
while (*tmp) | |
{ | |
if (strncmp((const char*)tmp, "GL_EXT_vertex_array", strlen("GL_EXT_vertex_array")) == 0) | |
{ | |
if ( | |
((glArrayElementEXT = wglGetProcAddress("glArrayElementEXT")) == NULL) || | |
((glColorPointerEXT = wglGetProcAddress("glColorPointerEXT")) == NULL) || | |
((glTexCoordPointerEXT = wglGetProcAddress("glTexCoordPointerEXT")) == NULL) || | |
((glVertexPointerEXT = wglGetProcAddress("glVertexPointerEXT")) == NULL) ) | |
{ | |
Sys_Error ("GetProcAddress for vertex extension failed"); | |
return; | |
} | |
return; | |
} | |
tmp++; | |
} | |
Sys_Error ("Vertex array extension not present"); | |
} | |
//int texture_mode = GL_NEAREST; | |
//int texture_mode = GL_NEAREST_MIPMAP_NEAREST; | |
//int texture_mode = GL_NEAREST_MIPMAP_LINEAR; | |
int texture_mode = GL_LINEAR; | |
//int texture_mode = GL_LINEAR_MIPMAP_NEAREST; | |
//int texture_mode = GL_LINEAR_MIPMAP_LINEAR; | |
int texture_extension_number = 1; | |
#ifdef _WIN32 | |
void CheckMultiTextureExtensions(void) | |
{ | |
if (strstr(gl_extensions, "GL_SGIS_multitexture ") && !COM_CheckParm("-nomtex")) { | |
Con_Printf("Multitexture extensions found.\n"); | |
qglMTexCoord2fSGIS = (void *) wglGetProcAddress("glMTexCoord2fSGIS"); | |
qglSelectTextureSGIS = (void *) wglGetProcAddress("glSelectTextureSGIS"); | |
gl_mtexable = true; | |
} | |
} | |
#else | |
void CheckMultiTextureExtensions(void) | |
{ | |
gl_mtexable = true; | |
} | |
#endif | |
/* | |
=============== | |
GL_Init | |
=============== | |
*/ | |
void GL_Init (void) | |
{ | |
gl_vendor = glGetString (GL_VENDOR); | |
Con_Printf ("GL_VENDOR: %s\n", gl_vendor); | |
gl_renderer = glGetString (GL_RENDERER); | |
Con_Printf ("GL_RENDERER: %s\n", gl_renderer); | |
gl_version = glGetString (GL_VERSION); | |
Con_Printf ("GL_VERSION: %s\n", gl_version); | |
gl_extensions = glGetString (GL_EXTENSIONS); | |
Con_Printf ("GL_EXTENSIONS: %s\n", gl_extensions); | |
// Con_Printf ("%s %s\n", gl_renderer, gl_version); | |
if (strnicmp(gl_renderer,"PowerVR",7)==0) | |
fullsbardraw = true; | |
if (strnicmp(gl_renderer,"Permedia",8)==0) | |
isPermedia = true; | |
CheckTextureExtensions (); | |
CheckMultiTextureExtensions (); | |
glClearColor (1,0,0,0); | |
glCullFace(GL_FRONT); | |
glEnable(GL_TEXTURE_2D); | |
glEnable(GL_ALPHA_TEST); | |
glAlphaFunc(GL_GREATER, 0.666); | |
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); | |
glShadeModel (GL_FLAT); | |
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); | |
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); | |
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); | |
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); | |
#if 0 | |
CheckArrayExtensions (); | |
glEnable (GL_VERTEX_ARRAY_EXT); | |
glEnable (GL_TEXTURE_COORD_ARRAY_EXT); | |
glVertexPointerEXT (3, GL_FLOAT, 0, 0, &glv.x); | |
glTexCoordPointerEXT (2, GL_FLOAT, 0, 0, &glv.s); | |
glColorPointerEXT (3, GL_FLOAT, 0, 0, &glv.r); | |
#endif | |
} | |
/* | |
================= | |
GL_BeginRendering | |
================= | |
*/ | |
void GL_BeginRendering (int *x, int *y, int *width, int *height) | |
{ | |
extern cvar_t gl_clear; | |
*x = *y = 0; | |
*width = WindowRect.right - WindowRect.left; | |
*height = WindowRect.bottom - WindowRect.top; | |
// if (!wglMakeCurrent( maindc, baseRC )) | |
// Sys_Error ("wglMakeCurrent failed"); | |
// glViewport (*x, *y, *width, *height); | |
} | |
void GL_EndRendering (void) | |
{ | |
if (!scr_skipupdate || block_drawing) | |
SwapBuffers(maindc); | |
// handle the mouse state when windowed if that's changed | |
if (modestate == MS_WINDOWED) | |
{ | |
if (!_windowed_mouse.value) { | |
if (windowed_mouse) { | |
IN_DeactivateMouse (); | |
IN_ShowMouse (); | |
windowed_mouse = false; | |
} | |
} else { | |
windowed_mouse = true; | |
if (key_dest == key_game && !mouseactive && ActiveApp) { | |
IN_ActivateMouse (); | |
IN_HideMouse (); | |
} else if (mouseactive && key_dest != key_game) { | |
IN_DeactivateMouse (); | |
IN_ShowMouse (); | |
} | |
} | |
} | |
if (fullsbardraw) | |
Sbar_Changed(); | |
} | |
void VID_SetPalette (unsigned char *palette) | |
{ | |
byte *pal; | |
unsigned r,g,b; | |
unsigned v; | |
int r1,g1,b1; | |
int j,k,l,m; | |
unsigned short i; | |
unsigned *table; | |
FILE *f; | |
char s[255]; | |
HWND hDlg, hProgress; | |
float gamma; | |
// | |
// 8 8 8 encoding | |
// | |
pal = palette; | |
table = d_8to24table; | |
for (i=0 ; i<256 ; i++) | |
{ | |
r = pal[0]; | |
g = pal[1]; | |
b = pal[2]; | |
pal += 3; | |
// v = (255<<24) + (r<<16) + (g<<8) + (b<<0); | |
// v = (255<<0) + (r<<8) + (g<<16) + (b<<24); | |
v = (255<<24) + (r<<0) + (g<<8) + (b<<16); | |
*table++ = v; | |
} | |
d_8to24table[255] &= 0xffffff; // 255 is transparent | |
// JACK: 3D distance calcs - k is last closest, l is the distance. | |
// FIXME: Precalculate this and cache to disk. | |
for (i=0; i < (1<<15); i++) { | |
/* Maps | |
000000000000000 | |
000000000011111 = Red = 0x1F | |
000001111100000 = Blue = 0x03E0 | |
111110000000000 = Grn = 0x7C00 | |
*/ | |
r = ((i & 0x1F) << 3)+4; | |
g = ((i & 0x03E0) >> 2)+4; | |
b = ((i & 0x7C00) >> 7)+4; | |
pal = (unsigned char *)d_8to24table; | |
for (v=0,k=0,l=10000*10000; v<256; v++,pal+=4) { | |
r1 = r-pal[0]; | |
g1 = g-pal[1]; | |
b1 = b-pal[2]; | |
j = (r1*r1)+(g1*g1)+(b1*b1); | |
if (j<l) { | |
k=v; | |
l=j; | |
} | |
} | |
d_15to8table[i]=k; | |
} | |
} | |
BOOL gammaworks; | |
void VID_ShiftPalette (unsigned char *palette) | |
{ | |
extern byte ramps[3][256]; | |
// VID_SetPalette (palette); | |
// gammaworks = SetDeviceGammaRamp (maindc, ramps); | |
} | |
void VID_SetDefaultMode (void) | |
{ | |
IN_DeactivateMouse (); | |
} | |
void VID_Shutdown (void) | |
{ | |
HGLRC hRC; | |
HDC hDC; | |
if (vid_initialized) | |
{ | |
vid_canalttab = false; | |
hRC = wglGetCurrentContext(); | |
hDC = wglGetCurrentDC(); | |
wglMakeCurrent(NULL, NULL); | |
if (hRC) | |
wglDeleteContext(hRC); | |
if (hDC && dibwindow) | |
ReleaseDC(dibwindow, hDC); | |
if (modestate == MS_FULLDIB) | |
ChangeDisplaySettings (NULL, 0); | |
if (maindc && dibwindow) | |
ReleaseDC (dibwindow, maindc); | |
AppActivate(false, false); | |
} | |
} | |
//========================================================================== | |
BOOL bSetupPixelFormat(HDC hDC) | |
{ | |
static PIXELFORMATDESCRIPTOR pfd = { | |
sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd | |
1, // version number | |
PFD_DRAW_TO_WINDOW // support window | |
| PFD_SUPPORT_OPENGL // support OpenGL | |
| PFD_DOUBLEBUFFER , // double buffered | |
PFD_TYPE_RGBA, // RGBA type | |
24, // 24-bit color depth | |
0, 0, 0, 0, 0, 0, // color bits ignored | |
0, // no alpha buffer | |
0, // shift bit ignored | |
0, // no accumulation buffer | |
0, 0, 0, 0, // accum bits ignored | |
32, // 32-bit z-buffer | |
0, // no stencil buffer | |
0, // no auxiliary buffer | |
PFD_MAIN_PLANE, // main layer | |
0, // reserved | |
0, 0, 0 // layer masks ignored | |
}; | |
int pixelformat; | |
if ( (pixelformat = ChoosePixelFormat(hDC, &pfd)) == 0 ) | |
{ | |
MessageBox(NULL, "ChoosePixelFormat failed", "Error", MB_OK); | |
return FALSE; | |
} | |
if (SetPixelFormat(hDC, pixelformat, &pfd) == FALSE) | |
{ | |
MessageBox(NULL, "SetPixelFormat failed", "Error", MB_OK); | |
return FALSE; | |
} | |
return TRUE; | |
} | |
byte scantokey[128] = | |
{ | |
// 0 1 2 3 4 5 6 7 | |
// 8 9 A B C D E F | |
0 , 27, '1', '2', '3', '4', '5', '6', | |
'7', '8', '9', '0', '-', '=', K_BACKSPACE, 9, // 0 | |
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', | |
'o', 'p', '[', ']', 13 , K_CTRL,'a', 's', // 1 | |
'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', | |
'\'' , '`', K_SHIFT,'\\', 'z', 'x', 'c', 'v', // 2 | |
'b', 'n', 'm', ',', '.', '/', K_SHIFT,'*', | |
K_ALT,' ', 0 , K_F1, K_F2, K_F3, K_F4, K_F5, // 3 | |
K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE , 0 , K_HOME, | |
K_UPARROW,K_PGUP,'-',K_LEFTARROW,'5',K_RIGHTARROW,'+',K_END, //4 | |
K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, 0, K_F11, | |
K_F12,0 , 0 , 0 , 0 , 0 , 0 , 0, // 5 | |
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, | |
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, // 6 | |
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, | |
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // 7 | |
}; | |
byte shiftscantokey[128] = | |
{ | |
// 0 1 2 3 4 5 6 7 | |
// 8 9 A B C D E F | |
0 , 27, '!', '@', '#', '$', '%', '^', | |
'&', '*', '(', ')', '_', '+', K_BACKSPACE, 9, // 0 | |
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', | |
'O', 'P', '{', '}', 13 , K_CTRL,'A', 'S', // 1 | |
'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', | |
'"' , '~', K_SHIFT,'|', 'Z', 'X', 'C', 'V', // 2 | |
'B', 'N', 'M', '<', '>', '?', K_SHIFT,'*', | |
K_ALT,' ', 0 , K_F1, K_F2, K_F3, K_F4, K_F5, // 3 | |
K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE , 0 , K_HOME, | |
K_UPARROW,K_PGUP,'_',K_LEFTARROW,'%',K_RIGHTARROW,'+',K_END, //4 | |
K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, 0, K_F11, | |
K_F12,0 , 0 , 0 , 0 , 0 , 0 , 0, // 5 | |
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, | |
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, // 6 | |
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, | |
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // 7 | |
}; | |
/* | |
======= | |
MapKey | |
Map from windows to quake keynums | |
======= | |
*/ | |
int MapKey (int key) | |
{ | |
key = (key>>16)&255; | |
if (key > 127) | |
return 0; | |
if (scantokey[key] == 0) | |
Con_DPrintf("key 0x%02x has no translation\n", key); | |
return scantokey[key]; | |
} | |
/* | |
=================================================================== | |
MAIN WINDOW | |
=================================================================== | |
*/ | |
/* | |
================ | |
ClearAllStates | |
================ | |
*/ | |
void ClearAllStates (void) | |
{ | |
int i; | |
// send an up event for each key, to make sure the server clears them all | |
for (i=0 ; i<256 ; i++) | |
{ | |
Key_Event (i, false); | |
} | |
Key_ClearStates (); | |
IN_ClearStates (); | |
} | |
void AppActivate(BOOL fActive, BOOL minimize) | |
/**************************************************************************** | |
* | |
* Function: AppActivate | |
* Parameters: fActive - True if app is activating | |
* | |
* Description: If the application is activating, then swap the system | |
* into SYSPAL_NOSTATIC mode so that our palettes will display | |
* correctly. | |
* | |
****************************************************************************/ | |
{ | |
MSG msg; | |
HDC hdc; | |
int i, t; | |
static BOOL sound_active; | |
ActiveApp = fActive; | |
Minimized = minimize; | |
// enable/disable sound on focus gain/loss | |
if (!ActiveApp && sound_active) | |
{ | |
S_BlockSound (); | |
sound_active = false; | |
} | |
else if (ActiveApp && !sound_active) | |
{ | |
S_UnblockSound (); | |
sound_active = true; | |
} | |
if (fActive) | |
{ | |
if (modestate == MS_FULLDIB) | |
{ | |
IN_ActivateMouse (); | |
IN_HideMouse (); | |
if (vid_canalttab && vid_wassuspended) { | |
vid_wassuspended = false; | |
ChangeDisplaySettings (&gdevmode, CDS_FULLSCREEN); | |
ShowWindow(mainwindow, SW_SHOWNORMAL); | |
} | |
} | |
else if ((modestate == MS_WINDOWED) && _windowed_mouse.value && key_dest == key_game) | |
{ | |
IN_ActivateMouse (); | |
IN_HideMouse (); | |
} | |
} | |
if (!fActive) | |
{ | |
if (modestate == MS_FULLDIB) | |
{ | |
IN_DeactivateMouse (); | |
IN_ShowMouse (); | |
if (vid_canalttab) { | |
ChangeDisplaySettings (NULL, 0); | |
vid_wassuspended = true; | |
} | |
} | |
else if ((modestate == MS_WINDOWED) && _windowed_mouse.value) | |
{ | |
IN_DeactivateMouse (); | |
IN_ShowMouse (); | |
} | |
} | |
} | |
/* main window procedure */ | |
LONG WINAPI MainWndProc ( | |
HWND hWnd, | |
UINT uMsg, | |
WPARAM wParam, | |
LPARAM lParam) | |
{ | |
LONG lRet = 1; | |
int fwKeys, xPos, yPos, fActive, fMinimized, temp; | |
extern unsigned int uiWheelMessage; | |
if ( uMsg == uiWheelMessage ) | |
uMsg = WM_MOUSEWHEEL; | |
switch (uMsg) | |
{ | |
case WM_KILLFOCUS: | |
if (modestate == MS_FULLDIB) | |
ShowWindow(mainwindow, SW_SHOWMINNOACTIVE); | |
break; | |
case WM_CREATE: | |
break; | |
case WM_MOVE: | |
window_x = (int) LOWORD(lParam); | |
window_y = (int) HIWORD(lParam); | |
VID_UpdateWindowStatus (); | |
break; | |
case WM_KEYDOWN: | |
case WM_SYSKEYDOWN: | |
Key_Event (MapKey(lParam), true); | |
break; | |
case WM_KEYUP: | |
case WM_SYSKEYUP: | |
Key_Event (MapKey(lParam), false); | |
break; | |
case WM_SYSCHAR: | |
// keep Alt-Space from happening | |
break; | |
// this is complicated because Win32 seems to pack multiple mouse events into | |
// one update sometimes, so we always check all states and look for events | |
case WM_LBUTTONDOWN: | |
case WM_LBUTTONUP: | |
case WM_RBUTTONDOWN: | |
case WM_RBUTTONUP: | |
case WM_MBUTTONDOWN: | |
case WM_MBUTTONUP: | |
case WM_MOUSEMOVE: | |
temp = 0; | |
if (wParam & MK_LBUTTON) | |
temp |= 1; | |
if (wParam & MK_RBUTTON) | |
temp |= 2; | |
if (wParam & MK_MBUTTON) | |
temp |= 4; | |
IN_MouseEvent (temp); | |
break; | |
// JACK: This is the mouse wheel with the Intellimouse | |
// Its delta is either positive or neg, and we generate the proper | |
// Event. | |
case WM_MOUSEWHEEL: | |
if ((short) HIWORD(wParam) > 0) { | |
Key_Event(K_MWHEELUP, true); | |
Key_Event(K_MWHEELUP, false); | |
} else { | |
Key_Event(K_MWHEELDOWN, true); | |
Key_Event(K_MWHEELDOWN, false); | |
} | |
break; | |
case WM_SIZE: | |
break; | |
case WM_CLOSE: | |
if (MessageBox (mainwindow, "Are you sure you want to quit?", "Confirm Exit", | |
MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION) == IDYES) | |
{ | |
Sys_Quit (); | |
} | |
break; | |
case WM_ACTIVATE: | |
fActive = LOWORD(wParam); | |
fMinimized = (BOOL) HIWORD(wParam); | |
AppActivate(!(fActive == WA_INACTIVE), fMinimized); | |
// fix the leftover Alt from any Alt-Tab or the like that switched us away | |
ClearAllStates (); | |
break; | |
case WM_DESTROY: | |
{ | |
if (dibwindow) | |
DestroyWindow (dibwindow); | |
PostQuitMessage (0); | |
} | |
break; | |
case MM_MCINOTIFY: | |
lRet = CDAudio_MessageHandler (hWnd, uMsg, wParam, lParam); | |
break; | |
default: | |
/* pass all unhandled messages to DefWindowProc */ | |
lRet = DefWindowProc (hWnd, uMsg, wParam, lParam); | |
break; | |
} | |
/* return 1 if handled message, 0 if not */ | |
return lRet; | |
} | |
/* | |
================= | |
VID_NumModes | |
================= | |
*/ | |
int VID_NumModes (void) | |
{ | |
return nummodes; | |
} | |
/* | |
================= | |
VID_GetModePtr | |
================= | |
*/ | |
vmode_t *VID_GetModePtr (int modenum) | |
{ | |
if ((modenum >= 0) && (modenum < nummodes)) | |
return &modelist[modenum]; | |
else | |
return &badmode; | |
} | |
/* | |
================= | |
VID_GetModeDescription | |
================= | |
*/ | |
char *VID_GetModeDescription (int mode) | |
{ | |
char *pinfo; | |
vmode_t *pv; | |
static char temp[100]; | |
if ((mode < 0) || (mode >= nummodes)) | |
return NULL; | |
if (!leavecurrentmode) | |
{ | |
pv = VID_GetModePtr (mode); | |
pinfo = pv->modedesc; | |
} | |
else | |
{ | |
sprintf (temp, "Desktop resolution (%dx%d)", | |
modelist[MODE_FULLSCREEN_DEFAULT].width, | |
modelist[MODE_FULLSCREEN_DEFAULT].height); | |
pinfo = temp; | |
} | |
return pinfo; | |
} | |
// KJB: Added this to return the mode driver name in description for console | |
char *VID_GetExtModeDescription (int mode) | |
{ | |
static char pinfo[40]; | |
vmode_t *pv; | |
if ((mode < 0) || (mode >= nummodes)) | |
return NULL; | |
pv = VID_GetModePtr (mode); | |
if (modelist[mode].type == MS_FULLDIB) | |
{ | |
if (!leavecurrentmode) | |
{ | |
sprintf(pinfo,"%s fullscreen", pv->modedesc); | |
} | |
else | |
{ | |
sprintf (pinfo, "Desktop resolution (%dx%d)", | |
modelist[MODE_FULLSCREEN_DEFAULT].width, | |
modelist[MODE_FULLSCREEN_DEFAULT].height); | |
} | |
} | |
else | |
{ | |
if (modestate == MS_WINDOWED) | |
sprintf(pinfo, "%s windowed", pv->modedesc); | |
else | |
sprintf(pinfo, "windowed"); | |
} | |
return pinfo; | |
} | |
/* | |
================= | |
VID_DescribeCurrentMode_f | |
================= | |
*/ | |
void VID_DescribeCurrentMode_f (void) | |
{ | |
Con_Printf ("%s\n", VID_GetExtModeDescription (vid_modenum)); | |
} | |
/* | |
================= | |
VID_NumModes_f | |
================= | |
*/ | |
void VID_NumModes_f (void) | |
{ | |
if (nummodes == 1) | |
Con_Printf ("%d video mode is available\n", nummodes); | |
else | |
Con_Printf ("%d video modes are available\n", nummodes); | |
} | |
/* | |
================= | |
VID_DescribeMode_f | |
================= | |
*/ | |
void VID_DescribeMode_f (void) | |
{ | |
int t, modenum; | |
modenum = Q_atoi (Cmd_Argv(1)); | |
t = leavecurrentmode; | |
leavecurrentmode = 0; | |
Con_Printf ("%s\n", VID_GetExtModeDescription (modenum)); | |
leavecurrentmode = t; | |
} | |
/* | |
================= | |
VID_DescribeModes_f | |
================= | |
*/ | |
void VID_DescribeModes_f (void) | |
{ | |
int i, lnummodes, t; | |
char *pinfo; | |
vmode_t *pv; | |
lnummodes = VID_NumModes (); | |
t = leavecurrentmode; | |
leavecurrentmode = 0; | |
for (i=1 ; i<lnummodes ; i++) | |
{ | |
pv = VID_GetModePtr (i); | |
pinfo = VID_GetExtModeDescription (i); | |
Con_Printf ("%2d: %s\n", i, pinfo); | |
} | |
leavecurrentmode = t; | |
} | |
void VID_InitDIB (HINSTANCE hInstance) | |
{ | |
WNDCLASS wc; | |
HDC hdc; | |
int i; | |
/* Register the frame class */ | |
wc.style = 0; | |
wc.lpfnWndProc = (WNDPROC)MainWndProc; | |
wc.cbClsExtra = 0; | |
wc.cbWndExtra = 0; | |
wc.hInstance = hInstance; | |
wc.hIcon = 0; | |
wc.hCursor = LoadCursor (NULL,IDC_ARROW); | |
wc.hbrBackground = NULL; | |
wc.lpszMenuName = 0; | |
wc.lpszClassName = "WinQuake"; | |
if (!RegisterClass (&wc) ) | |
Sys_Error ("Couldn't register window class"); | |
modelist[0].type = MS_WINDOWED; | |
if (COM_CheckParm("-width")) | |
modelist[0].width = Q_atoi(com_argv[COM_CheckParm("-width")+1]); | |
else | |
modelist[0].width = 640; | |
if (modelist[0].width < 320) | |
modelist[0].width = 320; | |
if (COM_CheckParm("-height")) | |
modelist[0].height= Q_atoi(com_argv[COM_CheckParm("-height")+1]); | |
else | |
modelist[0].height = modelist[0].width * 240/320; | |
if (modelist[0].height < 240) | |
modelist[0].height = 240; | |
sprintf (modelist[0].modedesc, "%dx%d", | |
modelist[0].width, modelist[0].height); | |
modelist[0].modenum = MODE_WINDOWED; | |
modelist[0].dib = 1; | |
modelist[0].fullscreen = 0; | |
modelist[0].halfscreen = 0; | |
modelist[0].bpp = 0; | |
nummodes = 1; | |
} | |
/* | |
================= | |
VID_InitFullDIB | |
================= | |
*/ | |
void VID_InitFullDIB (HINSTANCE hInstance) | |
{ | |
DEVMODE devmode; | |
int i, modenum, cmodes, originalnummodes, existingmode, numlowresmodes; | |
int j, bpp, done; | |
BOOL stat; | |
// enumerate >8 bpp modes | |
originalnummodes = nummodes; | |
modenum = 0; | |
do | |
{ | |
stat = EnumDisplaySettings (NULL, modenum, &devmode); | |
if ((devmode.dmBitsPerPel >= 15) && | |
(devmode.dmPelsWidth <= MAXWIDTH) && | |
(devmode.dmPelsHeight <= MAXHEIGHT) && | |
(nummodes < MAX_MODE_LIST)) | |
{ | |
devmode.dmFields = DM_BITSPERPEL | | |
DM_PELSWIDTH | | |
DM_PELSHEIGHT; | |
if (ChangeDisplaySettings (&devmode, CDS_TEST | CDS_FULLSCREEN) == | |
DISP_CHANGE_SUCCESSFUL) | |
{ | |
modelist[nummodes].type = MS_FULLDIB; | |
modelist[nummodes].width = devmode.dmPelsWidth; | |
modelist[nummodes].height = devmode.dmPelsHeight; | |
modelist[nummodes].modenum = 0; | |
modelist[nummodes].halfscreen = 0; | |
modelist[nummodes].dib = 1; | |
modelist[nummodes].fullscreen = 1; | |
modelist[nummodes].bpp = devmode.dmBitsPerPel; | |
sprintf (modelist[nummodes].modedesc, "%dx%dx%d", | |
devmode.dmPelsWidth, devmode.dmPelsHeight, | |
devmode.dmBitsPerPel); | |
// if the width is more than twice the height, reduce it by half because this | |
// is probably a dual-screen monitor | |
if (!COM_CheckParm("-noadjustaspect")) | |
{ | |
if (modelist[nummodes].width > (modelist[nummodes].height << 1)) | |
{ | |
modelist[nummodes].width >>= 1; | |
modelist[nummodes].halfscreen = 1; | |
sprintf (modelist[nummodes].modedesc, "%dx%dx%d", | |
modelist[nummodes].width, | |
modelist[nummodes].height, | |
modelist[nummodes].bpp); | |
} | |
} | |
for (i=originalnummodes, existingmode = 0 ; i<nummodes ; i++) | |
{ | |
if ((modelist[nummodes].width == modelist[i].width) && | |
(modelist[nummodes].height == modelist[i].height) && | |
(modelist[nummodes].bpp == modelist[i].bpp)) | |
{ | |
existingmode = 1; | |
break; | |
} | |
} | |
if (!existingmode) | |
{ | |
nummodes++; | |
} | |
} | |
} | |
modenum++; | |
} while (stat); | |
// see if there are any low-res modes that aren't being reported | |
numlowresmodes = sizeof(lowresmodes) / sizeof(lowresmodes[0]); | |
bpp = 16; | |
done = 0; | |
do | |
{ | |
for (j=0 ; (j<numlowresmodes) && (nummodes < MAX_MODE_LIST) ; j++) | |
{ | |
devmode.dmBitsPerPel = bpp; | |
devmode.dmPelsWidth = lowresmodes[j].width; | |
devmode.dmPelsHeight = lowresmodes[j].height; | |
devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; | |
if (ChangeDisplaySettings (&devmode, CDS_TEST | CDS_FULLSCREEN) == | |
DISP_CHANGE_SUCCESSFUL) | |
{ | |
modelist[nummodes].type = MS_FULLDIB; | |
modelist[nummodes].width = devmode.dmPelsWidth; | |
modelist[nummodes].height = devmode.dmPelsHeight; | |
modelist[nummodes].modenum = 0; | |
modelist[nummodes].halfscreen = 0; | |
modelist[nummodes].dib = 1; | |
modelist[nummodes].fullscreen = 1; | |
modelist[nummodes].bpp = devmode.dmBitsPerPel; | |
sprintf (modelist[nummodes].modedesc, "%dx%dx%d", | |
devmode.dmPelsWidth, devmode.dmPelsHeight, | |
devmode.dmBitsPerPel); | |
for (i=originalnummodes, existingmode = 0 ; i<nummodes ; i++) | |
{ | |
if ((modelist[nummodes].width == modelist[i].width) && | |
(modelist[nummodes].height == modelist[i].height) && | |
(modelist[nummodes].bpp == modelist[i].bpp)) | |
{ | |
existingmode = 1; | |
break; | |
} | |
} | |
if (!existingmode) | |
{ | |
nummodes++; | |
} | |
} | |
} | |
switch (bpp) | |
{ | |
case 16: | |
bpp = 32; | |
break; | |
case 32: | |
bpp = 24; | |
break; | |
case 24: | |
done = 1; | |
break; | |
} | |
} while (!done); | |
if (nummodes == originalnummodes) | |
Con_SafePrintf ("No fullscreen DIB modes found\n"); | |
} | |
qboolean VID_Is8bit() { | |
return is8bit; | |
} | |
#define GL_SHARED_TEXTURE_PALETTE_EXT 0x81FB | |
void VID_Init8bitPalette() | |
{ | |
// Check for 8bit Extensions and initialize them. | |
int i; | |
char thePalette[256*3]; | |
char *oldPalette, *newPalette; | |
glColorTableEXT = (void *)wglGetProcAddress("glColorTableEXT"); | |
if (!glColorTableEXT || strstr(gl_extensions, "GL_EXT_shared_texture_palette") || | |
COM_CheckParm("-no8bit")) | |
return; | |
Con_SafePrintf("8-bit GL extensions enabled.\n"); | |
glEnable( GL_SHARED_TEXTURE_PALETTE_EXT ); | |
oldPalette = (char *) d_8to24table; //d_8to24table3dfx; | |
newPalette = thePalette; | |
for (i=0;i<256;i++) { | |
*newPalette++ = *oldPalette++; | |
*newPalette++ = *oldPalette++; | |
*newPalette++ = *oldPalette++; | |
oldPalette++; | |
} | |
glColorTableEXT(GL_SHARED_TEXTURE_PALETTE_EXT, GL_RGB, 256, GL_RGB, GL_UNSIGNED_BYTE, | |
(void *) thePalette); | |
is8bit = TRUE; | |
} | |
static void Check_Gamma (unsigned char *pal) | |
{ | |
float f, inf; | |
unsigned char palette[768]; | |
int i; | |
if ((i = COM_CheckParm("-gamma")) == 0) { | |
if ((gl_renderer && strstr(gl_renderer, "Voodoo")) || | |
(gl_vendor && strstr(gl_vendor, "3Dfx"))) | |
vid_gamma = 1; | |
else | |
vid_gamma = 0.7; // default to 0.7 on non-3dfx hardware | |
} else | |
vid_gamma = Q_atof(com_argv[i+1]); | |
for (i=0 ; i<768 ; i++) | |
{ | |
f = pow ( (pal[i]+1)/256.0 , vid_gamma ); | |
inf = f*255 + 0.5; | |
if (inf < 0) | |
inf = 0; | |
if (inf > 255) | |
inf = 255; | |
palette[i] = inf; | |
} | |
memcpy (pal, palette, sizeof(palette)); | |
} | |
/* | |
=================== | |
VID_Init | |
=================== | |
*/ | |
void VID_Init (unsigned char *palette) | |
{ | |
int i, existingmode; | |
int basenummodes, width, height, bpp, findbpp, done; | |
byte *ptmp; | |
char gldir[MAX_OSPATH]; | |
HDC hdc; | |
DEVMODE devmode; | |
memset(&devmode, 0, sizeof(devmode)); | |
Cvar_RegisterVariable (&vid_mode); | |
Cvar_RegisterVariable (&vid_wait); | |
Cvar_RegisterVariable (&vid_nopageflip); | |
Cvar_RegisterVariable (&_vid_wait_override); | |
Cvar_RegisterVariable (&_vid_default_mode); | |
Cvar_RegisterVariable (&_vid_default_mode_win); | |
Cvar_RegisterVariable (&vid_config_x); | |
Cvar_RegisterVariable (&vid_config_y); | |
Cvar_RegisterVariable (&vid_stretch_by_2); | |
Cvar_RegisterVariable (&_windowed_mouse); | |
Cvar_RegisterVariable (&gl_ztrick); | |
Cmd_AddCommand ("vid_nummodes", VID_NumModes_f); | |
Cmd_AddCommand ("vid_describecurrentmode", VID_DescribeCurrentMode_f); | |
Cmd_AddCommand ("vid_describemode", VID_DescribeMode_f); | |
Cmd_AddCommand ("vid_describemodes", VID_DescribeModes_f); | |
hIcon = LoadIcon (global_hInstance, MAKEINTRESOURCE (IDI_ICON2)); | |
InitCommonControls(); | |
VID_InitDIB (global_hInstance); | |
basenummodes = nummodes = 1; | |
VID_InitFullDIB (global_hInstance); | |
if (COM_CheckParm("-window")) | |
{ | |
hdc = GetDC (NULL); | |
if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) | |
{ | |
Sys_Error ("Can't run in non-RGB mode"); | |
} | |
ReleaseDC (NULL, hdc); | |
windowed = true; | |
vid_default = MODE_WINDOWED; | |
} | |
else | |
{ | |
if (nummodes == 1) | |
Sys_Error ("No RGB fullscreen modes available"); | |
windowed = false; | |
if (COM_CheckParm("-mode")) | |
{ | |
vid_default = Q_atoi(com_argv[COM_CheckParm("-mode")+1]); | |
} | |
else | |
{ | |
if (COM_CheckParm("-current")) | |
{ | |
modelist[MODE_FULLSCREEN_DEFAULT].width = | |
GetSystemMetrics (SM_CXSCREEN); | |
modelist[MODE_FULLSCREEN_DEFAULT].height = | |
GetSystemMetrics (SM_CYSCREEN); | |
vid_default = MODE_FULLSCREEN_DEFAULT; | |
leavecurrentmode = 1; | |
} | |
else | |
{ | |
if (COM_CheckParm("-width")) | |
{ | |
width = Q_atoi(com_argv[COM_CheckParm("-width")+1]); | |
} | |
else | |
{ | |
width = 640; | |
} | |
if (COM_CheckParm("-bpp")) | |
{ | |
bpp = Q_atoi(com_argv[COM_CheckParm("-bpp")+1]); | |
findbpp = 0; | |
} | |
else | |
{ | |
bpp = 15; | |
findbpp = 1; | |
} | |
if (COM_CheckParm("-height")) | |
height = Q_atoi(com_argv[COM_CheckParm("-height")+1]); | |
// if they want to force it, add the specified mode to the list | |
if (COM_CheckParm("-force") && (nummodes < MAX_MODE_LIST)) | |
{ | |
modelist[nummodes].type = MS_FULLDIB; | |
modelist[nummodes].width = width; | |
modelist[nummodes].height = height; | |
modelist[nummodes].modenum = 0; | |
modelist[nummodes].halfscreen = 0; | |
modelist[nummodes].dib = 1; | |
modelist[nummodes].fullscreen = 1; | |
modelist[nummodes].bpp = bpp; | |
sprintf (modelist[nummodes].modedesc, "%dx%dx%d", | |
devmode.dmPelsWidth, devmode.dmPelsHeight, | |
devmode.dmBitsPerPel); | |
for (i=nummodes, existingmode = 0 ; i<nummodes ; i++) | |
{ | |
if ((modelist[nummodes].width == modelist[i].width) && | |
(modelist[nummodes].height == modelist[i].height) && | |
(modelist[nummodes].bpp == modelist[i].bpp)) | |
{ | |
existingmode = 1; | |
break; | |
} | |
} | |
if (!existingmode) | |
{ | |
nummodes++; | |
} | |
} | |
done = 0; | |
do | |
{ | |
if (COM_CheckParm("-height")) | |
{ | |
height = Q_atoi(com_argv[COM_CheckParm("-height")+1]); | |
for (i=1, vid_default=0 ; i<nummodes ; i++) | |
{ | |
if ((modelist[i].width == width) && | |
(modelist[i].height == height) && | |
(modelist[i].bpp == bpp)) | |
{ | |
vid_default = i; | |
done = 1; | |
break; | |
} | |
} | |
} | |
else | |
{ | |
for (i=1, vid_default=0 ; i<nummodes ; i++) | |
{ | |
if ((modelist[i].width == width) && (modelist[i].bpp == bpp)) | |
{ | |
vid_default = i; | |
done = 1; | |
break; | |
} | |
} | |
} | |
if (!done) | |
{ | |
if (findbpp) | |
{ | |
switch (bpp) | |
{ | |
case 15: | |
bpp = 16; | |
break; | |
case 16: | |
bpp = 32; | |
break; | |
case 32: | |
bpp = 24; | |
break; | |
case 24: | |
done = 1; | |
break; | |
} | |
} | |
else | |
{ | |
done = 1; | |
} | |
} | |
} while (!done); | |
if (!vid_default) | |
{ | |
Sys_Error ("Specified video mode not available"); | |
} | |
} | |
} | |
} | |
vid_initialized = true; | |
if ((i = COM_CheckParm("-conwidth")) != 0) | |
vid.conwidth = Q_atoi(com_argv[i+1]); | |
else | |
vid.conwidth = 640; | |
vid.conwidth &= 0xfff8; // make it a multiple of eight | |
if (vid.conwidth < 320) | |
vid.conwidth = 320; | |
// pick a conheight that matches with correct aspect | |
vid.conheight = vid.conwidth*3 / 4; | |
if ((i = COM_CheckParm("-conheight")) != 0) | |
vid.conheight = Q_atoi(com_argv[i+1]); | |
if (vid.conheight < 200) | |
vid.conheight = 200; | |
vid.maxwarpwidth = WARP_WIDTH; | |
vid.maxwarpheight = WARP_HEIGHT; | |
vid.colormap = host_colormap; | |
vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048)); | |
DestroyWindow (hwnd_dialog); | |
Check_Gamma(palette); | |
VID_SetPalette (palette); | |
VID_SetMode (vid_default, palette); | |
maindc = GetDC(mainwindow); | |
bSetupPixelFormat(maindc); | |
baseRC = wglCreateContext( maindc ); | |
if (!baseRC) | |
Sys_Error ("Could not initialize GL (wglCreateContext failed).\n\nMake sure you in are 65535 color mode, and try running -window."); | |
if (!wglMakeCurrent( maindc, baseRC )) | |
Sys_Error ("wglMakeCurrent failed"); | |
GL_Init (); | |
sprintf (gldir, "%s/glquake", com_gamedir); | |
Sys_mkdir (gldir); | |
vid_realmode = vid_modenum; | |
// Check for 3DFX Extensions and initialize them. | |
VID_Init8bitPalette(); | |
vid_menudrawfn = VID_MenuDraw; | |
vid_menukeyfn = VID_MenuKey; | |
strcpy (badmode.modedesc, "Bad mode"); | |
vid_canalttab = true; | |
if (COM_CheckParm("-fullsbar")) | |
fullsbardraw = true; | |
} | |
//======================================================== | |
// Video menu stuff | |
//======================================================== | |
extern void M_Menu_Options_f (void); | |
extern void M_Print (int cx, int cy, char *str); | |
extern void M_PrintWhite (int cx, int cy, char *str); | |
extern void M_DrawCharacter (int cx, int line, int num); | |
extern void M_DrawTransPic (int x, int y, qpic_t *pic); | |
extern void M_DrawPic (int x, int y, qpic_t *pic); | |
static int vid_line, vid_wmodes; | |
typedef struct | |
{ | |
int modenum; | |
char *desc; | |
int iscur; | |
} modedesc_t; | |
#define MAX_COLUMN_SIZE 9 | |
#define MODE_AREA_HEIGHT (MAX_COLUMN_SIZE + 2) | |
#define MAX_MODEDESCS (MAX_COLUMN_SIZE*3) | |
static modedesc_t modedescs[MAX_MODEDESCS]; | |
/* | |
================ | |
VID_MenuDraw | |
================ | |
*/ | |
void VID_MenuDraw (void) | |
{ | |
qpic_t *p; | |
char *ptr; | |
int lnummodes, i, j, k, column, row, dup, dupmode; | |
char temp[100]; | |
vmode_t *pv; | |
p = Draw_CachePic ("gfx/vidmodes.lmp"); | |
M_DrawPic ( (320-p->width)/2, 4, p); | |
vid_wmodes = 0; | |
lnummodes = VID_NumModes (); | |
for (i=1 ; (i<lnummodes) && (vid_wmodes < MAX_MODEDESCS) ; i++) | |
{ | |
ptr = VID_GetModeDescription (i); | |
pv = VID_GetModePtr (i); | |
k = vid_wmodes; | |
modedescs[k].modenum = i; | |
modedescs[k].desc = ptr; | |
modedescs[k].iscur = 0; | |
if (i == vid_modenum) | |
modedescs[k].iscur = 1; | |
vid_wmodes++; | |
} | |
if (vid_wmodes > 0) | |
{ | |
M_Print (2*8, 36+0*8, "Fullscreen Modes (WIDTHxHEIGHTxBPP)"); | |
column = 8; | |
row = 36+2*8; | |
for (i=0 ; i<vid_wmodes ; i++) | |
{ | |
if (modedescs[i].iscur) | |
M_PrintWhite (column, row, modedescs[i].desc); | |
else | |
M_Print (column, row, modedescs[i].desc); | |
column += 13*8; | |
if ((i % VID_ROW_SIZE) == (VID_ROW_SIZE - 1)) | |
{ | |
column = 8; | |
row += 8; | |
} | |
} | |
} | |
M_Print (3*8, 36 + MODE_AREA_HEIGHT * 8 + 8*2, | |
"Video modes must be set from the"); | |
M_Print (3*8, 36 + MODE_AREA_HEIGHT * 8 + 8*3, | |
"command line with -width <width>"); | |
M_Print (3*8, 36 + MODE_AREA_HEIGHT * 8 + 8*4, | |
"and -bpp <bits-per-pixel>"); | |
M_Print (3*8, 36 + MODE_AREA_HEIGHT * 8 + 8*6, | |
"Select windowed mode with -window"); | |
} | |
/* | |
================ | |
VID_MenuKey | |
================ | |
*/ | |
void VID_MenuKey (int key) | |
{ | |
switch (key) | |
{ | |
case K_ESCAPE: | |
S_LocalSound ("misc/menu1.wav"); | |
M_Menu_Options_f (); | |
break; | |
default: | |
break; | |
} | |
} |