- 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())) if (mData.Size() > 0 && data->isCompatible(mData.Last()))
{ {
// Merge with the last command. // 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; RenderCommand dg;
int method = 0; int method = 0;
if (!img->isValid()) return; if (!img || !img->isValid()) return;
dg.mType = DrawTypeTriangles; dg.mType = DrawTypeTriangles;
if (clipx1 > 0 || clipy1 > 0 || clipx2 < GetWidth() - 1 || clipy2 < GetHeight() - 1) 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); Set(ptr, vt[i].X, vt[i].Y, 0.f, vt[i].Z, vt[i].W, color);
ptr++; ptr++;
} }
dg.mIndexIndex = mIndices.Size(); dg.mIndexIndex = mIndices.Size();
if (idxcount > 0)
{
mIndices.Reserve(idxcount); mIndices.Reserve(idxcount);
for (size_t i = 0; i < idxcount; i++) for (size_t i = 0; i < idxcount; i++)
{ {
mIndices[dg.mIndexIndex + i] = ind[i] + dg.mVertIndex; mIndices[dg.mIndexIndex + i] = ind[i] + dg.mVertIndex;
} }
dg.mIndexCount = (int)idxcount; 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;
}
AddCommand(&dg); 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, // 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. // This ensures they are below the HUD, not above it.
dg.mScreenFade = screenFade;
mData.Insert(0, dg); mData.Insert(0, dg);
} }
} }

View file

@ -118,6 +118,7 @@ public:
ETexMode mDrawMode; ETexMode mDrawMode;
uint8_t mLightLevel; uint8_t mLightLevel;
uint8_t mFlags; uint8_t mFlags;
float mScreenFade;
bool useTransform; bool useTransform;
DMatrix3x3 transform; DMatrix3x3 transform;
@ -149,6 +150,7 @@ public:
mLightLevel == other.mLightLevel && mLightLevel == other.mLightLevel &&
mColor1.d == other.mColor1.d && mColor1.d == other.mColor1.d &&
useTransform == other.useTransform && useTransform == other.useTransform &&
mScreenFade == other.mScreenFade &&
( (
!useTransform || !useTransform ||
( (
@ -172,7 +174,7 @@ public:
int fullscreenautoaspect = 3; int fullscreenautoaspect = 3;
int cliptop = -1, clipleft = -1, clipwidth = -1, clipheight = -1; int cliptop = -1, clipleft = -1, clipwidth = -1, clipheight = -1;
int AddCommand(const RenderCommand *data); int AddCommand(RenderCommand *data);
void AddIndices(int firstvert, int count, ...); void AddIndices(int firstvert, int count, ...);
private: private:
void AddIndices(int firstvert, TArray<int> &v); void AddIndices(int firstvert, TArray<int> &v);
@ -187,7 +189,7 @@ public:
void AddPoly(FGameTexture *texture, FVector2 *points, int npoints, void AddPoly(FGameTexture *texture, FVector2 *points, int npoints,
double originx, double originy, double scalex, double scaley, double originx, double originy, double scalex, double scaley,
DAngle rotation, const FColormap &colormap, PalEntry flatcolor, double lightlevel, uint32_t *indices, size_t indexcount); 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, 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); 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); 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 ------------------------------------------------- // PUBLIC DATA DEFINITIONS -------------------------------------------------
EXTERN_CVAR(Int, snd_mididevice) 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. 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 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 std::unique_ptr<SoundStream> musicStream;
static TArray<SoundStream*> customStreams;
SoundStream *S_CreateCustomStream(size_t size, int samplerate, int numchannels, StreamCallback cb, void *userdata) SoundStream *S_CreateCustomStream(size_t size, int samplerate, int numchannels, StreamCallback cb, void *userdata)
{ {
int flags = 0; int flags = 0;
if (numchannels < 2) flags |= SoundStream::Mono; if (numchannels < 2) flags |= SoundStream::Mono;
auto stream = GSnd->CreateStream(cb, int(size), flags, samplerate, userdata); 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; return stream;
} }
@ -122,11 +130,19 @@ void S_StopCustomStream(SoundStream *stream)
if (stream) if (stream)
{ {
stream->Stop(); stream->Stop();
auto f = customStreams.Find(stream);
if (f < customStreams.Size()) customStreams.Delete(f);
delete stream; delete stream;
} }
} }
void S_PauseAllCustomStreams(bool on)
{
for (auto s : customStreams)
{
s->SetPaused(on);
}
}
static TArray<int16_t> convert; static TArray<int16_t> convert;
static bool FillStream(SoundStream* stream, void* buff, int len, void* userdata) 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); I_SetRelativeVolume(saved_relative_volume * factor);
} }
ZMusic_Stop(song); 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)) if (!ZMusic_Start(song, subsong, loop))
{ {
return false; return false;
@ -488,6 +507,8 @@ static void CheckReplayGain(const char *musicname, EMidiDevice playertype, const
{ {
mus_playing.replayGain = 0.f; mus_playing.replayGain = 0.f;
mus_playing.replayGainFactor = dBToAmplitude(mus_gainoffset); mus_playing.replayGainFactor = dBToAmplitude(mus_gainoffset);
fluid_gain.Callback();
mod_dumb_mastervolume.Callback();
if (!mus_usereplaygain) return; if (!mus_usereplaygain) return;
FileReader reader = mus_cb.OpenMusic(musicname); FileReader reader = mus_cb.OpenMusic(musicname);

View file

@ -41,6 +41,7 @@
#include "version.h" #include "version.h"
#include <zmusic.h> #include <zmusic.h>
EXTERN_CVAR(Bool, mus_usereplaygain)
//========================================================================== //==========================================================================
// //
// ADL Midi device // ADL Midi device
@ -121,9 +122,18 @@ CUSTOM_CVAR(String, fluid_patchset, GAMENAMELOWERCASE, CVAR_ARCHIVE | CVAR_GLOBA
} }
CUSTOM_CVAR(Float, fluid_gain, 0.5, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) CUSTOM_CVAR(Float, fluid_gain, 0.5, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
if (!mus_usereplaygain)
{ {
FORWARD_CVAR(fluid_gain); 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) CUSTOM_CVAR(Bool, fluid_reverb, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{ {
@ -492,7 +502,15 @@ 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) CUSTOM_CVAR(Float, mod_dumb_mastervolume, 1.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
if (!mus_usereplaygain)
{ {
FORWARD_CVAR(mod_dumb_mastervolume); 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); 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); SoundStream *S_CreateCustomStream(size_t size, int samplerate, int numchannels, StreamCallback cb, void *userdata);
void S_StopCustomStream(SoundStream* stream); void S_StopCustomStream(SoundStream* stream);
void S_PauseAllCustomStreams(bool on);
struct MusicCallbacks 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_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_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_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; 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. // sound is paused and a non-looped sound is being started.
// Such a sound would play right after unpausing which wouldn't sound right. // 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; return NULL;
} }

View file

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

View file

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

View file

@ -1287,6 +1287,42 @@ void FScanner::AddSymbol(const char* name, double value)
symbols.Insert(name, sym); 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 // 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)); } inline void AddSymbol(const char* name, uint32_t value) { return AddSymbol(name, uint64_t(value)); }
void AddSymbol(const char* name, double value); void AddSymbol(const char* name, double value);
void SkipToEndOfBlock(); void SkipToEndOfBlock();
int StartBraces(FScanner::SavedPos* braceend);
bool FoundEndBrace(FScanner::SavedPos& braceend);
static FString TokenName(int token, const char *string=NULL); static FString TokenName(int token, const char *string=NULL);
@ -113,7 +115,30 @@ public:
void MustGetNumber(bool evaluate = false); void MustGetNumber(bool evaluate = false);
bool CheckNumber(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(bool evaluate = false);
bool GetFloat(double& var, bool evaluate = false)
{
if (!GetFloat(evaluate)) return false;
var = Float;
return true;
}
void MustGetFloat(bool evaluate = false); void MustGetFloat(bool evaluate = false);
bool CheckFloat(bool evaluate = false); bool CheckFloat(bool evaluate = false);

View file

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

View file

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

View file

@ -154,13 +154,28 @@ int FDirectory::AddDirectory(const char *dirpath)
} }
else 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 // We shouldn't add backup files to the file system
continue; continue;
} }
size_t size = 0; size_t size = 0;
FString fn = FString(dirpath) + fi; 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)) if (GetFileInfo(fn, &size, nullptr))
{ {
AddEntry(fn, (int)size); AddEntry(fn, (int)size);
@ -209,7 +224,7 @@ void FDirectory::AddEntry(const char *fullpath, int size)
lump_p->LumpSize = size; lump_p->LumpSize = size;
lump_p->Owner = this; lump_p->Owner = this;
lump_p->Flags = 0; 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].Owner = this;
Lumps[i].Position = LittleLong(fileinfo[i].filepos); Lumps[i].Position = LittleLong(fileinfo[i].filepos);
Lumps[i].LumpSize = LittleLong(fileinfo[i].filelen); Lumps[i].LumpSize = LittleLong(fileinfo[i].filelen);
Lumps[i].CheckEmbedded(); Lumps[i].CheckEmbedded(filter);
} }
GenerateHash(); GenerateHash();
PostProcessArchive(&Lumps[0], sizeof(Lumps[0]), filter); PostProcessArchive(&Lumps[0], sizeof(Lumps[0]), filter);

View file

@ -233,12 +233,14 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter)
} }
name.ToLower(); name.ToLower();
if (name.IndexOf("__macosx") == 0)
continue; // skip Apple garbage. At this stage only the root folder matters,
if (i == 0) if (i == 0)
{ {
// check for special names, if one of these gets found this must be treated as a normal zip. // 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()); bool isspecial = name.IndexOf("/") < 0 || (filter && filter->reservedFolders.Find(name) < filter->reservedFolders.Size());
if (isspecial) break; if (isspecial) break;
name0 = name; name0 = name.Left(name.LastIndexOf("/")+1);
} }
else else
{ {
@ -252,7 +254,7 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter)
// at least one of the more common definition lumps must be present. // at least one of the more common definition lumps must be present.
for (auto &p : filter->requiredPrefixes) 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; foundspeciallump = true;
break; break;
@ -272,7 +274,6 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter)
int len = LittleShort(zip_fh->NameLength); int len = LittleShort(zip_fh->NameLength);
FString name(dirptr + sizeof(FZipCentralDirectoryInfo), len); FString name(dirptr + sizeof(FZipCentralDirectoryInfo), len);
if (name0.IsNotEmpty()) name = name.Mid(name0.Len());
dirptr += sizeof(FZipCentralDirectoryInfo) + dirptr += sizeof(FZipCentralDirectoryInfo) +
LittleShort(zip_fh->NameLength) + LittleShort(zip_fh->NameLength) +
LittleShort(zip_fh->ExtraLength) + LittleShort(zip_fh->ExtraLength) +
@ -285,6 +286,13 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter)
return false; 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 // skip Directories
if (name.IsEmpty() || (name.Back() == '/' && LittleLong(zip_fh->UncompressedSize) == 0)) 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->CRC32 = zip_fh->CRC32;
lump_p->CompressedSize = LittleLong(zip_fh->CompressedSize); lump_p->CompressedSize = LittleLong(zip_fh->CompressedSize);
lump_p->Position = LittleLong(zip_fh->LocalHeaderOffset); lump_p->Position = LittleLong(zip_fh->LocalHeaderOffset);
lump_p->CheckEmbedded(); lump_p->CheckEmbedded(filter);
lump_p++; lump_p++;
} }

