Kart-Public/src/win32/win_vid.c

1090 lines
28 KiB
C

// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// Copyright (C) 1998-2000 by DooM Legacy Team.
//
// 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.
//-----------------------------------------------------------------------------
/// \file
/// \brief win32 video driver for Doom Legacy
#include "../doomdef.h"
#ifdef _WINDOWS
#include <stdlib.h>
#include <stdarg.h>
#include "../d_clisrv.h"
#include "../i_system.h"
#include "../m_argv.h"
#include "../v_video.h"
#include "../st_stuff.h"
#include "../i_video.h"
#include "../z_zone.h"
#include "fabdxlib.h"
#include "../doomstat.h"
#include "win_main.h"
#include "../command.h"
#include "../screen.h"
#ifdef HWRENDER
#include "win_dll.h" // loading the render DLL
#include "../hardware/hw_drv.h" // calling driver init & shutdown
#include "../hardware/hw_main.h" // calling HWR module init & shutdown
#endif
// -------
// Globals
// -------
// this is the CURRENT rendermode!! very important: used by w_wad, and much other code
rendermode_t rendermode = render_soft;
static void OnTop_OnChange(void);
// synchronize page flipping with screen refresh
static CV_PossibleValue_t CV_NeverOnOff[] = {{-1, "Never"}, {0, "Off"}, {1, "On"}, {0, NULL}};
consvar_t cv_vidwait = {"vid_wait", "Off", CV_SAVE, CV_OnOff, OnTop_OnChange, 0, NULL, NULL, 0, 0, NULL};
static consvar_t cv_stretch = {"stretch", "On", CV_SAVE|CV_NOSHOWHELP, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
static consvar_t cv_ontop = {"ontop", "Never", 0, CV_NeverOnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
boolean highcolor;
static BOOL bDIBMode; // means we are using DIB instead of DirectDraw surfaces
static LPBITMAPINFO bmiMain = NULL;
static HDC hDCMain = NULL;
// -----------------
// Video modes stuff
// -----------------
#define MAX_EXTRA_MODES 36
static vmode_t extra_modes[MAX_EXTRA_MODES] = {{NULL, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, 0}};
static char names[MAX_EXTRA_MODES][10];
static INT32 numvidmodes; // total number of DirectDraw display modes
static vmode_t *pvidmodes; // start of videomodes list.
static vmode_t *pcurrentmode; // the current active videomode.
static BOOL bWinParm;
static INT32 WINAPI VID_SetWindowedDisplayMode(viddef_t *lvid, vmode_t *currentmode);
// this holds description of the startup video mode,
// the resolution is 320x200, windowed on the desktop
static char winmodenames[NUMSPECIALMODES][11] = {
// W to make sure it's the windowed mode
"320x200W",
"640x400W",
"960x600W",
"1280x800W"
};
vmode_t specialmodes[NUMSPECIALMODES] =
{
{
NULL,
winmodenames[0], // hehe
320, 200, //(200.0/320.0)*(320.0/240.0),
320, 1, // rowbytes, bytes per pixel
1, 2, // windowed (TRUE), numpages
NULL,
VID_SetWindowedDisplayMode, 0
},
{
NULL,
winmodenames[1], // haha
640, 400,
640, 1, // rowbytes, bytes per pixel
1, 2, // windowed (TRUE), numpages
NULL,
VID_SetWindowedDisplayMode, 0
},
{
NULL,
winmodenames[2], // hihi?
960, 600,
960, 1, // rowbytes, bytes per pixel
1, 2, // windowed (TRUE), numpages
NULL,
VID_SetWindowedDisplayMode, 0
},
{
NULL,
winmodenames[3], // hoho!
1280, 800,
1280, 1, // rowbytes, bytes per pixel
1, 2, // windowed (TRUE), numpages
NULL,
VID_SetWindowedDisplayMode, 0
}
};
// ------
// Protos
// ------
static void VID_Command_NumModes_f(void);
static void VID_Command_ModeInfo_f(void);
static void VID_Command_ModeList_f(void);
static void VID_Command_Mode_f(void);
static INT32 WINAPI VID_SetDirectDrawMode(viddef_t *lvid, vmode_t *currentmode);
static vmode_t *VID_GetModePtr(int modenum);
static VOID VID_Init(VOID);
static BOOL VID_FreeAndAllocVidbuffer(viddef_t *lvid);
#if 0
// Disable Composition in Vista DWM (Desktop Window Manager) ----------------
static HMODULE DMdll = NULL;
typedef HRESULT (CALLBACK *P_DwmIsCompositionEnabled) (BOOL *pfEnabled);
static P_DwmIsCompositionEnabled pfnDwmIsCompositionEnabled = NULL;
typedef HRESULT (CALLBACK *P_DwmEnableComposition) (BOOL fEnable);
static P_DwmEnableComposition pfnDwmEnableComposition = NULL;
static BOOL AeroWasEnabled = FALSE;
static inline VOID UnloadDM(VOID)
{
pfnDwmEnableComposition = NULL;
pfnDwmIsCompositionEnabled = NULL;
if (DMdll) FreeLibrary(DMdll);
DMdll = NULL;
}
static inline BOOL LoadDM(VOID)
{
if (DMdll)
return TRUE;
DMdll = LoadLibraryA("dwmapi.dll");
if (DMdll)
I_OutputMsg("dmwapi.dll loaded, Vista's Desktop Window Manager API\n");
else
return FALSE;
pfnDwmIsCompositionEnabled = (P_DwmIsCompositionEnabled)GetProcAddress(DMdll, "DwmIsCompositionEnabled");
if (pfnDwmIsCompositionEnabled)
I_OutputMsg("Composition Aero API found, DwmIsCompositionEnabled\n");
pfnDwmEnableComposition = (P_DwmEnableComposition)GetProcAddress(DMdll, "DwmEnableComposition");
if (pfnDwmEnableComposition)
I_OutputMsg("Composition Aero API found, DwmEnableComposition\n");
return TRUE;
}
static inline VOID DisableAero(VOID)
{
BOOL pfnDwmEnableCompositiond = FALSE;
AeroWasEnabled = FALSE;
if (!LoadDM())
return;
if (pfnDwmIsCompositionEnabled && SUCCEEDED(pfnDwmIsCompositionEnabled(&pfnDwmEnableCompositiond)))
I_OutputMsg("Got the result of DwmIsCompositionEnabled, %i\n", pfnDwmEnableCompositiond);
else
return;
if ((AeroWasEnabled = pfnDwmEnableCompositiond))
I_OutputMsg("Disable the Aero rendering\n");
else
return;
if (pfnDwmEnableComposition && SUCCEEDED(pfnDwmEnableComposition(FALSE)))
I_OutputMsg("Aero rendering disabled\n");
else
I_OutputMsg("We failed to disable the Aero rendering\n");
}
static inline VOID ResetAero(VOID)
{
if (pfnDwmEnableComposition && AeroWasEnabled)
{
if (SUCCEEDED(pfnDwmEnableComposition(AeroWasEnabled)))
I_OutputMsg("Aero rendering setting restored\n");
else
I_OutputMsg("We failed to restore Aero rendering\n");
}
UnloadDM();
}
#endif
// -----------------
// I_StartupGraphics
// Initialize video mode, setup dynamic screen size variables,
// and allocate screens.
// -----------------
void I_StartupGraphics(void)
{
if (graphics_started)
return;
#ifdef HWRENDER
else if (M_CheckParm("-opengl"))
rendermode = render_opengl;
else
#endif
rendermode = render_soft;
if (dedicated)
rendermode = render_none;
else
VID_Init();
// register exit code for graphics
I_AddExitFunc(I_ShutdownGraphics);
if (!dedicated) graphics_started = true;
}
// ------------------
// I_ShutdownGraphics
// Close the screen, restore previous video mode.
// ------------------
void I_ShutdownGraphics(void)
{
#ifdef HWRENDER
const rendermode_t oldrendermode = rendermode;
#endif
// This is BAD because it makes the I_Error box screw up!
// rendermode = render_none;
if (!graphics_started)
return;
CONS_Printf("I_ShutdownGraphics: ");
//FreeConsole();
//ResetAero();
// release windowed startup stuff
if (hDCMain)
{
ReleaseDC(hWndMain, hDCMain);
hDCMain = NULL;
}
if (bmiMain)
{
GlobalFree(bmiMain);
bmiMain = NULL;
}
#ifdef HWRENDER
if (oldrendermode != render_soft)
{
HWR_Shutdown(); // free stuff from the hardware renderer
HWD.pfnShutdown(); // close 3d card display
Shutdown3DDriver(); // free the driver DLL
}
#endif
// free the last video mode screen buffers
if (vid.buffer)
{
GlobalFree(vid.buffer);
vid.buffer = NULL;
}
#ifdef HWRENDER
if (rendermode == render_soft)
#endif
CloseDirectDraw();
graphics_started = false;
}
// --------------
// I_UpdateNoBlit
// --------------
void I_UpdateNoBlit(void)
{
// what is this?
}
// I_SkipFrame
//
// Returns true if it thinks we can afford to skip this frame
// from PrBoom's src/SDL/i_video.c
static inline boolean I_SkipFrame(void)
{
static boolean skip = false;
if (render_soft != rendermode)
return false;
skip = !skip;
switch (gamestate)
{
case GS_LEVEL:
if (!paused)
return false;
/* FALLTHRU */
#ifndef CLIENT_LOADINGSCREEN
case GS_WAITINGPLAYERS:
#endif
return skip; // Skip odd frames
default:
return false;
}
}
static void OnTop_OnChange(void)
{
const UINT uFlags = SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER;
RECT bounds;
int x = 0, y = 0, w = 0, h = 0;
if (!hWndMain || bAppFullScreen || cv_ontop.value == -1)
return;
GetWindowRect(hWndMain, &bounds);
AdjustWindowRectEx(&bounds, GetWindowLong(hWndMain, GWL_STYLE), 0, 0);
w = bounds.right - (x = bounds.left); h = bounds.bottom - (y = bounds.top);
if (cv_ontop.value && !paused)
SetWindowPos(hWndMain, HWND_TOP , x, y, w, h, uFlags);
else
SetWindowPos(hWndMain, HWND_NOTOPMOST, x, y, w, h, uFlags);
}
// --------------
// I_FinishUpdate
// --------------
void I_FinishUpdate(void)
{
if (rendermode == render_none)
return;
if (I_SkipFrame())
return;
// display a graph of ticrate
if (cv_ticrate.value)
SCR_DisplayTicRate();
//
if (bDIBMode)
{
// paranoia
if (!hDCMain || !bmiMain || !vid.buffer)
return;
// main game loop, still in a window (-win parm)
SetDIBitsToDevice(hDCMain, 0, 0, vid.width, vid.height, 0, 0, 0, vid.height, vid.buffer, bmiMain,
DIB_RGB_COLORS);
}
else
#ifdef HWRENDER
if (rendermode != render_soft)
HWD.pfnFinishUpdate(cv_vidwait.value);
else
#endif
{
// DIRECT DRAW
// copy virtual screen to real screen
// can fail when not active (alt-tab)
if (LockScreen())
{
/// \todo use directX blit here!!? a blit might use hardware with access
/// to main memory on recent hardware, and software blit of directX may be
/// optimized for p2 or mmx??
if (ScreenHeight > vid.height)
{
UINT8 *ptr = (UINT8 *)ScreenPtr;
size_t half_excess = ScreenPitch*(ScreenHeight-vid.height)/2;
memset(ptr, 0x1F, half_excess);
ptr += half_excess;
VID_BlitLinearScreen(screens[0], ptr, vid.width*vid.bpp, vid.height,
vid.width*vid.bpp, ScreenPitch);
ptr += vid.height*ScreenPitch;
memset(ptr, 0x1F, half_excess);
}
else
VID_BlitLinearScreen(screens[0], (UINT8 *)ScreenPtr, vid.width*vid.bpp, vid.height,
vid.width*vid.bpp, ScreenPitch);
UnlockScreen();
// swap screens
ScreenFlip(cv_vidwait.value);
}
}
}
// ---------------
// I_UpdateNoVsync
// ---------------
void I_UpdateNoVsync(void)
{
int real_vidwait = cv_vidwait.value;
cv_vidwait.value = 0;
I_FinishUpdate();
cv_vidwait.value = real_vidwait;
}
//
// This is meant to be called only by CONS_Printf() while game startup
//
void I_LoadingScreen(LPCSTR msg)
{
RECT rect;
// paranoia
if (!hDCMain || !bmiMain || !vid.buffer)
return;
GetClientRect(vid.WndParent, &rect);
SetDIBitsToDevice(hDCMain, 0, 0, vid.width, vid.height, 0, 0, 0, vid.height, vid.buffer, bmiMain, DIB_RGB_COLORS);
if (msg)
{
if (rect.bottom - rect.top > 32)
rect.top = rect.bottom - 32; // put msg on bottom of window
SetBkMode(hDCMain, TRANSPARENT);
SetTextColor(hDCMain, RGB(0x00, 0x00, 0x00));
DrawTextA(hDCMain, msg, -1, &rect, DT_WORDBREAK|DT_CENTER);
}
}
// ------------
// I_ReadScreen
// ------------
void I_ReadScreen(UINT8 *scr)
{
// DEBUGGING
if (rendermode != render_soft)
I_Error("I_ReadScreen: called while in non-software mode");
VID_BlitLinearScreen(screens[0], scr, vid.width*vid.bpp, vid.height, vid.width*vid.bpp,
vid.rowbytes);
}
// ------------
// I_SetPalette
// ------------
void I_SetPalette(RGBA_t *palette)
{
int i;
if (bDIBMode)
{
// set palette in RGBQUAD format, NOT THE SAME ORDER as PALETTEENTRY, grmpf!
RGBQUAD *pColors;
pColors = (RGBQUAD *)((LPBYTE)bmiMain + bmiMain->bmiHeader.biSize);
ZeroMemory(pColors, sizeof (RGBQUAD)*256);
for (i = 0; i < 256; i++, pColors++, palette++)
{
pColors->rgbRed = palette->s.red;
pColors->rgbGreen = palette->s.green;
pColors->rgbBlue = palette->s.blue;
}
}
else
#ifdef HWRENDER
if (rendermode == render_soft)
#endif
{
PALETTEENTRY mainpal[256];
// this clears the 'flag' for each color in palette
ZeroMemory(mainpal, sizeof mainpal);
// set palette in PALETTEENTRY format
for (i = 0; i < 256; i++, palette++)
{
mainpal[i].peRed = palette->s.red;
mainpal[i].peGreen = palette->s.green;
mainpal[i].peBlue = palette->s.blue;
}
SetDDPalette(mainpal); // set DirectDraw palette
}
}
//
// return number of video modes in pvidmodes list
// MODES ARE ZERO INDEXED. DO NOT USE (n > nummodes). USE >= INSTEAD.
//
INT32 VID_NumModes(void)
{
return numvidmodes;
}
// return a video mode number from the dimensions
// returns any available video mode if the mode was not found
INT32 VID_GetModeForSize(INT32 w, INT32 h)
{
vmode_t *pv = pvidmodes;
int modenum = 0;
// Fullscreen resolutions exist
if (numvidmodes > NUMSPECIALMODES)
{
// skip the special modes so that it finds only fullscreen modes
for (; pv && modenum < NUMSPECIALMODES; pv = pv->pnext, ++modenum);
for (; pv; pv = pv->pnext, ++modenum)
if (pv->width == (unsigned)w && pv->height == (unsigned)h)
return modenum;
// Try default video mode first
if (w != cv_scr_width.value || h != cv_scr_height.value)
return VID_GetModeForSize(cv_scr_width.value, cv_scr_height.value);
// didn't find, return first fullscreen mode
return NUMSPECIALMODES;
}
// rely only on special (windowed) modes
for (; pv && modenum < NUMSPECIALMODES; pv = pv->pnext, ++modenum)
if (pv->width == (unsigned)w && pv->height == (unsigned)h)
return modenum;
// Try default video mode first
if (w != cv_scr_width.value || h != cv_scr_height.value)
return VID_GetModeForSize(cv_scr_width.value, cv_scr_height.value);
// didn't find, return first windowed mode
return 0;
}
//
// Enumerate DirectDraw modes available
//
static int nummodes = 0;
static BOOL GetExtraModesCallback(int width, int height, int bpp)
{
#ifdef _DEBUG
CONS_Printf("mode %d x %d x %d bpp\n", width, height, bpp);
#endif
// skip all unwanted modes
if (highcolor && bpp != 15)
goto skip;
if (!highcolor && bpp != 8)
goto skip;
if (bpp > 16 || width > MAXVIDWIDTH || height > MAXVIDHEIGHT)
goto skip;
// check if we have space for this mode
if (nummodes >= MAX_EXTRA_MODES)
{
#ifdef _DEBUG
CONS_Printf("mode skipped (too many)\n");
#endif
return FALSE;
}
// store mode info
extra_modes[nummodes].pnext = &extra_modes[nummodes+1];
memset(names[nummodes], 0, 10);
snprintf(names[nummodes], 9, "%dx%d", width, height);
extra_modes[nummodes].name = names[nummodes];
extra_modes[nummodes].width = width;
extra_modes[nummodes].height = height;
// exactly, the current FinishUdpate() gets the rowbytes itself after locking the video buffer
// so for now we put anything here
extra_modes[nummodes].rowbytes = width;
extra_modes[nummodes].windowed = false;
extra_modes[nummodes].misc = 0; // unused
extra_modes[nummodes].pextradata = NULL;
extra_modes[nummodes].setmode = VID_SetDirectDrawMode;
extra_modes[nummodes].numpages = 3; // triple-buffer (but this value is unused)
extra_modes[nummodes].bytesperpixel = (bpp+1)>>3;
nummodes++;
skip:
return TRUE;
}
//
// Collect info about DirectDraw display modes we use
//
static inline VOID VID_GetExtraModes(VOID)
{
nummodes = 0;
EnumDirectDrawDisplayModes(GetExtraModesCallback);
// add the extra modes (not 320x200) at the start of the mode list (if there are any)
if (nummodes)
{
extra_modes[nummodes-1].pnext = NULL;
pvidmodes = &extra_modes[0];
numvidmodes += nummodes;
}
}
// ---------------
// WindowMode_Init
// Add windowed modes to the start of the list,
// mode 0 is used for windowed console startup (works on all computers with no DirectX)
// ---------------
static VOID WindowMode_Init(VOID)
{
int modenum;
for (modenum = 0; modenum < NUMSPECIALMODES - 1; modenum++)
specialmodes[modenum].pnext = &specialmodes[modenum + 1];
specialmodes[NUMSPECIALMODES-1].pnext = pvidmodes;
pvidmodes = specialmodes;
numvidmodes += NUMSPECIALMODES;
}
// *************************************************************************************
// VID_Init
// Initialize Video modes subsystem
// *************************************************************************************
static VOID VID_Init(VOID)
{
#ifdef _DEBUG
vmode_t *pv;
int iMode;
#endif
// if '-win' is specified on the command line, do not add DirectDraw modes
bWinParm = M_CheckParm("-win");
COM_AddCommand("vid_nummodes", VID_Command_NumModes_f);
COM_AddCommand("vid_modeinfo", VID_Command_ModeInfo_f);
COM_AddCommand("vid_modelist", VID_Command_ModeList_f);
COM_AddCommand("vid_mode", VID_Command_Mode_f);
CV_RegisterVar(&cv_vidwait);
CV_RegisterVar(&cv_stretch);
CV_RegisterVar(&cv_ontop);
// setup the videmodes list,
// note that mode 0 must always be VGA mode 0x13
pvidmodes = pcurrentmode = NULL;
numvidmodes = 0;
//DisableAero();
// store the main window handle in viddef struct
SetWindowPos(hWndMain, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE|SWP_NOSENDCHANGING|SWP_NOSIZE|SWP_NOMOVE);
vid.WndParent = hWndMain;
vid.buffer = NULL;
// we startup in windowed mode using DIB bitmap
// we will use DirectDraw when switching fullScreen and entering main game loop
bDIBMode = TRUE;
bAppFullScreen = FALSE;
#ifdef HWRENDER
// initialize the appropriate display device
if (rendermode != render_soft)
{
const char *drvname = NULL;
switch (rendermode)
{
case render_opengl:
drvname = "r_opengl.dll";
break;
default:
I_Error("Unknown hardware render mode");
}
// load the DLL
if (drvname && Init3DDriver(drvname))
{
int hwdversion = HWD.pfnGetRenderVersion();
if (hwdversion != VERSION)
CONS_Alert(CONS_WARNING, M_GetText("This r_opengl version is not supported, use it at your own risk!\n"));
// perform initialisations
HWD.pfnInit(I_Error);
// get available display modes for the device
HWD.pfnGetModeList(&pvidmodes, &numvidmodes);
}
else
{
switch (rendermode)
{
case render_opengl:
I_Error("Error initializing OpenGL");
default:
break;
}
rendermode = render_soft;
}
}
if (rendermode == render_soft)
#endif
if (!bWinParm)
{
if (!CreateDirectDrawInstance())
bWinParm = TRUE;
else // get available display modes for the device
VID_GetExtraModes();
}
// the game boots in 320x200 standard VGA, but
// we need a highcolor mode to run the game in highcolor
if (highcolor && !numvidmodes)
I_Error("Cannot run in highcolor - No 15bit highcolor DirectX video mode found.");
// add windowed mode at the start of the list, very important!
WindowMode_Init();
if (!numvidmodes)
I_Error("No display modes available.");
#ifdef _DEBUG // DEBUG
for (iMode = 0, pv = pvidmodes; pv; pv = pv->pnext, iMode++)
I_OutputMsg("#%02d: %dx%dx%dbpp (desc: '%s')\n", iMode, pv->width, pv->height, pv->bytesperpixel, pv->name);
#endif
// set the startup screen in a window
VID_SetMode(0);
}
// --------------------------
// VID_SetWindowedDisplayMode
// Display the startup 320x200 console screen into a window on the desktop,
// switching to fullscreen display only when we will enter the main game loop.
// - we can display error message boxes for startup errors
// - we can set the last used resolution only once, when entering the main game loop
// --------------------------
static INT32 WINAPI VID_SetWindowedDisplayMode(viddef_t *lvid, vmode_t *currentmode)
{
RECT bounds;
int x = 0, y = 0, w = 0, h = 0;
UNREFERENCED_PARAMETER(currentmode);
I_OutputMsg("VID_SetWindowedDisplayMode()\n");
lvid->u.numpages = 1; // not used
lvid->direct = NULL; // DOS remains
lvid->buffer = NULL;
// allocate screens
if (!VID_FreeAndAllocVidbuffer(lvid))
return -1;
// lvid->buffer should be NULL here!
bmiMain = GlobalAlloc(GPTR, sizeof (BITMAPINFO) + (sizeof (RGBQUAD)*256));
if (!bmiMain)
I_Error("VID_SWDM(): No mem");
// setup a BITMAPINFO to allow copying our video buffer to the desktop,
// with color conversion as needed
bmiMain->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
bmiMain->bmiHeader.biWidth = lvid->width;
bmiMain->bmiHeader.biHeight= -(lvid->height);
bmiMain->bmiHeader.biPlanes = 1;
bmiMain->bmiHeader.biBitCount = 8;
bmiMain->bmiHeader.biCompression = BI_RGB;
// center window on the desktop
bounds.left = 0;
bounds.right = lvid->width;
bounds.top = 0;
bounds.bottom = lvid->height;
AdjustWindowRectEx(&bounds, GetWindowLong(hWndMain, GWL_STYLE), FALSE, GetWindowLong(hWndMain, GWL_EXSTYLE));
w = bounds.right-bounds.left;
h = bounds.bottom-bounds.top;
x = (GetSystemMetrics(SM_CXSCREEN)-w)/2;
y = (GetSystemMetrics(SM_CYSCREEN)-h)/2;
if (devparm)
MoveWindow(hWndMain, x<<1, y<<1, w, h, TRUE);
else
MoveWindow(hWndMain, x, y, w, h, TRUE);
SetFocus(hWndMain);
ShowWindow(hWndMain, SW_SHOW);
hDCMain = GetDC(hWndMain);
if (!hDCMain)
I_Error("VID_SWDM(): GetDC FAILED");
return 1;
}
// ========================================================================
// Returns a vmode_t from the video modes list, given a video mode number.
// ========================================================================
vmode_t *VID_GetModePtr(int modenum)
{
vmode_t *pv;
pv = pvidmodes;
if (!pv)
I_Error("VID_error: No video mode found\n");
while (modenum--)
{
pv = pv->pnext;
if (!pv)
I_Error("VID_error: Mode not available\n");
}
return pv;
}
//
// return the name of a video mode
//
const char *VID_GetModeName(INT32 modenum)
{
return (VID_GetModePtr(modenum))->name;
}
// ========================================================================
// Sets a video mode
// ========================================================================
INT32 VID_SetMode(INT32 modenum)
{
int vstat;
vmode_t *pnewmode;
if (dedicated)
return 0;
I_OutputMsg("VID_SetMode(%d)\n", modenum);
// if mode 0 (windowed) we must not be fullscreen already,
// if other mode, check it is not mode 0 and existing
if (modenum >= numvidmodes)
{
if (!pcurrentmode)
modenum = 0; // revert to the default base vid mode
else
I_Error("Unknown video mode: %d\n", modenum);
}
else if (bAppFullScreen && modenum < NUMSPECIALMODES)
I_Error("Tried to switch from fullscreen back to windowed mode %d\n", modenum);
pnewmode = VID_GetModePtr(modenum);
// dont switch to the same display mode
if (pnewmode == pcurrentmode)
return 1;
// initialize the new mode
pcurrentmode = pnewmode;
// initialize vidbuffer size for setmode
vid.width = pcurrentmode->width;
vid.height = pcurrentmode->height;
vid.rowbytes = pcurrentmode->rowbytes;
vid.bpp = pcurrentmode->bytesperpixel;
if (modenum) // if not 320x200 windowed mode, it's actually a hack
{
if (rendermode == render_opengl)
{
// don't accept depth < 16 for OpenGL mode (too much ugly)
if (cv_scr_depth.value < 16)
CV_SetValue(&cv_scr_depth, 16);
vid.bpp = cv_scr_depth.value/8;
vid.u.windowed = (bWinParm || !cv_fullscreen.value);
pcurrentmode->bytesperpixel = vid.bpp;
pcurrentmode->windowed = vid.u.windowed;
}
}
vstat = (*pcurrentmode->setmode)(&vid, pcurrentmode);
if (vstat == -1)
I_Error("Not enough mem for VID_SetMode\n");
else if (vstat == -2)
I_Error("Couldn't set video mode because it failed the test\n");
else if (vstat == -3)
I_Error("Couldn't set video mode because it failed the change?\n");
else if (!vstat)
I_Error("Couldn't set video mode %d (%dx%d %d bits)\n", modenum, vid.width, vid.height, (vid.bpp*8));// hardware could not setup mode
else
CONS_Printf(M_GetText("Mode changed to %d (%s)\n"), modenum, pcurrentmode->name);
vid.modenum = modenum;
// tell game engine to recalc all tables and realloc buffers based on new values
vid.recalc = 1;
if (modenum < NUMSPECIALMODES)
{
// we are in startup windowed mode
bAppFullScreen = FALSE;
bDIBMode = TRUE;
}
else
{
// we switch to fullscreen
bAppFullScreen = TRUE;
bDIBMode = FALSE;
#ifdef HWRENDER
if (rendermode != render_soft)
{
// purge all patch graphics stored in software format
//Z_FreeTags (PU_PURGELEVEL, PU_PURGELEVEL+100);
HWR_Startup();
}
#endif
}
I_RestartSysMouse();
return 1;
}
// ========================================================================
// Free the video buffer of the last video mode,
// allocate a new buffer for the video mode to set.
// ========================================================================
static BOOL VID_FreeAndAllocVidbuffer(viddef_t *lvid)
{
const DWORD vidbuffersize = (lvid->width * lvid->height * lvid->bpp * NUMSCREENS);
// free allocated buffer for previous video mode
if (lvid->buffer)
GlobalFree(lvid->buffer);
// allocate & clear the new screen buffer
lvid->buffer = GlobalAlloc(GPTR, vidbuffersize);
if (!lvid->buffer)
return FALSE;
ZeroMemory(lvid->buffer, vidbuffersize);
I_OutputMsg("VID_FreeAndAllocVidbuffer done, vidbuffersize: %x\n",(UINT32)vidbuffersize);
return TRUE;
}
// ========================================================================
// Set video mode routine for DirectDraw display modes
// Out: 1 ok,
// 0 hardware could not set mode,
// -1 no mem
// ========================================================================
static INT32 WINAPI VID_SetDirectDrawMode(viddef_t *lvid, vmode_t *currentmode)
{
UNREFERENCED_PARAMETER(currentmode);
I_OutputMsg("VID_SetDirectDrawMode...\n");
// DD modes do double-buffer page flipping, but the game engine doesn't need this..
lvid->u.numpages = 2;
// release ddraw surfaces etc..
ReleaseChtuff();
// clean up any old vid buffer lying around, alloc new if needed
if (!VID_FreeAndAllocVidbuffer(lvid))
return -1; // no mem
// should clear video mem here
// note use lvid->bpp instead of 8...will this be needed? will we support other than 256color
// in software ?
if (!InitDirectDrawe(hWndMain, lvid->width, lvid->height, 8, TRUE)) // TRUE currently always full screen
return 0; // could not set mode
// this is NOT used with DirectDraw modes, game engine should never use this directly
// but rather render to memory bitmap buffer
lvid->direct = NULL;
if (!cv_stretch.value && fabsf((float)vid.width/vid.height - ((float)BASEVIDWIDTH/BASEVIDHEIGHT)) > 1.0E-36f)
vid.height = (int)(vid.width * ((float)BASEVIDHEIGHT/BASEVIDWIDTH));// Adjust the height to match
return 1;
}
// ========================================================================
// VIDEO MODE CONSOLE COMMANDS
// ========================================================================
// vid_nummodes
//
static void VID_Command_NumModes_f(void)
{
CONS_Printf(M_GetText("%d video mode(s) available(s)\n"), VID_NumModes());
}
// vid_modeinfo <modenum>
//
static void VID_Command_ModeInfo_f(void)
{
vmode_t *pv;
int modenum;
if (COM_Argc() != 2)
modenum = vid.modenum; // describe the current mode
else
modenum = atoi(COM_Argv(1)); // the given mode number
if (modenum >= VID_NumModes()
|| (!bWinParm && modenum < NUMSPECIALMODES)) // don't accept the windowed modes
{
CONS_Printf(M_GetText("Video mode not present\n"));
return;
}
pv = VID_GetModePtr(modenum);
CONS_Printf("\x82" "%s\n", VID_GetModeName(modenum));
CONS_Printf(M_GetText("width: %d\nheight: %d\n"),
pv->width, pv->height);
if (rendermode == render_soft)
CONS_Printf(M_GetText("bytes per scanline: %d\nbytes per pixel: %d\nnumpages: %d\n"),
pv->rowbytes, pv->bytesperpixel, pv->numpages);
}
// vid_modelist
//
static void VID_Command_ModeList_f(void)
{
int i, numodes;
const char *pinfo;
vmode_t *pv;
numodes = VID_NumModes();
// hide windowed modes unless using them
i = (!bWinParm) ? NUMSPECIALMODES : 0;
for (; i < numodes; i++)
{
pv = VID_GetModePtr(i);
pinfo = VID_GetModeName(i);
if (pv->bytesperpixel == 1)
CONS_Printf("%d: %s\n", i, pinfo);
else
CONS_Printf("%d: %s (hicolor)\n", i, pinfo);
}
}
// vid_mode <modenum>
//
static void VID_Command_Mode_f(void)
{
int modenum;
if (COM_Argc() != 2)
{
CONS_Printf(M_GetText("vid_mode <modenum> : set video mode, current video mode %i\n"), vid.modenum);
return;
}
modenum = atoi(COM_Argv(1));
if (modenum >= VID_NumModes()
|| (!bWinParm && modenum < NUMSPECIALMODES)) // don't accept the windowed modes
CONS_Printf(M_GetText("Video mode not present\n"));
else
setmodeneeded = modenum + 1; // request vid mode change
}
#endif