mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-11-11 07:12:16 +00:00
- fullscreen toggle and some cleanup. Not fully working yet.
This commit is contained in:
parent
89ce74443b
commit
babe55819e
15 changed files with 827 additions and 728 deletions
|
@ -987,6 +987,7 @@ set (PCH_SOURCES
|
|||
v_collection.cpp
|
||||
v_draw.cpp
|
||||
v_font.cpp
|
||||
v_framebuffer.cpp
|
||||
v_palette.cpp
|
||||
v_paltest.cpp
|
||||
v_pfx.cpp
|
||||
|
|
|
@ -99,6 +99,7 @@
|
|||
#include "r_data/r_vanillatrans.h"
|
||||
|
||||
EXTERN_CVAR(Bool, hud_althud)
|
||||
EXTERN_CVAR(Bool, fullscreen)
|
||||
void DrawHUD();
|
||||
void D_DoAnonStats();
|
||||
|
||||
|
@ -673,13 +674,9 @@ void D_Display ()
|
|||
// fullscreen toggle has been requested
|
||||
if (setmodeneeded)
|
||||
{
|
||||
// Change screen mode.
|
||||
/*
|
||||
if (Video->ToggleFullscreen())
|
||||
{
|
||||
setsizeneeded = true;
|
||||
}
|
||||
*/
|
||||
screen->ToggleFullscreen(fullscreen);
|
||||
setsizeneeded = true;
|
||||
setmodeneeded = false;
|
||||
}
|
||||
|
||||
// change the view size if needed
|
||||
|
@ -696,7 +693,6 @@ void D_Display ()
|
|||
R_ExecuteSetViewSize (r_viewpoint, r_viewwindow);
|
||||
}
|
||||
}
|
||||
setmodeneeded = false;
|
||||
|
||||
// [RH] Allow temporarily disabling wipes
|
||||
if (NoWipe)
|
||||
|
|
|
@ -140,11 +140,13 @@ void CheckerInterleaved3D::Present() const
|
|||
int windowHOffset = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
/* this needs to be done differently!
|
||||
if (!fullscreen) {
|
||||
I_SaveWindowedPos(); // update win_y CVAR
|
||||
windowHOffset = (win_x + WINDOW_BORDER_HORIZONTAL_PARITY) % 2;
|
||||
windowVOffset = (win_y + WINDOW_BORDER_VERTICAL_PARITY) % 2;
|
||||
}
|
||||
*/
|
||||
#endif // _WIN32
|
||||
|
||||
GLRenderer->mPresent3dCheckerShader->Uniforms->WindowPositionParity =
|
||||
|
@ -184,10 +186,12 @@ void ColumnInterleaved3D::Present() const
|
|||
int windowHOffset = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
/* this needs to be done differently!
|
||||
if (!fullscreen) {
|
||||
I_SaveWindowedPos(); // update win_y CVAR
|
||||
windowHOffset = (win_x + WINDOW_BORDER_HORIZONTAL_PARITY) % 2;
|
||||
}
|
||||
*/
|
||||
#endif // _WIN32
|
||||
|
||||
GLRenderer->mPresent3dColumnShader->Uniforms->WindowPositionParity = windowHOffset;
|
||||
|
@ -207,10 +211,12 @@ void RowInterleaved3D::Present() const
|
|||
int windowVOffset = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
/* this needs to be done differently!
|
||||
if (! fullscreen) {
|
||||
I_SaveWindowedPos(); // update win_y CVAR
|
||||
windowVOffset = (win_y + WINDOW_BORDER_VERTICAL_PARITY) % 2;
|
||||
}
|
||||
*/
|
||||
#endif // _WIN32
|
||||
|
||||
GLRenderer->mPresent3dRowShader->Uniforms->WindowPositionParity =
|
||||
|
|
|
@ -46,8 +46,9 @@ public:
|
|||
virtual bool IsFullscreen();
|
||||
virtual void SetVSync(bool vsync);
|
||||
|
||||
int GetClientWidth();
|
||||
int GetClientHeight();
|
||||
int GetClientWidth() override;
|
||||
int GetClientHeight() override;
|
||||
void ToggleFullscreen(bool yes) override;
|
||||
|
||||
protected:
|
||||
bool UpdatePending;
|
||||
|
|
|
@ -556,6 +556,12 @@ bool SystemFrameBuffer::IsFullscreen()
|
|||
return CocoaVideo::IsFullscreen();
|
||||
}
|
||||
|
||||
void SystemFrameBuffer::ToggleFullscreen(bool yes)
|
||||
{
|
||||
SetMode(...); // todo
|
||||
}
|
||||
|
||||
|
||||
void SystemFrameBuffer::SetVSync(bool vsync)
|
||||
{
|
||||
const GLint value = vsync ? 1 : 0;
|
||||
|
|
|
@ -23,8 +23,9 @@ public:
|
|||
|
||||
friend class SDLGLVideo;
|
||||
|
||||
int GetClientWidth();
|
||||
int GetClientHeight();
|
||||
int GetClientWidth() override;
|
||||
int GetClientHeight() override;
|
||||
void ToggleFullscreen(bool yes) override;
|
||||
|
||||
SDL_Window *GetSDLWindow() { return Screen; }
|
||||
|
||||
|
|
|
@ -309,6 +309,11 @@ void SystemFrameBuffer::SwapBuffers()
|
|||
SDL_GL_SwapWindow (Screen);
|
||||
}
|
||||
|
||||
void SystemFrameBuffer::ToggleFullscreen(bool yes)
|
||||
{
|
||||
... // todo
|
||||
}
|
||||
|
||||
int SystemFrameBuffer::GetClientWidth()
|
||||
{
|
||||
int width = 0;
|
||||
|
|
557
src/v_framebuffer.cpp
Normal file
557
src/v_framebuffer.cpp
Normal 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;
|
||||
};
|
||||
|
501
src/v_video.cpp
501
src/v_video.cpp
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
**
|
||||
** Video basics and init code.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** 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>
|
||||
|
@ -74,10 +67,6 @@
|
|||
#include "i_time.h"
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -156,10 +145,7 @@ DFrameBuffer *screen;
|
|||
|
||||
CVAR (Int, vid_defwidth, 640, 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 (Int, vid_showpalette, 0, 0)
|
||||
|
||||
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
|
||||
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)
|
||||
{
|
||||
Printf ("CleanXfac: %d\nCleanYfac: %d\n", CleanXfac, CleanYfac);
|
||||
|
@ -1109,9 +620,6 @@ void V_Init (bool restart)
|
|||
if ( (i = Args->CheckValue ("-height")) )
|
||||
height = atoi (i);
|
||||
|
||||
if ( (i = Args->CheckValue ("-bits")) )
|
||||
bits = atoi (i);
|
||||
|
||||
if (width == 0)
|
||||
{
|
||||
if (height == 0)
|
||||
|
@ -1128,11 +636,10 @@ void V_Init (bool restart)
|
|||
{
|
||||
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);
|
||||
}
|
||||
// Update screen palette when restarting
|
||||
|
|
|
@ -408,6 +408,7 @@ public:
|
|||
|
||||
// Returns true if running fullscreen.
|
||||
virtual bool IsFullscreen () = 0;
|
||||
virtual void ToggleFullscreen(bool yes) {}
|
||||
|
||||
// Changes the vsync setting, if supported by the device.
|
||||
virtual void SetVSync (bool vsync);
|
||||
|
|
|
@ -7,6 +7,9 @@ class SystemFrameBuffer : public DFrameBuffer
|
|||
{
|
||||
typedef DFrameBuffer Super;
|
||||
|
||||
void SaveWindowedPos();
|
||||
void RestoreWindowedPos();
|
||||
|
||||
public:
|
||||
SystemFrameBuffer() {}
|
||||
// Actually, hMonitor is a HMONITOR, but it's passed as a void * as there
|
||||
|
@ -17,16 +20,17 @@ public:
|
|||
void SetVSync (bool vsync);
|
||||
void SwapBuffers();
|
||||
|
||||
int GetClientWidth();
|
||||
int GetClientHeight();
|
||||
int GetClientWidth() override;
|
||||
int GetClientHeight() override;
|
||||
|
||||
bool IsFullscreen();
|
||||
bool IsFullscreen() override;
|
||||
void ToggleFullscreen(bool yes) override;
|
||||
|
||||
void InitializeState();
|
||||
|
||||
protected:
|
||||
|
||||
void PositionWindow();
|
||||
void PositionWindow(bool fullscreen);
|
||||
|
||||
void ResetGammaTable();
|
||||
void SetGammaTable(uint16_t * tbl);
|
||||
|
|
|
@ -32,8 +32,10 @@
|
|||
**
|
||||
*/
|
||||
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
|
||||
#include "hardware.h"
|
||||
#include "c_dispatch.h"
|
||||
|
@ -44,10 +46,7 @@
|
|||
#include "swrenderer/r_swrenderer.h"
|
||||
|
||||
EXTERN_CVAR (Bool, fullscreen)
|
||||
|
||||
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_CVAR(Int, vid_maxfps)
|
||||
|
||||
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 ()
|
||||
{
|
||||
|
@ -137,116 +132,87 @@ void I_InitGraphics ()
|
|||
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;
|
||||
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;
|
||||
I_SetFPSLimit(0);
|
||||
}
|
||||
|
||||
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
|
||||
// keep its upperleft corner visible.
|
||||
if (winx + winw > scrwidth)
|
||||
if (limit < 0)
|
||||
{
|
||||
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)
|
||||
{
|
||||
winy = scrheight - winh;
|
||||
}
|
||||
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 (limit == 0)
|
||||
{ // no limit
|
||||
if (FPSLimitEvent != NULL)
|
||||
{
|
||||
// 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;
|
||||
CloseHandle(FPSLimitEvent);
|
||||
FPSLimitEvent = NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
DPrintf(DMSG_NOTIFY, "FPS timer disabled\n");
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,9 +37,6 @@
|
|||
#include "i_video.h"
|
||||
#include "v_video.h"
|
||||
|
||||
void I_SaveWindowedPos ();
|
||||
void I_RestoreWindowedPos ();
|
||||
|
||||
void I_SetFPSLimit(int limit);
|
||||
void I_FPSLimit();
|
||||
|
||||
|
|
|
@ -66,7 +66,11 @@ PFNWGLCHOOSEPIXELFORMATARBPROC myWglChoosePixelFormatARB; // = (PFNWGLCHOOSEPIXE
|
|||
PFNWGLCREATECONTEXTATTRIBSARBPROC myWglCreateContextAttribsARB;
|
||||
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)
|
||||
{
|
||||
|
@ -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;
|
||||
LONG style, exStyle;
|
||||
|
||||
RECT monRect;
|
||||
|
||||
if (!m_Fullscreen) SaveWindowedPos();
|
||||
if (m_Monitor)
|
||||
{
|
||||
MONITORINFOEX mi;
|
||||
|
@ -712,8 +860,9 @@ void SystemFrameBuffer::PositionWindow()
|
|||
AdjustWindowRectEx(&windowRect, style, FALSE, exStyle);
|
||||
MoveWindow(Window, windowRect.left, windowRect.top, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, FALSE);
|
||||
|
||||
I_RestoreWindowedPos();
|
||||
RestoreWindowedPos();
|
||||
}
|
||||
m_Fullscreen = fullscreen;
|
||||
SetSize(GetClientWidth(), GetClientHeight());
|
||||
}
|
||||
|
||||
|
@ -726,12 +875,8 @@ void SystemFrameBuffer::PositionWindow()
|
|||
SystemFrameBuffer::SystemFrameBuffer(void *hMonitor, bool fullscreen) : DFrameBuffer(vid_defwidth, vid_defheight)
|
||||
{
|
||||
m_Monitor = hMonitor;
|
||||
m_Fullscreen = fullscreen;
|
||||
|
||||
|
||||
m_displayDeviceName = 0;
|
||||
PositionWindow();
|
||||
|
||||
PositionWindow(fullscreen);
|
||||
|
||||
if (!static_cast<Win32GLVideo *>(Video)->InitHardware(Window, 0))
|
||||
{
|
||||
|
@ -778,7 +923,7 @@ SystemFrameBuffer::SystemFrameBuffer(void *hMonitor, bool fullscreen) : DFrameBu
|
|||
SystemFrameBuffer::~SystemFrameBuffer()
|
||||
{
|
||||
ResetGammaTable();
|
||||
I_SaveWindowedPos();
|
||||
SaveWindowedPos();
|
||||
|
||||
ShowWindow (Window, SW_SHOW);
|
||||
SetWindowLong(Window, GWL_STYLE, WS_VISIBLE | WS_CLIPSIBLINGS | WS_OVERLAPPEDWINDOW);
|
||||
|
@ -837,6 +982,17 @@ bool SystemFrameBuffer::IsFullscreen()
|
|||
return m_Fullscreen;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void SystemFrameBuffer::ToggleFullscreen(bool yes)
|
||||
{
|
||||
PositionWindow(yes);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
|
|
@ -42,108 +42,3 @@
|
|||
#include "c_cvars.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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue