- Backend update from Raze

This commit is contained in:
Christoph Oelckers 2021-04-19 12:58:35 +02:00
parent 55ce0510c2
commit ba146ed5e5
43 changed files with 473 additions and 168 deletions

View file

@ -189,8 +189,9 @@ DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, PushTriangle, Shape2D_PushTriangle)
//
//==========================================================================
int F2DDrawer::AddCommand(const RenderCommand *data)
int F2DDrawer::AddCommand(RenderCommand *data)
{
data->mScreenFade = screenFade;
if (mData.Size() > 0 && data->isCompatible(mData.Last()))
{
// Merge with the last command.
@ -738,12 +739,12 @@ void F2DDrawer::AddPoly(FGameTexture *texture, FVector2 *points, int npoints,
//
//==========================================================================
void F2DDrawer::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 F2DDrawer::AddPoly(FGameTexture* img, FVector4* vt, size_t vtcount, const unsigned int* ind, size_t idxcount, int translation, PalEntry color, FRenderStyle style, int clipx1, int clipy1, int clipx2, int clipy2)
{
RenderCommand dg;
int method = 0;
if (!img->isValid()) return;
if (!img || !img->isValid()) return;
dg.mType = DrawTypeTriangles;
if (clipx1 > 0 || clipy1 > 0 || clipx2 < GetWidth() - 1 || clipy2 < GetHeight() - 1)
@ -769,14 +770,28 @@ void F2DDrawer::AddPoly(FGameTexture* img, FVector4* vt, size_t vtcount, unsigne
Set(ptr, vt[i].X, vt[i].Y, 0.f, vt[i].Z, vt[i].W, color);
ptr++;
}
dg.mIndexIndex = mIndices.Size();
mIndices.Reserve(idxcount);
for (size_t i = 0; i < idxcount; i++)
if (idxcount > 0)
{
mIndices[dg.mIndexIndex + i] = ind[i] + dg.mVertIndex;
mIndices.Reserve(idxcount);
for (size_t i = 0; i < idxcount; i++)
{
mIndices[dg.mIndexIndex + i] = ind[i] + dg.mVertIndex;
}
dg.mIndexCount = (int)idxcount;
}
else
{
// If we have no index buffer, treat this as an unindexed list of triangles.
mIndices.Reserve(vtcount);
for (size_t i = 0; i < vtcount; i++)
{
mIndices[dg.mIndexIndex + i] = i + dg.mVertIndex;
}
dg.mIndexCount = (int)vtcount;
}
dg.mIndexCount = (int)idxcount;
AddCommand(&dg);
}
@ -941,6 +956,7 @@ void F2DDrawer::AddColorOnlyQuad(int x1, int y1, int w, int h, PalEntry color, F
{
// 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.
dg.mScreenFade = screenFade;
mData.Insert(0, dg);
}
}

View file

@ -118,6 +118,7 @@ public:
ETexMode mDrawMode;
uint8_t mLightLevel;
uint8_t mFlags;
float mScreenFade;
bool useTransform;
DMatrix3x3 transform;
@ -149,6 +150,7 @@ public:
mLightLevel == other.mLightLevel &&
mColor1.d == other.mColor1.d &&
useTransform == other.useTransform &&
mScreenFade == other.mScreenFade &&
(
!useTransform ||
(
@ -172,7 +174,7 @@ public:
int fullscreenautoaspect = 3;
int cliptop = -1, clipleft = -1, clipwidth = -1, clipheight = -1;
int AddCommand(const RenderCommand *data);
int AddCommand(RenderCommand *data);
void AddIndices(int firstvert, int count, ...);
private:
void AddIndices(int firstvert, TArray<int> &v);
@ -187,7 +189,7 @@ public:
void AddPoly(FGameTexture *texture, FVector2 *points, int npoints,
double originx, double originy, double scalex, double scaley,
DAngle rotation, const FColormap &colormap, PalEntry flatcolor, double lightlevel, uint32_t *indices, size_t indexcount);
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 AddPoly(FGameTexture* img, FVector4 *vt, size_t vtcount, const 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, int local_origin = false, double flatscale = 1.0, PalEntry color = 0xffffffff, ERenderStyle rs = STYLE_Normal);

View file

@ -82,8 +82,11 @@ static MusicCallbacks mus_cb = { nullptr, DefaultOpenMusic };
// PUBLIC DATA DEFINITIONS -------------------------------------------------
EXTERN_CVAR(Int, snd_mididevice)
EXTERN_CVAR(Float, mod_dumb_mastervolume)
EXTERN_CVAR(Float, fluid_gain)
CVAR(Bool, mus_calcgain, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // changing this will only take effect for the next song.
CVAR(Bool, mus_calcgain, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // changing this will only take effect for the next song.
CVAR(Bool, mus_usereplaygain, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // changing this will only take effect for the next song.
CUSTOM_CVAR(Float, mus_gainoffset, 0.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // for customizing the base volume
{
@ -107,13 +110,18 @@ void S_SetMusicCallbacks(MusicCallbacks* cb)
//==========================================================================
static std::unique_ptr<SoundStream> musicStream;
static TArray<SoundStream*> customStreams;
SoundStream *S_CreateCustomStream(size_t size, int samplerate, int numchannels, StreamCallback cb, void *userdata)
{
int flags = 0;
if (numchannels < 2) flags |= SoundStream::Mono;
auto stream = GSnd->CreateStream(cb, int(size), flags, samplerate, userdata);
if (stream) stream->Play(true, 1);
if (stream)
{
stream->Play(true, 1);
customStreams.Push(stream);
}
return stream;
}
@ -122,11 +130,19 @@ void S_StopCustomStream(SoundStream *stream)
if (stream)
{
stream->Stop();
auto f = customStreams.Find(stream);
if (f < customStreams.Size()) customStreams.Delete(f);
delete stream;
}
}
void S_PauseAllCustomStreams(bool on)
{
for (auto s : customStreams)
{
s->SetPaused(on);
}
}
static TArray<int16_t> convert;
static bool FillStream(SoundStream* stream, void* buff, int len, void* userdata)
@ -214,6 +230,9 @@ static bool S_StartMusicPlaying(ZMusic_MusicStream song, bool loop, float rel_vo
I_SetRelativeVolume(saved_relative_volume * factor);
}
ZMusic_Stop(song);
// make sure the volume modifiers update properly in case replay gain settings have changed.
fluid_gain.Callback();
mod_dumb_mastervolume.Callback();
if (!ZMusic_Start(song, subsong, loop))
{
return false;
@ -488,6 +507,8 @@ static void CheckReplayGain(const char *musicname, EMidiDevice playertype, const
{
mus_playing.replayGain = 0.f;
mus_playing.replayGainFactor = dBToAmplitude(mus_gainoffset);
fluid_gain.Callback();
mod_dumb_mastervolume.Callback();
if (!mus_usereplaygain) return;
FileReader reader = mus_cb.OpenMusic(musicname);

View file

@ -41,6 +41,7 @@
#include "version.h"
#include <zmusic.h>
EXTERN_CVAR(Bool, mus_usereplaygain)
//==========================================================================
//
// ADL Midi device
@ -122,7 +123,16 @@ CUSTOM_CVAR(String, fluid_patchset, GAMENAMELOWERCASE, CVAR_ARCHIVE | CVAR_GLOBA
CUSTOM_CVAR(Float, fluid_gain, 0.5, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
FORWARD_CVAR(fluid_gain);
if (!mus_usereplaygain)
{
FORWARD_CVAR(fluid_gain);
}
else
{
// Replay gain will disable the user setting for consistency.
float newval;
ChangeMusicSetting(zmusic_fluid_gain, mus_playing.handle, 0.5f, & newval);
}
}
CUSTOM_CVAR(Bool, fluid_reverb, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
@ -493,6 +503,14 @@ CUSTOM_CVAR(Int, mod_autochip_scan_threshold, 12, CVAR_ARCHIVE | CVAR_GLOBAL
CUSTOM_CVAR(Float, mod_dumb_mastervolume, 1.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
FORWARD_CVAR(mod_dumb_mastervolume);
if (!mus_usereplaygain)
{
FORWARD_CVAR(mod_dumb_mastervolume);
}
else
{
float newval;
ChangeMusicSetting(zmusic_mod_dumb_mastervolume, mus_playing.handle, 0.5f, &newval);
}
}

View file

@ -14,6 +14,7 @@ class SoundStream;
typedef bool(*StreamCallback)(SoundStream* stream, void* buff, int len, void* userdata);
SoundStream *S_CreateCustomStream(size_t size, int samplerate, int numchannels, StreamCallback cb, void *userdata);
void S_StopCustomStream(SoundStream* stream);
void S_PauseAllCustomStreams(bool on);
struct MusicCallbacks
{

View file

@ -31,6 +31,7 @@ enum EChanFlag
CHANF_OVERLAP = 8192, // [MK] Does not stop any sounds in the channel and instead plays over them.
CHANF_LOCAL = 16384, // only plays locally for the calling actor
CHANF_TRANSIENT = 32768, // Do not record in savegames - used for sounds that get restarted outside the sound system (e.g. ambients in SW and Blood)
CHANF_FORCE = 65536, // Start, even if sound is paused.
};
typedef TFlags<EChanFlag> EChanFlags;

View file

@ -528,7 +528,7 @@ FSoundChan *SoundEngine::StartSound(int type, const void *source,
// sound is paused and a non-looped sound is being started.
// Such a sound would play right after unpausing which wouldn't sound right.
if (!(chanflags & CHANF_LOOP) && !(chanflags & (CHANF_UI|CHANF_NOPAUSE)) && SoundPaused)
if (!(chanflags & CHANF_LOOP) && !(chanflags & (CHANF_UI|CHANF_NOPAUSE|CHANF_FORCE)) && SoundPaused)
{
return NULL;
}

View file

@ -696,6 +696,12 @@ void ReadBindings(int lump, bool override)
dest = &AutomapBindings;
sc.MustGetString();
}
else if (sc.Compare("unbind"))
{
sc.MustGetString();
dest->UnbindKey(sc.String);
continue;
}
key = GetConfigKeyFromName(sc.String);
sc.MustGetString();
dest->SetBind(key, sc.String, override);

View file

@ -76,12 +76,15 @@ void D_ProcessEvents (void)
continue;
if (ev->type == EV_DeviceChange)
UpdateJoystickMenu(I_UpdateDeviceList());
if (gamestate == GS_INTRO)
continue;
if (C_Responder (ev))
continue; // console ate the event
if (M_Responder (ev))
continue; // menu ate the event
if (gamestate != GS_INTRO) // GS_INTRO blocks the UI.
{
if (C_Responder(ev))
continue; // console ate the event
if (M_Responder(ev))
continue; // menu ate the event
}
G_Responder (ev);
}
}

View file

@ -1287,6 +1287,42 @@ void FScanner::AddSymbol(const char* name, double value)
symbols.Insert(name, sym);
}
//==========================================================================
//
//
//
//==========================================================================
int FScanner::StartBraces(FScanner::SavedPos* braceend)
{
if (CheckString("{"))
{
auto here = SavePos();
SkipToEndOfBlock();
*braceend = SavePos();
RestorePos(here);
return 0;
}
else
{
ScriptError("'{' expected");
return -1;
}
}
//==========================================================================
//
//
//
//==========================================================================
bool FScanner::FoundEndBrace(FScanner::SavedPos& braceend)
{
auto here = SavePos();
return here.SavedScriptPtr >= braceend.SavedScriptPtr;
}
//==========================================================================
//
// a class that remembers a parser position

View file

@ -94,6 +94,8 @@ public:
inline void AddSymbol(const char* name, uint32_t value) { return AddSymbol(name, uint64_t(value)); }
void AddSymbol(const char* name, double value);
void SkipToEndOfBlock();
int StartBraces(FScanner::SavedPos* braceend);
bool FoundEndBrace(FScanner::SavedPos& braceend);
static FString TokenName(int token, const char *string=NULL);
@ -113,7 +115,30 @@ public:
void MustGetNumber(bool evaluate = false);
bool CheckNumber(bool evaluate = false);
bool GetNumber(int& var, bool evaluate = false)
{
if (!GetNumber(evaluate)) return false;
var = Number;
return true;
}
bool GetString(FString& var)
{
if (!GetString()) return false;
var = String;
return true;
}
bool GetFloat(bool evaluate = false);
bool GetFloat(double& var, bool evaluate = false)
{
if (!GetFloat(evaluate)) return false;
var = Float;
return true;
}
void MustGetFloat(bool evaluate = false);
bool CheckFloat(bool evaluate = false);

View file

@ -13,7 +13,6 @@ struct FStartupInfo
int LoadLights = -1;
int LoadBrightmaps = -1;
int LoadWidescreen = -1;
int modern = 0;
enum
{
DefaultStartup,

View file

@ -293,7 +293,7 @@ bool F7ZFile::Open(bool quiet, LumpFilterInfo *filter)
lump_p->Owner = this;
lump_p->Flags = LUMPF_FULLPATH|LUMPF_COMPRESSED;
lump_p->Position = i;
lump_p->CheckEmbedded();
lump_p->CheckEmbedded(filter);
lump_p++;
}
// Resize the lump record array to its actual size

View file

@ -154,13 +154,28 @@ int FDirectory::AddDirectory(const char *dirpath)
}
else
{
if (strstr(fi, ".orig") || strstr(fi, ".bak"))
if (strstr(fi, ".orig") || strstr(fi, ".bak") || strstr(fi, ".cache"))
{
// We shouldn't add backup files to the file system
continue;
}
size_t size = 0;
FString fn = FString(dirpath) + fi;
// The next one is courtesy of EDuke32. :(
// Putting cache files in the application directory is very bad style.
// Unfortunately, having a garbage file named "texture" present will cause serious problems down the line.
if (!stricmp(fi, "textures"))
{
FILE* f = fopen(fn, "rb");
if (f)
{
char check[3]{};
fread(check, 1, 3, f);
if (!memcmp(check, "LZ4", 3)) continue;
}
}
if (GetFileInfo(fn, &size, nullptr))
{
AddEntry(fn, (int)size);
@ -209,7 +224,7 @@ void FDirectory::AddEntry(const char *fullpath, int size)
lump_p->LumpSize = size;
lump_p->Owner = this;
lump_p->Flags = 0;
lump_p->CheckEmbedded();
lump_p->CheckEmbedded(nullptr);
}

View file

@ -109,7 +109,7 @@ bool FPakFile::Open(bool quiet, LumpFilterInfo* filter)
Lumps[i].Owner = this;
Lumps[i].Position = LittleLong(fileinfo[i].filepos);
Lumps[i].LumpSize = LittleLong(fileinfo[i].filelen);
Lumps[i].CheckEmbedded();
Lumps[i].CheckEmbedded(filter);
}
GenerateHash();
PostProcessArchive(&Lumps[0], sizeof(Lumps[0]), filter);

View file

@ -233,12 +233,14 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter)
}
name.ToLower();
if (name.IndexOf("__macosx") == 0)
continue; // skip Apple garbage. At this stage only the root folder matters,
if (i == 0)
{
// check for special names, if one of these gets found this must be treated as a normal zip.
bool isspecial = name.IndexOf("/") < 0 || (filter && filter->reservedFolders.Find(name) < filter->reservedFolders.Size());
if (isspecial) break;
name0 = name;
name0 = name.Left(name.LastIndexOf("/")+1);
}
else
{
@ -252,7 +254,7 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter)
// at least one of the more common definition lumps must be present.
for (auto &p : filter->requiredPrefixes)
{
if (name.IndexOf(name0 + p) == 0)
if (name.IndexOf(name0 + p) == 0 || name.LastIndexOf(p) == name.Len() - strlen(p))
{
foundspeciallump = true;
break;
@ -272,7 +274,6 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter)
int len = LittleShort(zip_fh->NameLength);
FString name(dirptr + sizeof(FZipCentralDirectoryInfo), len);
if (name0.IsNotEmpty()) name = name.Mid(name0.Len());
dirptr += sizeof(FZipCentralDirectoryInfo) +
LittleShort(zip_fh->NameLength) +
LittleShort(zip_fh->ExtraLength) +
@ -284,7 +285,14 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter)
if (!quiet) Printf(TEXTCOLOR_RED "\n%s: Central directory corrupted.", FileName.GetChars());
return false;
}
if (name.IndexOf("__macosx") == 0 || name.IndexOf("__MACOSX") == 0)
{
skipped++;
continue; // Weed out Apple's resource fork garbage right here because it interferes with safe operation.
}
if (name0.IsNotEmpty()) name = name.Mid(name0.Len());
// skip Directories
if (name.IsEmpty() || (name.Back() == '/' && LittleLong(zip_fh->UncompressedSize) == 0))
{
@ -329,7 +337,7 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter)
lump_p->CRC32 = zip_fh->CRC32;
lump_p->CompressedSize = LittleLong(zip_fh->CompressedSize);
lump_p->Position = LittleLong(zip_fh->LocalHeaderOffset);
lump_p->CheckEmbedded();
lump_p->CheckEmbedded(filter);
lump_p++;
}

View file

@ -76,14 +76,14 @@ struct FileSystem::LumpRecord
shortName.String[8] = 0;
longName = "";
Namespace = lump->GetNamespace();
resourceId = 0;
resourceId = -1;
}
else if ((lump->Flags & LUMPF_EMBEDDED) || !lump->getName() || !*lump->getName())
{
shortName.qword = 0;
longName = "";
Namespace = ns_hidden;
resourceId = 0;
resourceId = -1;
}
else
{

View file

@ -122,7 +122,7 @@ static bool IsWadInFolder(const FResourceFile* const archive, const char* const
return 0 == filePath.CompareNoCase(resPath);
}
void FResourceLump::CheckEmbedded()
void FResourceLump::CheckEmbedded(LumpFilterInfo* lfi)
{
// Checks for embedded archives
const char *c = strstr(FullName, ".wad");
@ -130,22 +130,13 @@ void FResourceLump::CheckEmbedded()
{
Flags |= LUMPF_EMBEDDED;
}
/* later
else
else if (lfi) for (auto& fstr : lfi->embeddings)
{
if (c==NULL) c = strstr(Name, ".zip");
if (c==NULL) c = strstr(Name, ".pk3");
if (c==NULL) c = strstr(Name, ".7z");
if (c==NULL) c = strstr(Name, ".pak");
if (c && strlen(c) <= 4)
if (!stricmp(FullName, fstr))
{
// Mark all embedded archives in any directory
Flags |= LUMPF_EMBEDDED;
memset(Name, 0, 8);
}
}
*/
}

View file

@ -15,6 +15,7 @@ struct LumpFilterInfo
// The following are for checking if the root directory of a zip can be removed.
TArray<FString> reservedFolders;
TArray<FString> requiredPrefixes;
TArray<FString> embeddings;
std::function<void()> postprocessFunc;
};
@ -111,7 +112,7 @@ public:
virtual int GetIndexNum() const { return -1; }
virtual int GetNamespace() const { return 0; }
void LumpNameSetup(FString iname);
void CheckEmbedded();
void CheckEmbedded(LumpFilterInfo* lfi);
virtual FCompressedBuffer GetRawData();
void *Lock(); // validates the cache and increases the refcount.

View file

@ -232,6 +232,7 @@ DEFINE_ACTION_FUNCTION(FSavegameManager, LoadSavegame)
void FSavegameManagerBase::DoSave(int Selected, const char *savegamestring)
{
RemoveNewSaveNode();
if (Selected != 0)
{
auto node = SaveGames[Selected];

View file

@ -80,6 +80,8 @@ FFlatVertexBuffer::FFlatVertexBuffer(int width, int height)
mVertexBuffer = screen->CreateVertexBuffer();
mIndexBuffer = screen->CreateIndexBuffer();
int data[4] = {};
mIndexBuffer->SetData(4, data); // On Vulkan this may not be empty, so set some dummy defaults to avoid crashes.
unsigned int bytesize = BUFFER_SIZE * sizeof(FFlatVertex);
mVertexBuffer->SetData(bytesize, nullptr, false);

View file

@ -9,7 +9,6 @@
class FRenderState;
struct secplane_t;
struct subsector_t;
struct FFlatVertex
{

View file

@ -4,8 +4,6 @@
#include "tarray.h"
#include "vectors.h"
struct FLevelLocals;
namespace hwrenderer
{

View file

@ -200,9 +200,8 @@ struct StreamData
FVector4 uSplitBottomPlane;
FVector4 uDetailParms;
#ifdef NPOT_EMULATION
FVector2 uNpotEmulation;
#endif
FVector4 uNpotEmulation;
FVector4 padding1, padding2, padding3;
};
class FRenderState
@ -295,7 +294,7 @@ public:
mStreamData.uDynLightColor = { 0.0f, 0.0f, 0.0f, 1.0f };
mStreamData.uDetailParms = { 0.0f, 0.0f, 0.0f, 0.0f };
#ifdef NPOT_EMULATION
mStreamData.uNpotEmulation = { 0,0 };
mStreamData.uNpotEmulation = { 0,0,0,0 };
#endif
mModelMatrix.loadIdentity();
mTextureMatrix.loadIdentity();
@ -490,7 +489,7 @@ public:
void SetNpotEmulation(float factor, float offset)
{
#ifdef NPOT_EMULATION
mStreamData.uNpotEmulation = { offset, factor };
mStreamData.uNpotEmulation = { offset, factor, 0, 0 };
#endif
}

View file

@ -62,13 +62,7 @@
#include "hw_renderstate.h"
#include "v_video.h"
#include "hwrenderer/data/buffers.h"
// 57 world units roughly represent one sky texel for the glTranslate call.
enum
{
skyoffsetfactor = 57
};
#include "version.h"
//-----------------------------------------------------------------------------
//
@ -150,7 +144,7 @@ FSkyVertexBuffer::~FSkyVertexBuffer()
//
//-----------------------------------------------------------------------------
void FSkyVertexBuffer::SkyVertex(int r, int c, bool zflip)
void FSkyVertexBuffer::SkyVertexDoom(int r, int c, bool zflip)
{
static const FAngle maxSideAngle = 60.f;
static const float scale = 10000.;
@ -187,6 +181,37 @@ void FSkyVertexBuffer::SkyVertex(int r, int c, bool zflip)
mVertices.Push(vert);
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FSkyVertexBuffer::SkyVertexBuild(int r, int c, bool zflip)
{
static const FAngle maxSideAngle = 60.f;
static const float scale = 10000.;
FAngle topAngle = (c / (float)mColumns * 360.f);
FVector2 pos = topAngle.ToVector(scale);
float z = (!zflip) ? (mRows - r) * 4000.f : -(mRows - r) * 4000.f;
FSkyVertex vert;
vert.color = r == 0 ? 0xffffff : 0xffffffff;
// And the texture coordinates.
if (zflip) r = mRows * 2 - r;
vert.u = 0.5f + (-c / (float)mColumns);
vert.v = (r / (float)(2*mRows));
// And finally the vertex.
vert.x = pos.X;
vert.y = z - 1.f;
vert.z = pos.Y;
mVertices.Push(vert);
}
//-----------------------------------------------------------------------------
//
@ -194,27 +219,58 @@ void FSkyVertexBuffer::SkyVertex(int r, int c, bool zflip)
//
//-----------------------------------------------------------------------------
void FSkyVertexBuffer::CreateSkyHemisphere(int hemi)
void FSkyVertexBuffer::CreateSkyHemisphereDoom(int hemi)
{
int r, c;
bool zflip = !!(hemi & SKYHEMI_LOWER);
mPrimStart.Push(mVertices.Size());
mPrimStartDoom.Push(mVertices.Size());
for (c = 0; c < mColumns; c++)
{
SkyVertex(1, c, zflip);
SkyVertexDoom(1, c, zflip);
}
// The total number of triangles per hemisphere can be calculated
// as follows: rows * columns * 2 + 2 (for the top cap).
for (r = 0; r < mRows; r++)
{
mPrimStart.Push(mVertices.Size());
mPrimStartDoom.Push(mVertices.Size());
for (c = 0; c <= mColumns; c++)
{
SkyVertex(r + zflip, c, zflip);
SkyVertex(r + 1 - zflip, c, zflip);
SkyVertexDoom(r + zflip, c, zflip);
SkyVertexDoom(r + 1 - zflip, c, zflip);
}
}
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FSkyVertexBuffer::CreateSkyHemisphereBuild(int hemi)
{
int r, c;
bool zflip = !!(hemi & SKYHEMI_LOWER);
mPrimStartBuild.Push(mVertices.Size());
for (c = 0; c < mColumns; c++)
{
SkyVertexBuild(1, c, zflip);
}
// The total number of triangles per hemisphere can be calculated
// as follows: rows * columns * 2 + 2 (for the top cap).
for (r = 0; r < mRows; r++)
{
mPrimStartBuild.Push(mVertices.Size());
for (c = 0; c <= mColumns; c++)
{
SkyVertexBuild(r + zflip, c, zflip);
SkyVertexBuild(r + 1 - zflip, c, zflip);
}
}
}
@ -248,9 +304,13 @@ void FSkyVertexBuffer::CreateDome()
mColumns = 128;
mRows = 4;
CreateSkyHemisphere(SKYHEMI_UPPER);
CreateSkyHemisphere(SKYHEMI_LOWER);
mPrimStart.Push(mVertices.Size());
CreateSkyHemisphereDoom(SKYHEMI_UPPER);
CreateSkyHemisphereDoom(SKYHEMI_LOWER);
mPrimStartDoom.Push(mVertices.Size());
CreateSkyHemisphereBuild(SKYHEMI_UPPER);
CreateSkyHemisphereBuild(SKYHEMI_LOWER);
mPrimStartBuild.Push(mVertices.Size());
mSideStart = mVertices.Size();
mFaceStart[0] = mSideStart + 10;
@ -324,7 +384,7 @@ void FSkyVertexBuffer::CreateDome()
//
//-----------------------------------------------------------------------------
void FSkyVertexBuffer::SetupMatrices(FGameTexture *tex, float x_offset, float y_offset, bool mirror, int mode, VSMatrix &modelMatrix, VSMatrix &textureMatrix, bool tiled)
void FSkyVertexBuffer::SetupMatrices(FGameTexture *tex, float x_offset, float y_offset, bool mirror, int mode, VSMatrix &modelMatrix, VSMatrix &textureMatrix, bool tiled, float xscale, float yscale)
{
float texw = tex->GetDisplayWidth();
float texh = tex->GetDisplayHeight();
@ -332,37 +392,46 @@ void FSkyVertexBuffer::SetupMatrices(FGameTexture *tex, float x_offset, float y_
modelMatrix.loadIdentity();
modelMatrix.rotate(-180.0f + x_offset, 0.f, 1.f, 0.f);
float xscale = texw < 1024.f ? floorf(1024.f / float(texw)) : 1.f;
float yscale = 1.f;
if (xscale == 0) xscale = texw < 1024.f ? floorf(1024.f / float(texw)) : 1.f;
auto texskyoffset = tex->GetSkyOffset() + skyoffset;
if (texh <= 128 && tiled)
if (yscale == 0)
{
modelMatrix.translate(0.f, (-40 + texskyoffset)*skyoffsetfactor, 0.f);
modelMatrix.scale(1.f, 1.2f * 1.17f, 1.f);
yscale = 240.f / texh;
}
else if (texh < 128)
{
// smaller sky textures must be tiled. We restrict it to 128 sky pixels, though
modelMatrix.translate(0.f, -1250.f, 0.f);
modelMatrix.scale(1.f, 128 / 230.f, 1.f);
yscale = float(128 / texh); // intentionally left as integer.
}
else if (texh < 200)
{
modelMatrix.translate(0.f, -1250.f, 0.f);
modelMatrix.scale(1.f, texh / 230.f, 1.f);
}
else if (texh <= 240)
{
modelMatrix.translate(0.f, (200 - texh + texskyoffset)*skyoffsetfactor, 0.f);
modelMatrix.scale(1.f, 1.f + ((texh - 200.f) / 200.f) * 1.17f, 1.f);
if (texh <= 128 && tiled)
{
modelMatrix.translate(0.f, (-40 + texskyoffset) * skyoffsetfactor, 0.f);
modelMatrix.scale(1.f, 1.2f * 1.17f, 1.f);
yscale = 240.f / texh;
}
else if (texh < 128)
{
// smaller sky textures must be tiled. We restrict it to 128 sky pixels, though
modelMatrix.translate(0.f, -1250.f, 0.f);
modelMatrix.scale(1.f, 128 / 230.f, 1.f);
yscale = float(128 / texh); // intentionally left as integer.
}
else if (texh < 200)
{
modelMatrix.translate(0.f, -1250.f, 0.f);
modelMatrix.scale(1.f, texh / 230.f, 1.f);
yscale = 1.f;
}
else if (texh <= 240)
{
modelMatrix.translate(0.f, (200 - texh + texskyoffset) * skyoffsetfactor, 0.f);
modelMatrix.scale(1.f, 1.f + ((texh - 200.f) / 200.f) * 1.17f, 1.f);
yscale = 1.f;
}
else
{
modelMatrix.translate(0.f, (-40 + texskyoffset) * skyoffsetfactor, 0.f);
modelMatrix.scale(1.f, 1.2f * 1.17f, 1.f);
yscale = 240.f / texh;
}
}
else
{
modelMatrix.translate(0.f, (-40 + texskyoffset)*skyoffsetfactor, 0.f);
modelMatrix.scale(1.f, 1.2f * 1.17f, 1.f);
yscale = 240.f / texh;
modelMatrix.translate(0.f, (-40 + texskyoffset) * skyoffsetfactor, 0.f);
modelMatrix.scale(1.f, 0.8f * 1.17f, 1.f);
}
textureMatrix.loadIdentity();
textureMatrix.scale(mirror ? -xscale : xscale, yscale, 1.f);
@ -375,7 +444,7 @@ void FSkyVertexBuffer::SetupMatrices(FGameTexture *tex, float x_offset, float y_
//
//-----------------------------------------------------------------------------
void FSkyVertexBuffer::RenderRow(FRenderState& state, EDrawType prim, int row, bool apply)
void FSkyVertexBuffer::RenderRow(FRenderState& state, EDrawType prim, int row, TArray<unsigned int>& mPrimStart, bool apply)
{
state.Draw(prim, mPrimStart[row], mPrimStart[row + 1] - mPrimStart[row]);
}
@ -386,36 +455,35 @@ void FSkyVertexBuffer::RenderRow(FRenderState& state, EDrawType prim, int row, b
//
//-----------------------------------------------------------------------------
void FSkyVertexBuffer::RenderDome(FRenderState& state, FGameTexture* tex, float x_offset, float y_offset, bool mirror, int mode, bool tiled)
void FSkyVertexBuffer::RenderDome(FRenderState& state, FGameTexture* tex, int mode, bool which)
{
if (tex)
auto& primStart = which ? mPrimStartBuild : mPrimStartDoom;
if (tex && tex->isValid())
{
state.SetMaterial(tex, UF_Texture, 0, CLAMP_NONE, 0, -1);
state.EnableModelMatrix(true);
state.EnableTextureMatrix(true);
SetupMatrices(tex, x_offset, y_offset, mirror, mode, state.mModelMatrix, state.mTextureMatrix, tiled);
}
int rc = mRows + 1;
// The caps only get drawn for the main layer but not for the overlay.
if (mode == FSkyVertexBuffer::SKYMODE_MAINLAYER && tex != NULL)
if (mode == FSkyVertexBuffer::SKYMODE_MAINLAYER && tex != nullptr)
{
auto& col = R_GetSkyCapColor(tex);
state.SetObjectColor(col.first);
state.EnableTexture(false);
RenderRow(state, DT_TriangleFan, 0);
RenderRow(state, DT_TriangleFan, 0, primStart);
state.SetObjectColor(col.second);
RenderRow(state, DT_TriangleFan, rc);
RenderRow(state, DT_TriangleFan, rc, primStart);
state.EnableTexture(true);
}
state.SetObjectColor(0xffffffff);
for (int i = 1; i <= mRows; i++)
{
RenderRow(state, DT_TriangleStrip, i, i == 1);
RenderRow(state, DT_TriangleStrip, rc + i, false);
RenderRow(state, DT_TriangleStrip, i, primStart, i == 1);
RenderRow(state, DT_TriangleStrip, rc + i, primStart, false);
}
state.EnableTextureMatrix(false);
@ -423,13 +491,29 @@ void FSkyVertexBuffer::RenderDome(FRenderState& state, FGameTexture* tex, float
}
//-----------------------------------------------------------------------------
//
// This is only for Doom-style skies.
//
//-----------------------------------------------------------------------------
void FSkyVertexBuffer::RenderDome(FRenderState& state, FGameTexture* tex, float x_offset, float y_offset, bool mirror, int mode, bool tiled, float xscale, float yscale)
{
if (tex)
{
SetupMatrices(tex, x_offset, y_offset, mirror, mode, state.mModelMatrix, state.mTextureMatrix, tiled, xscale, yscale);
}
RenderDome(state, tex, mode, false);
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FSkyVertexBuffer::RenderBox(FRenderState& state, FTextureID texno, FSkyBox* tex, float x_offset, bool sky2, float stretch, const FVector3& skyrotatevector, const FVector3& skyrotatevector2)
void FSkyVertexBuffer::RenderBox(FRenderState& state, FSkyBox* tex, float x_offset, bool sky2, float stretch, const FVector3& skyrotatevector, const FVector3& skyrotatevector2)
{
int faces;

View file

@ -11,6 +11,12 @@ class IVertexBuffer;
struct HWSkyPortal;
struct HWDrawInfo;
// 57 world units roughly represent one sky texel for the glTranslate call.
enum
{
skyoffsetfactor = 57
};
struct FSkyVertex
{
float x, y, z, u, v;
@ -55,7 +61,8 @@ public:
IVertexBuffer *mVertexBuffer;
TArray<FSkyVertex> mVertices;
TArray<unsigned int> mPrimStart;
TArray<unsigned int> mPrimStartDoom;
TArray<unsigned int> mPrimStartBuild;
int mRows, mColumns;
@ -63,15 +70,17 @@ public:
int mFaceStart[7];
int mSideStart;
void SkyVertex(int r, int c, bool yflip);
void CreateSkyHemisphere(int hemi);
void SkyVertexDoom(int r, int c, bool yflip);
void SkyVertexBuild(int r, int c, bool yflip);
void CreateSkyHemisphereDoom(int hemi);
void CreateSkyHemisphereBuild(int hemi);
void CreateDome();
public:
FSkyVertexBuffer();
~FSkyVertexBuffer();
void SetupMatrices(FGameTexture *tex, float x_offset, float y_offset, bool mirror, int mode, VSMatrix &modelmatrix, VSMatrix &textureMatrix, bool tiled);
void SetupMatrices(FGameTexture *tex, float x_offset, float y_offset, bool mirror, int mode, VSMatrix &modelmatrix, VSMatrix &textureMatrix, bool tiled, float xscale = 0, float vertscale = 0);
std::pair<IVertexBuffer *, IIndexBuffer *> GetBufferObjects() const
{
return std::make_pair(mVertexBuffer, nullptr);
@ -83,8 +92,9 @@ public:
else return mSideStart;
}
void RenderRow(FRenderState& state, EDrawType prim, int row, bool apply = true);
void RenderDome(FRenderState& state, FGameTexture* tex, float x_offset, float y_offset, bool mirror, int mode, bool tiled);
void RenderBox(FRenderState& state, FTextureID texno, FSkyBox* tex, float x_offset, bool sky2, float stretch, const FVector3& skyrotatevector, const FVector3& skyrotatevector2);
void RenderRow(FRenderState& state, EDrawType prim, int row, TArray<unsigned int>& mPrimStart, bool apply = true);
void RenderDome(FRenderState& state, FGameTexture* tex, int mode, bool which);
void RenderDome(FRenderState& state, FGameTexture* tex, float x_offset, float y_offset, bool mirror, int mode, bool tiled, float xscale = 0, float yscale = 0);
void RenderBox(FRenderState& state, FSkyBox* tex, float x_offset, bool sky2, float stretch, const FVector3& skyrotatevector, const FVector3& skyrotatevector2);
};

View file

@ -85,7 +85,6 @@ void Draw2D(F2DDrawer *drawer, FRenderState &state)
vb.UploadData(&vertices[0], vertices.Size(), &indices[0], indices.Size());
state.SetVertexBuffer(&vb);
state.EnableFog(false);
state.SetScreenFade(drawer->screenFade);
for(auto &cmd : commands)
{
@ -94,6 +93,7 @@ void Draw2D(F2DDrawer *drawer, FRenderState &state)
state.SetRenderStyle(cmd.mRenderStyle);
state.EnableBrightmap(!(cmd.mRenderStyle.Flags & STYLEF_ColorIsFixed));
state.EnableFog(2); // Special 2D mode 'fog'.
state.SetScreenFade(cmd.mScreenFade);
state.SetTextureMode(cmd.mDrawMode);

View file

@ -45,7 +45,6 @@
#include "hw_shadowmap.h"
struct sector_t;
struct FPortalSceneState;
class FSkyVertexBuffer;
class IIndexBuffer;
@ -147,7 +146,7 @@ public:
IntRect mScreenViewport;
IntRect mSceneViewport;
IntRect mOutputLetterbox;
float mSceneClearColor[4];
float mSceneClearColor[4]{ 0,0,0,255 };
public:
DFrameBuffer (int width=1, int height=1);

View file

@ -163,9 +163,8 @@ static const char *shaderBindings = R"(
vec4 uSplitBottomPlane;
vec4 uDetailParms;
#ifdef NPOT_EMULATION
vec2 uNpotEmulation;
#endif
vec4 uNpotEmulation;
vec4 padding1, padding2, padding3;
};
layout(set = 0, binding = 3, std140) uniform StreamUBO {
@ -297,6 +296,9 @@ std::unique_ptr<VulkanShader> VkShaderManager::LoadFragShader(FString shadername
code << defines;
code << "\n$placeholder$"; // here the code can later add more needed #defines.
code << "\n#define MAX_STREAM_DATA " << std::to_string(MAX_STREAM_DATA).c_str() << "\n";
#ifdef NPOT_EMULATION
code << "#define NPOT_EMULATION\n";
#endif
code << shaderBindings;
FString placeholder = "\n";

View file

@ -390,7 +390,7 @@ void VulkanFrameBuffer::PrecacheMaterial(FMaterial *mat, int translation)
IHardwareTexture *VulkanFrameBuffer::CreateHardwareTexture(int numchannels)
{
return new VkHardwareTexture();
return new VkHardwareTexture(numchannels);
}
FMaterial* VulkanFrameBuffer::CreateMaterial(FGameTexture* tex, int scaleflags)

View file

@ -37,8 +37,9 @@
VkHardwareTexture *VkHardwareTexture::First = nullptr;
VkHardwareTexture::VkHardwareTexture()
VkHardwareTexture::VkHardwareTexture(int numchannels)
{
mTexelsize = numchannels;
Next = First;
First = this;
if (Next) Next->Prev = this;
@ -126,7 +127,8 @@ void VkHardwareTexture::CreateImage(FTexture *tex, int translation, int flags)
if (!tex->isHardwareCanvas())
{
FTextureBuffer texbuffer = tex->CreateTexBuffer(translation, flags | CTF_ProcessData);
CreateTexture(texbuffer.mWidth, texbuffer.mHeight, 4, VK_FORMAT_B8G8R8A8_UNORM, texbuffer.mBuffer);
bool indexed = flags & CTF_Indexed;
CreateTexture(texbuffer.mWidth, texbuffer.mHeight,indexed? 1 : 4, indexed? VK_FORMAT_R8_UNORM : VK_FORMAT_B8G8R8A8_UNORM, texbuffer.mBuffer, !indexed);
}
else
{
@ -156,7 +158,7 @@ void VkHardwareTexture::CreateImage(FTexture *tex, int translation, int flags)
}
}
void VkHardwareTexture::CreateTexture(int w, int h, int pixelsize, VkFormat format, const void *pixels)
void VkHardwareTexture::CreateTexture(int w, int h, int pixelsize, VkFormat format, const void *pixels, bool mipmap)
{
if (w <= 0 || h <= 0)
throw CVulkanError("Trying to create zero size texture");
@ -177,7 +179,7 @@ void VkHardwareTexture::CreateTexture(int w, int h, int pixelsize, VkFormat form
ImageBuilder imgbuilder;
imgbuilder.setFormat(format);
imgbuilder.setSize(w, h, GetMipLevels(w, h));
imgbuilder.setSize(w, h, !mipmap ? 1 : GetMipLevels(w, h));
imgbuilder.setUsage(VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
mImage.Image = imgbuilder.create(fb->device);
mImage.Image->SetDebugName("VkHardwareTexture.mImage");
@ -203,7 +205,7 @@ void VkHardwareTexture::CreateTexture(int w, int h, int pixelsize, VkFormat form
fb->FrameDeleteList.Buffers.push_back(std::move(stagingBuffer));
mImage.GenerateMipmaps(cmdbuffer);
if (mipmap) mImage.GenerateMipmaps(cmdbuffer);
}
int VkHardwareTexture::GetMipLevels(int w, int h)
@ -268,6 +270,7 @@ uint8_t *VkHardwareTexture::MapBuffer()
unsigned int VkHardwareTexture::CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, const char *name)
{
CreateTexture(w, h, mTexelsize, mTexelsize == 4 ? VK_FORMAT_B8G8R8A8_UNORM : VK_FORMAT_R8_UNORM, buffer, mipmap);
return 0;
}
@ -371,10 +374,6 @@ VulkanDescriptorSet* VkMaterial::GetDescriptorSet(const FMaterialState& state)
int clampmode = state.mClampMode;
int translation = state.mTranslation;
auto remap = translation <= 0 ? nullptr : GPalette.TranslationToTable(translation);
if (remap)
translation = remap->Index;
clampmode = base->GetClampMode(clampmode);
for (auto& set : mDescriptorSets)
@ -395,10 +394,23 @@ VulkanDescriptorSet* VkMaterial::GetDescriptorSet(const FMaterialState& state)
MaterialLayerInfo *layer;
auto systex = static_cast<VkHardwareTexture*>(GetLayer(0, state.mTranslation, &layer));
update.addCombinedImageSampler(descriptor.get(), 0, systex->GetImage(layer->layerTexture, state.mTranslation, layer->scaleFlags)->View.get(), sampler, systex->mImage.Layout);
for (int i = 1; i < numLayers; i++)
if (!(layer->scaleFlags & CTF_Indexed))
{
auto systex = static_cast<VkHardwareTexture*>(GetLayer(i, 0, &layer));
update.addCombinedImageSampler(descriptor.get(), i, systex->GetImage(layer->layerTexture, 0, layer->scaleFlags)->View.get(), sampler, systex->mImage.Layout);
for (int i = 1; i < numLayers; i++)
{
auto systex = static_cast<VkHardwareTexture*>(GetLayer(i, 0, &layer));
update.addCombinedImageSampler(descriptor.get(), i, systex->GetImage(layer->layerTexture, 0, layer->scaleFlags)->View.get(), sampler, systex->mImage.Layout);
}
}
else
{
for (int i = 1; i < 3; i++)
{
auto systex = static_cast<VkHardwareTexture*>(GetLayer(i, translation, &layer));
update.addCombinedImageSampler(descriptor.get(), i, systex->GetImage(layer->layerTexture, 0, layer->scaleFlags)->View.get(), sampler, systex->mImage.Layout);
}
numLayers = 3;
}
auto dummyImage = fb->GetRenderPassManager()->GetNullTextureView();

View file

@ -24,7 +24,7 @@ class VkHardwareTexture : public IHardwareTexture
{
friend class VkMaterial;
public:
VkHardwareTexture();
VkHardwareTexture(int numchannels);
~VkHardwareTexture();
static void ResetAll();
@ -45,7 +45,7 @@ public:
private:
void CreateImage(FTexture *tex, int translation, int flags);
void CreateTexture(int w, int h, int pixelsize, VkFormat format, const void *pixels);
void CreateTexture(int w, int h, int pixelsize, VkFormat format, const void *pixels, bool mipmap);
static int GetMipLevels(int w, int h);
static VkHardwareTexture *First;

View file

@ -605,13 +605,13 @@ void DStatusBarCore::DrawGraphic(FGameTexture* tex, double x, double y, int flag
//
//============================================================================
void DStatusBarCore::DrawRotated(FTextureID texture, double x, double y, double angle, int flags, double Alpha, double scaleX, double scaleY, PalEntry color, int translation, ERenderStyle style)
void DStatusBarCore::DrawRotated(FTextureID texture, double x, double y, int flags, double angle, double Alpha, double scaleX, double scaleY, PalEntry color, int translation, ERenderStyle style)
{
if (!texture.isValid())
return;
FGameTexture* tex = TexMan.GetGameTexture(texture, !(flags & DI_DONTANIMATE));
DrawRotated(tex, x, y, angle, flags, Alpha, scaleX, scaleY, color, translation, style);
DrawRotated(tex, x, y, flags, angle, Alpha, scaleX, scaleY, color, translation, style);
}
void DStatusBarCore::DrawRotated(FGameTexture* tex, double x, double y, int flags, double angle, double Alpha, double scaleX, double scaleY, PalEntry color, int translation, ERenderStyle style)

View file

@ -186,7 +186,7 @@ public:
void StatusbarToRealCoords(double& x, double& y, double& w, double& h) const;
void DrawGraphic(FGameTexture* texture, double x, double y, int flags, double Alpha, double boxwidth, double boxheight, double scaleX, double scaleY, PalEntry color = 0xffffffff, int translation = 0, ERenderStyle style = STYLE_Translucent, double clipwidth = -1.0);
void DrawGraphic(FTextureID texture, double x, double y, int flags, double Alpha, double boxwidth, double boxheight, double scaleX, double scaleY, PalEntry color = 0xffffffff, int translation = 0, ERenderStyle style = STYLE_Translucent, double clipwidth = -1.0);
void DrawRotated(FTextureID texture, double x, double y, double angle, int flags, double Alpha, double scaleX, double scaleY, PalEntry color = 0xffffffff, int translation = 0, ERenderStyle style = STYLE_Translucent);
void DrawRotated(FTextureID texture, double x, double y, int flags, double angle, double Alpha, double scaleX, double scaleY, PalEntry color = 0xffffffff, int translation = 0, ERenderStyle style = STYLE_Translucent);
void DrawRotated(FGameTexture* tex, double x, double y, int flags, double angle, double Alpha, double scaleX, double scaleY, PalEntry color = 0xffffffff, int translation = 0, ERenderStyle style = STYLE_Translucent);
void DrawString(FFont* font, const FString& cstring, double x, double y, int flags, double Alpha, int translation, int spacing, EMonospacing monospacing, int shadowX, int shadowY, double scaleX, double scaleY, int pt);
void TransformRect(double& x, double& y, double& w, double& h, int flags = 0);

View file

@ -48,7 +48,6 @@ void AnimTexture::SetFrameSize(int format, int width, int height)
FTexture::SetSize(width, height);
Image.Resize(width * height * (format == Paletted ? 1 : 3));
memset(Image.Data(), 0, Image.Size());
CleanHardwareTextures();
}
void AnimTexture::SetFrame(const uint8_t* palette, const void* data_)
@ -81,7 +80,6 @@ void AnimTexture::SetFrame(const uint8_t* palette, const void* data_)
}
else memcpy(Image.Data(), data_, Width * Height * (pixelformat == Paletted ? 1 : 3));
}
CleanHardwareTextures();
}
//===========================================================================
@ -156,10 +154,13 @@ void AnimTextures::SetSize(int format, int width, int height)
static_cast<AnimTexture*>(tex[1]->GetTexture())->SetFrameSize(format, width, height);
tex[0]->SetSize(width, height);
tex[1]->SetSize(width, height);
tex[0]->CleanHardwareData();
tex[1]->CleanHardwareData();
}
void AnimTextures::SetFrame(const uint8_t* palette, const void* data)
{
active ^= 1;
static_cast<AnimTexture*>(tex[active]->GetTexture())->SetFrame(palette, data);
tex[active]->CleanHardwareData();
}

View file

@ -30,6 +30,7 @@
#include "v_video.h"
static IHardwareTexture* (*layercallback)(int layer, int translation);
TArray<UserShaderDesc> usershaders;
void FMaterial::SetLayerCallback(IHardwareTexture* (*cb)(int layer, int translation))
{

View file

@ -82,6 +82,7 @@ private:
template <typename Polygon> Node* eliminateHoles(const Polygon& points, Node* outerNode);
void eliminateHole(Node* hole, Node* outerNode);
Node* findHoleBridge(Node* hole, Node* outerNode);
bool sectorContainsSector(const Node* m, const Node* p);
void indexCurve(Node* start);
Node* sortLinked(Node* list);
int32_t zOrder(const double x_, const double y_);
@ -91,6 +92,8 @@ private:
double area(const Node* p, const Node* q, const Node* r) const;
bool equals(const Node* p1, const Node* p2);
bool intersects(const Node* p1, const Node* q1, const Node* p2, const Node* q2);
bool onSegment(const Node* p, const Node* q, const Node* r);
int sign(double val);
bool intersectsPolygon(const Node* a, const Node* b);
bool locallyInside(const Node* a, const Node* b);
bool middleInside(const Node* a, const Node* b);
@ -116,16 +119,18 @@ private:
template <typename... Args>
T* construct(Args&&... args) {
if (currentIndex >= blockSize) {
currentBlock = alloc.allocate(blockSize);
currentBlock = alloc_traits::allocate(alloc, blockSize);
allocations.emplace_back(currentBlock);
currentIndex = 0;
}
T* object = &currentBlock[currentIndex++];
alloc.construct(object, std::forward<Args>(args)...);
alloc_traits::construct(alloc, object, std::forward<Args>(args)...);
return object;
}
void reset(std::size_t newBlockSize) {
for (auto allocation : allocations) alloc.deallocate(allocation, blockSize);
for (auto allocation : allocations) {
alloc_traits::deallocate(alloc, allocation, blockSize);
}
allocations.clear();
blockSize = std::max<std::size_t>(1, newBlockSize);
currentBlock = nullptr;
@ -138,6 +143,7 @@ private:
std::size_t blockSize = 1;
std::vector<T*> allocations;
Alloc alloc;
typedef typename std::allocator_traits<Alloc> alloc_traits;
};
ObjectPool<Node> nodes;
};
@ -165,7 +171,7 @@ void Earcut<N>::operator()(const Polygon& points) {
indices.reserve(len + points[0].size());
Node* outerNode = linkedList(points[0], true);
if (!outerNode) return;
if (!outerNode || outerNode->prev == outerNode->next) return;
if (points.size() > 1) outerNode = eliminateHoles(points, outerNode);
@ -244,8 +250,7 @@ Earcut<N>::filterPoints(Node* start, Node* end) {
do {
again = false;
if (!p->steiner && (equals(p, p->next) /*|| area(p->prev, p, p->next) == 0*/))
{
if (!p->steiner && (equals(p, p->next) || area(p->prev, p, p->next) == 0)) {
removeNode(p);
p = end = p->prev;
@ -304,7 +309,7 @@ void Earcut<N>::earcutLinked(Node* ear, int pass) {
// if this didn't work, try curing all small self-intersections locally
else if (pass == 1) {
ear = cureLocalIntersections(ear);
ear = cureLocalIntersections(filterPoints(ear));
earcutLinked(ear, 2);
// as a last resort, try splitting the remaining polygon into two
@ -401,7 +406,7 @@ Earcut<N>::cureLocalIntersections(Node* start) {
p = p->next;
} while (p != start);
return p;
return filterPoints(p);
}
// try splitting polygon into two and triangulate them independently
@ -464,6 +469,9 @@ void Earcut<N>::eliminateHole(Node* hole, Node* outerNode) {
outerNode = findHoleBridge(hole, outerNode);
if (outerNode) {
Node* b = splitPolygon(outerNode, hole);
// filter out colinear points around cuts
filterPoints(outerNode, outerNode->next);
filterPoints(b, b->next);
}
}
@ -497,7 +505,7 @@ Earcut<N>::findHoleBridge(Node* hole, Node* outerNode) {
if (!m) return 0;
if (hx == qx) return m->prev;
if (hx == qx) return m; // hole touches outer segment; pick leftmost endpoint
// look for points inside the triangle of hole Vertex, segment intersection and endpoint;
// if there are no points found, we have a valid connection;
@ -507,28 +515,35 @@ Earcut<N>::findHoleBridge(Node* hole, Node* outerNode) {
double tanMin = std::numeric_limits<double>::infinity();
double tanCur = 0;
p = m->next;
p = m;
double mx = m->x;
double my = m->y;
while (p != stop) {
do {
if (hx >= p->x && p->x >= mx && hx != p->x &&
pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p->x, p->y)) {
tanCur = std::abs(hy - p->y) / (hx - p->x); // tangential
if ((tanCur < tanMin || (tanCur == tanMin && p->x > m->x)) && locallyInside(p, hole)) {
if (locallyInside(p, hole) &&
(tanCur < tanMin || (tanCur == tanMin && (p->x > m->x || sectorContainsSector(m, p))))) {
m = p;
tanMin = tanCur;
}
}
p = p->next;
}
} while (p != stop);
return m;
}
// whether sector in vertex m contains sector in vertex p in the same coordinates
template <typename N>
bool Earcut<N>::sectorContainsSector(const Node* m, const Node* p) {
return area(m->prev, m, p->prev) < 0 && area(p->next, m, m->next) < 0;
}
// interlink polygon nodes in z-order
template <typename N>
void Earcut<N>::indexCurve(Node* start) {
@ -644,7 +659,8 @@ Earcut<N>::getLeftmost(Node* start) {
Node* p = start;
Node* leftmost = start;
do {
if (p->x < leftmost->x) leftmost = p;
if (p->x < leftmost->x || (p->x == leftmost->x && p->y < leftmost->y))
leftmost = p;
p = p->next;
} while (p != start);
@ -662,8 +678,10 @@ bool Earcut<N>::pointInTriangle(double ax, double ay, double bx, double by, doub
// check if a diagonal between two polygon nodes is valid (lies in polygon interior)
template <typename N>
bool Earcut<N>::isValidDiagonal(Node* a, Node* b) {
return a->next->i != b->i && a->prev->i != b->i && !intersectsPolygon(a, b) &&
locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b);
return a->next->i != b->i && a->prev->i != b->i && !intersectsPolygon(a, b) && // dones't intersect other edges
((locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && // locally visible
(area(a->prev, a, b->prev) != 0.0 || area(a, b->prev, b) != 0.0)) || // does not create opposite-facing sectors
(equals(a, b) && area(a->prev, a, a->next) > 0 && area(b->prev, b, b->next) > 0)); // special zero-length case
}
// signed area of a triangle
@ -681,10 +699,33 @@ bool Earcut<N>::equals(const Node* p1, const Node* p2) {
// check if two segments intersect
template <typename N>
bool Earcut<N>::intersects(const Node* p1, const Node* q1, const Node* p2, const Node* q2) {
if ((equals(p1, q1) && equals(p2, q2)) ||
(equals(p1, q2) && equals(p2, q1))) return true;
return (area(p1, q1, p2) > 0) != (area(p1, q1, q2) > 0) &&
(area(p2, q2, p1) > 0) != (area(p2, q2, q1) > 0);
int o1 = sign(area(p1, q1, p2));
int o2 = sign(area(p1, q1, q2));
int o3 = sign(area(p2, q2, p1));
int o4 = sign(area(p2, q2, q1));
if (o1 != o2 && o3 != o4) return true; // general case
if (o1 == 0 && onSegment(p1, p2, q1)) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1
if (o2 == 0 && onSegment(p1, q2, q1)) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1
if (o3 == 0 && onSegment(p2, p1, q2)) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2
if (o4 == 0 && onSegment(p2, q1, q2)) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2
return false;
}
// for collinear points p, q, r, check if point q lies on segment pr
template <typename N>
bool Earcut<N>::onSegment(const Node* p, const Node* q, const Node* r) {
return q->x <= std::max<double>(p->x, r->x) &&
q->x >= std::min<double>(p->x, r->x) &&
q->y <= std::max<double>(p->y, r->y) &&
q->y >= std::min<double>(p->y, r->y);
}
template <typename N>
int Earcut<N>::sign(double val) {
return (0.0 < val) - (val < 0.0);
}
// check if a polygon diagonal intersects any polygon segments

View file

@ -2,6 +2,7 @@
#include <stddef.h>
#include <stdint.h>
#include <algorithm>
#define MAXWIDTH 12000
#define MAXHEIGHT 5000
@ -101,3 +102,6 @@ enum EStateUseFlags
SUF_WEAPON = 4,
SUF_ITEM = 8,
};
using std::min;
using std::max;

View file

@ -103,4 +103,14 @@ inline void fillshort(void* buff, size_t count, uint16_t clear)
template<typename T> inline constexpr T Sgn(const T& val) { return (val > 0) - (val < 0); }
inline int sizeToBits(int w)
{
int j = 15;
while ((j > 1) && ((1 << j) > w))
j--;
return j;
}
#endif

View file

@ -33,9 +33,7 @@ class VSMatrix {
public:
VSMatrix()
{
}
VSMatrix() = default;
VSMatrix(int)
{

View file

@ -54,7 +54,6 @@ void AddLightAssociation(const char *actor, const char *frame, const char *light
void InitializeActorLights(TArray<FLightAssociation> &LightAssociations);
void ParseColorization(FScanner& sc);
TArray<UserShaderDesc> usershaders;
extern TDeletingArray<FLightDefaults *> LightDefaults;
extern int AttenuationIsSet;

View file

@ -1,6 +1,8 @@
#pragma once
#include "hw_aabbtree.h"
struct FLevelLocals;
// Axis aligned bounding box tree used for ray testing treelines.
class DoomLevelAABBTree : public hwrenderer::LevelAABBTree
{

View file

@ -62,7 +62,7 @@ void HWSkyPortal::DrawContents(HWDrawInfo *di, FRenderState &state)
auto skybox = origin->texture[0] ? dynamic_cast<FSkyBox*>(origin->texture[0]->GetTexture()) : nullptr;
if (skybox)
{
vertexBuffer->RenderBox(state, origin->skytexno1, skybox, origin->x_offset[0], origin->sky2, di->Level->info->pixelstretch, di->Level->info->skyrotatevector, di->Level->info->skyrotatevector2);
vertexBuffer->RenderBox(state, skybox, origin->x_offset[0], origin->sky2, di->Level->info->pixelstretch, di->Level->info->skyrotatevector, di->Level->info->skyrotatevector2);
}
else
{