SRB2/src/win32/win_vid.c

1110 lines
28 KiB
C
Raw Normal View History

2014-03-15 16:59:03 +00:00
// 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", "On", 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;
2020-05-06 22:35:54 +00:00
int vid_opengl_state = 0;
2014-03-15 16:59:03 +00:00
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;
}
2020-02-18 00:11:56 +00:00
void VID_StartupOpenGL(void){}
2019-09-09 01:25:18 +00:00
2014-03-15 16:59:03 +00:00
// ------------------
// 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;
//case GS_TIMEATTACK: -- sorry optimisation but now we have a cool level platter and that being laggardly looks terrible
2014-03-15 16:59:03 +00:00
#ifndef CLIENT_LOADINGSCREEN
/* FALLTHRU */
2014-03-15 16:59:03 +00:00
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;
// draw captions if enabled
if (cv_closedcaptioning.value)
SCR_ClosedCaptions();
2014-03-15 16:59:03 +00:00
// display a graph of ticrate
if (cv_ticrate.value)
SCR_DisplayTicRate();
2019-11-18 01:22:47 +00:00
if (cv_showping.value && netgame && consoleplayer != serverplayer)
SCR_DisplayLocalPing();
Introducing Marathon Run. (I was going to call it Marathon Mode, but NiGHTS Mode being right next to it on the menu looked terrible.) Basically a dedicated Record Attack-like experience for speedrunning the game as a continuous chunk rather than ILs. Has several quality of life features. Benefits include: * An unambiguous real-time bar across the bottom of the screen, always displaying the current time, ticking up until you reach the ending. * Disable the console (pausing is still allowed, but the timer will still increment). * Automatically skip intermissions as if you're holding down the spin button. * Show centiseconds on HUD automatically, like record attack. * "Live Event Backups" - a category of run fit for major events like GDQ, where recovery from crashes or chokes makes for better entertainment. Essentially a modified SP savefile, down to using the same basic functions, but has its own filename and tweaked internal layout. * "spmarathon_start" MainCfg block parameter and "marathonnext" mapheader parameter, allowing for a customised flow (makes this fit for purpose for an eventual SUGOI port). * Disabling inter-level custom cutscenes by default with a menu option to toggle this (won't show up if the mod doesn't *have* any custom cutscenes), although either way ending cutscenes (vanilla or custom) remain intact since is time is called before them. * Won't show up if you have a mod that consists of only one level (determined by spmarathon_start's nextlevel; this won't trip if you manually set its marathonnext). * Unconditional gratitude on the evaluation screen, instead of a negging "Try again..." if you didn't get all the emeralds (which you may not have been aiming for). * Gorgeous new menu (no new assets required, unless you wanna give it a header later). Changes which were required for the above but affect other areas of the game include: * "useBlackRock" MainCFG block parameter, which can be used to disable the presence of the Black Rock or Egg Rock in both the Evaluation screen and the Marathon Run menu (for total conversions with different stories). * Disabling Continues in NiGHTS mode, to match the most common singleplayer experience post 2.2.4's release (is reverted if useContinues is set to true). * Hiding the exitmove "powerup" outside of multiplayer. (Okay, this isn't really related, I just saw this bug in action a lot while doing test runs and got annoyed enough to fix it here.) * The ability to use V_DrawPromptBack (in hardcode only at the moment, but) to draw in terms of pixels rather than rows of text, by providing negative instead of positive inputs). * A refactoring of redundant game saves smattered across the ending, credits, and evaluation - in addition to saving the game slightly earlier. * Minor m_menu.c touchups and refactorings here and there. Built using feedback from the official server's #speedruns channel, among other places.
2020-05-14 22:10:00 +00:00
if (marathonmode)
SCR_DisplayMarathonInfo();
2014-03-15 16:59:03 +00:00
//
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;
}
2020-02-18 00:11:56 +00:00
void VID_CheckRenderer(void) {}
2020-05-06 22:35:54 +00:00
void VID_CheckGLLoaded(rendermode_t oldrender)
{
(void)oldrender;
}
2019-09-08 21:27:35 +00:00
2014-03-15 16:59:03 +00:00
// ========================================================================
// 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)
2014-03-15 16:59:03 +00:00
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