mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-28 23:12:24 +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_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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 =
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
||||||
|
|
|
@ -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
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
|
** 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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue