- fullscreen toggle and some cleanup. Not fully working yet.

This commit is contained in:
Christoph Oelckers 2018-06-17 22:09:25 +02:00
parent 89ce74443b
commit babe55819e
15 changed files with 827 additions and 728 deletions

View file

@ -987,6 +987,7 @@ set (PCH_SOURCES
v_collection.cpp v_collection.cpp
v_draw.cpp v_draw.cpp
v_font.cpp v_font.cpp
v_framebuffer.cpp
v_palette.cpp v_palette.cpp
v_paltest.cpp v_paltest.cpp
v_pfx.cpp v_pfx.cpp

View file

@ -99,6 +99,7 @@
#include "r_data/r_vanillatrans.h" #include "r_data/r_vanillatrans.h"
EXTERN_CVAR(Bool, hud_althud) EXTERN_CVAR(Bool, hud_althud)
EXTERN_CVAR(Bool, fullscreen)
void DrawHUD(); void DrawHUD();
void D_DoAnonStats(); void D_DoAnonStats();
@ -673,13 +674,9 @@ void D_Display ()
// fullscreen toggle has been requested // fullscreen toggle has been requested
if (setmodeneeded) if (setmodeneeded)
{ {
// Change screen mode. screen->ToggleFullscreen(fullscreen);
/* setsizeneeded = true;
if (Video->ToggleFullscreen()) setmodeneeded = false;
{
setsizeneeded = true;
}
*/
} }
// change the view size if needed // change the view size if needed
@ -696,7 +693,6 @@ void D_Display ()
R_ExecuteSetViewSize (r_viewpoint, r_viewwindow); R_ExecuteSetViewSize (r_viewpoint, r_viewwindow);
} }
} }
setmodeneeded = false;
// [RH] Allow temporarily disabling wipes // [RH] Allow temporarily disabling wipes
if (NoWipe) if (NoWipe)

View file

@ -140,11 +140,13 @@ void CheckerInterleaved3D::Present() const
int windowHOffset = 0; int windowHOffset = 0;
#ifdef _WIN32 #ifdef _WIN32
/* this needs to be done differently!
if (!fullscreen) { if (!fullscreen) {
I_SaveWindowedPos(); // update win_y CVAR I_SaveWindowedPos(); // update win_y CVAR
windowHOffset = (win_x + WINDOW_BORDER_HORIZONTAL_PARITY) % 2; windowHOffset = (win_x + WINDOW_BORDER_HORIZONTAL_PARITY) % 2;
windowVOffset = (win_y + WINDOW_BORDER_VERTICAL_PARITY) % 2; windowVOffset = (win_y + WINDOW_BORDER_VERTICAL_PARITY) % 2;
} }
*/
#endif // _WIN32 #endif // _WIN32
GLRenderer->mPresent3dCheckerShader->Uniforms->WindowPositionParity = GLRenderer->mPresent3dCheckerShader->Uniforms->WindowPositionParity =
@ -184,10 +186,12 @@ void ColumnInterleaved3D::Present() const
int windowHOffset = 0; int windowHOffset = 0;
#ifdef _WIN32 #ifdef _WIN32
/* this needs to be done differently!
if (!fullscreen) { if (!fullscreen) {
I_SaveWindowedPos(); // update win_y CVAR I_SaveWindowedPos(); // update win_y CVAR
windowHOffset = (win_x + WINDOW_BORDER_HORIZONTAL_PARITY) % 2; windowHOffset = (win_x + WINDOW_BORDER_HORIZONTAL_PARITY) % 2;
} }
*/
#endif // _WIN32 #endif // _WIN32
GLRenderer->mPresent3dColumnShader->Uniforms->WindowPositionParity = windowHOffset; GLRenderer->mPresent3dColumnShader->Uniforms->WindowPositionParity = windowHOffset;
@ -207,10 +211,12 @@ void RowInterleaved3D::Present() const
int windowVOffset = 0; int windowVOffset = 0;
#ifdef _WIN32 #ifdef _WIN32
/* this needs to be done differently!
if (! fullscreen) { if (! fullscreen) {
I_SaveWindowedPos(); // update win_y CVAR I_SaveWindowedPos(); // update win_y CVAR
windowVOffset = (win_y + WINDOW_BORDER_VERTICAL_PARITY) % 2; windowVOffset = (win_y + WINDOW_BORDER_VERTICAL_PARITY) % 2;
} }
*/
#endif // _WIN32 #endif // _WIN32
GLRenderer->mPresent3dRowShader->Uniforms->WindowPositionParity = GLRenderer->mPresent3dRowShader->Uniforms->WindowPositionParity =

View file

@ -46,8 +46,9 @@ public:
virtual bool IsFullscreen(); virtual bool IsFullscreen();
virtual void SetVSync(bool vsync); virtual void SetVSync(bool vsync);
int GetClientWidth(); int GetClientWidth() override;
int GetClientHeight(); int GetClientHeight() override;
void ToggleFullscreen(bool yes) override;
protected: protected:
bool UpdatePending; bool UpdatePending;

View file

