- backend sync with GZDoom to pull in a few bugfixes and formatting corrections.

This commit is contained in:
Christoph Oelckers 2020-05-26 23:12:04 +02:00
parent 143e338d9f
commit d52600663d
55 changed files with 1121 additions and 243 deletions

View file

@ -37,11 +37,15 @@
#include "vm.h"
#include "c_cvars.h"
#include "v_draw.h"
#include "v_video.h"
#include "fcolormap.h"
F2DDrawer* twod;
static F2DDrawer drawer;
F2DDrawer* twod = &drawer;
EXTERN_CVAR(Float, transsouls)
CVAR(Float, classic_scaling_factor, 1.0, CVAR_ARCHIVE)
CVAR(Float, classic_scaling_pixelaspect, 1.2f, CVAR_ARCHIVE)
IMPLEMENT_CLASS(DShape2DTransform, false, false)
@ -393,6 +397,7 @@ void F2DDrawer::SetColorOverlay(PalEntry color, float alpha, PalEntry &vertexcol
void F2DDrawer::AddTexture(FGameTexture* img, DrawParms& parms)
{
if (parms.style.BlendOp == STYLEOP_None) return; // not supposed to be drawn.
assert(img && img->isValid());
double xscale = parms.destwidth / parms.texwidth;
double yscale = parms.destheight / parms.texheight;
@ -676,7 +681,20 @@ void F2DDrawer::AddPoly(FGameTexture* img, FVector4* vt, size_t vtcount, unsigne
//
//==========================================================================
void F2DDrawer::AddFlatFill(int left, int top, int right, int bottom, FGameTexture *src, bool local_origin)
float F2DDrawer::GetClassicFlatScalarWidth()
{
float ar = 4.f / 3.f / (float)ActiveRatio((float)screen->GetWidth(), (float)screen->GetHeight());
float sw = 320.f * classic_scaling_factor / (float)screen->GetWidth() / ar;
return sw;
}
float F2DDrawer::GetClassicFlatScalarHeight()
{
float sh = 240.f / classic_scaling_pixelaspect * classic_scaling_factor / (float)screen->GetHeight();
return sh;
}
void F2DDrawer::AddFlatFill(int left, int top, int right, int bottom, FGameTexture *src, int local_origin, double flatscale)
{
float fU1, fU2, fV1, fV2;
@ -689,27 +707,100 @@ void F2DDrawer::AddFlatFill(int left, int top, int right, int bottom, FGameTextu
dg.mTexture = src;
dg.mFlags = DTF_Wrap;
// scaling is not used here.
if (!local_origin)
{
fU1 = float(left) / (float)src->GetDisplayWidth();
fV1 = float(top) / (float)src->GetDisplayHeight();
fU2 = float(right) / (float)src->GetDisplayWidth();
fV2 = float(bottom) / (float)src->GetDisplayHeight();
}
else
float fs = 1.f / float(flatscale);
bool flipc = false;
float sw = GetClassicFlatScalarWidth();
float sh = GetClassicFlatScalarHeight();
switch (local_origin)
{
case 0:
fU1 = float(left) / (float)src->GetDisplayWidth() * fs;
fV1 = float(top) / (float)src->GetDisplayHeight() * fs;
fU2 = float(right) / (float)src->GetDisplayWidth() * fs;
fV2 = float(bottom) / (float)src->GetDisplayHeight() * fs;
break;
case 1:
fU1 = 0;
fV1 = 0;
fU2 = float(right - left) / (float)src->GetDisplayWidth();
fV2 = float(bottom - top) / (float)src->GetDisplayHeight();
fU2 = float(right - left) / (float)src->GetDisplayWidth() * fs;
fV2 = float(bottom - top) / (float)src->GetDisplayHeight() * fs;
break;
// The following are for drawing frames with elements of pnly one orientation
case 2: // flip vertically
fU1 = 0;
fV2 = 0;
fU2 = float(right - left) / (float)src->GetDisplayWidth() * fs;
fV1 = float(bottom - top) / (float)src->GetDisplayHeight() * fs;
break;
case 3: // flip horizontally
fU2 = 0;
fV1 = 0;
fU1 = float(right - left) / (float)src->GetDisplayWidth() * fs;
fV2 = float(bottom - top) / (float)src->GetDisplayHeight() * fs;
break;
case 4: // flip vertically and horizontally
fU2 = 0;
fV2 = 0;
fU1 = float(right - left) / (float)src->GetDisplayWidth() * fs;
fV1 = float(bottom - top) / (float)src->GetDisplayHeight() * fs;
break;
case 5: // flip coordinates
fU1 = 0;
fV1 = 0;
fU2 = float(bottom - top) / (float)src->GetDisplayWidth() * fs;
fV2 = float(right - left) / (float)src->GetDisplayHeight() * fs;
break;
case 6: // flip coordinates and vertically
fU2 = 0;
fV1 = 0;
fU1 = float(bottom - top) / (float)src->GetDisplayWidth() * fs;
fV2 = float(right - left) / (float)src->GetDisplayHeight() * fs;
break;
case 7: // flip coordinates and horizontally
fU1 = 0;
fV2 = 0;
fU2 = float(bottom - top) / (float)src->GetDisplayWidth() * fs;
fV1 = float(right - left) / (float)src->GetDisplayHeight() * fs;
break;
case -1: // classic flat scaling
fU1 = float(left) / (float)src->GetDisplayWidth() * fs * sw;
fV1 = float(top) / (float)src->GetDisplayHeight() * fs * sh;
fU2 = float(right) / (float)src->GetDisplayWidth() * fs * sw;
fV2 = float(bottom) / (float)src->GetDisplayHeight() * fs * sh;
break;
case -2: // classic scaling for screen bevel
fU1 = 0;
fV1 = 0;
fU2 = float(right - left) / (float)src->GetDisplayWidth() * fs * sw;
fV2 = float(bottom - top) / (float)src->GetDisplayHeight() * fs * sh;
break;
}
dg.mVertIndex = (int)mVertices.Reserve(4);
auto ptr = &mVertices[dg.mVertIndex];
ptr->Set(left, top, 0, fU1, fV1, 0xffffffff); ptr++;
ptr->Set(left, bottom, 0, fU1, fV2, 0xffffffff); ptr++;
ptr->Set(right, top, 0, fU2, fV1, 0xffffffff); ptr++;
if (local_origin < 4)
{
ptr->Set(left, bottom, 0, fU1, fV2, 0xffffffff); ptr++;
ptr->Set(right, top, 0, fU2, fV1, 0xffffffff); ptr++;
}
else
{
ptr->Set(left, bottom, 0, fU2, fV1, 0xffffffff); ptr++;
ptr->Set(right, top, 0, fU1, fV2, 0xffffffff); ptr++;
}
ptr->Set(right, bottom, 0, fU2, fV2, 0xffffffff); ptr++;
dg.mIndexIndex = mIndices.Size();
dg.mIndexCount += 6;
@ -724,7 +815,7 @@ void F2DDrawer::AddFlatFill(int left, int top, int right, int bottom, FGameTextu
//
//===========================================================================
void F2DDrawer::AddColorOnlyQuad(int x1, int y1, int w, int h, PalEntry color, FRenderStyle *style)
void F2DDrawer::AddColorOnlyQuad(int x1, int y1, int w, int h, PalEntry color, FRenderStyle *style, bool prepend)
{
RenderCommand dg;
@ -740,7 +831,13 @@ void F2DDrawer::AddColorOnlyQuad(int x1, int y1, int w, int h, PalEntry color, F
dg.mIndexIndex = mIndices.Size();
dg.mIndexCount += 6;
AddIndices(dg.mVertIndex, 6, 0, 1, 2, 1, 3, 2);
AddCommand(&dg);
if (!prepend) AddCommand(&dg);
else
{
// Only needed by Raze's fullscreen blends because they are being calculated late when half of the 2D content has already been submitted,
// This ensures they are below the HUD, not above it.
mData.Insert(0, dg);
}
}
void F2DDrawer::ClearScreen(PalEntry color)

View file

@ -174,6 +174,8 @@ private:
void SetColorOverlay(PalEntry color, float alpha, PalEntry &vertexcolor, PalEntry &overlaycolor);
public:
float GetClassicFlatScalarWidth();
float GetClassicFlatScalarHeight();
void AddTexture(FGameTexture* img, DrawParms& parms);
void AddShape(FGameTexture *img, DShape2D *shape, DrawParms &parms);
void AddPoly(FGameTexture *texture, FVector2 *points, int npoints,
@ -182,9 +184,9 @@ public:
void AddPoly(FGameTexture* img, FVector4 *vt, size_t vtcount, unsigned int *ind, size_t idxcount, int translation, PalEntry color, FRenderStyle style, int clipx1, int clipy1, int clipx2, int clipy2);
void FillPolygon(int* rx1, int* ry1, int* xb1, int32_t npoints, int picnum, int palette, int shade, int props, const FVector2& xtex, const FVector2& ytex, const FVector2& otex,
int clipx1, int clipy1, int clipx2, int clipy2);
void AddFlatFill(int left, int top, int right, int bottom, FGameTexture *src, bool local_origin = false);
void AddFlatFill(int left, int top, int right, int bottom, FGameTexture *src, int local_origin = false, double flatscale = 1.0);
void AddColorOnlyQuad(int left, int top, int width, int height, PalEntry color, FRenderStyle *style = nullptr);
void AddColorOnlyQuad(int left, int top, int width, int height, PalEntry color, FRenderStyle *style = nullptr, bool prepend = false);
void ClearScreen(PalEntry color = 0xff000000);
void AddDim(PalEntry color, float damount, int x1, int y1, int w, int h);
void AddClear(int left, int top, int right, int bottom, int palcolor, uint32_t color);
@ -198,7 +200,7 @@ public:
int GetWidth() const { return Width; }
int GetHeight() const { return Height; }
void SetSize(int w, int h) { Width = w; Height = h; }
void Begin() { isIn2D = true; }
void Begin(int w, int h) { isIn2D = true; Width = w; Height = h; }
void End() { isIn2D = false; }
bool HasBegun2D() { return isIn2D; }

View file

@ -43,6 +43,7 @@
EXTERN_CVAR(Int, vid_aspect)
EXTERN_CVAR(Int, uiscale)
CVAR(Bool, ui_screenborder_classic_scaling, true, CVAR_ARCHIVE)
// Helper for ActiveRatio and CheckRatio. Returns the forced ratio type, or -1 if none.
int ActiveFakeRatio(int width, int height)
@ -1161,10 +1162,11 @@ void FillBorder (F2DDrawer *drawer, FGameTexture *img)
if (img != NULL)
{
drawer->AddFlatFill(0, 0, Width, bordtop, img); // Top
drawer->AddFlatFill(0, bordtop, bordleft, Height - bordbottom, img); // Left
drawer->AddFlatFill(Width - bordright, bordtop, Width, Height - bordbottom, img); // Right
drawer->AddFlatFill(0, Height - bordbottom, Width, Height, img); // Bottom
int filltype = (ui_screenborder_classic_scaling) ? -1 : 0;
drawer->AddFlatFill(0, 0, Width, bordtop, img, filltype); // Top
drawer->AddFlatFill(0, bordtop, bordleft, Height - bordbottom, img, filltype); // Left
drawer->AddFlatFill(Width - bordright, bordtop, Width, Height - bordbottom, img, filltype); // Right
drawer->AddFlatFill(0, Height - bordbottom, Width, Height, img, filltype); // Bottom
}
else
{
@ -1222,7 +1224,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Screen, DrawThickLine, DrawThickLine)
//==========================================================================
//
// DCanvas :: Clear
// ClearRect
//
// Set an area to a specified color.
//
@ -1281,7 +1283,7 @@ DEFINE_ACTION_FUNCTION(_Screen, Clear)
//==========================================================================
//
// DCanvas :: Dim
// DoDim
//
// Applies a colored overlay to an area of the screen.
//
@ -1351,9 +1353,10 @@ DEFINE_ACTION_FUNCTION(_Screen, Dim)
void DrawBorder (F2DDrawer *drawer, FTextureID picnum, int x1, int y1, int x2, int y2)
{
int filltype = (ui_screenborder_classic_scaling) ? -1 : 0;
if (picnum.isValid())
{
drawer->AddFlatFill (x1, y1, x2, y2, TexMan.GetGameTexture(picnum, false));
drawer->AddFlatFill (x1, y1, x2, y2, TexMan.GetGameTexture(picnum, false), filltype);
}
else
{

View file

@ -219,7 +219,6 @@ void DoDim(F2DDrawer* drawer, PalEntry color, float amount, int x1, int y1, int
void Dim(F2DDrawer* drawer, PalEntry color, float damount, int x1, int y1, int w, int h, FRenderStyle* style = nullptr);
void FillBorder(F2DDrawer *drawer, FGameTexture* img); // Fills the border around a 4:3 part of the screen on non-4:3 displays
void DrawFrame(F2DDrawer* drawer, int left, int top, int width, int height);
void DrawBorder(F2DDrawer* drawer, FTextureID, int x1, int y1, int x2, int y2);
void DrawFrame(F2DDrawer* twod, PalEntry color, int left, int top, int width, int height, int thickness);

View file

@ -39,7 +39,6 @@
#include <stdlib.h>
#include <stdexcept>
#include "i_sound.h"
#include "i_music.h"
#include "printf.h"
@ -51,13 +50,6 @@
#include "filereadermusicinterface.h"
#include <zmusic.h>
static bool MusicPaused; // whether music is paused
MusPlayingInfo mus_playing; // music currently being played
static FPlayList PlayList;
float relative_volume = 1.f;
float saved_relative_volume = 1.0f; // this could be used to implement an ACS FadeMusic function
MusicVolumeMap MusicVolumes;
MidiDeviceMap MidiDevices;
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
extern float S_GetMusicVolume (const char *music);
@ -66,6 +58,13 @@ static void S_ActivatePlayList(bool goBack);
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static bool MusicPaused; // whether music is paused
MusPlayingInfo mus_playing; // music currently being played
static FPlayList PlayList;
float relative_volume = 1.f;
float saved_relative_volume = 1.0f; // this could be used to implement an ACS FadeMusic function
MusicVolumeMap MusicVolumes;
MidiDeviceMap MidiDevices;
static FileReader DefaultOpenMusic(const char* fn)
{
@ -223,10 +222,10 @@ void S_UpdateMusic ()
}
else
{
S_StopMusic(true);
S_StopMusic(true);
}
}
}
}
}
//==========================================================================
@ -265,11 +264,11 @@ void S_ActivatePlayList (bool goBack)
{
pos = goBack ? PlayList.Backup () : PlayList.Advance ();
if (pos == startpos)
{
{
PlayList.Clear();
Printf ("Cannot play anything in the playlist.\n");
return;
}
}
}
}
@ -342,48 +341,48 @@ bool S_ChangeMusic(const char* musicname, int order, bool looping, bool force)
return true;
}
int lumpnum = -1;
int length = 0;
ZMusic_MusicStream handle = nullptr;
int lumpnum = -1;
int length = 0;
ZMusic_MusicStream handle = nullptr;
MidiDeviceSetting* devp = MidiDevices.CheckKey(musicname);
// Strip off any leading file:// component.
if (strncmp(musicname, "file://", 7) == 0)
{
musicname += 7;
}
// Strip off any leading file:// component.
if (strncmp(musicname, "file://", 7) == 0)
{
musicname += 7;
}
// opening the music must be done by the game because it's different depending on the game's file system use.
FileReader reader = mus_cb.OpenMusic(musicname);
if (!reader.isOpen()) return false;
if (!reader.isOpen()) return false;
// shutdown old music
// shutdown old music
S_StopMusic(true);
// Just record it if volume is 0 or music was disabled
// Just record it if volume is 0 or music was disabled
if (snd_musicvolume <= 0 || !mus_enabled)
{
mus_playing.loop = looping;
mus_playing.name = musicname;
mus_playing.baseorder = order;
mus_playing.LastSong = musicname;
return true;
}
{
mus_playing.loop = looping;
mus_playing.name = musicname;
mus_playing.baseorder = order;
mus_playing.LastSong = musicname;
return true;
}
// load & register it
if (handle != nullptr)
{
mus_playing.handle = handle;
}
else
{
auto mreader = GetMusicReader(reader); // this passes the file reader to the newly created wrapper.
// load & register it
if (handle != nullptr)
{
mus_playing.handle = handle;
}
else
{
auto mreader = GetMusicReader(reader); // this passes the file reader to the newly created wrapper.
mus_playing.handle = ZMusic_OpenSong(mreader, devp ? (EMidiDevice)devp->device : MDEV_DEFAULT, devp ? devp->args.GetChars() : "");
if (mus_playing.handle == nullptr)
{
Printf("Unable to load %s: %s\n", mus_playing.name.GetChars(), ZMusic_GetLastError());
}
if (mus_playing.handle == nullptr)
{
Printf("Unable to load %s: %s\n", mus_playing.name.GetChars(), ZMusic_GetLastError());
}
}
mus_playing.loop = looping;
mus_playing.name = musicname;
@ -574,19 +573,19 @@ UNSAFE_CCMD (playlist)
{
Printf("Could not open " TEXTCOLOR_BOLD "%s" TEXTCOLOR_NORMAL ": %s\n", argv[1], strerror(errno));
return;
}
}
if (PlayList.GetNumSongs () > 0)
{
if (argc == 3)
{
if (argc == 3)
{
if (stricmp (argv[2], "shuffle") == 0)
{
PlayList.Shuffle ();
}
}
else
{
{
PlayList.SetPosition (atoi (argv[2]));
}
}
}
S_ActivatePlayList (false);
}
@ -645,7 +644,7 @@ CCMD (playlistprev)
{
PlayList.Backup ();
S_ActivatePlayList (true);
}
}
}
//==========================================================================

View file

@ -183,7 +183,6 @@ struct FSoundChan : public FISoundChannel
// CHAN_VOICE is for oof, sight, or other voice sounds
// CHAN_ITEM is for small things and item pickup
// CHAN_BODY is for generic body sounds
// Channels below 0 are reserved for CHAN_AUTO.
enum EChannel
{

View file

@ -59,11 +59,11 @@ const char *KeyNames[NUM_KEYS] =
nullptr, "Escape", "1", "2", "3", "4", "5", "6", //00
"7", "8", "9", "0", "-", "=", "Backspace","Tab", //08
"Q", "W", "E", "R", "T", "Y", "U", "I", //10
"O", "P", "[", "]", "Enter", "LCtrl", "A", "S", //18
"O", "P", "[", "]", "Enter", "Ctrl", "A", "S", //18
"D", "F", "G", "H", "J", "K", "L", ";", //20
"'", "`", "LShift", "\\", "Z", "X", "C", "V", //28
"'", "`", "Shift", "\\", "Z", "X", "C", "V", //28
"B", "N", "M", ",", ".", "/", "RShift", "KP*", //30
"LAlt", "Space", "CapsLock", "F1", "F2", "F3", "F4", "F5", //38
"Alt", "Space", "CapsLock", "F1", "F2", "F3", "F4", "F5", //38
"F6", "F7", "F8", "F9", "F10", "NumLock", "Scroll", "KP7", //40
"KP8", "KP9", "KP-", "KP4", "KP5", "KP6", "KP+", "KP1", //48
"KP2", "KP3", "KP0", "KP.", nullptr, nullptr, "OEM102", "F11", //50
@ -717,13 +717,25 @@ void C_SetDefaultKeys(const char* baseconfig)
while ((lump = fileSystem.FindLumpFullName(baseconfig, &lastlump)) != -1)
{
if (fileSystem.GetFileContainer(lump) > 0) break;
ReadBindings(lump, true);
// [SW] - We need to check to see the origin of the DEFBINDS... if it
// Comes from an IWAD/IPK3/IPK7 allow it to override the users settings...
// If it comes from a user mod however, don't.
if (fileSystem.GetFileContainer(lump) > fileSystem.GetMaxIwadNum())
ReadBindings(lump, false);
else
ReadBindings(lump, true);
}
lastlump = 0;
while ((lump = fileSystem.FindLump("DEFBINDS", &lastlump)) != -1)
{
ReadBindings(lump, false);
// [SW] - We need to check to see the origin of the DEFBINDS... if it
// Comes from an IWAD/IPK3/IPK7 allow it to override the users settings...
// If it comes from a user mod however, don't.
if (fileSystem.GetFileContainer(lump) > fileSystem.GetMaxIwadNum())
ReadBindings(lump, false);
else
ReadBindings(lump, true);
}
}

View file

@ -0,0 +1,160 @@
/*
** gl_cycler.cpp
** Implements the cycler for dynamic lights and texture shaders.
**
**---------------------------------------------------------------------------
** Copyright 2003 Timothy Stump
** Copyright 2006 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 <math.h>
#include "serializer.h"
#include "cycler.h"
//==========================================================================
//
// This will never be called with a null-def, so don't bother with that case.
//
//==========================================================================
FSerializer &Serialize(FSerializer &arc, const char *key, FCycler &c, FCycler *def)
{
if (arc.BeginObject(key))
{
arc("start", c.m_start, def->m_start)
("end", c.m_end, def->m_end)
("current", c.m_current, def->m_current)
("time", c.m_time, def->m_time)
("cycle", c.m_cycle, def->m_cycle)
("increment", c.m_increment, def->m_increment)
("shouldcycle", c.m_shouldCycle, def->m_shouldCycle)
.Enum("type", c.m_cycleType)
.EndObject();
}
return arc;
}
//==========================================================================
//
//
//
//==========================================================================
void FCycler::SetParams(double start, double end, double cycle, bool update)
{
if (!update || cycle != m_cycle)
{
m_cycle = cycle;
m_time = 0.;
m_increment = true;
m_current = start;
}
else
{
// When updating and keeping the same cycle, scale the current light size to the new dimensions.
double fact = (m_current - m_start) / (m_end - m_start);
m_current = start + fact *(end - start);
}
m_start = start;
m_end = end;
}
//==========================================================================
//
//
//
//==========================================================================
void FCycler::Update(double diff)
{
double mult, angle;
double step = m_end - m_start;
if (!m_shouldCycle)
{
return;
}
m_time += diff;
if (m_time >= m_cycle)
{
m_time = m_cycle;
}
mult = m_time / m_cycle;
switch (m_cycleType)
{
case CYCLE_Linear:
if (m_increment)
{
m_current = m_start + (step * mult);
}
else
{
m_current = m_end - (step * mult);
}
break;
case CYCLE_Sin:
angle = double(M_PI * 2. * mult);
mult = g_sin(angle);
mult = (mult + 1.) / 2.;
m_current = m_start + (step * mult);
break;
case CYCLE_Cos:
angle = double(M_PI * 2. * mult);
mult = g_cos(angle);
mult = (mult + 1.) / 2.;
m_current = m_start + (step * mult);
break;
case CYCLE_SawTooth:
m_current = m_start + (step * mult);
break;
case CYCLE_Square:
if (m_increment)
{
m_current = m_start;
}
else
{
m_current = m_end;
}
break;
}
if (m_time == m_cycle)
{
m_time = 0.;
m_increment = !m_increment;
}
}

View file

@ -0,0 +1,43 @@
#ifndef __GL_CYCLER_H
#define __GL_CYCLER_H
class FSerializer;
enum CycleType
{
CYCLE_Linear,
CYCLE_Sin,
CYCLE_Cos,
CYCLE_SawTooth,
CYCLE_Square
};
class FCycler;
FSerializer &Serialize(FSerializer &arc, const char *key, FCycler &c, FCycler *def);
class FCycler
{
friend FSerializer &Serialize(FSerializer &arc, const char *key, FCycler &c, FCycler *def);
public:
FCycler() = default;
FCycler(const FCycler &other) = default;
FCycler &operator=(const FCycler &other) = default;
void Update(double diff);
void SetParams(double start, double end, double cycle, bool update = false);
void ShouldCycle(bool sc) { m_shouldCycle = sc; }
void SetCycleType(CycleType ct) { m_cycleType = ct; }
double GetVal() { return m_current; }
inline operator double () const { return m_current; }
double m_start, m_end, m_current;
double m_time, m_cycle;
bool m_increment, m_shouldCycle;
CycleType m_cycleType;
};
#endif

View file

@ -1,6 +1,7 @@
#pragma once
#include "zstring.h"
#include "intrect.h"
struct SystemCallbacks
{
@ -11,7 +12,11 @@ struct SystemCallbacks
bool (*CaptureModeInGame)();
void (*CrashInfo)(char* buffer, size_t bufflen, const char* lfstr);
void (*PlayStartupSound)(const char* name);
bool (*IsSpecialUI)();
bool (*DisableTextureFilter)();
void (*OnScreenSizeChanged)();
IntRect(*GetSceneRect)();
FString(*GetLocationDescription)();
};
extern SystemCallbacks *sysCallbacks;

View file

@ -462,6 +462,7 @@ xx(Friend)
xx(Strifeally)
xx(Standing)
xx(Countsecret)
xx(NoCount)
xx(Score)
xx(Roll)
xx(Scale)

View file

@ -34,6 +34,7 @@ struct FRemapTable
int Index;
int NumEntries; // # of elements in this table (usually 256)
bool Inactive = false; // This table is inactive and should be treated as if it was passed as NULL
bool TwodOnly = false; // Only used for 2D rendering
bool ForFont = false; // Mark font translations because they may require different handling than the ones for sprites-
private:

View file

@ -1062,7 +1062,6 @@ FSerializer &Serialize(FSerializer &arc, const char *key, float &value, float *d
FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTextureID *defval)
{
#if 0
if (arc.isWriting())
{
if (!arc.w->inObject() || defval == nullptr || value != *defval)
@ -1140,7 +1139,6 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTe
}
}
}
#endif
return arc;
}

View file

@ -89,6 +89,7 @@ FFont* SmallFont, * SmallFont2, * BigFont, * BigUpper, * ConFont, * Intermission
FFont *FFont::FirstFont = nullptr;
int NumTextColors;
static bool translationsLoaded;
// PRIVATE DATA DEFINITIONS ------------------------------------------------
@ -138,7 +139,9 @@ FFont *V_GetFont(const char *name, const char *fontlumpname)
head == MAKE_ID(0xE1,0xE6,0xD5,0x1A))
{
FFont *CreateSingleLumpFont (const char *fontname, int lump);
return CreateSingleLumpFont (name, lump);
font = CreateSingleLumpFont (name, lump);
if (translationsLoaded) font->LoadTranslations();
return font;
}
}
FTextureID picnum = TexMan.CheckForTexture (name, ETextureType::Any);
@ -148,12 +151,15 @@ FFont *V_GetFont(const char *name, const char *fontlumpname)
if (tex && tex->GetSourceLump() >= folderfile)
{
FFont *CreateSinglePicFont(const char *name);
return CreateSinglePicFont (name);
font = CreateSinglePicFont (name);
return font;
}
}
if (folderdata.Size() > 0)
{
return new FFont(name, nullptr, name, HU_FONTSTART, HU_FONTSIZE, 1, -1);
font = new FFont(name, nullptr, name, HU_FONTSTART, HU_FONTSIZE, 1, -1);
if (translationsLoaded) font->LoadTranslations();
return font;
}
}
return font;
@ -728,13 +734,6 @@ void V_InitFonts()
OriginalSmallFont = new FFont("OriginalSmallFont", "STCFN%.3d", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1, -1, false, true);
}
if (SmallFont)
{
uint32_t colors[256] = {};
SmallFont->RecordAllTextureColors(colors);
if (OriginalSmallFont != nullptr) OriginalSmallFont->SetDefaultTranslation(colors);
NewSmallFont->SetDefaultTranslation(colors);
}
if (!(SmallFont2 = V_GetFont("SmallFont2"))) // Only used by Strife
{
@ -770,13 +769,6 @@ void V_InitFonts()
OriginalBigFont = new FFont("OriginalBigFont", nullptr, "bigfont", HU_FONTSTART, HU_FONTSIZE, 1, -1, -1, false, true);
}
if (BigFont)
{
uint32_t colors[256] = {};
BigFont->RecordAllTextureColors(colors);
if (OriginalBigFont != nullptr) OriginalBigFont->SetDefaultTranslation(colors);
}
// let PWAD BIGFONTs override the stock BIGUPPER font. (This check needs to be made smarter.)
if (BigUpper && BigFont->Type != FFont::Folder && BigUpper->Type == FFont::Folder)
{
@ -833,7 +825,22 @@ void V_LoadTranslations()
for (auto font = FFont::FirstFont; font; font = font->Next)
{
if (!font->noTranslate) font->LoadTranslations();
else font->ActiveColors = 0;
}
if (BigFont)
{
uint32_t colors[256] = {};
BigFont->RecordAllTextureColors(colors);
if (OriginalBigFont != nullptr) OriginalBigFont->SetDefaultTranslation(colors);
}
if (SmallFont)
{
uint32_t colors[256] = {};
SmallFont->RecordAllTextureColors(colors);
if (OriginalSmallFont != nullptr) OriginalSmallFont->SetDefaultTranslation(colors);
NewSmallFont->SetDefaultTranslation(colors);
}
translationsLoaded = true;
}
void V_ClearFonts()

View file

@ -38,7 +38,6 @@
#include "palentry.h"
#include "name.h"
class DCanvas;
class FGameTexture;
struct FRemapTable;
@ -156,7 +155,7 @@ protected:
int TranslationType = 0;
int Displacement = 0;
char Cursor;
bool noTranslate;
bool noTranslate = false;
bool translateUntranslated;
bool MixedCase = false;
bool forceremap = false;
@ -167,7 +166,7 @@ protected:
int XMove = INT_MIN;
};
TArray<CharData> Chars;
int ActiveColors;
int ActiveColors = -1;
TArray<int> Translations;
uint8_t PatchRemap[256];

View file

@ -110,7 +110,7 @@ enum EInPlace { EC_InPlace };
#define DECLARE_ABSTRACT_CLASS(cls,parent) \
public: \
virtual PClass *StaticType() const; \
PClass *StaticType() const override; \
static ClassReg RegistrationInfo, * const RegistrationInfoPtr; \
typedef parent Super; \
private: \

View file

@ -46,6 +46,7 @@
#include "i_interface.h"
#include "menustate.h"
#include "engineerrors.h"
#include "keydef.h"
EXTERN_CVAR(Int, m_use_mouse)

View file

@ -53,7 +53,7 @@ void CalculateCPUSpeed()
PerfToSec = 1.0 / frequency;
PerfToMillisec = 1000.0 / frequency;
//if (!batchrun)
if (!batchrun)
{
Printf("CPU speed: %.0f MHz\n", 0.001 / PerfToMillisec);
}

View file

@ -53,12 +53,12 @@
#include "version.h"
#include "printf.h"
#include "gl/system/gl_framebuffer.h"
#include "gl_framebuffer.h"
#ifdef HAVE_VULKAN
#include "vulkan/system/vk_framebuffer.h"
#endif
#ifdef HAVE_SOFTPOLY
#include "rendering/polyrenderer/backend/poly_framebuffer.h"
#include "poly_framebuffer.h"
#endif
extern bool ToggleFullscreen;
@ -807,7 +807,7 @@ CUSTOM_CVAR(Bool, vid_hidpi, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINI
// ---------------------------------------------------------------------------
bool I_SetCursor(FTexture *cursorpic)
bool I_SetCursor(FGameTexture *cursorpic)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSCursor* cursor = nil;

View file

@ -1,24 +1,33 @@
//-----------------------------------------------------------------------------
//
// Copyright 1993-1996 id Software
// Copyright 1999-2016 Randy Heit
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//
//-----------------------------------------------------------------------------
//
/*
**---------------------------------------------------------------------------
** Copyright 2016 Randy Heit
** 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 <fnmatch.h>
#ifdef __APPLE__
@ -26,7 +35,6 @@
#endif // __APPLE__
#include "cmdlib.h"
#include "d_protocol.h"
#include "i_system.h"
#include "gameconfigfile.h"
#include "x86.h"

View file

@ -53,7 +53,6 @@
// MACROS ------------------------------------------------------------------
// TYPES -------------------------------------------------------------------
bool batchrun;
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------

View file

@ -34,6 +34,7 @@
// HEADER FILES ------------------------------------------------------------
#include "i_module.h"
#include "i_soundinternal.h"
#include "i_system.h"
#include "i_video.h"
#include "m_argv.h"
@ -47,15 +48,15 @@
#include "gl_sysfb.h"
#include "gl_system.h"
#include "gl/renderer/gl_renderer.h"
#include "gl/system/gl_framebuffer.h"
#include "gl_renderer.h"
#include "gl_framebuffer.h"
#ifdef HAVE_VULKAN
#include "rendering/vulkan/system/vk_framebuffer.h"
#include "vulkan/system/vk_framebuffer.h"
#endif
#ifdef HAVE_SOFTPOLY
#include "rendering/polyrenderer/backend/poly_framebuffer.h"
#include "poly_framebuffer.h"
#endif
// MACROS ------------------------------------------------------------------

View file

@ -52,7 +52,7 @@
#include "win32basevideo.h"
#include "cmdlib.h"
#include "gl/system/gl_framebuffer.h"
#include "gl_framebuffer.h"
CVAR(Int, vid_adapter, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)

View file

@ -53,7 +53,7 @@
#include "engineerrors.h"
#include "win32glvideo.h"
#include "gl/system/gl_framebuffer.h"
#include "gl_framebuffer.h"
EXTERN_CVAR(Int, vid_adapter)
EXTERN_CVAR(Bool, vid_hdr)

View file

@ -2,7 +2,7 @@
#include "win32basevideo.h"
#include "c_cvars.h"
#include "rendering/polyrenderer/backend/poly_framebuffer.h"
#include "poly_framebuffer.h"
EXTERN_CVAR(Bool, vid_fullscreen)

View file

@ -2,7 +2,7 @@
#include "win32basevideo.h"
#include "c_cvars.h"
#include "rendering/vulkan/system/vk_framebuffer.h"
#include "vulkan/system/vk_framebuffer.h"
EXTERN_CVAR(Bool, vid_fullscreen)

View file

@ -18,10 +18,6 @@
** 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.
** 4. When not used as part of ZDoom or a ZDoom derivative, this code will be
** covered by the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or (at
** your option) any later version.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@ -48,7 +44,6 @@
#include "m_random.h"
#include "v_font.h"
#include "templates.h"
#include "palutil.h"
extern FRandom pr_exrandom;
FMemArena FxAlloc(65536);
@ -2918,7 +2913,6 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build)
texcheck:
// Do a bounds check for the texture index. Note that count can change at run time so this needs to read the value from the texture manager.
#if 0
auto * ptr = (FArray*)&TexMan.Textures;
auto * countptr = &ptr->Count;
ExpEmit bndp(build, REGT_POINTER);
@ -2928,7 +2922,6 @@ texcheck:
build->Emit(OP_BOUND_R, to.RegNum, bndc.RegNum);
bndp.Free(build);
bndc.Free(build);
#endif
return to;
}
@ -6365,7 +6358,7 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx)
if (Object->ValueType->isRealPointer())
{
auto ptype = Object->ValueType->toPointer()->PointedType;
if (ptype->isContainer())
if (ptype && ptype->isContainer())
{
auto ret = ResolveMember(ctx, ctx.Class, Object, static_cast<PContainerType *>(ptype));
delete this;

View file

@ -43,7 +43,7 @@ void Dictionary::Serialize(FSerializer &arc)
Dictionary *pointerToDeserializedDictionary;
arc(key, pointerToDeserializedDictionary);
Map.TransferFrom(pointerToDeserializedDictionary->Map);
delete pointerToDeserializedDictionary;
pointerToDeserializedDictionary->Destroy();
}
}
@ -62,7 +62,7 @@ static void DictInsert(Dictionary *dict, const FString &key, const FString &valu
static void DictAt(const Dictionary *dict, const FString &key, FString *result)
{
const FString *value = dict->Map.CheckKey(key);
*result = value ? *value : FString("");
*result = value ? *value : FString();
}
static void DictToString(const Dictionary *dict, FString *result)

View file

@ -18,10 +18,6 @@
** 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.
** 4. When not used as part of ZDoom or a ZDoom derivative, this code will be
** covered by the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or (at
** your option) any later version.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

View file

@ -19,10 +19,6 @@
** 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.
** 4. When not used as part of ZDoom or a ZDoom derivative, this code will be
** covered by the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or (at
** your option) any later version.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

View file

@ -19,10 +19,6 @@
** 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.
** 4. When not used as part of ZDoom or a ZDoom derivative, this code will be
** covered by the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or (at
** your option) any later version.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

View file

@ -92,7 +92,7 @@ struct TexInit
{
FString TexName;
ETextureType UseType = ETextureType::Null;
FImageTexture *Texture = nullptr;
FGameTexture *GameTexture = nullptr;
bool Silent = false;
bool HasLine = false;
bool UseOffsets = false;

View file

@ -430,7 +430,7 @@ CUSTOM_CVAR(Int, r_spriteadjust, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
float FTexCoordInfo::RowOffset(float rowoffset) const
{
float scale = fabs(mScale.Y);
float scale = fabsf(mScale.Y);
if (scale == 1.f || mWorldPanning) return rowoffset;
else return rowoffset / scale;
}
@ -443,7 +443,7 @@ float FTexCoordInfo::RowOffset(float rowoffset) const
float FTexCoordInfo::TextureOffset(float textureoffset) const
{
float scale = fabs(mScale.X);
float scale = fabsf(mScale.X);
if (scale == 1.f || mWorldPanning) return textureoffset;
else return textureoffset / scale;
}
@ -458,7 +458,7 @@ float FTexCoordInfo::TextureAdjustWidth() const
{
if (mWorldPanning)
{
float tscale = fabs(mTempScale.X);
float tscale = fabsf(mTempScale.X);
if (tscale == 1.f) return (float)mRenderWidth;
else return mWidth / fabs(tscale);
}

View file

@ -84,7 +84,7 @@ class FGameTexture
float DisplayWidth, DisplayHeight;
float ScaleX, ScaleY;
int8_t shouldUpscaleFlag = 0; // Without explicit setup, scaling is disabled for a texture.
int8_t shouldUpscaleFlag = 1;
ETextureType UseType = ETextureType::Wall; // This texture's primary purpose
SpritePositioningInfo* spi = nullptr;
@ -133,7 +133,7 @@ public:
ETextureType GetUseType() const { return UseType; }
void SetUpscaleFlag(int what) { shouldUpscaleFlag = what; }
int GetUpscaleFlag() { return shouldUpscaleFlag; }
int GetUpscaleFlag() { return shouldUpscaleFlag == 1; }
FTexture* GetTexture() { return Base.get(); }
int GetSourceLump() const { return Base->GetSourceLump(); }
@ -208,6 +208,7 @@ public:
void CopySize(FGameTexture* BaseTexture)
{
Base->CopySize(BaseTexture->Base.get());
SetDisplaySize(BaseTexture->GetDisplayWidth(), BaseTexture->GetDisplayHeight());
}
// Glowing is a pure material property that should not filter down to the actual texture objects.
@ -235,12 +236,20 @@ public:
DisplayHeight = h;
ScaleX = TexelWidth / w;
ScaleY = TexelHeight / h;
if (shouldUpscaleFlag < 2)
{
shouldUpscaleFlag = ScaleX < 2 && ScaleY < 2;
}
// compensate for roundoff errors
if (int(ScaleX * w) != TexelWidth) ScaleX += (1 / 65536.);
if (int(ScaleY * h) != TexelHeight) ScaleY += (1 / 65536.);
}
void SetBase(FTexture* Tex)
{
Base = Tex;
}
void SetOffsets(int which, int x, int y)
{
LeftOffset[which] = x;
@ -257,8 +266,12 @@ public:
{
ScaleX = x;
ScaleY = y;
DisplayWidth = x * TexelWidth;
DisplayHeight = y * TexelHeight;
if (shouldUpscaleFlag < 2)
{
shouldUpscaleFlag = ScaleX < 2 && ScaleY < 2;
}
DisplayWidth = TexelWidth / x;
DisplayHeight = TexelHeight / y;
}
const SpritePositioningInfo& GetSpritePositioning(int which) { if (spi == nullptr) SetupSpriteData(); return spi[which]; }

View file

@ -514,7 +514,7 @@ int calcShouldUpscale(FGameTexture *tex)
return 0;
// already scaled?
if (tex->GetDisplayWidth() >= 2* tex->GetTexelWidth() || tex->GetDisplayHeight() >= 2*tex->GetTexelHeight())
if (tex->GetScaleX() >= 2.f || tex->GetScaleY() > 2.f)
return 0;
return CTF_Upscale;

View file

@ -175,10 +175,8 @@ int FImageSource::CopyPixels(FBitmap *bmp, int conversion)
{
if (conversion == luminance) conversion = normal; // luminance images have no use as an RGB source.
PalEntry *palette = GPalette.BaseColors;
for(int i=1;i<256;i++) palette[i].a = 255; // set proper alpha values
auto ppix = CreatePalettedPixels(conversion);
bmp->CopyPixelData(0, 0, ppix.Data(), Width, Height, Height, 1, 0, palette, nullptr);
for(int i=1;i<256;i++) palette[i].a = 0;
return 0;
}

View file

@ -60,11 +60,11 @@ FImageTexture::FImageTexture(FImageSource *img) noexcept
void FImageTexture::SetFromImage()
{
auto img = mImage;
Width = img->GetWidth();
Height = img->GetHeight();
Width = img->GetWidth();
Height = img->GetHeight();
Masked = img->bMasked;
bTranslucent = img->bTranslucent;
bTranslucent = img->bTranslucent;
}
//===========================================================================
//
@ -72,9 +72,9 @@ void FImageTexture::SetFromImage()
//
//===========================================================================
FBitmap FImageTexture::GetBgraBitmap(const PalEntry* p, int* trans)
FBitmap FImageTexture::GetBgraBitmap(const PalEntry *p, int *trans)
{
return mImage->GetCachedBitmap(p, bNoRemap0 ? FImageSource::noremap0 : FImageSource::normal, trans);
return mImage->GetCachedBitmap(p, bNoRemap0? FImageSource::noremap0 : FImageSource::normal, trans);
}
//===========================================================================
@ -85,7 +85,7 @@ FBitmap FImageTexture::GetBgraBitmap(const PalEntry* p, int* trans)
TArray<uint8_t> FImageTexture::Get8BitPixels(bool alpha)
{
return mImage->GetPalettedPixels(alpha ? alpha : bNoRemap0 ? FImageSource::noremap0 : FImageSource::normal);
return mImage->GetPalettedPixels(alpha? alpha : bNoRemap0 ? FImageSource::noremap0 : FImageSource::normal);
}
//===========================================================================

View file

@ -138,17 +138,18 @@ void FMultipatchTextureBuilder::MakeTexture(BuildInfo &buildinfo, ETextureType u
{
buildinfo.texture = new FGameTexture(nullptr, buildinfo.Name);
buildinfo.texture->SetUseType(usetype);
buildinfo.texture->SetSize(buildinfo.Width, buildinfo.Height);
buildinfo.texture->SetOffsets(0, buildinfo.LeftOffset[0], buildinfo.TopOffset[0]); // These are needed for construction of other multipatch textures.
buildinfo.texture->SetOffsets(1, buildinfo.LeftOffset[1], buildinfo.TopOffset[1]);
buildinfo.texture->SetScale((float)buildinfo.Scale.X, (float)buildinfo.Scale.X);
buildinfo.texture->SetWorldPanning(buildinfo.bWorldPanning);
buildinfo.texture->SetNoDecals(buildinfo.bNoDecals);
TexMan.AddGameTexture(buildinfo.texture);
}
void FMultipatchTextureBuilder::AddImageToTexture(FImageTexture *tex, BuildInfo& buildinfo)
{
buildinfo.texture->Setup(tex);
buildinfo.texture->SetOffsets(0, buildinfo.LeftOffset[0], buildinfo.TopOffset[0]);
buildinfo.texture->SetOffsets(1, buildinfo.LeftOffset[1], buildinfo.TopOffset[1]);
buildinfo.texture->SetScale((float)buildinfo.Scale.X, (float)buildinfo.Scale.X);
buildinfo.texture->SetWorldPanning(buildinfo.bWorldPanning);
buildinfo.texture->SetNoDecals(buildinfo.bNoDecals);
buildinfo.texture->SetBase(tex);
calcShouldUpscale(buildinfo.texture); // calculate this once at insertion
}
@ -812,10 +813,10 @@ void FMultipatchTextureBuilder::ResolvePatches(BuildInfo &buildinfo)
{
FGameTexture *tex = TexMan.GetGameTexture(texno);
if (tex != nullptr && tex->isValid() && dynamic_cast<FImageTexture*>(tex->GetTexture()))
if (tex != nullptr && tex->isValid() && (tex->GetTexture() == nullptr || dynamic_cast<FImageTexture*>(tex->GetTexture())))
{
//We cannot set the image source yet. First all textures need to be resolved.
buildinfo.Inits[i].Texture = static_cast<FImageTexture*>(tex->GetTexture());
//We cannot set the image texture yet. First all textures need to be resolved.
buildinfo.Inits[i].GameTexture = tex;
bool iscomplex = !!complex.CheckKey(tex);
if (iscomplex) complex.Insert(buildinfo.texture, true);
buildinfo.bComplex |= iscomplex;
@ -830,13 +831,15 @@ void FMultipatchTextureBuilder::ResolvePatches(BuildInfo &buildinfo)
// The patch is bogus. Remove it.
if (buildinfo.Inits[i].HasLine) buildinfo.Inits[i].sc.Message(MSG_WARNING, "Invalid patch '%s' in texture '%s'\n", buildinfo.Inits[i].TexName.GetChars(), buildinfo.Name.GetChars());
else Printf(TEXTCOLOR_YELLOW "Invalid patch '%s' in texture '%s'\n", buildinfo.Inits[i].TexName.GetChars(), buildinfo.Name.GetChars());
buildinfo.Inits.Delete(i);
buildinfo.Parts.Delete(i);
i--;
}
}
}
for (unsigned i = 0; i < buildinfo.Inits.Size(); i++)
{
if (buildinfo.Inits[i].Texture == nullptr)
if (buildinfo.Inits[i].GameTexture == nullptr)
{
buildinfo.Inits.Delete(i);
buildinfo.Parts.Delete(i);
@ -876,10 +879,10 @@ void FMultipatchTextureBuilder::ResolveAllPatches()
{
if (buildinfo.Parts[j].TexImage == nullptr)
{
auto image = buildinfo.Inits[j].Texture;
if (image->GetImage() != nullptr)
auto image = buildinfo.Inits[j].GameTexture->GetTexture();
if (image && image->GetImage() != nullptr)
{
buildinfo.Parts[j].TexImage = image;
buildinfo.Parts[j].TexImage = static_cast<FImageTexture*>(image);
donesomething = true;
}
else hasEmpty = true;
@ -901,7 +904,6 @@ void FMultipatchTextureBuilder::ResolveAllPatches()
!buildinfo.bComplex)
{
AddImageToTexture(buildinfo.Parts[0].TexImage, buildinfo);
buildinfo.texture->Setup(buildinfo.Parts[0].TexImage);
done = true;
}
}

View file

@ -31,7 +31,6 @@
**
*/
#include "filesystem.h"
#include "textures.h"
#include "skyboxtexture.h"

View file

@ -50,6 +50,12 @@ private:
int texnum;
};
class FNullTextureID : public FTextureID
{
public:
FNullTextureID() : FTextureID(0) {}
};
// This is for the script interface which needs to do casts from int to texture.
class FSetTextureID : public FTextureID
{

View file

@ -1541,3 +1541,9 @@ FTextureID FTextureID::operator +(int offset) throw()
if (texnum + offset >= TexMan.NumTextures()) return FTextureID(-1);
return FTextureID(texnum + offset);
}
CCMD(flushtextures)
{
TexMan.FlushAll();
}

View file

@ -4,13 +4,13 @@
#include "tarray.h"
#include "textureid.h"
#include "basics.h"
#include "sc_man.h"
#include "texmanip.h"
#include "name.h"
class FxAddSub;
struct BuildInfo;
class FMultipatchTextureBuilder;
class FScanner;
int PalCheck(int tex);
// Texture manager

View file

@ -124,12 +124,6 @@ class FMultipatchTextureBuilder;
extern int r_spriteadjustSW, r_spriteadjustHW;
class FNullTextureID : public FTextureID
{
public:
FNullTextureID() : FTextureID(0) {}
};
enum FTextureFormat : uint32_t
{
TEX_Pal,
@ -287,7 +281,6 @@ public:
public:
FTextureBuffer CreateTexBuffer(int translation, int flags = 0);
virtual bool DetermineTranslucency();
bool GetTranslucency()
{
@ -359,7 +352,7 @@ protected:
void SetFromImage();
public:
FImageTexture(FImageSource* image) noexcept;
virtual TArray<uint8_t> Get8BitPixels(bool alphatex);
TArray<uint8_t> Get8BitPixels(bool alphatex) override;
void SetImage(FImageSource* img)
{

View file

@ -0,0 +1,82 @@
/*
** v_collection.cpp
** Holds a collection of images
**
**---------------------------------------------------------------------------
** Copyright 1998-2006 Randy Heit
** 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 "v_collection.h"
#include "v_font.h"
#include "v_video.h"
#include "filesystem.h"
#include "texturemanager.h"
FImageCollection::FImageCollection ()
{
}
FImageCollection::FImageCollection (const char **patchNames, int numPatches)
{
Add (patchNames, numPatches);
}
void FImageCollection::Init (const char **patchNames, int numPatches, ETextureType namespc)
{
ImageMap.Clear();
Add(patchNames, numPatches, namespc);
}
// [MH] Mainly for mugshots with skins and SBARINFO
void FImageCollection::Add (const char **patchNames, int numPatches, ETextureType namespc)
{
int OldCount = ImageMap.Size();
ImageMap.Resize(OldCount + numPatches);
for (int i = 0; i < numPatches; ++i)
{
FTextureID picnum = TexMan.CheckForTexture(patchNames[i], namespc);
ImageMap[OldCount + i] = picnum;
}
}
void FImageCollection::Uninit ()
{
ImageMap.Clear();
}
FGameTexture *FImageCollection::operator[] (int index) const
{
if ((unsigned int)index >= ImageMap.Size())
{
return NULL;
}
return ImageMap[index].Exists()? TexMan.GetGameTexture(ImageMap[index], true) : NULL;
}

View file

@ -0,0 +1,58 @@
/*
** v_collection.h
**
**---------------------------------------------------------------------------
** Copyright 1998-2006 Randy Heit
** 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.
**---------------------------------------------------------------------------
**
*/
#ifndef __V_COLLECTION_H__
#define __V_COLLECTION_H__
#include "tarray.h"
#include "textureid.h"
class FGameTexture;
class FImageCollection
{
public:
FImageCollection();
FImageCollection(const char **patchNames, int numPatches);
void Init(const char **patchnames, int numPatches, ETextureType namespc = ETextureType::Any);
void Add(const char **patchnames, int numPatches, ETextureType namespc = ETextureType::Any);
void Uninit();
FGameTexture *operator[] (int index) const;
protected:
TArray<FTextureID> ImageMap;
};
#endif //__V_COLLECTION_H__

View file

@ -3,6 +3,9 @@
#include <stddef.h>
#include <stdint.h>
#define MAXWIDTH 12000
#define MAXHEIGHT 5000
//
// fixed point, 32bit as 16.16.
//

View file

@ -39,15 +39,15 @@
#include "files.h"
#include "md5.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#ifndef _WIN32
#include <pwd.h>
#include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
/*
progdir will hold the path up to the game directory, including the slash

View file

@ -43,6 +43,8 @@
#include <unistd.h>
#include <fnmatch.h>
#include "cmdlib.h"
static const char *pattern;
static int matchfile(const struct dirent *ent)

View file

@ -10,6 +10,7 @@ enum
};
#ifndef _WIN32
#include <dirent.h>
struct findstate_t

View file

@ -0,0 +1,31 @@
#pragma once
struct IntRect
{
int left, top;
int width, height;
void Offset(int xofs, int yofs)
{
left += xofs;
top += yofs;
}
void AddToRect(int x, int y)
{
if (x < left)
left = x;
if (x > left + width)
width = x - left;
if (y < top)
top = y;
if (y > top + height)
height = y - top;
}
};

View file

@ -0,0 +1,87 @@
#ifndef __M_BBOX_H__
#define __M_BBOX_H__
#include <float.h>
#include "vectors.h"
enum
{
BOXTOP,
BOXBOTTOM,
BOXLEFT,
BOXRIGHT
}; // bbox coordinates
class FBoundingBox
{
public:
FBoundingBox()
{
ClearBox();
}
FBoundingBox(double left, double bottom, double right, double top)
{
m_Box[BOXTOP] = top;
m_Box[BOXLEFT] = left;
m_Box[BOXRIGHT] = right;
m_Box[BOXBOTTOM] = bottom;
}
FBoundingBox(double x, double y, double radius)
{
setBox(x, y, radius);
}
void setBox(double x, double y, double radius)
{
m_Box[BOXTOP] = y + radius;
m_Box[BOXLEFT] = x - radius;
m_Box[BOXRIGHT] = x + radius;
m_Box[BOXBOTTOM] = y - radius;
}
void ClearBox ()
{
m_Box[BOXTOP] = m_Box[BOXRIGHT] = -FLT_MAX;
m_Box[BOXBOTTOM] = m_Box[BOXLEFT] = FLT_MAX;
}
// Returns a bounding box that encloses both bounding boxes
FBoundingBox operator | (const FBoundingBox &box2) const
{
return FBoundingBox(m_Box[BOXLEFT] < box2.m_Box[BOXLEFT] ? m_Box[BOXLEFT] : box2.m_Box[BOXLEFT],
m_Box[BOXBOTTOM] < box2.m_Box[BOXBOTTOM] ? m_Box[BOXBOTTOM] : box2.m_Box[BOXBOTTOM],
m_Box[BOXRIGHT] > box2.m_Box[BOXRIGHT] ? m_Box[BOXRIGHT] : box2.m_Box[BOXRIGHT],
m_Box[BOXTOP] > box2.m_Box[BOXTOP] ? m_Box[BOXTOP] : box2.m_Box[BOXTOP]);
}
void AddToBox(const DVector2 &pos)
{
if (pos.X < m_Box[BOXLEFT])
m_Box[BOXLEFT] = pos.X;
if (pos.X > m_Box[BOXRIGHT])
m_Box[BOXRIGHT] = pos.X;
if (pos.Y < m_Box[BOXBOTTOM])
m_Box[BOXBOTTOM] = pos.Y;
if (pos.Y > m_Box[BOXTOP])
m_Box[BOXTOP] = pos.Y;
}
inline double Top () const { return m_Box[BOXTOP]; }
inline double Bottom () const { return m_Box[BOXBOTTOM]; }
inline double Left () const { return m_Box[BOXLEFT]; }
inline double Right () const { return m_Box[BOXRIGHT]; }
void Set(int index, double value) {m_Box[index] = value;}
protected:
double m_Box[4];
};
#endif //__M_BBOX_H__

View file

@ -0,0 +1,101 @@
/*
** Render memory allocation
** Copyright (c) 2016-2020 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#include <stdlib.h>
#include "templates.h"
#include "r_memory.h"
#include <stdlib.h>
void *RenderMemory::AllocBytes(int size)
{
size = (size + 15) / 16 * 16; // 16-byte align
if (UsedBlocks.empty() || UsedBlocks.back()->Position + size > BlockSize)
{
if (!FreeBlocks.empty())
{
auto block = std::move(FreeBlocks.back());
block->Position = 0;
FreeBlocks.pop_back();
UsedBlocks.push_back(std::move(block));
}
else
{
UsedBlocks.push_back(std::unique_ptr<MemoryBlock>(new MemoryBlock()));
}
}
auto &block = UsedBlocks.back();
void *data = block->Data + block->Position;
block->Position += size;
return data;
}
void RenderMemory::Clear()
{
while (!UsedBlocks.empty())
{
auto block = std::move(UsedBlocks.back());
UsedBlocks.pop_back();
FreeBlocks.push_back(std::move(block));
}
}
static void* Aligned_Alloc(size_t alignment, size_t size)
{
void* ptr;
#if defined (_MSC_VER) || defined (__MINGW32__)
ptr = _aligned_malloc(size, alignment);
if (!ptr)
throw std::bad_alloc();
#else
// posix_memalign required alignment to be a min of sizeof(void *)
if (alignment < sizeof(void*))
alignment = sizeof(void*);
if (posix_memalign((void**)&ptr, alignment, size))
throw std::bad_alloc();
#endif
return ptr;
}
static void Aligned_Free(void* ptr)
{
if (ptr)
{
#if defined _MSC_VER
_aligned_free(ptr);
#else
free(ptr);
#endif
}
}
RenderMemory::MemoryBlock::MemoryBlock() : Data(static_cast<uint8_t*>(Aligned_Alloc(16, BlockSize))), Position(0)
{
}
RenderMemory::MemoryBlock::~MemoryBlock()
{
Aligned_Free(Data);
}

View file

@ -0,0 +1,43 @@
#pragma once
#include <memory>
#include <vector>
// Memory needed for the duration of a frame rendering
class RenderMemory
{
public:
void Clear();
template<typename T>
T *AllocMemory(int size = 1)
{
return (T*)AllocBytes(sizeof(T) * size);
}
template<typename T, typename... Types>
T *NewObject(Types &&... args)
{
void *ptr = AllocBytes(sizeof(T));
return new (ptr)T(std::forward<Types>(args)...);
}
private:
void *AllocBytes(int size);
enum { BlockSize = 1024 * 1024 };
struct MemoryBlock
{
MemoryBlock();
~MemoryBlock();
MemoryBlock(const MemoryBlock &) = delete;
MemoryBlock &operator=(const MemoryBlock &) = delete;
uint8_t *Data;
uint32_t Position;
};
std::vector<std::unique_ptr<MemoryBlock>> UsedBlocks;
std::vector<std::unique_ptr<MemoryBlock>> FreeBlocks;
};

View file

@ -0,0 +1,166 @@
/*
** weightedlist.h
** A weighted list template class
**
**---------------------------------------------------------------------------
** Copyright 1998-2006 Randy Heit
** 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 <stdlib.h>
#include <stdint.h>
class FRandom;
template<class T>
class TWeightedList
{
template<class U>
struct Choice
{
Choice(uint16_t w, U v) : Next(NULL), Weight(w), RandomVal(0), Value(v) {}
Choice<U> *Next;
uint16_t Weight;
uint8_t RandomVal; // 0 (never) - 255 (always)
T Value;
};
public:
TWeightedList (FRandom &pr) : Choices (NULL), RandomClass (pr) {}
~TWeightedList ()
{
Choice<T> *choice = Choices;
while (choice != NULL)
{
Choice<T> *next = choice->Next;
delete choice;
choice = next;
}
}
void AddEntry (T value, uint16_t weight);
T PickEntry () const;
void ReplaceValues (T oldval, T newval);
private:
Choice<T> *Choices;
FRandom &RandomClass;
void RecalcRandomVals ();
TWeightedList &operator= (const TWeightedList &) { return *this; }
};
template<class T>
void TWeightedList<T>::AddEntry (T value, uint16_t weight)
{
if (weight == 0)
{ // If the weight is 0, don't bother adding it,
// since it will never be chosen.
return;
}
Choice<T> **insAfter = &Choices, *insBefore = Choices;
Choice<T> *theNewOne;
while (insBefore != NULL && insBefore->Weight < weight)
{
insAfter = &insBefore->Next;
insBefore = insBefore->Next;
}
theNewOne = new Choice<T> (weight, value);
*insAfter = theNewOne;
theNewOne->Next = insBefore;
RecalcRandomVals ();
}
template<class T>
T TWeightedList<T>::PickEntry () const
{
uint8_t randomnum = RandomClass();
Choice<T> *choice = Choices;
while (choice != NULL && randomnum > choice->RandomVal)
{
choice = choice->Next;
}
return choice != NULL ? choice->Value : NULL;
}
template<class T>
void TWeightedList<T>::RecalcRandomVals ()
{
// Redistribute the RandomVals so that they form the correct
// distribution (as determined by the range of weights).
int numChoices, weightSums;
Choice<T> *choice;
double randVal, weightDenom;
if (Choices == NULL)
{ // No choices, so nothing to do.
return;
}
numChoices = 1;
weightSums = 0;
for (choice = Choices; choice->Next != NULL; choice = choice->Next)
{
++numChoices;
weightSums += choice->Weight;
}
weightSums += choice->Weight;
choice->RandomVal = 255; // The last choice is always randomval 255
randVal = 0.0;
weightDenom = 1.0 / (double)weightSums;
for (choice = Choices; choice->Next != NULL; choice = choice->Next)
{
randVal += (double)choice->Weight * weightDenom;
choice->RandomVal = (uint8_t)(randVal * 255.0);
}
}
// Replace all values that match oldval with newval
template<class T>
void TWeightedList<T>::ReplaceValues(T oldval, T newval)
{
Choice<T> *choice;
for (choice = Choices; choice != NULL; choice = choice->Next)
{
if (choice->Value == oldval)
{
choice->Value = newval;
}
}
}

View file

@ -41,6 +41,7 @@
#include "renderstyle.h"
#include "c_cvars.h"
#include "v_2ddrawer.h"
#include "intrect.h"
//#include "hwrenderer/dynlights/hw_shadowmap.h"
static const int VID_MIN_WIDTH = 640;
@ -79,35 +80,6 @@ enum EHWCaps
};
struct IntRect
{
int left, top;
int width, height;
void Offset(int xofs, int yofs)
{
left += xofs;
top += yofs;
}
void AddToRect(int x, int y)
{
if (x < left)
left = x;
if (x > left + width)
width = x - left;
if (y < top)
top = y;
if (y > top + height)
height = y - top;
}
};
extern int DisplayWidth, DisplayHeight;
void V_UpdateModeSize (int width, int height);