View file

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

View file

@ -122,7 +122,7 @@ static bool IsWadInFolder(const FResourceFile* const archive, const char* const
return 0 == filePath.CompareNoCase(resPath); return 0 == filePath.CompareNoCase(resPath);
} }
void FResourceLump::CheckEmbedded() void FResourceLump::CheckEmbedded(LumpFilterInfo* lfi)
{ {
// Checks for embedded archives // Checks for embedded archives
const char *c = strstr(FullName, ".wad"); const char *c = strstr(FullName, ".wad");
@ -130,22 +130,13 @@ void FResourceLump::CheckEmbedded()
{ {
Flags |= LUMPF_EMBEDDED; Flags |= LUMPF_EMBEDDED;
} }
/* later else if (lfi) for (auto& fstr : lfi->embeddings)
else
{ {
if (c==NULL) c = strstr(Name, ".zip"); if (!stricmp(FullName, fstr))
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)
{ {
// Mark all embedded archives in any directory
Flags |= LUMPF_EMBEDDED; 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. // The following are for checking if the root directory of a zip can be removed.
TArray<FString> reservedFolders; TArray<FString> reservedFolders;
TArray<FString> requiredPrefixes; TArray<FString> requiredPrefixes;
TArray<FString> embeddings;
std::function<void()> postprocessFunc; std::function<void()> postprocessFunc;
}; };
@ -111,7 +112,7 @@ public:
virtual int GetIndexNum() const { return -1; } virtual int GetIndexNum() const { return -1; }
virtual int GetNamespace() const { return 0; } virtual int GetNamespace() const { return 0; }
void LumpNameSetup(FString iname); void LumpNameSetup(FString iname);
void CheckEmbedded(); void CheckEmbedded(LumpFilterInfo* lfi);
virtual FCompressedBuffer GetRawData(); virtual FCompressedBuffer GetRawData();
void *Lock(); // validates the cache and increases the refcount. 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) void FSavegameManagerBase::DoSave(int Selected, const char *savegamestring)
{ {
RemoveNewSaveNode();
if (Selected != 0) if (Selected != 0)
{ {
auto node = SaveGames[Selected]; auto node = SaveGames[Selected];

View file

@ -80,6 +80,8 @@ FFlatVertexBuffer::FFlatVertexBuffer(int width, int height)
mVertexBuffer = screen->CreateVertexBuffer(); mVertexBuffer = screen->CreateVertexBuffer();
mIndexBuffer = screen->CreateIndexBuffer(); 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); unsigned int bytesize = BUFFER_SIZE * sizeof(FFlatVertex);
mVertexBuffer->SetData(bytesize, nullptr, false); mVertexBuffer->SetData(bytesize, nullptr, false);

View file

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

View file

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

View file

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

View file

@ -62,13 +62,7 @@
#include "hw_renderstate.h" #include "hw_renderstate.h"
#include "v_video.h" #include "v_video.h"
#include "hwrenderer/data/buffers.h" #include "hwrenderer/data/buffers.h"
#include "version.h"
// 57 world units roughly represent one sky texel for the glTranslate call.
enum
{
skyoffsetfactor = 57
};
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// //
@ -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 FAngle maxSideAngle = 60.f;
static const float scale = 10000.; static const float scale = 10000.;
@ -187,6 +181,37 @@ void FSkyVertexBuffer::SkyVertex(int r, int c, bool zflip)
mVertices.Push(vert); 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; int r, c;
bool zflip = !!(hemi & SKYHEMI_LOWER); bool zflip = !!(hemi & SKYHEMI_LOWER);
mPrimStart.Push(mVertices.Size()); mPrimStartDoom.Push(mVertices.Size());
for (c = 0; c < mColumns; c++) for (c = 0; c < mColumns; c++)
{ {
SkyVertex(1, c, zflip); SkyVertexDoom(1, c, zflip);
} }
// The total number of triangles per hemisphere can be calculated // The total number of triangles per hemisphere can be calculated
// as follows: rows * columns * 2 + 2 (for the top cap). // as follows: rows * columns * 2 + 2 (for the top cap).
for (r = 0; r < mRows; r++) for (r = 0; r < mRows; r++)
{ {
mPrimStart.Push(mVertices.Size()); mPrimStartDoom.Push(mVertices.Size());
for (c = 0; c <= mColumns; c++) for (c = 0; c <= mColumns; c++)
{ {
SkyVertex(r + zflip, c, zflip); SkyVertexDoom(r + zflip, c, zflip);
SkyVertex(r + 1 - 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; mColumns = 128;
mRows = 4; mRows = 4;
CreateSkyHemisphere(SKYHEMI_UPPER); CreateSkyHemisphereDoom(SKYHEMI_UPPER);
CreateSkyHemisphere(SKYHEMI_LOWER); CreateSkyHemisphereDoom(SKYHEMI_LOWER);
mPrimStart.Push(mVertices.Size()); mPrimStartDoom.Push(mVertices.Size());
CreateSkyHemisphereBuild(SKYHEMI_UPPER);
CreateSkyHemisphereBuild(SKYHEMI_LOWER);
mPrimStartBuild.Push(mVertices.Size());
mSideStart = mVertices.Size(); mSideStart = mVertices.Size();
mFaceStart[0] = mSideStart + 10; 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 texw = tex->GetDisplayWidth();
float texh = tex->GetDisplayHeight(); float texh = tex->GetDisplayHeight();
@ -332,9 +392,10 @@ void FSkyVertexBuffer::SetupMatrices(FGameTexture *tex, float x_offset, float y_
modelMatrix.loadIdentity(); modelMatrix.loadIdentity();
modelMatrix.rotate(-180.0f + x_offset, 0.f, 1.f, 0.f); modelMatrix.rotate(-180.0f + x_offset, 0.f, 1.f, 0.f);
float xscale = texw < 1024.f ? floorf(1024.f / float(texw)) : 1.f; if (xscale == 0) xscale = texw < 1024.f ? floorf(1024.f / float(texw)) : 1.f;
float yscale = 1.f;
auto texskyoffset = tex->GetSkyOffset() + skyoffset; auto texskyoffset = tex->GetSkyOffset() + skyoffset;
if (yscale == 0)
{
if (texh <= 128 && tiled) if (texh <= 128 && tiled)
{ {
modelMatrix.translate(0.f, (-40 + texskyoffset) * skyoffsetfactor, 0.f); modelMatrix.translate(0.f, (-40 + texskyoffset) * skyoffsetfactor, 0.f);
@ -352,11 +413,13 @@ void FSkyVertexBuffer::SetupMatrices(FGameTexture *tex, float x_offset, float y_
{ {
modelMatrix.translate(0.f, -1250.f, 0.f); modelMatrix.translate(0.f, -1250.f, 0.f);
modelMatrix.scale(1.f, texh / 230.f, 1.f); modelMatrix.scale(1.f, texh / 230.f, 1.f);
yscale = 1.f;
} }
else if (texh <= 240) else if (texh <= 240)
{ {
modelMatrix.translate(0.f, (200 - texh + texskyoffset) * skyoffsetfactor, 0.f); 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); modelMatrix.scale(1.f, 1.f + ((texh - 200.f) / 200.f) * 1.17f, 1.f);
yscale = 1.f;
} }
else else
{ {
@ -364,6 +427,12 @@ void FSkyVertexBuffer::SetupMatrices(FGameTexture *tex, float x_offset, float y_
modelMatrix.scale(1.f, 1.2f * 1.17f, 1.f); modelMatrix.scale(1.f, 1.2f * 1.17f, 1.f);
yscale = 240.f / texh; yscale = 240.f / texh;
} }
}
else
{
modelMatrix.translate(0.f, (-40 + texskyoffset) * skyoffsetfactor, 0.f);
modelMatrix.scale(1.f, 0.8f * 1.17f, 1.f);
}
textureMatrix.loadIdentity(); textureMatrix.loadIdentity();
textureMatrix.scale(mirror ? -xscale : xscale, yscale, 1.f); textureMatrix.scale(mirror ? -xscale : xscale, yscale, 1.f);
textureMatrix.translate(1.f, y_offset / texh, 1.f); textureMatrix.translate(1.f, y_offset / texh, 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]); 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.SetMaterial(tex, UF_Texture, 0, CLAMP_NONE, 0, -1);
state.EnableModelMatrix(true); state.EnableModelMatrix(true);
state.EnableTextureMatrix(true); state.EnableTextureMatrix(true);
SetupMatrices(tex, x_offset, y_offset, mirror, mode, state.mModelMatrix, state.mTextureMatrix, tiled);
} }
int rc = mRows + 1; int rc = mRows + 1;
// The caps only get drawn for the main layer but not for the overlay. // 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); auto& col = R_GetSkyCapColor(tex);
state.SetObjectColor(col.first); state.SetObjectColor(col.first);
state.EnableTexture(false); state.EnableTexture(false);
RenderRow(state, DT_TriangleFan, 0); RenderRow(state, DT_TriangleFan, 0, primStart);
state.SetObjectColor(col.second); state.SetObjectColor(col.second);
RenderRow(state, DT_TriangleFan, rc); RenderRow(state, DT_TriangleFan, rc, primStart);
state.EnableTexture(true); state.EnableTexture(true);
} }
state.SetObjectColor(0xffffffff); state.SetObjectColor(0xffffffff);
for (int i = 1; i <= mRows; i++) for (int i = 1; i <= mRows; i++)
{ {
RenderRow(state, DT_TriangleStrip, i, i == 1); RenderRow(state, DT_TriangleStrip, i, primStart, i == 1);
RenderRow(state, DT_TriangleStrip, rc + i, false); RenderRow(state, DT_TriangleStrip, rc + i, primStart, false);
} }
state.EnableTextureMatrix(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; int faces;

View file

@ -11,6 +11,12 @@ class IVertexBuffer;
struct HWSkyPortal; struct HWSkyPortal;
struct HWDrawInfo; struct HWDrawInfo;
// 57 world units roughly represent one sky texel for the glTranslate call.
enum
{
skyoffsetfactor = 57
};
struct FSkyVertex struct FSkyVertex
{ {
float x, y, z, u, v; float x, y, z, u, v;
@ -55,7 +61,8 @@ public:
IVertexBuffer *mVertexBuffer; IVertexBuffer *mVertexBuffer;
TArray<FSkyVertex> mVertices; TArray<FSkyVertex> mVertices;
TArray<unsigned int> mPrimStart; TArray<unsigned int> mPrimStartDoom;
TArray<unsigned int> mPrimStartBuild;
int mRows, mColumns; int mRows, mColumns;
@ -63,15 +70,17 @@ public:
int mFaceStart[7]; int mFaceStart[7];
int mSideStart; int mSideStart;
void SkyVertex(int r, int c, bool yflip); void SkyVertexDoom(int r, int c, bool yflip);
void CreateSkyHemisphere(int hemi); void SkyVertexBuild(int r, int c, bool yflip);
void CreateSkyHemisphereDoom(int hemi);
void CreateSkyHemisphereBuild(int hemi);
void CreateDome(); void CreateDome();
public: public:
FSkyVertexBuffer(); FSkyVertexBuffer();
~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 std::pair<IVertexBuffer *, IIndexBuffer *> GetBufferObjects() const
{ {
return std::make_pair(mVertexBuffer, nullptr); return std::make_pair(mVertexBuffer, nullptr);
@ -83,8 +92,9 @@ public:
else return mSideStart; else return mSideStart;
} }
void RenderRow(FRenderState& state, EDrawType prim, int row, bool apply = true); void RenderRow(FRenderState& state, EDrawType prim, int row, TArray<unsigned int>& mPrimStart, bool apply = true);
void RenderDome(FRenderState& state, FGameTexture* tex, float x_offset, float y_offset, bool mirror, int mode, bool tiled); void RenderDome(FRenderState& state, FGameTexture* tex, int mode, bool which);
void RenderBox(FRenderState& state, FTextureID texno, FSkyBox* tex, float x_offset, bool sky2, float stretch, const FVector3& skyrotatevector, const FVector3& skyrotatevector2); 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()); vb.UploadData(&vertices[0], vertices.Size(), &indices[0], indices.Size());
state.SetVertexBuffer(&vb); state.SetVertexBuffer(&vb);
state.EnableFog(false); state.EnableFog(false);
state.SetScreenFade(drawer->screenFade);
for(auto &cmd : commands) for(auto &cmd : commands)
{ {
@ -94,6 +93,7 @@ void Draw2D(F2DDrawer *drawer, FRenderState &state)
state.SetRenderStyle(cmd.mRenderStyle); state.SetRenderStyle(cmd.mRenderStyle);
state.EnableBrightmap(!(cmd.mRenderStyle.Flags & STYLEF_ColorIsFixed)); state.EnableBrightmap(!(cmd.mRenderStyle.Flags & STYLEF_ColorIsFixed));
state.EnableFog(2); // Special 2D mode 'fog'. state.EnableFog(2); // Special 2D mode 'fog'.
state.SetScreenFade(cmd.mScreenFade);
state.SetTextureMode(cmd.mDrawMode); state.SetTextureMode(cmd.mDrawMode);

View file

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

View file

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

View file

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

View file

@ -37,8 +37,9 @@
VkHardwareTexture *VkHardwareTexture::First = nullptr; VkHardwareTexture *VkHardwareTexture::First = nullptr;
VkHardwareTexture::VkHardwareTexture() VkHardwareTexture::VkHardwareTexture(int numchannels)
{ {
mTexelsize = numchannels;
Next = First; Next = First;
First = this; First = this;
if (Next) Next->Prev = this; if (Next) Next->Prev = this;
@ -126,7 +127,8 @@ void VkHardwareTexture::CreateImage(FTexture *tex, int translation, int flags)
if (!tex->isHardwareCanvas()) if (!tex->isHardwareCanvas())
{ {
FTextureBuffer texbuffer = tex->CreateTexBuffer(translation, flags | CTF_ProcessData); 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 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) if (w <= 0 || h <= 0)
throw CVulkanError("Trying to create zero size texture"); 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; ImageBuilder imgbuilder;
imgbuilder.setFormat(format); 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); 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 = imgbuilder.create(fb->device);
mImage.Image->SetDebugName("VkHardwareTexture.mImage"); 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)); fb->FrameDeleteList.Buffers.push_back(std::move(stagingBuffer));
mImage.GenerateMipmaps(cmdbuffer); if (mipmap) mImage.GenerateMipmaps(cmdbuffer);
} }
int VkHardwareTexture::GetMipLevels(int w, int h) 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) 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; return 0;
} }
@ -371,10 +374,6 @@ VulkanDescriptorSet* VkMaterial::GetDescriptorSet(const FMaterialState& state)
int clampmode = state.mClampMode; int clampmode = state.mClampMode;
int translation = state.mTranslation; int translation = state.mTranslation;
auto remap = translation <= 0 ? nullptr : GPalette.TranslationToTable(translation);
if (remap)
translation = remap->Index;
clampmode = base->GetClampMode(clampmode); clampmode = base->GetClampMode(clampmode);
for (auto& set : mDescriptorSets) for (auto& set : mDescriptorSets)
@ -395,11 +394,24 @@ VulkanDescriptorSet* VkMaterial::GetDescriptorSet(const FMaterialState& state)
MaterialLayerInfo *layer; MaterialLayerInfo *layer;
auto systex = static_cast<VkHardwareTexture*>(GetLayer(0, state.mTranslation, &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); update.addCombinedImageSampler(descriptor.get(), 0, systex->GetImage(layer->layerTexture, state.mTranslation, layer->scaleFlags)->View.get(), sampler, systex->mImage.Layout);
if (!(layer->scaleFlags & CTF_Indexed))
{
for (int i = 1; i < numLayers; i++) for (int i = 1; i < numLayers; i++)
{ {
auto systex = static_cast<VkHardwareTexture*>(GetLayer(i, 0, &layer)); 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); 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(); auto dummyImage = fb->GetRenderPassManager()->GetNullTextureView();
for (int i = numLayers; i < SHADER_MIN_REQUIRED_TEXTURE_LAYERS; i++) for (int i = numLayers; i < SHADER_MIN_REQUIRED_TEXTURE_LAYERS; i++)

View file

@ -24,7 +24,7 @@ class VkHardwareTexture : public IHardwareTexture
{ {
friend class VkMaterial; friend class VkMaterial;
public: public:
VkHardwareTexture(); VkHardwareTexture(int numchannels);
~VkHardwareTexture(); ~VkHardwareTexture();
static void ResetAll(); static void ResetAll();
@ -45,7 +45,7 @@ public:
private: private:
void CreateImage(FTexture *tex, int translation, int flags); 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 int GetMipLevels(int w, int h);
static VkHardwareTexture *First; 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()) if (!texture.isValid())
return; return;
FGameTexture* tex = TexMan.GetGameTexture(texture, !(flags & DI_DONTANIMATE)); 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) 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 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(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 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 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 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); 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); FTexture::SetSize(width, height);
Image.Resize(width * height * (format == Paletted ? 1 : 3)); Image.Resize(width * height * (format == Paletted ? 1 : 3));
memset(Image.Data(), 0, Image.Size()); memset(Image.Data(), 0, Image.Size());
CleanHardwareTextures();
} }
void AnimTexture::SetFrame(const uint8_t* palette, const void* data_) 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)); 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); static_cast<AnimTexture*>(tex[1]->GetTexture())->SetFrameSize(format, width, height);
tex[0]->SetSize(width, height); tex[0]->SetSize(width, height);
tex[1]->SetSize(width, height); tex[1]->SetSize(width, height);
tex[0]->CleanHardwareData();
tex[1]->CleanHardwareData();
} }
void AnimTextures::SetFrame(const uint8_t* palette, const void* data) void AnimTextures::SetFrame(const uint8_t* palette, const void* data)
{ {
active ^= 1; active ^= 1;
static_cast<AnimTexture*>(tex[active]->GetTexture())->SetFrame(palette, data); static_cast<AnimTexture*>(tex[active]->GetTexture())->SetFrame(palette, data);
tex[active]->CleanHardwareData();
} }

View file

@ -30,6 +30,7 @@
#include "v_video.h" #include "v_video.h"
static IHardwareTexture* (*layercallback)(int layer, int translation); static IHardwareTexture* (*layercallback)(int layer, int translation);
TArray<UserShaderDesc> usershaders;
void FMaterial::SetLayerCallback(IHardwareTexture* (*cb)(int layer, int translation)) 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); template <typename Polygon> Node* eliminateHoles(const Polygon& points, Node* outerNode);
void eliminateHole(Node* hole, Node* outerNode); void eliminateHole(Node* hole, Node* outerNode);
Node* findHoleBridge(Node* hole, Node* outerNode); Node* findHoleBridge(Node* hole, Node* outerNode);
bool sectorContainsSector(const Node* m, const Node* p);
void indexCurve(Node* start); void indexCurve(Node* start);
Node* sortLinked(Node* list); Node* sortLinked(Node* list);
int32_t zOrder(const double x_, const double y_); 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; double area(const Node* p, const Node* q, const Node* r) const;
bool equals(const Node* p1, const Node* p2); bool equals(const Node* p1, const Node* p2);
bool intersects(const Node* p1, const Node* q1, const Node* p2, const Node* q2); 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 intersectsPolygon(const Node* a, const Node* b);
bool locallyInside(const Node* a, const Node* b); bool locallyInside(const Node* a, const Node* b);
bool middleInside(const Node* a, const Node* b); bool middleInside(const Node* a, const Node* b);
@ -116,16 +119,18 @@ private:
template <typename... Args> template <typename... Args>
T* construct(Args&&... args) { T* construct(Args&&... args) {
if (currentIndex >= blockSize) { if (currentIndex >= blockSize) {
currentBlock = alloc.allocate(blockSize); currentBlock = alloc_traits::allocate(alloc, blockSize);
allocations.emplace_back(currentBlock); allocations.emplace_back(currentBlock);
currentIndex = 0; currentIndex = 0;
} }
T* object = &currentBlock[currentIndex++]; T* object = &currentBlock[currentIndex++];
alloc.construct(object, std::forward<Args>(args)...); alloc_traits::construct(alloc, object, std::forward<Args>(args)...);
return object; return object;
} }
void reset(std::size_t newBlockSize) { 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(); allocations.clear();
blockSize = std::max<std::size_t>(1, newBlockSize); blockSize = std::max<std::size_t>(1, newBlockSize);
currentBlock = nullptr; currentBlock = nullptr;
@ -138,6 +143,7 @@ private:
std::size_t blockSize = 1; std::size_t blockSize = 1;
std::vector<T*> allocations; std::vector<T*> allocations;
Alloc alloc; Alloc alloc;
typedef typename std::allocator_traits<Alloc> alloc_traits;
}; };
ObjectPool<Node> nodes; ObjectPool<Node> nodes;
}; };
@ -165,7 +171,7 @@ void Earcut<N>::operator()(const Polygon& points) {
indices.reserve(len + points[0].size()); indices.reserve(len + points[0].size());
Node* outerNode = linkedList(points[0], true); Node* outerNode = linkedList(points[0], true);
if (!outerNode) return; if (!outerNode || outerNode->prev == outerNode->next) return;
if (points.size() > 1) outerNode = eliminateHoles(points, outerNode); if (points.size() > 1) outerNode = eliminateHoles(points, outerNode);
@ -244,8 +250,7 @@ Earcut<N>::filterPoints(Node* start, Node* end) {
do { do {
again = false; 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); removeNode(p);
p = end = p->prev; 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 // if this didn't work, try curing all small self-intersections locally
else if (pass == 1) { else if (pass == 1) {
ear = cureLocalIntersections(ear); ear = cureLocalIntersections(filterPoints(ear));
earcutLinked(ear, 2); earcutLinked(ear, 2);
// as a last resort, try splitting the remaining polygon into two // as a last resort, try splitting the remaining polygon into two
@ -401,7 +406,7 @@ Earcut<N>::cureLocalIntersections(Node* start) {
p = p->next; p = p->next;
} while (p != start); } while (p != start);
return p; return filterPoints(p);
} }
// try splitting polygon into two and triangulate them independently // 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); outerNode = findHoleBridge(hole, outerNode);
if (outerNode) { if (outerNode) {
Node* b = splitPolygon(outerNode, hole); Node* b = splitPolygon(outerNode, hole);
// filter out colinear points around cuts
filterPoints(outerNode, outerNode->next);
filterPoints(b, b->next); filterPoints(b, b->next);
} }
} }
@ -497,7 +505,7 @@ Earcut<N>::findHoleBridge(Node* hole, Node* outerNode) {
if (!m) return 0; 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; // look for points inside the triangle of hole Vertex, segment intersection and endpoint;
// if there are no points found, we have a valid connection; // 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 tanMin = std::numeric_limits<double>::infinity();
double tanCur = 0; double tanCur = 0;
p = m->next; p = m;
double mx = m->x; double mx = m->x;
double my = m->y; double my = m->y;
while (p != stop) { do {
if (hx >= p->x && p->x >= mx && hx != p->x && 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)) { 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 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; m = p;
tanMin = tanCur; tanMin = tanCur;
} }
} }
p = p->next; p = p->next;
} } while (p != stop);
return m; 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 // interlink polygon nodes in z-order
template <typename N> template <typename N>
void Earcut<N>::indexCurve(Node* start) { void Earcut<N>::indexCurve(Node* start) {
@ -644,7 +659,8 @@ Earcut<N>::getLeftmost(Node* start) {
Node* p = start; Node* p = start;
Node* leftmost = start; Node* leftmost = start;
do { 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; p = p->next;
} while (p != start); } 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) // check if a diagonal between two polygon nodes is valid (lies in polygon interior)
template <typename N> template <typename N>
bool Earcut<N>::isValidDiagonal(Node* a, Node* b) { bool Earcut<N>::isValidDiagonal(Node* a, Node* b) {
return a->next->i != b->i && a->prev->i != b->i && !intersectsPolygon(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); ((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 // signed area of a triangle
@ -681,10 +699,33 @@ bool Earcut<N>::equals(const Node* p1, const Node* p2) {
// check if two segments intersect // check if two segments intersect
template <typename N> template <typename N>
bool Earcut<N>::intersects(const Node* p1, const Node* q1, const Node* p2, const Node* q2) { bool Earcut<N>::intersects(const Node* p1, const Node* q1, const Node* p2, const Node* q2) {
if ((equals(p1, q1) && equals(p2, q2)) || int o1 = sign(area(p1, q1, p2));
(equals(p1, q2) && equals(p2, q1))) return true; int o2 = sign(area(p1, q1, q2));
return (area(p1, q1, p2) > 0) != (area(p1, q1, q2) > 0) && int o3 = sign(area(p2, q2, p1));
(area(p2, q2, p1) > 0) != (area(p2, q2, q1) > 0); 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 // check if a polygon diagonal intersects any polygon segments

View file

@ -2,6 +2,7 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <algorithm>
#define MAXWIDTH 12000 #define MAXWIDTH 12000
#define MAXHEIGHT 5000 #define MAXHEIGHT 5000
@ -101,3 +102,6 @@ enum EStateUseFlags
SUF_WEAPON = 4, SUF_WEAPON = 4,
SUF_ITEM = 8, 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); } 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 #endif

View file

@ -33,9 +33,7 @@ class VSMatrix {
public: public:
VSMatrix() VSMatrix() = default;
{
}
VSMatrix(int) 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 InitializeActorLights(TArray<FLightAssociation> &LightAssociations);
void ParseColorization(FScanner& sc); void ParseColorization(FScanner& sc);
TArray<UserShaderDesc> usershaders;
extern TDeletingArray<FLightDefaults *> LightDefaults; extern TDeletingArray<FLightDefaults *> LightDefaults;
extern int AttenuationIsSet; extern int AttenuationIsSet;

View file

@ -1,6 +1,8 @@
#pragma once #pragma once
#include "hw_aabbtree.h" #include "hw_aabbtree.h"
struct FLevelLocals;
// Axis aligned bounding box tree used for ray testing treelines. // Axis aligned bounding box tree used for ray testing treelines.
class DoomLevelAABBTree : public hwrenderer::LevelAABBTree 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; auto skybox = origin->texture[0] ? dynamic_cast<FSkyBox*>(origin->texture[0]->GetTexture()) : nullptr;
if (skybox) 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 else
{ {