@ -556,6 +556,12 @@ bool SystemFrameBuffer::IsFullscreen()
return CocoaVideo::IsFullscreen(); return CocoaVideo::IsFullscreen();
} }
void SystemFrameBuffer::ToggleFullscreen(bool yes)
{
SetMode(...); // todo
}
void SystemFrameBuffer::SetVSync(bool vsync) void SystemFrameBuffer::SetVSync(bool vsync)
{ {
const GLint value = vsync ? 1 : 0; const GLint value = vsync ? 1 : 0;

View file

@ -23,8 +23,9 @@ public:
friend class SDLGLVideo; friend class SDLGLVideo;
int GetClientWidth(); int GetClientWidth() override;
int GetClientHeight(); int GetClientHeight() override;
void ToggleFullscreen(bool yes) override;
SDL_Window *GetSDLWindow() { return Screen; } SDL_Window *GetSDLWindow() { return Screen; }

View file

@ -309,6 +309,11 @@ void SystemFrameBuffer::SwapBuffers()
SDL_GL_SwapWindow (Screen); SDL_GL_SwapWindow (Screen);
} }
void SystemFrameBuffer::ToggleFullscreen(bool yes)
{
... // todo
}
int SystemFrameBuffer::GetClientWidth() int SystemFrameBuffer::GetClientWidth()
{ {
int width = 0; int width = 0;

557
src/v_framebuffer.cpp Normal file
View file

@ -0,0 +1,557 @@
/*
** The base framebuffer class
**
**---------------------------------------------------------------------------
** Copyright 1999-2016 Randy Heit
** Copyright 2005-2018 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include <stdio.h>
#include "i_system.h"
#include "x86.h"
#include "actor.h"
#include "v_video.h"
#include "c_dispatch.h"
#include "sbar.h"
#include "hardware.h"
#include "r_utility.h"
#include "r_renderer.h"
#include "vm.h"
#include "r_videoscale.h"
#include "i_time.h"
CVAR(Bool, gl_scale_viewport, true, CVAR_ARCHIVE);
CVAR(Bool, vid_fps, false, 0)
CVAR(Int, vid_showpalette, 0, 0)
EXTERN_CVAR(Bool, ticker)
EXTERN_CVAR(Float, vid_brightness)
EXTERN_CVAR(Float, vid_contrast)
EXTERN_CVAR(Int, screenblocks)
void V_DrawPaletteTester(int pal);
//==========================================================================
//
// DCanvas :: CalcGamma
//
//==========================================================================
void DFrameBuffer::CalcGamma (float gamma, uint8_t gammalookup[256])
{
// I found this formula on the web at
// <http://panda.mostang.com/sane/sane-gamma.html>,
// but that page no longer exits.
double invgamma = 1.f / gamma;
int i;
for (i = 0; i < 256; i++)
{
gammalookup[i] = (uint8_t)(255.0 * pow (i / 255.0, invgamma) + 0.5);
}
}
//==========================================================================
//
// DSimpleCanvas Constructor
//
// A simple canvas just holds a buffer in main memory.
//
//==========================================================================
DSimpleCanvas::DSimpleCanvas (int width, int height, bool bgra)
: DCanvas (width, height, bgra)
{
PixelBuffer = nullptr;
Resize(width, height);
}
void DSimpleCanvas::Resize(int width, int height)
{
Width = width;
Height = height;
if (PixelBuffer != NULL)
{
delete[] PixelBuffer;
PixelBuffer = NULL;
}
// Making the pitch a power of 2 is very bad for performance
// Try to maximize the number of cache lines that can be filled
// for each column drawing operation by making the pitch slightly
// longer than the width. The values used here are all based on
// empirical evidence.
if (width <= 640)
{
// For low resolutions, just keep the pitch the same as the width.
// Some speedup can be seen using the technique below, but the speedup
// is so marginal that I don't consider it worthwhile.
Pitch = width;
}
else
{
// If we couldn't figure out the CPU's L1 cache line size, assume
// it's 32 bytes wide.
if (CPU.DataL1LineSize == 0)
{
CPU.DataL1LineSize = 32;
}
// The Athlon and P3 have very different caches, apparently.
// I am going to generalize the Athlon's performance to all AMD
// processors and the P3's to all non-AMD processors. I don't know
// how smart that is, but I don't have a vast plethora of
// processors to test with.
if (CPU.bIsAMD)
{
Pitch = width + CPU.DataL1LineSize;
}
else
{
Pitch = width + MAX(0, CPU.DataL1LineSize - 8);
}
}
int bytes_per_pixel = Bgra ? 4 : 1;
PixelBuffer = new uint8_t[Pitch * height * bytes_per_pixel];
memset (PixelBuffer, 0, Pitch * height * bytes_per_pixel);
}
//==========================================================================
//
// DSimpleCanvas Destructor
//
//==========================================================================
DSimpleCanvas::~DSimpleCanvas ()
{
if (PixelBuffer != NULL)
{
delete[] PixelBuffer;
PixelBuffer = NULL;
}
}
//==========================================================================
//
// DFrameBuffer Constructor
//
// A frame buffer canvas is the most common and represents the image that
// gets drawn to the screen.
//
//==========================================================================
DFrameBuffer::DFrameBuffer (int width, int height)
{
SetSize(width, height);
}
void DFrameBuffer::SetSize(int width, int height)
{
Width = ViewportScaledWidth(width, height);
Height = ViewportScaledHeight(width, height);
}
//==========================================================================
//
// DFrameBuffer :: DrawRateStuff
//
// Draws the fps counter, dot ticker, and palette debug.
//
//==========================================================================
void DFrameBuffer::DrawRateStuff ()
{
// Draws frame time and cumulative fps
if (vid_fps)
{
uint64_t ms = screen->FrameTime;
uint64_t howlong = ms - LastMS;
if ((signed)howlong >= 0)
{
char fpsbuff[40];
int chars;
int rate_x;
int textScale = active_con_scale();
chars = mysnprintf (fpsbuff, countof(fpsbuff), "%2llu ms (%3llu fps)", howlong, LastCount);
rate_x = Width / textScale - ConFont->StringWidth(&fpsbuff[0]);
Clear (rate_x * textScale, 0, Width, ConFont->GetHeight() * textScale, GPalette.BlackIndex, 0);
DrawText (ConFont, CR_WHITE, rate_x, 0, (char *)&fpsbuff[0],
DTA_VirtualWidth, screen->GetWidth() / textScale,
DTA_VirtualHeight, screen->GetHeight() / textScale,
DTA_KeepRatio, true, TAG_DONE);
uint32_t thisSec = (uint32_t)(ms/1000);
if (LastSec < thisSec)
{
LastCount = FrameCount / (thisSec - LastSec);
LastSec = thisSec;
FrameCount = 0;
}
FrameCount++;
}
LastMS = ms;
}
// draws little dots on the bottom of the screen
if (ticker)
{
int64_t t = I_GetTime();
int64_t tics = t - LastTic;
LastTic = t;
if (tics > 20) tics = 20;
int i;
for (i = 0; i < tics*2; i += 2) Clear(i, Height-1, i+1, Height, 255, 0);
for ( ; i < 20*2; i += 2) Clear(i, Height-1, i+1, Height, 0, 0);
}
// draws the palette for debugging
if (vid_showpalette)
{
V_DrawPaletteTester(vid_showpalette);
}
}
//==========================================================================
//
// Palette stuff.
//
//==========================================================================
void DFrameBuffer::GetFlashedPalette(PalEntry pal[256])
{
DoBlending(SourcePalette, pal, 256, Flash.r, Flash.g, Flash.b, Flash.a);
}
PalEntry *DFrameBuffer::GetPalette()
{
return SourcePalette;
}
bool DFrameBuffer::SetFlash(PalEntry rgb, int amount)
{
Flash = PalEntry(amount, rgb.r, rgb.g, rgb.b);
return true;
}
void DFrameBuffer::GetFlash(PalEntry &rgb, int &amount)
{
rgb = Flash;
rgb.a = 0;
amount = Flash.a;
}
//==========================================================================
//
// DFrameBuffer :: SetVSync
//
// Turns vertical sync on and off, if supported.
//
//==========================================================================
void DFrameBuffer::SetVSync (bool vsync)
{
}
//==========================================================================
//
// DFrameBuffer :: WipeStartScreen
//
// Grabs a copy of the screen currently displayed to serve as the initial
// frame of a screen wipe. Also determines which screenwipe will be
// performed.
//
//==========================================================================
bool DFrameBuffer::WipeStartScreen(int type)
{
return false;
}
//==========================================================================
//
// DFrameBuffer :: WipeEndScreen
//
// Grabs a copy of the most-recently drawn, but not yet displayed, screen
// to serve as the final frame of a screen wipe.
//
//==========================================================================
void DFrameBuffer::WipeEndScreen()
{
}
//==========================================================================
//
// DFrameBuffer :: WipeDo
//
// Draws one frame of a screenwipe. Should be called no more than 35
// times per second. If called less than that, ticks indicates how many
// ticks have passed since the last call.
//
//==========================================================================
bool DFrameBuffer::WipeDo(int ticks)
{
return false;
}
//==========================================================================
//
// DFrameBuffer :: WipeCleanup
//
//==========================================================================
void DFrameBuffer::WipeCleanup()
{
}
//==========================================================================
//
// DFrameBuffer :: InitPalette
//
//==========================================================================
void DFrameBuffer::InitPalette()
{
memcpy(SourcePalette, GPalette.BaseColors, sizeof(PalEntry) * 256);
UpdatePalette();
}
//==========================================================================
//
//
//
//==========================================================================
void DFrameBuffer::BuildGammaTable(uint16_t *gammaTable)
{
float gamma = clamp<float>(Gamma, 0.1f, 4.f);
float contrast = clamp<float>(vid_contrast, 0.1f, 3.f);
float bright = clamp<float>(vid_brightness, -0.8f, 0.8f);
double invgamma = 1 / gamma;
double norm = pow(255., invgamma - 1);
for (int i = 0; i < 256; i++)
{
double val = i * contrast - (contrast - 1) * 127;
val += bright * 128;
if (gamma != 1) val = pow(val, invgamma) / norm;
gammaTable[i] = gammaTable[i + 256] = gammaTable[i + 512] = (uint16_t)clamp<double>(val * 256, 0, 0xffff);
}
}
//==========================================================================
//
// DFrameBuffer :: GetCaps
//
//==========================================================================
EXTERN_CVAR(Bool, r_drawvoxels)
uint32_t DFrameBuffer::GetCaps()
{
ActorRenderFeatureFlags FlagSet = 0;
if (V_IsPolyRenderer())
FlagSet |= RFF_POLYGONAL | RFF_TILTPITCH | RFF_SLOPE3DFLOORS;
else
{
FlagSet |= RFF_UNCLIPPEDTEX;
if (r_drawvoxels)
FlagSet |= RFF_VOXELS;
}
if (V_IsTrueColor())
FlagSet |= RFF_TRUECOLOR;
else
FlagSet |= RFF_COLORMAP;
return (uint32_t)FlagSet;
}
void DFrameBuffer::RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, double FOV)
{
SWRenderer->RenderTextureView(tex, Viewpoint, FOV);
}
void DFrameBuffer::WriteSavePic(player_t *player, FileWriter *file, int width, int height)
{
SWRenderer->WriteSavePic(player, file, width, height);
}
//==========================================================================
//
// Calculates the viewport values needed for 2D and 3D operations
//
//==========================================================================
void DFrameBuffer::SetViewportRects(IntRect *bounds)
{
if (bounds)
{
mSceneViewport = *bounds;
mScreenViewport = *bounds;
mOutputLetterbox = *bounds;
return;
}
// Special handling so the view with a visible status bar displays properly
int height, width;
if (screenblocks >= 10)
{
height = GetHeight();
width = GetWidth();
}
else
{
height = (screenblocks*GetHeight() / 10) & ~7;
width = (screenblocks*GetWidth() / 10);
}
// Back buffer letterbox for the final output
int clientWidth = GetClientWidth();
int clientHeight = GetClientHeight();
if (clientWidth == 0 || clientHeight == 0)
{
// When window is minimized there may not be any client area.
// Pretend to the rest of the render code that we just have a very small window.
clientWidth = 160;
clientHeight = 120;
}
int screenWidth = GetWidth();
int screenHeight = GetHeight();
float scaleX, scaleY;
if (ViewportIsScaled43())
{
scaleX = MIN(clientWidth / (float)screenWidth, clientHeight / (screenHeight * 1.2f));
scaleY = scaleX * 1.2f;
}
else
{
scaleX = MIN(clientWidth / (float)screenWidth, clientHeight / (float)screenHeight);
scaleY = scaleX;
}
mOutputLetterbox.width = (int)round(screenWidth * scaleX);
mOutputLetterbox.height = (int)round(screenHeight * scaleY);
mOutputLetterbox.left = (clientWidth - mOutputLetterbox.width) / 2;
mOutputLetterbox.top = (clientHeight - mOutputLetterbox.height) / 2;
// The entire renderable area, including the 2D HUD
mScreenViewport.left = 0;
mScreenViewport.top = 0;
mScreenViewport.width = screenWidth;
mScreenViewport.height = screenHeight;
// Viewport for the 3D scene
mSceneViewport.left = viewwindowx;
mSceneViewport.top = screenHeight - (height + viewwindowy - ((height - viewheight) / 2));
mSceneViewport.width = viewwidth;
mSceneViewport.height = height;
// Scale viewports to fit letterbox
bool notScaled = ((mScreenViewport.width == ViewportScaledWidth(mScreenViewport.width, mScreenViewport.height)) &&
(mScreenViewport.width == ViewportScaledHeight(mScreenViewport.width, mScreenViewport.height)) &&
!ViewportIsScaled43());
if (gl_scale_viewport && !IsFullscreen() && notScaled)
{
mScreenViewport.width = mOutputLetterbox.width;
mScreenViewport.height = mOutputLetterbox.height;
mSceneViewport.left = (int)round(mSceneViewport.left * scaleX);
mSceneViewport.top = (int)round(mSceneViewport.top * scaleY);
mSceneViewport.width = (int)round(mSceneViewport.width * scaleX);
mSceneViewport.height = (int)round(mSceneViewport.height * scaleY);
}
}
//===========================================================================
//
// Calculates the OpenGL window coordinates for a zdoom screen position
//
//===========================================================================
int DFrameBuffer::ScreenToWindowX(int x)
{
return mScreenViewport.left + (int)round(x * mScreenViewport.width / (float)GetWidth());
}
int DFrameBuffer::ScreenToWindowY(int y)
{
return mScreenViewport.top + mScreenViewport.height - (int)round(y * mScreenViewport.height / (float)GetHeight());
}
void DFrameBuffer::ScaleCoordsFromWindow(int16_t &x, int16_t &y)
{
int letterboxX = mOutputLetterbox.left;
int letterboxY = mOutputLetterbox.top;
int letterboxWidth = mOutputLetterbox.width;
int letterboxHeight = mOutputLetterbox.height;
x = int16_t((x - letterboxX) * Width / letterboxWidth);
y = int16_t((y - letterboxY) * Height / letterboxHeight);
}
//===========================================================================
//
//
//
//===========================================================================
#define DBGBREAK assert(0)
class DDummyFrameBuffer : public DFrameBuffer
{
typedef DFrameBuffer Super;
public:
DDummyFrameBuffer(int width, int height)
: DFrameBuffer(0, 0)
{
SetVirtualSize(width, height);
}
// These methods should never be called.
void Update() { DBGBREAK; }
bool IsFullscreen() { DBGBREAK; return 0; }
int GetClientWidth() { DBGBREAK; return 0; }
int GetClientHeight() { DBGBREAK; return 0; }
float Gamma;
};

View file

@ -1,5 +1,5 @@
/* /*
** ** Video basics and init code.
** **
**--------------------------------------------------------------------------- **---------------------------------------------------------------------------
** Copyright 1999-2016 Randy Heit ** Copyright 1999-2016 Randy Heit
@ -31,13 +31,6 @@
**--------------------------------------------------------------------------- **---------------------------------------------------------------------------
** **
*/ */
//-----------------------------------------------------------------------------
//
// DESCRIPTION:
// Functions to draw patches (by post) directly to screen->
// Functions to blit a block to the screen->
//
//-----------------------------------------------------------------------------
#include <stdio.h> #include <stdio.h>
@ -74,10 +67,6 @@
#include "i_time.h" #include "i_time.h"
EXTERN_CVAR(Bool, cl_capfps) EXTERN_CVAR(Bool, cl_capfps)
EXTERN_CVAR(Float, vid_brightness)
EXTERN_CVAR(Float, vid_contrast)
CVAR(Bool, gl_scale_viewport, true, CVAR_ARCHIVE);
EXTERN_CVAR(Int, screenblocks)
CUSTOM_CVAR(Int, vid_maxfps, 200, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CUSTOM_CVAR(Int, vid_maxfps, 200, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
{ {
@ -156,10 +145,7 @@ DFrameBuffer *screen;
CVAR (Int, vid_defwidth, 640, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Int, vid_defwidth, 640, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Int, vid_defheight, 480, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Int, vid_defheight, 480, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Int, vid_defbits, 8, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, vid_fps, false, 0)
CVAR (Bool, ticker, false, 0) CVAR (Bool, ticker, false, 0)
CVAR (Int, vid_showpalette, 0, 0)
CUSTOM_CVAR (Bool, vid_vsync, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CUSTOM_CVAR (Bool, vid_vsync, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{ {
@ -171,10 +157,6 @@ CUSTOM_CVAR (Bool, vid_vsync, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
// [RH] Set true when vid_setmode command has been executed // [RH] Set true when vid_setmode command has been executed
bool setmodeneeded = false; bool setmodeneeded = false;
// [RH] Resolution to change to when setmodeneeded is true
int NewWidth, NewHeight, NewBits;
void V_DrawPaletteTester(int pal);
//========================================================================== //==========================================================================
// //
@ -480,477 +462,6 @@ static void BuildTransTable (const PalEntry *palette)
} }
} }
//==========================================================================
//
// DCanvas :: CalcGamma
//
//==========================================================================
void DFrameBuffer::CalcGamma (float gamma, uint8_t gammalookup[256])
{
// I found this formula on the web at
// <http://panda.mostang.com/sane/sane-gamma.html>,
// but that page no longer exits.
double invgamma = 1.f / gamma;
int i;
for (i = 0; i < 256; i++)
{
gammalookup[i] = (uint8_t)(255.0 * pow (i / 255.0, invgamma) + 0.5);
}
}
//==========================================================================
//
// DSimpleCanvas Constructor
//
// A simple canvas just holds a buffer in main memory.
//
//==========================================================================
DSimpleCanvas::DSimpleCanvas (int width, int height, bool bgra)
: DCanvas (width, height, bgra)
{
PixelBuffer = nullptr;
Resize(width, height);
}
void DSimpleCanvas::Resize(int width, int height)
{
Width = width;
Height = height;
if (PixelBuffer != NULL)
{
delete[] PixelBuffer;
PixelBuffer = NULL;
}
// Making the pitch a power of 2 is very bad for performance
// Try to maximize the number of cache lines that can be filled
// for each column drawing operation by making the pitch slightly
// longer than the width. The values used here are all based on
// empirical evidence.
if (width <= 640)
{
// For low resolutions, just keep the pitch the same as the width.
// Some speedup can be seen using the technique below, but the speedup
// is so marginal that I don't consider it worthwhile.
Pitch = width;
}
else
{
// If we couldn't figure out the CPU's L1 cache line size, assume
// it's 32 bytes wide.
if (CPU.DataL1LineSize == 0)
{
CPU.DataL1LineSize = 32;
}
// The Athlon and P3 have very different caches, apparently.
// I am going to generalize the Athlon's performance to all AMD
// processors and the P3's to all non-AMD processors. I don't know
// how smart that is, but I don't have a vast plethora of
// processors to test with.
if (CPU.bIsAMD)
{
Pitch = width + CPU.DataL1LineSize;
}
else
{
Pitch = width + MAX(0, CPU.DataL1LineSize - 8);
}
}
int bytes_per_pixel = Bgra ? 4 : 1;
PixelBuffer = new uint8_t[Pitch * height * bytes_per_pixel];
memset (PixelBuffer, 0, Pitch * height * bytes_per_pixel);
}
//==========================================================================
//
// DSimpleCanvas Destructor
//
//==========================================================================
DSimpleCanvas::~DSimpleCanvas ()
{
if (PixelBuffer != NULL)
{
delete[] PixelBuffer;
PixelBuffer = NULL;
}
}
//==========================================================================
//
// DFrameBuffer Constructor
//
// A frame buffer canvas is the most common and represents the image that
// gets drawn to the screen.
//
//==========================================================================
DFrameBuffer::DFrameBuffer (int width, int height)
{
SetSize(width, height);
}
void DFrameBuffer::SetSize(int width, int height)
{
Width = ViewportScaledWidth(width, height);
Height = ViewportScaledHeight(width, height);
}
//==========================================================================
//
// DFrameBuffer :: DrawRateStuff
//
// Draws the fps counter, dot ticker, and palette debug.
//
//==========================================================================
void DFrameBuffer::DrawRateStuff ()
{
// Draws frame time and cumulative fps
if (vid_fps)
{
uint64_t ms = screen->FrameTime;
uint64_t howlong = ms - LastMS;
if ((signed)howlong >= 0)
{
char fpsbuff[40];
int chars;
int rate_x;
int textScale = active_con_scale();
chars = mysnprintf (fpsbuff, countof(fpsbuff), "%2" PRIu64 " ms (%3" PRIu64 " fps)", howlong, LastCount);
rate_x = Width / textScale - ConFont->StringWidth(&fpsbuff[0]);
Clear (rate_x * textScale, 0, Width, ConFont->GetHeight() * textScale, GPalette.BlackIndex, 0);
DrawText (ConFont, CR_WHITE, rate_x, 0, (char *)&fpsbuff[0],
DTA_VirtualWidth, screen->GetWidth() / textScale,
DTA_VirtualHeight, screen->GetHeight() / textScale,
DTA_KeepRatio, true, TAG_DONE);
uint32_t thisSec = (uint32_t)(ms/1000);
if (LastSec < thisSec)
{
LastCount = FrameCount / (thisSec - LastSec);
LastSec = thisSec;
FrameCount = 0;
}
FrameCount++;
}
LastMS = ms;
}
// draws little dots on the bottom of the screen
if (ticker)
{
int64_t t = I_GetTime();
int64_t tics = t - LastTic;
LastTic = t;
if (tics > 20) tics = 20;
int i;
for (i = 0; i < tics*2; i += 2) Clear(i, Height-1, i+1, Height, 255, 0);
for ( ; i < 20*2; i += 2) Clear(i, Height-1, i+1, Height, 0, 0);
}
// draws the palette for debugging
if (vid_showpalette)
{
V_DrawPaletteTester(vid_showpalette);
}
}
//==========================================================================
//
// Palette stuff.
//
//==========================================================================
void DFrameBuffer::GetFlashedPalette(PalEntry pal[256])
{
DoBlending(SourcePalette, pal, 256, Flash.r, Flash.g, Flash.b, Flash.a);
}
PalEntry *DFrameBuffer::GetPalette()
{
return SourcePalette;
}
bool DFrameBuffer::SetFlash(PalEntry rgb, int amount)
{
Flash = PalEntry(amount, rgb.r, rgb.g, rgb.b);
return true;
}
void DFrameBuffer::GetFlash(PalEntry &rgb, int &amount)
{
rgb = Flash;
rgb.a = 0;
amount = Flash.a;
}
//==========================================================================
//
// DFrameBuffer :: SetVSync
//
// Turns vertical sync on and off, if supported.
//
//==========================================================================
void DFrameBuffer::SetVSync (bool vsync)
{
}
//==========================================================================
//
// DFrameBuffer :: WipeStartScreen
//
// Grabs a copy of the screen currently displayed to serve as the initial
// frame of a screen wipe. Also determines which screenwipe will be
// performed.
//
//==========================================================================
bool DFrameBuffer::WipeStartScreen(int type)
{
return false;
}
//==========================================================================
//
// DFrameBuffer :: WipeEndScreen
//
// Grabs a copy of the most-recently drawn, but not yet displayed, screen
// to serve as the final frame of a screen wipe.
//
//==========================================================================
void DFrameBuffer::WipeEndScreen()
{
}
//==========================================================================
//
// DFrameBuffer :: WipeDo
//
// Draws one frame of a screenwipe. Should be called no more than 35
// times per second. If called less than that, ticks indicates how many
// ticks have passed since the last call.
//
//==========================================================================
bool DFrameBuffer::WipeDo(int ticks)
{
return false;
}
//==========================================================================
//
// DFrameBuffer :: WipeCleanup
//
//==========================================================================
void DFrameBuffer::WipeCleanup()
{
}
//==========================================================================
//
// DFrameBuffer :: InitPalette
//
//==========================================================================
void DFrameBuffer::InitPalette()
{
memcpy(SourcePalette, GPalette.BaseColors, sizeof(PalEntry) * 256);
UpdatePalette();
}
//==========================================================================
//
//
//
//==========================================================================
void DFrameBuffer::BuildGammaTable(uint16_t *gammaTable)
{
float gamma = clamp<float>(Gamma, 0.1f, 4.f);
float contrast = clamp<float>(vid_contrast, 0.1f, 3.f);
float bright = clamp<float>(vid_brightness, -0.8f, 0.8f);
double invgamma = 1 / gamma;
double norm = pow(255., invgamma - 1);
for (int i = 0; i < 256; i++)
{
double val = i * contrast - (contrast - 1) * 127;
val += bright * 128;
if (gamma != 1) val = pow(val, invgamma) / norm;
gammaTable[i] = gammaTable[i + 256] = gammaTable[i + 512] = (uint16_t)clamp<double>(val * 256, 0, 0xffff);
}
}
//==========================================================================
//
// DFrameBuffer :: GetCaps
//
//==========================================================================
EXTERN_CVAR(Bool, r_drawvoxels)
uint32_t DFrameBuffer::GetCaps()
{
ActorRenderFeatureFlags FlagSet = 0;
if (V_IsPolyRenderer())
FlagSet |= RFF_POLYGONAL | RFF_TILTPITCH | RFF_SLOPE3DFLOORS;
else
{
FlagSet |= RFF_UNCLIPPEDTEX;
if (r_drawvoxels)
FlagSet |= RFF_VOXELS;
}
if (V_IsTrueColor())
FlagSet |= RFF_TRUECOLOR;
else
FlagSet |= RFF_COLORMAP;
return (uint32_t)FlagSet;
}
void DFrameBuffer::RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, double FOV)
{
SWRenderer->RenderTextureView(tex, Viewpoint, FOV);
}
void DFrameBuffer::WriteSavePic(player_t *player, FileWriter *file, int width, int height)
{
SWRenderer->WriteSavePic(player, file, width, height);
}
//==========================================================================
//
// Calculates the viewport values needed for 2D and 3D operations
//
//==========================================================================
void DFrameBuffer::SetViewportRects(IntRect *bounds)
{
if (bounds)
{
mSceneViewport = *bounds;
mScreenViewport = *bounds;
mOutputLetterbox = *bounds;
return;
}
// Special handling so the view with a visible status bar displays properly
int height, width;
if (screenblocks >= 10)
{
height = GetHeight();
width = GetWidth();
}
else
{
height = (screenblocks*GetHeight() / 10) & ~7;
width = (screenblocks*GetWidth() / 10);
}
// Back buffer letterbox for the final output
int clientWidth = GetClientWidth();
int clientHeight = GetClientHeight();
if (clientWidth == 0 || clientHeight == 0)
{
// When window is minimized there may not be any client area.
// Pretend to the rest of the render code that we just have a very small window.
clientWidth = 160;
clientHeight = 120;
}
int screenWidth = GetWidth();
int screenHeight = GetHeight();
float scaleX, scaleY;
if (ViewportIsScaled43())
{
scaleX = MIN(clientWidth / (float)screenWidth, clientHeight / (screenHeight * 1.2f));
scaleY = scaleX * 1.2f;
}
else
{
scaleX = MIN(clientWidth / (float)screenWidth, clientHeight / (float)screenHeight);
scaleY = scaleX;
}
mOutputLetterbox.width = (int)round(screenWidth * scaleX);
mOutputLetterbox.height = (int)round(screenHeight * scaleY);
mOutputLetterbox.left = (clientWidth - mOutputLetterbox.width) / 2;
mOutputLetterbox.top = (clientHeight - mOutputLetterbox.height) / 2;
// The entire renderable area, including the 2D HUD
mScreenViewport.left = 0;
mScreenViewport.top = 0;
mScreenViewport.width = screenWidth;
mScreenViewport.height = screenHeight;
// Viewport for the 3D scene
mSceneViewport.left = viewwindowx;
mSceneViewport.top = screenHeight - (height + viewwindowy - ((height - viewheight) / 2));
mSceneViewport.width = viewwidth;
mSceneViewport.height = height;
// Scale viewports to fit letterbox
bool notScaled = ((mScreenViewport.width == ViewportScaledWidth(mScreenViewport.width, mScreenViewport.height)) &&
(mScreenViewport.width == ViewportScaledHeight(mScreenViewport.width, mScreenViewport.height)) &&
!ViewportIsScaled43());
if (gl_scale_viewport && !IsFullscreen() && notScaled)
{
mScreenViewport.width = mOutputLetterbox.width;
mScreenViewport.height = mOutputLetterbox.height;
mSceneViewport.left = (int)round(mSceneViewport.left * scaleX);
mSceneViewport.top = (int)round(mSceneViewport.top * scaleY);
mSceneViewport.width = (int)round(mSceneViewport.width * scaleX);
mSceneViewport.height = (int)round(mSceneViewport.height * scaleY);
}
}
//===========================================================================
//
// Calculates the OpenGL window coordinates for a zdoom screen position
//
//===========================================================================
int DFrameBuffer::ScreenToWindowX(int x)
{
return mScreenViewport.left + (int)round(x * mScreenViewport.width / (float)GetWidth());
}
int DFrameBuffer::ScreenToWindowY(int y)
{
return mScreenViewport.top + mScreenViewport.height - (int)round(y * mScreenViewport.height / (float)GetHeight());
}
void DFrameBuffer::ScaleCoordsFromWindow(int16_t &x, int16_t &y)
{
int letterboxX = mOutputLetterbox.left;
int letterboxY = mOutputLetterbox.top;
int letterboxWidth = mOutputLetterbox.width;
int letterboxHeight = mOutputLetterbox.height;
x = int16_t((x - letterboxX) * Width / letterboxWidth);
y = int16_t((y - letterboxY) * Height / letterboxHeight);
}
CCMD(clean) CCMD(clean)
{ {
Printf ("CleanXfac: %d\nCleanYfac: %d\n", CleanXfac, CleanYfac); Printf ("CleanXfac: %d\nCleanYfac: %d\n", CleanXfac, CleanYfac);
@ -1109,9 +620,6 @@ void V_Init (bool restart)
if ( (i = Args->CheckValue ("-height")) ) if ( (i = Args->CheckValue ("-height")) )
height = atoi (i); height = atoi (i);
if ( (i = Args->CheckValue ("-bits")) )
bits = atoi (i);
if (width == 0) if (width == 0)
{ {
if (height == 0) if (height == 0)
@ -1128,11 +636,10 @@ void V_Init (bool restart)
{ {
height = (width * 6) / 8; height = (width * 6) / 8;
} }
// Remember the passed arguments for the next time the game starts up windowed.
vid_defwidth = width;
vid_defheight = height;
if (bits == 0)
{
bits = vid_defbits;
}
screen = new DDummyFrameBuffer (width, height); screen = new DDummyFrameBuffer (width, height);
} }
// Update screen palette when restarting // Update screen palette when restarting

View file

@ -408,6 +408,7 @@ public:
// Returns true if running fullscreen. // Returns true if running fullscreen.
virtual bool IsFullscreen () = 0; virtual bool IsFullscreen () = 0;
virtual void ToggleFullscreen(bool yes) {}
// Changes the vsync setting, if supported by the device. // Changes the vsync setting, if supported by the device.
virtual void SetVSync (bool vsync); virtual void SetVSync (bool vsync);

View file

@ -7,6 +7,9 @@ class SystemFrameBuffer : public DFrameBuffer
{ {
typedef DFrameBuffer Super; typedef DFrameBuffer Super;
void SaveWindowedPos();
void RestoreWindowedPos();
public: public:
SystemFrameBuffer() {} SystemFrameBuffer() {}
// Actually, hMonitor is a HMONITOR, but it's passed as a void * as there // Actually, hMonitor is a HMONITOR, but it's passed as a void * as there
@ -17,16 +20,17 @@ public:
void SetVSync (bool vsync); void SetVSync (bool vsync);
void SwapBuffers(); void SwapBuffers();
int GetClientWidth(); int GetClientWidth() override;
int GetClientHeight(); int GetClientHeight() override;
bool IsFullscreen(); bool IsFullscreen() override;
void ToggleFullscreen(bool yes) override;
void InitializeState(); void InitializeState();
protected: protected:
void PositionWindow(); void PositionWindow(bool fullscreen);
void ResetGammaTable(); void ResetGammaTable();
void SetGammaTable(uint16_t * tbl); void SetGammaTable(uint16_t * tbl);

View file

@ -32,8 +32,10 @@
** **
*/ */
#define _WIN32_WINNT 0x0501
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#include <mmsystem.h>
#include "hardware.h" #include "hardware.h"
#include "c_dispatch.h" #include "c_dispatch.h"
@ -44,10 +46,7 @@
#include "swrenderer/r_swrenderer.h" #include "swrenderer/r_swrenderer.h"
EXTERN_CVAR (Bool, fullscreen) EXTERN_CVAR (Bool, fullscreen)
EXTERN_CVAR(Int, vid_maxfps)
CVAR(Int, win_x, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Int, win_y, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Bool, win_maximized, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
extern HWND Window; extern HWND Window;
@ -87,10 +86,6 @@ CUSTOM_CVAR(Int, vid_gpuswitch, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINI
} }
CCMD (vid_restart)
{
}
void I_ShutdownGraphics () void I_ShutdownGraphics ()
{ {
@ -137,116 +132,87 @@ void I_InitGraphics ()
atterm (I_ShutdownGraphics); atterm (I_ShutdownGraphics);
} }
/** Remaining code is common to Win32 and Linux **/
// VIDEO WRAPPERS --------------------------------------------------------- static UINT FPSLimitTimer;
HANDLE FPSLimitEvent;
//==========================================================================
//
// SetFPSLimit
//
// Initializes an event timer to fire at a rate of <limit>/sec. The video
// update will wait for this timer to trigger before updating.
//
// Pass 0 as the limit for unlimited.
// Pass a negative value for the limit to use the value of vid_maxfps.
//
//==========================================================================
static void GetCenteredPos (int &winx, int &winy, int &winw, int &winh, int &scrwidth, int &scrheight) static void StopFPSLimit()
{ {
DEVMODE displaysettings; I_SetFPSLimit(0);
RECT rect;
int cx, cy;
memset (&displaysettings, 0, sizeof(displaysettings));
displaysettings.dmSize = sizeof(displaysettings);
EnumDisplaySettings (NULL, ENUM_CURRENT_SETTINGS, &displaysettings);
scrwidth = (int)displaysettings.dmPelsWidth;
scrheight = (int)displaysettings.dmPelsHeight;
GetWindowRect (Window, &rect);
cx = scrwidth / 2;
cy = scrheight / 2;
winx = cx - (winw = rect.right - rect.left) / 2;
winy = cy - (winh = rect.bottom - rect.top) / 2;
} }
static void KeepWindowOnScreen (int &winx, int &winy, int winw, int winh, int scrwidth, int scrheight) void I_SetFPSLimit(int limit)
{ {
// If the window is too large to fit entirely on the screen, at least if (limit < 0)
// keep its upperleft corner visible.
if (winx + winw > scrwidth)
{ {
winx = scrwidth - winw; limit = vid_maxfps;
} }
if (winx < 0) // Kill any leftover timer.
if (FPSLimitTimer != 0)
{ {
winx = 0; timeKillEvent(FPSLimitTimer);
FPSLimitTimer = 0;
} }
if (winy + winh > scrheight) if (limit == 0)
{ { // no limit
winy = scrheight - winh; if (FPSLimitEvent != NULL)
}
if (winy < 0)
{
winy = 0;
}
}
void I_SaveWindowedPos ()
{
// Don't save if we were run with the -0 option.
if (Args->CheckParm ("-0"))
{
return;
}
// Make sure we only save the window position if it's not fullscreen.
static const int WINDOW_STYLE = WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX;
if ((GetWindowLong (Window, GWL_STYLE) & WINDOW_STYLE) == WINDOW_STYLE)
{
RECT wrect;
if (GetWindowRect (Window, &wrect))
{ {
// If (win_x,win_y) specify to center the window, don't change them CloseHandle(FPSLimitEvent);
// if the window is still centered. FPSLimitEvent = NULL;
if (win_x < 0 || win_y < 0)
{
int winx, winy, winw, winh, scrwidth, scrheight;
GetCenteredPos (winx, winy, winw, winh, scrwidth, scrheight);
KeepWindowOnScreen (winx, winy, winw, winh, scrwidth, scrheight);
if (win_x < 0 && winx == wrect.left)
{
wrect.left = win_x;
}
if (win_y < 0 && winy == wrect.top)
{
wrect.top = win_y;
}
}
win_x = wrect.left;
win_y = wrect.top;
} }
DPrintf(DMSG_NOTIFY, "FPS timer disabled\n");
win_maximized = IsZoomed(Window) == TRUE;
}
}
void I_RestoreWindowedPos ()
{
int winx, winy, winw, winh, scrwidth, scrheight;
GetCenteredPos (winx, winy, winw, winh, scrwidth, scrheight);
// Just move to (0,0) if we were run with the -0 option.
if (Args->CheckParm ("-0"))
{
winx = winy = 0;
} }
else else
{ {
if (win_x >= 0) if (FPSLimitEvent == NULL)
{ {
winx = win_x; FPSLimitEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
if (FPSLimitEvent == NULL)
{ // Could not create event, so cannot use timer.
Printf(DMSG_WARNING, "Failed to create FPS limitter event\n");
return;
}
} }
if (win_y >= 0) atterm(StopFPSLimit);
// Set timer event as close as we can to limit/sec, in milliseconds.
UINT period = 1000 / limit;
FPSLimitTimer = timeSetEvent(period, 0, (LPTIMECALLBACK)FPSLimitEvent, 0, TIME_PERIODIC | TIME_CALLBACK_EVENT_SET);
if (FPSLimitTimer == 0)
{ {
winy = win_y; CloseHandle(FPSLimitEvent);
FPSLimitEvent = NULL;
Printf("Failed to create FPS limiter timer\n");
return;
} }
KeepWindowOnScreen (winx, winy, winw, winh, scrwidth, scrheight); DPrintf(DMSG_NOTIFY, "FPS timer set to %u ms\n", period);
} }
MoveWindow (Window, winx, winy, winw, winh, TRUE);
if (win_maximized && !Args->CheckParm("-0"))
ShowWindow(Window, SW_MAXIMIZE);
} }
//==========================================================================
//
// StopFPSLimit
//
// Used for cleanup during application shutdown.
//
//==========================================================================
void I_FPSLimit()
{
if (FPSLimitEvent != NULL)
{
WaitForSingleObject(FPSLimitEvent, 1000);
}
}

View file

@ -37,9 +37,6 @@
#include "i_video.h" #include "i_video.h"
#include "v_video.h" #include "v_video.h"
void I_SaveWindowedPos ();
void I_RestoreWindowedPos ();
void I_SetFPSLimit(int limit); void I_SetFPSLimit(int limit);
void I_FPSLimit(); void I_FPSLimit();

View file

@ -66,7 +66,11 @@ PFNWGLCHOOSEPIXELFORMATARBPROC myWglChoosePixelFormatARB; // = (PFNWGLCHOOSEPIXE
PFNWGLCREATECONTEXTATTRIBSARBPROC myWglCreateContextAttribsARB; PFNWGLCREATECONTEXTATTRIBSARBPROC myWglCreateContextAttribsARB;
PFNWGLSWAPINTERVALEXTPROC myWglSwapIntervalExtProc; PFNWGLSWAPINTERVALEXTPROC myWglSwapIntervalExtProc;
CVAR(Int, vid_adapter, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Int, win_x, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Int, win_y, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Bool, win_maximized, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Bool, gl_debug, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) CUSTOM_CVAR(Bool, gl_debug, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{ {
@ -652,19 +656,163 @@ void Win32GLVideo::Shutdown()
} }
//==========================================================================
//
// Windows framebuffer
//
//==========================================================================
//========================================================================== //==========================================================================
// //
// //
// //
//========================================================================== //==========================================================================
void SystemFrameBuffer::PositionWindow() static void GetCenteredPos(int &winx, int &winy, int &winw, int &winh, int &scrwidth, int &scrheight)
{
DEVMODE displaysettings;
RECT rect;
int cx, cy;
memset(&displaysettings, 0, sizeof(displaysettings));
displaysettings.dmSize = sizeof(displaysettings);
EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &displaysettings);
scrwidth = (int)displaysettings.dmPelsWidth;
scrheight = (int)displaysettings.dmPelsHeight;
GetWindowRect(Window, &rect);
cx = scrwidth / 2;
cy = scrheight / 2;
winx = cx - (winw = rect.right - rect.left) / 2;
winy = cy - (winh = rect.bottom - rect.top) / 2;
}
//==========================================================================
//
//
//
//==========================================================================
static void KeepWindowOnScreen(int &winx, int &winy, int winw, int winh, int scrwidth, int scrheight)
{
// If the window is too large to fit entirely on the screen, at least
// keep its upperleft corner visible.
if (winx + winw > scrwidth)
{
winx = scrwidth - winw;
}
if (winx < 0)
{
winx = 0;
}
if (winy + winh > scrheight)
{
winy = scrheight - winh;
}
if (winy < 0)
{
winy = 0;
}
}
//==========================================================================
//
//
//
//==========================================================================
void SystemFrameBuffer::SaveWindowedPos()
{
// Don't save if we were run with the -0 option.
if (Args->CheckParm("-0"))
{
return;
}
// Make sure we only save the window position if it's not fullscreen.
static const int WINDOW_STYLE = WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX;
if ((GetWindowLong(Window, GWL_STYLE) & WINDOW_STYLE) == WINDOW_STYLE)
{
RECT wrect;
if (GetWindowRect(Window, &wrect))
{
// If (win_x,win_y) specify to center the window, don't change them
// if the window is still centered.
if (win_x < 0 || win_y < 0)
{
int winx, winy, winw, winh, scrwidth, scrheight;
GetCenteredPos(winx, winy, winw, winh, scrwidth, scrheight);
KeepWindowOnScreen(winx, winy, winw, winh, scrwidth, scrheight);
if (win_x < 0 && winx == wrect.left)
{
wrect.left = win_x;
}
if (win_y < 0 && winy == wrect.top)
{
wrect.top = win_y;
}
}
win_x = wrect.left;
win_y = wrect.top;
}
win_maximized = IsZoomed(Window) == TRUE;
}
}
//==========================================================================
//
//
//
//==========================================================================
void SystemFrameBuffer::RestoreWindowedPos()
{
int winx, winy, winw, winh, scrwidth, scrheight;
GetCenteredPos(winx, winy, winw, winh, scrwidth, scrheight);
// Just move to (0,0) if we were run with the -0 option.
if (Args->CheckParm("-0"))
{
winx = winy = 0;
}
else
{
if (win_x >= 0)
{
winx = win_x;
}
if (win_y >= 0)
{
winy = win_y;
}
KeepWindowOnScreen(winx, winy, winw, winh, scrwidth, scrheight);
}
MoveWindow(Window, winx, winy, winw, winh, TRUE);
if (win_maximized && !Args->CheckParm("-0"))
ShowWindow(Window, SW_MAXIMIZE);
}
//==========================================================================
//
//
//
//==========================================================================
void SystemFrameBuffer::PositionWindow(bool fullscreen)
{ {
RECT r; RECT r;
LONG style, exStyle; LONG style, exStyle;
RECT monRect; RECT monRect;
if (!m_Fullscreen) SaveWindowedPos();
if (m_Monitor) if (m_Monitor)
{ {
MONITORINFOEX mi; MONITORINFOEX mi;
@ -712,8 +860,9 @@ void SystemFrameBuffer::PositionWindow()
AdjustWindowRectEx(&windowRect, style, FALSE, exStyle); AdjustWindowRectEx(&windowRect, style, FALSE, exStyle);
MoveWindow(Window, windowRect.left, windowRect.top, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, FALSE); MoveWindow(Window, windowRect.left, windowRect.top, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, FALSE);
I_RestoreWindowedPos(); RestoreWindowedPos();
} }
m_Fullscreen = fullscreen;
SetSize(GetClientWidth(), GetClientHeight()); SetSize(GetClientWidth(), GetClientHeight());
} }
@ -726,12 +875,8 @@ void SystemFrameBuffer::PositionWindow()
SystemFrameBuffer::SystemFrameBuffer(void *hMonitor, bool fullscreen) : DFrameBuffer(vid_defwidth, vid_defheight) SystemFrameBuffer::SystemFrameBuffer(void *hMonitor, bool fullscreen) : DFrameBuffer(vid_defwidth, vid_defheight)
{ {
m_Monitor = hMonitor; m_Monitor = hMonitor;
m_Fullscreen = fullscreen;
m_displayDeviceName = 0; m_displayDeviceName = 0;
PositionWindow(); PositionWindow(fullscreen);
if (!static_cast<Win32GLVideo *>(Video)->InitHardware(Window, 0)) if (!static_cast<Win32GLVideo *>(Video)->InitHardware(Window, 0))
{ {
@ -778,7 +923,7 @@ SystemFrameBuffer::SystemFrameBuffer(void *hMonitor, bool fullscreen) : DFrameBu
SystemFrameBuffer::~SystemFrameBuffer() SystemFrameBuffer::~SystemFrameBuffer()
{ {
ResetGammaTable(); ResetGammaTable();
I_SaveWindowedPos(); SaveWindowedPos();
ShowWindow (Window, SW_SHOW); ShowWindow (Window, SW_SHOW);
SetWindowLong(Window, GWL_STYLE, WS_VISIBLE | WS_CLIPSIBLINGS | WS_OVERLAPPEDWINDOW); SetWindowLong(Window, GWL_STYLE, WS_VISIBLE | WS_CLIPSIBLINGS | WS_OVERLAPPEDWINDOW);
@ -837,6 +982,17 @@ bool SystemFrameBuffer::IsFullscreen()
return m_Fullscreen; return m_Fullscreen;
} }
//==========================================================================
//
//
//
//==========================================================================
void SystemFrameBuffer::ToggleFullscreen(bool yes)
{
PositionWindow(yes);
}
//========================================================================== //==========================================================================
// //
// //

View file

@ -42,108 +42,3 @@
#include "c_cvars.h" #include "c_cvars.h"
#include "i_system.h" #include "i_system.h"
// MACROS ------------------------------------------------------------------
// TYPES -------------------------------------------------------------------
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
static void StopFPSLimit();
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
EXTERN_CVAR(Int, vid_maxfps)
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static UINT FPSLimitTimer;
// PUBLIC DATA DEFINITIONS -------------------------------------------------
HANDLE FPSLimitEvent;
CVAR (Int, vid_adapter, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
//==========================================================================
//
// SetFPSLimit
//
// Initializes an event timer to fire at a rate of <limit>/sec. The video
// update will wait for this timer to trigger before updating.
//
// Pass 0 as the limit for unlimited.
// Pass a negative value for the limit to use the value of vid_maxfps.
//
//==========================================================================
void I_SetFPSLimit(int limit)
{
if (limit < 0)
{
limit = vid_maxfps;
}
// Kill any leftover timer.
if (FPSLimitTimer != 0)
{
timeKillEvent(FPSLimitTimer);
FPSLimitTimer = 0;
}
if (limit == 0)
{ // no limit
if (FPSLimitEvent != NULL)
{
CloseHandle(FPSLimitEvent);
FPSLimitEvent = NULL;
}
DPrintf(DMSG_NOTIFY, "FPS timer disabled\n");
}
else
{
if (FPSLimitEvent == NULL)
{
FPSLimitEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
if (FPSLimitEvent == NULL)
{ // Could not create event, so cannot use timer.
Printf(DMSG_WARNING, "Failed to create FPS limitter event\n");
return;
}
}
atterm(StopFPSLimit);
// Set timer event as close as we can to limit/sec, in milliseconds.
UINT period = 1000 / limit;
FPSLimitTimer = timeSetEvent(period, 0, (LPTIMECALLBACK)FPSLimitEvent, 0, TIME_PERIODIC | TIME_CALLBACK_EVENT_SET);
if (FPSLimitTimer == 0)
{
CloseHandle(FPSLimitEvent);
FPSLimitEvent = NULL;
Printf("Failed to create FPS limiter timer\n");
return;
}
DPrintf(DMSG_NOTIFY, "FPS timer set to %u ms\n", period);
}
}
//==========================================================================
//
// StopFPSLimit
//
// Used for cleanup during application shutdown.
//
//==========================================================================
static void StopFPSLimit()
{
I_SetFPSLimit(0);
}
void I_FPSLimit()
{
if (FPSLimitEvent != NULL)
{
WaitForSingleObject(FPSLimitEvent, 1000);
}
}