- Backend update from GZDoom

* music system improvements
* Zip64 support
* fixes for menu scaling on ultrawide screens
* Mac default paths fixed
* lightmap code (not active yet)
This commit is contained in:
Christoph Oelckers 2022-04-25 11:13:55 +02:00
parent 380864d6fb
commit 21b4862460
48 changed files with 906 additions and 144 deletions

View file

@ -1101,6 +1101,7 @@ set (PCH_SOURCES
common/2d/v_2ddrawer.cpp
common/2d/v_drawtext.cpp
common/2d/v_draw.cpp
common/2d/wipe.cpp
common/thirdparty/gain_analysis.cpp
common/thirdparty/sfmt/SFMT.cpp
common/fonts/singlelumpfont.cpp

444
source/common/2d/wipe.cpp Executable file
View file

@ -0,0 +1,444 @@
/*
** wipe.cpp
** Screen wipe implementation
**
**---------------------------------------------------------------------------
** Copyright 1998-2016 Randy Heit
** Copyright 2005-2022 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "v_video.h"
#include "m_random.h"
#include "wipe.h"
#include "bitmap.h"
#include "hw_material.h"
#include "v_draw.h"
#include "s_soundinternal.h"
#include "i_time.h"
class FBurnTexture : public FTexture
{
TArray<uint32_t> WorkBuffer;
public:
FBurnTexture(int w, int h)
: WorkBuffer(w*h, true)
{
Width = w;
Height = h;
}
FBitmap GetBgraBitmap(const PalEntry*, int *trans) override
{
FBitmap bmp;
bmp.Create(Width, Height);
bmp.CopyPixelDataRGB(0, 0, (uint8_t*)WorkBuffer.Data(), Width, Height, 4, Width*4, 0, CF_RGBA, nullptr);
if (trans) *trans = 0;
return bmp;
}
uint32_t *GetBuffer()
{
return WorkBuffer.Data();
}
};
int wipe_CalcBurn (uint8_t *burnarray, int width, int height, int density)
{
// This is a modified version of the fire that was once used
// on the player setup menu.
static int voop;
int a, b;
uint8_t *from;
// generator
from = &burnarray[width * height];
b = voop;
voop += density / 3;
for (a = 0; a < density/8; a++)
{
unsigned int offs = (a+b) & (width - 1);
unsigned int v = M_Random();
v = min(from[offs] + 4 + (v & 15) + (v >> 3) + (M_Random() & 31), 255u);
from[offs] = from[width*2 + ((offs + width*3/2) & (width - 1))] = v;
}
density = min(density + 10, width * 7);
from = burnarray;
for (b = 0; b <= height; b += 2)
{
uint8_t *pixel = from;
// special case: first pixel on line
uint8_t *p = pixel + (width << 1);
unsigned int top = *p + *(p + width - 1) + *(p + 1);
unsigned int bottom = *(pixel + (width << 2));
unsigned int c1 = (top + bottom) >> 2;
if (c1 > 1) c1--;
*pixel = c1;
*(pixel + width) = (c1 + bottom) >> 1;
pixel++;
// main line loop
for (a = 1; a < width-1; a++)
{
// sum top pixels
p = pixel + (width << 1);
top = *p + *(p - 1) + *(p + 1);
// bottom pixel
bottom = *(pixel + (width << 2));
// combine pixels
c1 = (top + bottom) >> 2;
if (c1 > 1) c1--;
// store pixels
*pixel = c1;
*(pixel + width) = (c1 + bottom) >> 1; // interpolate
// next pixel
pixel++;
}
// special case: last pixel on line
p = pixel + (width << 1);
top = *p + *(p - 1) + *(p - width + 1);
bottom = *(pixel + (width << 2));
c1 = (top + bottom) >> 2;
if (c1 > 1) c1--;
*pixel = c1;
*(pixel + width) = (c1 + bottom) >> 1;
// next line
from += width << 1;
}
// Check for done-ness. (Every pixel with level 126 or higher counts as done.)
for (a = width * height, from = burnarray; a != 0; --a, ++from)
{
if (*from < 126)
{
return density;
}
}
return -1;
}
// TYPES -------------------------------------------------------------------
class Wiper_Crossfade : public Wiper
{
public:
bool Run(int ticks) override;
private:
int Clock = 0;
};
class Wiper_Melt : public Wiper
{
public:
Wiper_Melt();
bool Run(int ticks) override;
private:
enum { WIDTH = 320, HEIGHT = 200 };
int y[WIDTH];
};
class Wiper_Burn : public Wiper
{
public:
~Wiper_Burn();
bool Run(int ticks) override;
void SetTextures(FGameTexture *startscreen, FGameTexture *endscreen) override;
private:
static const int WIDTH = 64, HEIGHT = 64;
uint8_t BurnArray[WIDTH * (HEIGHT + 5)] = {0};
FBurnTexture *BurnTexture = nullptr;
int Density = 4;
int BurnTime = 8;
};
//===========================================================================
//
// Screen wipes
//
//===========================================================================
Wiper *Wiper::Create(int type)
{
switch(type)
{
case wipe_Burn:
return new Wiper_Burn;
case wipe_Fade:
return new Wiper_Crossfade;
case wipe_Melt:
return new Wiper_Melt;
default:
return nullptr;
}
}
//==========================================================================
//
// OpenGLFrameBuffer :: WipeCleanup
//
// Release any resources that were specifically created for the wipe.
//
//==========================================================================
Wiper::~Wiper()
{
if (startScreen != nullptr) delete startScreen;
if (endScreen != nullptr) delete endScreen;
}
//==========================================================================
//
// WIPE: CROSSFADE ---------------------------------------------------------
//
//==========================================================================
//==========================================================================
//
// OpenGLFrameBuffer :: Wiper_Crossfade :: Run
//
// Fades the old screen into the new one over 32 ticks.
//
//==========================================================================
bool Wiper_Crossfade::Run(int ticks)
{
Clock += ticks;
DrawTexture(twod, startScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, TAG_DONE);
DrawTexture(twod, endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, DTA_Alpha, clamp(Clock / 32.f, 0.f, 1.f), TAG_DONE);
return Clock >= 32;
}
//==========================================================================
//
// OpenGLFrameBuffer :: Wiper_Melt Constructor
//
//==========================================================================
Wiper_Melt::Wiper_Melt()
{
y[0] = -(M_Random() & 15);
for (int i = 1; i < WIDTH; ++i)
{
y[i] = clamp(y[i-1] + (M_Random() % 3) - 1, -15, 0);
}
}
//==========================================================================
//
// OpenGLFrameBuffer :: Wiper_Melt :: Run
//
// Melts the old screen into the new one over 32 ticks.
//
//==========================================================================
bool Wiper_Melt::Run(int ticks)
{
bool done;
DrawTexture(twod, endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, TAG_DONE);
// Copy the old screen in vertical strips on top of the new one.
while (ticks--)
{
done = true;
for (int i = 0; i < WIDTH; i++)
{
if (y[i] < HEIGHT)
{
if (y[i] < 0)
y[i]++;
else if (y[i] < 16)
y[i] += y[i] + 1;
else
y[i] = min<int>(y[i] + 8, HEIGHT);
done = false;
}
if (ticks == 0)
{
struct {
int32_t x;
int32_t y;
} dpt;
struct {
int32_t left;
int32_t top;
int32_t right;
int32_t bottom;
} rect;
// Only draw for the final tick.
int w = startScreen->GetTexelWidth();
int h = startScreen->GetTexelHeight();
dpt.x = i * w / WIDTH;
dpt.y = max(0, y[i] * h / HEIGHT);
rect.left = dpt.x;
rect.top = 0;
rect.right = (i + 1) * w / WIDTH;
rect.bottom = h - dpt.y;
if (rect.bottom > rect.top)
{
DrawTexture(twod, startScreen, 0, dpt.y, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_ClipLeft, rect.left, DTA_ClipRight, rect.right, DTA_Masked, false, TAG_DONE);
}
}
}
}
return done;
}
//==========================================================================
//
// OpenGLFrameBuffer :: Wiper_Burn Constructor
//
//==========================================================================
void Wiper_Burn::SetTextures(FGameTexture *startscreen, FGameTexture *endscreen)
{
startScreen = startscreen;
endScreen = endscreen;
BurnTexture = new FBurnTexture(WIDTH, HEIGHT);
auto mat = FMaterial::ValidateTexture(endScreen, false);
mat->ClearLayers();
mat->AddTextureLayer(BurnTexture, false);
}
//==========================================================================
//
// OpenGLFrameBuffer :: Wiper_Burn Destructor
//
//==========================================================================
Wiper_Burn::~Wiper_Burn()
{
if (BurnTexture != nullptr) delete BurnTexture;
}
//==========================================================================
//
// OpenGLFrameBuffer :: Wiper_Burn :: Run
//
//==========================================================================
bool Wiper_Burn::Run(int ticks)
{
bool done;
BurnTime += ticks;
ticks *= 2;
// Make the fire burn
done = false;
while (!done && ticks--)
{
Density = wipe_CalcBurn(BurnArray, WIDTH, HEIGHT, Density);
done = (Density < 0);
}
BurnTexture->CleanHardwareTextures();
endScreen->CleanHardwareData(false); // this only cleans the descriptor sets for the Vulkan backend. We do not want to delete the wipe screen's hardware texture here.
const uint8_t *src = BurnArray;
uint32_t *dest = (uint32_t *)BurnTexture->GetBuffer();
for (int y = HEIGHT; y != 0; --y)
{
for (int x = WIDTH; x != 0; --x)
{
uint8_t s = clamp<int>((*src++)*2, 0, 255);
*dest++ = MAKEARGB(s,255,255,255);
}
}
DrawTexture(twod, startScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, TAG_DONE);
DrawTexture(twod, endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Burn, true, DTA_Masked, false, TAG_DONE);
// The fire may not always stabilize, so the wipe is forced to end
// after an arbitrary maximum time.
return done || (BurnTime > 40);
}
void PerformWipe(FTexture* startimg, FTexture* endimg, int wipe_type, bool stopsound, std::function<void()> overlaydrawer)
{
// wipe update
uint64_t wipestart, nowtime, diff;
bool done;
GSnd->SetSfxPaused(true, 1);
I_FreezeTime(true);
twod->End();
assert(startimg != nullptr && endimg != nullptr);
auto starttex = MakeGameTexture(startimg, nullptr, ETextureType::SWCanvas);
auto endtex = MakeGameTexture(endimg, nullptr, ETextureType::SWCanvas);
auto wiper = Wiper::Create(wipe_type);
wiper->SetTextures(starttex, endtex);
wipestart = I_msTime();
do
{
do
{
I_WaitVBL(2);
nowtime = I_msTime();
diff = (nowtime - wipestart) * 40 / 1000; // Using 35 here feels too slow.
} while (diff < 1);
wipestart = nowtime;
twod->Begin(screen->GetWidth(), screen->GetHeight());
done = wiper->Run(1);
if (overlaydrawer) overlaydrawer();
twod->End();
screen->Update();
twod->OnFrameDone();
} while (!done);
delete wiper;
I_FreezeTime(false);
GSnd->SetSfxPaused(false, 1);
}

38
source/common/2d/wipe.h Executable file
View file

@ -0,0 +1,38 @@
#ifndef __F_WIPE_H__
#define __F_WIPE_H__
#include "stdint.h"
#include <functional>
class FTexture;
int wipe_CalcBurn(uint8_t *buffer, int width, int height, int density);
enum
{
wipe_None, // don't bother
wipe_Melt, // weird screen melt
wipe_Burn, // fade in shape of fire
wipe_Fade, // crossfade from old to new
wipe_NUMWIPES
};
class Wiper
{
protected:
FGameTexture *startScreen = nullptr, *endScreen = nullptr;
public:
virtual ~Wiper();
virtual bool Run(int ticks) = 0;
virtual void SetTextures(FGameTexture *startscreen, FGameTexture *endscreen)
{
startScreen = startscreen;
endScreen = endscreen;
}
static Wiper *Create(int type);
};
void PerformWipe(FTexture* startimg, FTexture* endimg, int wipe_type, bool stopsound, std::function<void()> overlaydrawer);
#endif

View file

@ -200,7 +200,8 @@ static void SetupWgOpn()
static void SetupDMXGUS()
{
int lump = fileSystem.CheckNumForFullName("DMXGUS");
int lump = fileSystem.CheckNumForName("DMXGUSC", ns_global);
if (lump < 0) lump = fileSystem.CheckNumForName("DMXGUS", ns_global);
if (lump < 0)
{
return;

View file

@ -194,6 +194,7 @@ FileReader FSF2Reader::OpenFile(const char *name)
FZipPatReader::FZipPatReader(const char *filename)
{
mAllowAbsolutePaths = true;
resf = FResourceFile::OpenResourceFile(filename, true);
}
@ -218,6 +219,7 @@ FileReader FZipPatReader::OpenFile(const char *name)
return lump->NewReader();
}
}
fr.OpenFile(name);
return fr;
}
@ -478,13 +480,6 @@ FSoundFontReader *FSoundFontManager::OpenSoundFont(const char *name, int allowed
}
}
auto sfi = FindSoundFont(name, allowed);
if (sfi != nullptr)
{
if (sfi->type == SF_SF2) return new FSF2Reader(sfi->mFilename);
else return new FZipPatReader(sfi->mFilename);
}
// The sound font collection did not yield any good results.
// Next check if the file is a .sf file
if (allowed & SF_SF2)
{
@ -500,6 +495,7 @@ FSoundFontReader *FSoundFontManager::OpenSoundFont(const char *name, int allowed
}
}
}
// Next check if the file is a resource file (it should contains gus patches and a timidity.cfg file)
if (allowed & SF_GUS)
{
FileReader fr;
@ -523,6 +519,13 @@ FSoundFontReader *FSoundFontManager::OpenSoundFont(const char *name, int allowed
return new FPatchSetReader(name);
}
}
// Lastly check in the sound font collection for a specific item or pick the first valid item available.
auto sfi = FindSoundFont(name, allowed);
if (sfi != nullptr)
{
if (sfi->type == SF_SF2) return new FSF2Reader(sfi->mFilename);
else return new FZipPatReader(sfi->mFilename);
}
return nullptr;
}

View file

@ -278,7 +278,7 @@ CUSTOM_CVAR(String, opn_custom_bank, "", CVAR_ARCHIVE | CVAR_VIRTUAL)
//==========================================================================
CUSTOM_CVAR(String, midi_config, GAMENAMELOWERCASE, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
CUSTOM_CVAR(String, midi_config, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
FORWARD_STRING_CVAR(gus_config);
}

View file

@ -55,9 +55,6 @@ struct FLatchedValue
static TArray<FLatchedValue> LatchedValues;
bool FBaseCVar::m_DoNoSet = false;
bool FBaseCVar::m_UseCallback = false;
FBaseCVar *CVars = NULL;
int cvar_defflags;
@ -523,6 +520,7 @@ void FBaseCVar::EnableNoSet ()
void FBaseCVar::EnableCallbacks ()
{
m_inEnable = true;
m_UseCallback = true;
FBaseCVar *cvar = CVars;
@ -534,6 +532,7 @@ void FBaseCVar::EnableCallbacks ()
}
cvar = cvar->m_Next;
}
m_inEnable = false;
}
void FBaseCVar::DisableCallbacks ()

View file

@ -210,14 +210,17 @@ protected:
uint32_t Flags;
bool inCallback = false;
public:
static inline bool m_inEnable = false;
private:
FBaseCVar (const FBaseCVar &var) = delete;
FBaseCVar (const char *name, uint32_t flags);
void (*m_Callback)(FBaseCVar &);
FBaseCVar *m_Next;
static bool m_UseCallback;
static bool m_DoNoSet;
static inline bool m_UseCallback = false;
static inline bool m_DoNoSet = false;
void *m_ExtraDataPointer;

View file

@ -51,7 +51,6 @@
#include "s_music.h"
#include "m_argv.h"
#include "i_interface.h"
#include "gamecontrol.h"
CVAR(Bool, inter_subtitles, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
@ -313,16 +312,14 @@ bool StartCutscene(CutsceneDef& cs, int flags, const CompletionFunc& completion_
cs.Create(runner);
if (!ScreenJobValidate())
{
runner->Destroy();
runner = nullptr;
DeleteScreenJob();
return false;
}
if (sysCallbacks.StartCutscene) sysCallbacks.StartCutscene(flags & SJ_BLOCKUI);
}
catch (...)
{
if (runner) runner->Destroy();
runner = nullptr;
DeleteScreenJob();
throw;
}
return true;

View file

@ -115,7 +115,7 @@ bool FCompressedBuffer::Decompress(char *destbuffer)
//
//-----------------------------------------------------------------------
static uint32_t Zip_FindCentralDir(FileReader &fin)
static uint32_t Zip_FindCentralDir(FileReader &fin, bool* zip64)
{
unsigned char buf[BUFREADCOMMENT + 4];
uint32_t FileSize;
@ -145,15 +145,18 @@ static uint32_t Zip_FindCentralDir(FileReader &fin)
for (i = (int)uReadSize - 3; (i--) > 0;)
{
if (buf[i] == 'P' && buf[i+1] == 'K' && buf[i+2] == 5 && buf[i+3] == 6)
if (buf[i] == 'P' && buf[i+1] == 'K' && buf[i+2] == 5 && buf[i+3] == 6 && !*zip64 && uPosFound == 0)
{
*zip64 = false;
uPosFound = uReadPos + i;
break;
}
if (buf[i] == 'P' && buf[i+1] == 'K' && buf[i+2] == 6 && buf[i+3] == 6)
{
*zip64 = true;
uPosFound = uReadPos + i;
return uPosFound;
}
}
if (uPosFound != 0)
break;
}
return uPosFound;
}
@ -172,8 +175,8 @@ FZipFile::FZipFile(const char * filename, FileReader &file)
bool FZipFile::Open(bool quiet, LumpFilterInfo* filter)
{
uint32_t centraldir = Zip_FindCentralDir(Reader);
FZipEndOfCentralDirectory info;
bool zip64 = false;
uint32_t centraldir = Zip_FindCentralDir(Reader, &zip64);
int skipped = 0;
Lumps = NULL;
@ -184,25 +187,50 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter)
return false;
}
// Read the central directory info.
Reader.Seek(centraldir, FileReader::SeekSet);
Reader.Read(&info, sizeof(FZipEndOfCentralDirectory));
// No multi-disk zips!
if (info.NumEntries != info.NumEntriesOnAllDisks ||
info.FirstDisk != 0 || info.DiskNumber != 0)
uint64_t dirsize, DirectoryOffset;
if (!zip64)
{
if (!quiet) Printf(TEXTCOLOR_RED "\n%s: Multipart Zip files are not supported.\n", FileName.GetChars());
return false;
}
FZipEndOfCentralDirectory info;
// Read the central directory info.
Reader.Seek(centraldir, FileReader::SeekSet);
Reader.Read(&info, sizeof(FZipEndOfCentralDirectory));
NumLumps = LittleShort(info.NumEntries);
// No multi-disk zips!
if (info.NumEntries != info.NumEntriesOnAllDisks ||
info.FirstDisk != 0 || info.DiskNumber != 0)
{
if (!quiet) Printf(TEXTCOLOR_RED "\n%s: Multipart Zip files are not supported.\n", FileName.GetChars());
return false;
}
NumLumps = LittleShort(info.NumEntries);
dirsize = LittleLong(info.DirectorySize);
DirectoryOffset = LittleLong(info.DirectoryOffset);
}
else
{
FZipEndOfCentralDirectory64 info;
// Read the central directory info.
Reader.Seek(centraldir, FileReader::SeekSet);
Reader.Read(&info, sizeof(FZipEndOfCentralDirectory64));
// No multi-disk zips!
if (info.NumEntries != info.NumEntriesOnAllDisks ||
info.FirstDisk != 0 || info.DiskNumber != 0)
{
if (!quiet) Printf(TEXTCOLOR_RED "\n%s: Multipart Zip files are not supported.\n", FileName.GetChars());
return false;
}
NumLumps = info.NumEntries;
dirsize = info.DirectorySize;
DirectoryOffset = info.DirectoryOffset;
}
Lumps = new FZipLump[NumLumps];
// Load the entire central directory. Too bad that this contains variable length entries...
int dirsize = LittleLong(info.DirectorySize);
void *directory = malloc(dirsize);
Reader.Seek(LittleLong(info.DirectoryOffset), FileReader::SeekSet);
Reader.Seek(DirectoryOffset, FileReader::SeekSet);
Reader.Read(directory, dirsize);
char *dirptr = (char*)directory;
@ -305,7 +333,7 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter)
if (name0.IsNotEmpty()) name = name.Mid(name0.Len());
// skip Directories
if (name.IsEmpty() || (name.Back() == '/' && LittleLong(zip_fh->UncompressedSize) == 0))
if (name.IsEmpty() || (name.Back() == '/' && LittleLong(zip_fh->UncompressedSize32) == 0))
{
skipped++;
continue;
@ -335,9 +363,39 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter)
FixPathSeperator(name);
name.ToLower();
uint32_t UncompressedSize =LittleLong(zip_fh->UncompressedSize32);
uint32_t CompressedSize = LittleLong(zip_fh->CompressedSize32);
uint64_t LocalHeaderOffset = LittleLong(zip_fh->LocalHeaderOffset32);
if (zip_fh->ExtraLength > 0)
{
uint8_t* rawext = (uint8_t*)zip_fh + sizeof(*zip_fh) + zip_fh->NameLength;
uint32_t ExtraLength = LittleLong(zip_fh->ExtraLength);
while (ExtraLength > 0)
{
auto zip_64 = (FZipCentralDirectoryInfo64BitExt*)rawext;
uint32_t BlockLength = LittleLong(zip_64->Length);
rawext += BlockLength + 4;
ExtraLength -= BlockLength + 4;
if (LittleLong(zip_64->Type) == 1 && BlockLength >= 0x18)
{
if (zip_64->CompressedSize > 0x7fffffff || zip_64->UncompressedSize > 0x7fffffff)
{
// The file system is limited to 32 bit file sizes;
if (!quiet) Printf(TEXTCOLOR_YELLOW "\n%s: '%s' is too large.\n", FileName.GetChars(), name.GetChars());
skipped++;
continue;
}
UncompressedSize = (uint32_t)zip_64->UncompressedSize;
CompressedSize = (uint32_t)zip_64->CompressedSize;
LocalHeaderOffset = zip_64->LocalHeaderOffset;
}
}
}
lump_p->LumpNameSetup(name);
lump_p->LumpSize = LittleLong(zip_fh->UncompressedSize);
lump_p->LumpSize = UncompressedSize;
lump_p->Owner = this;
// The start of the Reader will be determined the first time it is accessed.
lump_p->Flags = LUMPF_FULLPATH;
@ -346,8 +404,8 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter)
if (lump_p->Method != METHOD_STORED) lump_p->Flags |= LUMPF_COMPRESSED;
lump_p->GPFlags = zip_fh->Flags;
lump_p->CRC32 = zip_fh->CRC32;
lump_p->CompressedSize = LittleLong(zip_fh->CompressedSize);
lump_p->Position = LittleLong(zip_fh->LocalHeaderOffset);
lump_p->CompressedSize = CompressedSize;
lump_p->Position = LocalHeaderOffset;
lump_p->CheckEmbedded(filter);
lump_p++;
@ -585,15 +643,15 @@ int AppendCentralDirectory(FileWriter *zip_file, const char *filename, FCompress
dir.ModTime = LittleShort(dostime.first);
dir.ModDate = LittleShort(dostime.second);
dir.CRC32 = content.mCRC32;
dir.CompressedSize = LittleLong(content.mCompressedSize);
dir.UncompressedSize = LittleLong(content.mSize);
dir.CompressedSize32 = LittleLong(content.mCompressedSize);
dir.UncompressedSize32 = LittleLong(content.mSize);
dir.NameLength = LittleShort((unsigned short)strlen(filename));
dir.ExtraLength = 0;
dir.CommentLength = 0;
dir.StartingDiskNumber = 0;
dir.InternalAttributes = 0;
dir.ExternalAttributes = 0;
dir.LocalHeaderOffset = LittleLong(position);
dir.LocalHeaderOffset32 = LittleLong(position);
if (zip_file->Write(&dir, sizeof(dir)) != sizeof(dir) ||
zip_file->Write(filename, strlen(filename)) != strlen(filename))

View file

@ -15,7 +15,7 @@ struct FZipLump : public FResourceLump
uint8_t Method;
bool NeedFileStart;
int CompressedSize;
int Position;
int64_t Position;
unsigned CRC32;
virtual FileReader *GetReader();

View file

@ -17,6 +17,22 @@ struct FZipEndOfCentralDirectory
uint16_t ZipCommentLength;
} FORCE_PACKED;
struct FZipEndOfCentralDirectory64
{
uint32_t Magic;
uint64_t StructSize;
uint16_t VersionMadeBy;
uint16_t VersionNeeded;
uint32_t DiskNumber;
uint32_t FirstDisk;
uint64_t NumEntries;
uint64_t NumEntriesOnAllDisks;
uint64_t DirectorySize;
uint64_t DirectoryOffset;
uint16_t ZipCommentLength;
} FORCE_PACKED;
// FZipFileInfo
struct FZipCentralDirectoryInfo
{
@ -28,18 +44,28 @@ struct FZipCentralDirectoryInfo
uint16_t ModTime;
uint16_t ModDate;
uint32_t CRC32;
uint32_t CompressedSize;
uint32_t UncompressedSize;
uint32_t CompressedSize32;
uint32_t UncompressedSize32;
uint16_t NameLength;
uint16_t ExtraLength;
uint16_t CommentLength;
uint16_t StartingDiskNumber;
uint16_t InternalAttributes;
uint32_t ExternalAttributes;
uint32_t LocalHeaderOffset;
uint32_t LocalHeaderOffset32;
// file name and other variable length info follows
} FORCE_PACKED;
struct FZipCentralDirectoryInfo64BitExt
{
uint16_t Type;
uint16_t Length;
uint64_t UncompressedSize;
uint64_t CompressedSize;
uint64_t LocalHeaderOffset;
uint32_t DiskNo;
} FORCE_PACKED;
// FZipLocalHeader
struct FZipLocalFileHeader
{
@ -57,7 +83,6 @@ struct FZipLocalFileHeader
// file name and other variable length info follows
} FORCE_PACKED;
#pragma pack()
#define ZIP_LOCALFILE MAKE_ID('P','K',3,4)

View file

@ -753,6 +753,12 @@ static void ParseListMenu(FScanner &sc)
desc->mFromEngine = fileSystem.GetFileContainer(sc.LumpNum) == 0; // flags menu if the definition is from the IWAD.
desc->mVirtWidth = -2;
desc->mCustomSizeSet = false;
if (DefaultListMenuSettings->mCustomSizeSet)
{
desc->mVirtHeight = DefaultListMenuSettings->mVirtHeight;
desc->mVirtWidth = DefaultListMenuSettings->mVirtWidth;
desc->mCustomSizeSet = true;
}
ParseListMenuBody(sc, desc, -1);
ReplaceMenu(sc, desc);
@ -1496,7 +1502,7 @@ static void InitMusicMenus()
{
DMenuDescriptor **advmenu = MenuDescriptors.CheckKey("AdvSoundOptions");
auto soundfonts = sfmanager.GetList();
std::tuple<const char *, int, const char *> sfmenus[] = { std::make_tuple("GusConfigMenu", SF_SF2 | SF_GUS, "midi_config"),
std::tuple<const char *, int, const char *> sfmenus[] = { std::make_tuple("GusConfigMenu", SF_GUS, "midi_config"),
std::make_tuple("WildMidiConfigMenu", SF_GUS, "wildmidi_config"),
std::make_tuple("TimidityConfigMenu", SF_SF2 | SF_GUS, "timidity_config"),
std::make_tuple("FluidPatchsetMenu", SF_SF2, "fluid_patchset"),

View file

@ -459,6 +459,7 @@ DEFINE_ACTION_FUNCTION(FSavegameManager, SavegameCount)
FSaveGameNode *FSavegameManagerBase::GetSavegame(int i)
{
if ((unsigned)i >= SaveGames.Size()) ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Bad savegame index");
return SaveGames[i];
}

View file

@ -71,17 +71,17 @@ void M_GetMacSearchDirectories(FString& user_docs, FString& user_app_support, FS
? "~/" GAME_DIR
: (path + "/" GAME_DIR);
#define LIBRARY_APPSUPPORT "/Library/Application Support"
#define LIBRARY_APPSUPPORT "/Library/Application Support/"
path = M_GetMacAppSupportPath();
user_app_support = path.IsEmpty()
? "~" LIBRARY_APPSUPPORT
: (path);
? "~" LIBRARY_APPSUPPORT GAME_DIR
: (path + "/" GAME_DIR);
path = GetSpecialPath(NSApplicationSupportDirectory, YES, NSLocalDomainMask);
local_app_support = path.IsEmpty()
? LIBRARY_APPSUPPORT
: (path);
? LIBRARY_APPSUPPORT GAME_DIR
: (path + "/" GAME_DIR);
#undef LIBRARY_APPSUPPORT
}

View file

@ -362,6 +362,29 @@ void OpenGLFrameBuffer::BlurScene(float amount)
GLRenderer->BlurScene(amount);
}
void OpenGLFrameBuffer::InitLightmap(int LMTextureSize, int LMTextureCount, TArray<uint16_t>& LMTextureData)
{
if (LMTextureData.Size() > 0)
{
GLint activeTex = 0;
glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex);
glActiveTexture(GL_TEXTURE0 + 17);
if (GLRenderer->mLightMapID == 0)
glGenTextures(1, (GLuint*)&GLRenderer->mLightMapID);
glBindTexture(GL_TEXTURE_2D_ARRAY, GLRenderer->mLightMapID);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB16F, LMTextureSize, LMTextureSize, LMTextureCount, 0, GL_RGB, GL_HALF_FLOAT, &LMTextureData[0]);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
glActiveTexture(activeTex);
LMTextureData.Reset(); // We no longer need this, release the memory
}
}
void OpenGLFrameBuffer::SetViewportRects(IntRect *bounds)
{
Super::SetViewportRects(bounds);

View file

@ -50,6 +50,8 @@ public:
IIndexBuffer *CreateIndexBuffer() override;
IDataBuffer *CreateDataBuffer(int bindingpoint, bool ssbo, bool needsresize) override;
void InitLightmap(int LMTextureSize, int LMTextureCount, TArray<uint16_t>& LMTextureData) override;
// Retrieves a buffer containing image data for a screenshot.
// Hint: Pitch can be negative for upside-down images, in which case buffer
// points to the last row in the buffer, which will be the first row output.

View file

@ -61,6 +61,8 @@ public:
FPresent3DRowShader *mPresent3dRowShader = nullptr;
FShadowMapShader *mShadowMapShader = nullptr;
int mLightMapID = 0;
//FRotator mAngles;
FGLRenderer(OpenGLFrameBuffer *fb);

View file

@ -300,6 +300,7 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char *
// textures
uniform sampler2D tex;
uniform sampler2D ShadowMap;
uniform sampler2DArray LightMap;
uniform sampler2D texture2;
uniform sampler2D texture3;
uniform sampler2D texture4;
@ -621,11 +622,14 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char *
char stringbuf[20];
mysnprintf(stringbuf, 20, "texture%d", i);
tempindex = glGetUniformLocation(hShader, stringbuf);
if (tempindex > 0) glUniform1i(tempindex, i - 1);
if (tempindex != -1) glUniform1i(tempindex, i - 1);
}
int shadowmapindex = glGetUniformLocation(hShader, "ShadowMap");
if (shadowmapindex > 0) glUniform1i(shadowmapindex, 16);
if (shadowmapindex != -1) glUniform1i(shadowmapindex, 16);
int lightmapindex = glGetUniformLocation(hShader, "LightMap");
if (lightmapindex != -1) glUniform1i(lightmapindex, 17);
glUseProgram(0);
return linked;

View file

@ -207,29 +207,28 @@ void GLBuffer::Unlock()
}
void GLBuffer::Resize(size_t newsize)
{
assert(!nomap); // only mappable buffers can be resized.
if (newsize > buffersize && !nomap)
{
if (newsize > buffersize)
{
/*
// reallocate the buffer with twice the size
unsigned int oldbuffer = mBufferId;
if (isData)
{
// Create new bigger memory
char* memoryNew = (char*)(new uint64_t[newsize / 8 + 16]);
// first unmap the old buffer
Bind();
glUnmapBuffer(mUseType);
// Copy old data
memcpy(memoryNew, memory, buffersize);
glGenBuffers(1, &mBufferId);
SetData(newsize, nullptr, false);
glBindBuffer(GL_COPY_READ_BUFFER, oldbuffer);
// Delete old memory
delete[] memory;
// copy contents and delete the old buffer.
glCopyBufferSubData(GL_COPY_READ_BUFFER, mUseType, 0, 0, buffersize);
glBindBuffer(GL_COPY_READ_BUFFER, 0);
glDeleteBuffers(1, &oldbuffer);
buffersize = newsize;
InvalidateBufferState();
*/
memory = memoryNew;
buffersize = newsize;
}
else
{
// TODO
}
}
}

View file

@ -24,7 +24,7 @@ enum
VATTR_VERTEX2,
VATTR_NORMAL,
VATTR_NORMAL2,
VATTR_LIGHTMAP,
VATTR_MAX
};

View file

@ -93,10 +93,11 @@ FFlatVertexBuffer::FFlatVertexBuffer(int width, int height, int pipelineNbr):
static const FVertexBufferAttribute format[] = {
{ 0, VATTR_VERTEX, VFmt_Float3, (int)myoffsetof(FFlatVertex, x) },
{ 0, VATTR_TEXCOORD, VFmt_Float2, (int)myoffsetof(FFlatVertex, u) }
{ 0, VATTR_TEXCOORD, VFmt_Float2, (int)myoffsetof(FFlatVertex, u) },
{ 0, VATTR_LIGHTMAP, VFmt_Float3, (int)myoffsetof(FFlatVertex, lu) },
};
mVertexBufferPipeline[n]->SetFormat(1, 2, sizeof(FFlatVertex), format);
mVertexBufferPipeline[n]->SetFormat(1, 3, sizeof(FFlatVertex), format);
}
mVertexBuffer = mVertexBufferPipeline[mPipelinePos];

View file

@ -14,6 +14,8 @@ struct FFlatVertex
{
float x, z, y; // world position
float u, v; // texture coordinates
float lu, lv; // lightmap texture coordinates
float lindex; // lightmap texture index
void Set(float xx, float zz, float yy, float uu, float vv)
{
@ -22,6 +24,19 @@ struct FFlatVertex
y = yy;
u = uu;
v = vv;
lindex = -1.0f;
}
void Set(float xx, float zz, float yy, float uu, float vv, float llu, float llv, float llindex)
{
x = xx;
z = zz;
y = yy;
u = uu;
v = vv;
lu = llu;
lv = llv;
lindex = llindex;
}
void SetVertex(float _x, float _y, float _z = 0)

View file

@ -46,10 +46,11 @@ FModelVertexBuffer::FModelVertexBuffer(bool needindex, bool singleframe)
{ 0, VATTR_VERTEX, VFmt_Float3, (int)myoffsetof(FModelVertex, x) },
{ 0, VATTR_TEXCOORD, VFmt_Float2, (int)myoffsetof(FModelVertex, u) },
{ 0, VATTR_NORMAL, VFmt_Packed_A2R10G10B10, (int)myoffsetof(FModelVertex, packedNormal) },
{ 0, VATTR_LIGHTMAP, VFmt_Float3, (int)myoffsetof(FModelVertex, lu) },
{ 1, VATTR_VERTEX2, VFmt_Float3, (int)myoffsetof(FModelVertex, x) },
{ 1, VATTR_NORMAL2, VFmt_Packed_A2R10G10B10, (int)myoffsetof(FModelVertex, packedNormal) }
};
mVertexBuffer->SetFormat(2, 5, sizeof(FModelVertex), format);
mVertexBuffer->SetFormat(2, 6, sizeof(FModelVertex), format);
}
//===========================================================================

View file

@ -894,7 +894,7 @@ void PPShadowMap::Update(PPRenderState* renderstate)
/////////////////////////////////////////////////////////////////////////////
CVAR(Bool, gl_custompost, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
CVAR(Bool, gl_custompost, true, 0)
void PPCustomShaders::Run(PPRenderState *renderstate, FString target)
{

View file

@ -7,6 +7,8 @@ struct FModelVertex
float x, y, z; // world position
float u, v; // texture coordinates
unsigned packedNormal; // normal vector as GL_INT_2_10_10_10_REV.
float lu, lv; // lightmap texture coordinates
float lindex; // lightmap texture index
void Set(float xx, float yy, float zz, float uu, float vv)
{
@ -15,6 +17,9 @@ struct FModelVertex
z = zz;
u = uu;
v = vv;
lu = 0.0f;
lv = 0.0f;
lindex = -1.0f;
}
void SetNormal(float nx, float ny, float nz)

View file

@ -29,10 +29,4 @@ void I_PolyPresentUnlock(int x, int y, int w, int h);
void I_PolyPresentDeinit();
// Pause a bit.
// [RH] Despite the name, it apparently never waited for the VBL, even in
// the original DOS version (if the Heretic/Hexen source is any indicator).
void I_WaitVBL(int count);
#endif // __I_VIDEO_H__

View file

@ -287,7 +287,7 @@ void PolyRenderState::Apply()
PolyPushConstants constants;
constants.uFogEnabled = fogset;
constants.uTextureMode = GetTextureModeAndFlags(mTempTM);
constants.uTextureMode = (mTextureMode == TM_NORMAL && mTempTM == TM_OPAQUE ? TM_OPAQUE : mTextureMode);
constants.uLightDist = mLightParms[0];
constants.uLightFactor = mLightParms[1];
constants.uFogDensity = mLightParms[2];

View file

@ -281,6 +281,12 @@ void V_UpdateModeSize (int width, int height)
CleanHeight = screen->GetHeight() / CleanYfac;
int w = screen->GetWidth();
int h = screen->GetHeight();
// clamp screen aspect ratio to 17:10, for anything wider the width will be reduced
double aspect = (double)w / h;
if (aspect > 1.7) w = int(w * 1.7 / aspect);
int factor;
if (w < 640) factor = 1;
else if (w >= 1024 && w < 1280) factor = 2;

View file

@ -220,6 +220,8 @@ public:
virtual int GetClientHeight() = 0;
virtual void BlurScene(float amount) {}
virtual void InitLightmap(int LMTextureSize, int LMTextureCount, TArray<uint16_t>& LMTextureData) {}
// Interface to hardware rendering resources
virtual IVertexBuffer *CreateVertexBuffer() { return nullptr; }
virtual IIndexBuffer *CreateIndexBuffer() { return nullptr; }

View file

@ -78,6 +78,7 @@ void VkRenderBuffers::BeginFrame(int width, int height, int sceneWidth, int scen
CreateScene(width, height, samples);
CreateShadowmap();
CreateLightmapSampler();
mWidth = width;
mHeight = height;
@ -264,3 +265,41 @@ void VkRenderBuffers::CreateShadowmap()
ShadowmapSampler->SetDebugName("VkRenderBuffers.ShadowmapSampler");
}
}
void VkRenderBuffers::CreateLightmapSampler()
{
if (!Lightmap.Image)
{
auto fb = GetVulkanFrameBuffer();
ImageBuilder builder;
builder.setSize(1, 1);
builder.setFormat(VK_FORMAT_R16G16B16A16_SFLOAT);
builder.setUsage(VK_IMAGE_USAGE_SAMPLED_BIT);
Lightmap.Image = builder.create(fb->device);
Lightmap.Image->SetDebugName("VkRenderBuffers.Lightmap");
ImageViewBuilder viewbuilder;
viewbuilder.setType(VK_IMAGE_VIEW_TYPE_2D_ARRAY);
viewbuilder.setImage(Lightmap.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT);
Lightmap.View = viewbuilder.create(fb->device);
Lightmap.View->SetDebugName("VkRenderBuffers.LightmapView");
VkImageTransition barrier;
barrier.addImage(&Lightmap, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, true);
barrier.execute(fb->GetDrawCommands());
}
if (!LightmapSampler)
{
auto fb = GetVulkanFrameBuffer();
SamplerBuilder builder;
builder.setMipmapMode(VK_SAMPLER_MIPMAP_MODE_LINEAR);
builder.setMinFilter(VK_FILTER_LINEAR);
builder.setMagFilter(VK_FILTER_LINEAR);
builder.setAddressMode(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE);
LightmapSampler = builder.create(fb->device);
LightmapSampler->SetDebugName("VkRenderBuffers.LightmapSampler");
}
}

View file

@ -32,6 +32,9 @@ public:
VkTextureImage Shadowmap;
std::unique_ptr<VulkanSampler> ShadowmapSampler;
VkTextureImage Lightmap;
std::unique_ptr<VulkanSampler> LightmapSampler;
private:
void CreatePipeline(int width, int height);
void CreateScene(int width, int height, VkSampleCountFlagBits samples);
@ -40,6 +43,7 @@ private:
void CreateSceneFog(int width, int height, VkSampleCountFlagBits samples);
void CreateSceneNormal(int width, int height, VkSampleCountFlagBits samples);
void CreateShadowmap();
void CreateLightmapSampler();
VkSampleCountFlagBits GetBestSampleCount();
int mWidth = 0;

View file

@ -130,6 +130,7 @@ void VkRenderPassManager::CreateDynamicSetLayout()
builder.addBinding(2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
builder.addBinding(3, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
builder.addBinding(4, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
builder.addBinding(5, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
DynamicSetLayout = builder.create(GetVulkanFrameBuffer()->device);
DynamicSetLayout->SetDebugName("VkRenderPassManager.DynamicSetLayout");
}
@ -177,7 +178,7 @@ void VkRenderPassManager::CreateDescriptorPool()
DescriptorPoolBuilder builder;
builder.addPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 3);
builder.addPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1);
builder.addPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1);
builder.addPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2);
builder.setMaxSets(1);
DynamicDescriptorPool = builder.create(GetVulkanFrameBuffer()->device);
DynamicDescriptorPool->SetDebugName("VkRenderPassManager.DynamicDescriptorPool");
@ -249,6 +250,7 @@ void VkRenderPassManager::UpdateDynamicSet()
update.addBuffer(DynamicSet.get(), 2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, fb->MatrixBuffer->UniformBuffer->mBuffer.get(), 0, sizeof(MatricesUBO));
update.addBuffer(DynamicSet.get(), 3, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, fb->StreamBuffer->UniformBuffer->mBuffer.get(), 0, sizeof(StreamUBO));
update.addCombinedImageSampler(DynamicSet.get(), 4, fb->GetBuffers()->Shadowmap.View.get(), fb->GetBuffers()->ShadowmapSampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
update.addCombinedImageSampler(DynamicSet.get(), 5, fb->GetBuffers()->Lightmap.View.get(), fb->GetBuffers()->LightmapSampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
update.updateSets(fb->device);
}
@ -376,7 +378,7 @@ std::unique_ptr<VulkanPipeline> VkRenderPassSetup::CreatePipeline(const VkPipeli
VK_FORMAT_A2B10G10R10_SNORM_PACK32
};
bool inputLocations[6] = { false, false, false, false, false, false };
bool inputLocations[7] = { false, false, false, false, false, false, false };
for (size_t i = 0; i < vfmt.Attrs.size(); i++)
{
@ -386,7 +388,7 @@ std::unique_ptr<VulkanPipeline> VkRenderPassSetup::CreatePipeline(const VkPipeli
}
// Vulkan requires an attribute binding for each location specified in the shader
for (int i = 0; i < 6; i++)
for (int i = 0; i < 7; i++)
{
if (!inputLocations[i])
builder.addVertexAttribute(i, 0, VK_FORMAT_R32G32B32_SFLOAT, 0);

View file

@ -172,6 +172,7 @@ static const char *shaderBindings = R"(
};
layout(set = 0, binding = 4) uniform sampler2D ShadowMap;
layout(set = 0, binding = 5) uniform sampler2DArray LightMap;
// textures
layout(set = 1, binding = 0) uniform sampler2D tex;

View file

@ -38,7 +38,7 @@ class ImageBuilder
public:
ImageBuilder();
void setSize(int width, int height, int miplevels = 1);
void setSize(int width, int height, int miplevels = 1, int arrayLayers = 1);
void setSamples(VkSampleCountFlagBits samples);
void setFormat(VkFormat format);
void setUsage(VkImageUsageFlags imageUsage, VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_GPU_ONLY, VmaAllocationCreateFlags allocFlags = 0);
@ -60,6 +60,7 @@ class ImageViewBuilder
public:
ImageViewBuilder();
void setType(VkImageViewType type);
void setImage(VulkanImage *image, VkFormat format, VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT);
std::unique_ptr<VulkanImageView> create(VulkanDevice *device);
@ -374,11 +375,12 @@ inline ImageBuilder::ImageBuilder()
imageInfo.flags = 0;
}
inline void ImageBuilder::setSize(int width, int height, int mipLevels)
inline void ImageBuilder::setSize(int width, int height, int mipLevels, int arrayLayers)
{
imageInfo.extent.width = width;
imageInfo.extent.height = height;
imageInfo.mipLevels = mipLevels;
imageInfo.arrayLayers = arrayLayers;
}
inline void ImageBuilder::setSamples(VkSampleCountFlagBits samples)
@ -447,7 +449,7 @@ inline std::unique_ptr<VulkanImage> ImageBuilder::create(VulkanDevice *device, V
*allocatedBytes = allocatedInfo.size;
}
return std::make_unique<VulkanImage>(device, image, allocation, imageInfo.extent.width, imageInfo.extent.height, imageInfo.mipLevels);
return std::make_unique<VulkanImage>(device, image, allocation, imageInfo.extent.width, imageInfo.extent.height, imageInfo.mipLevels, imageInfo.arrayLayers);
}
inline std::unique_ptr<VulkanImage> ImageBuilder::tryCreate(VulkanDevice *device)
@ -459,7 +461,7 @@ inline std::unique_ptr<VulkanImage> ImageBuilder::tryCreate(VulkanDevice *device
if (result != VK_SUCCESS)
return nullptr;
return std::make_unique<VulkanImage>(device, image, allocation, imageInfo.extent.width, imageInfo.extent.height, imageInfo.mipLevels);
return std::make_unique<VulkanImage>(device, image, allocation, imageInfo.extent.width, imageInfo.extent.height, imageInfo.mipLevels, imageInfo.arrayLayers);
}
/////////////////////////////////////////////////////////////////////////////
@ -474,12 +476,18 @@ inline ImageViewBuilder::ImageViewBuilder()
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
}
inline void ImageViewBuilder::setType(VkImageViewType type)
{
viewInfo.viewType = type;
}
inline void ImageViewBuilder::setImage(VulkanImage *image, VkFormat format, VkImageAspectFlags aspectMask)
{
viewInfo.image = image->image;
viewInfo.format = format;
viewInfo.subresourceRange.levelCount = image->mipLevels;
viewInfo.subresourceRange.aspectMask = aspectMask;
viewInfo.subresourceRange.layerCount = image->layerCount;
}
inline std::unique_ptr<VulkanImageView> ImageViewBuilder::create(VulkanDevice *device)

View file

@ -579,6 +579,81 @@ void VulkanFrameBuffer::BeginFrame()
}
}
void VulkanFrameBuffer::InitLightmap(int LMTextureSize, int LMTextureCount, TArray<uint16_t>& LMTextureData)
{
if (LMTextureData.Size() > 0)
{
int w = LMTextureSize;
int h = LMTextureSize;
int count = LMTextureCount;
int pixelsize = 8;
auto& lightmap = mActiveRenderBuffers->Lightmap;
if (lightmap.Image)
{
FrameDeleteList.Images.push_back(std::move(lightmap.Image));
FrameDeleteList.ImageViews.push_back(std::move(lightmap.View));
lightmap.reset();
}
ImageBuilder builder;
builder.setSize(w, h, 1, count);
builder.setFormat(VK_FORMAT_R16G16B16A16_SFLOAT);
builder.setUsage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
lightmap.Image = builder.create(device);
lightmap.Image->SetDebugName("VkRenderBuffers.Lightmap");
ImageViewBuilder viewbuilder;
viewbuilder.setType(VK_IMAGE_VIEW_TYPE_2D_ARRAY);
viewbuilder.setImage(lightmap.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT);
lightmap.View = viewbuilder.create(device);
lightmap.View->SetDebugName("VkRenderBuffers.LightmapView");
auto cmdbuffer = GetTransferCommands();
int totalSize = w * h * count * pixelsize;
BufferBuilder bufbuilder;
bufbuilder.setSize(totalSize);
bufbuilder.setUsage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY);
std::unique_ptr<VulkanBuffer> stagingBuffer = bufbuilder.create(device);
stagingBuffer->SetDebugName("VkHardwareTexture.mStagingBuffer");
uint16_t one = 0x3c00; // half-float 1.0
uint16_t* src = &LMTextureData[0];
uint16_t* data = (uint16_t*)stagingBuffer->Map(0, totalSize);
for (int i = w * h * count; i > 0; i--)
{
*(data++) = *(src++);
*(data++) = *(src++);
*(data++) = *(src++);
*(data++) = one;
}
stagingBuffer->Unmap();
VkImageTransition imageTransition;
imageTransition.addImage(&lightmap, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true, 0, count);
imageTransition.execute(cmdbuffer);
VkBufferImageCopy region = {};
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.imageSubresource.layerCount = count;
region.imageExtent.depth = 1;
region.imageExtent.width = w;
region.imageExtent.height = h;
cmdbuffer->copyBufferToImage(stagingBuffer->buffer, lightmap.Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
VkImageTransition barrier;
barrier.addImage(&lightmap, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false, 0, count);
barrier.execute(cmdbuffer);
FrameTextureUpload.Buffers.push_back(std::move(stagingBuffer));
FrameTextureUpload.TotalSize += totalSize;
LMTextureData.Reset(); // We no longer need this, release the memory
}
}
void VulkanFrameBuffer::PushGroup(const FString &name)
{
if (!gpuStatActive)

View file

@ -85,6 +85,7 @@ public:
void SetTextureFilterMode() override;
void StartPrecaching() override;
void BeginFrame() override;
void InitLightmap(int LMTextureSize, int LMTextureCount, TArray<uint16_t>& LMTextureData) override;
void BlurScene(float amount) override;
void PostProcessScene(bool swscene, int fixedcm, float flash, const std::function<void()> &afterBloomDrawEndScene2D) override;
void AmbientOccludeScene(float m5) override;

View file

@ -79,7 +79,7 @@ private:
class VulkanImage
{
public:
VulkanImage(VulkanDevice *device, VkImage image, VmaAllocation allocation, int width, int height, int mipLevels);
VulkanImage(VulkanDevice *device, VkImage image, VmaAllocation allocation, int width, int height, int mipLevels, int layerCount);
~VulkanImage();
void SetDebugName(const char *name) { device->SetDebugObjectName(name, (uint64_t)image, VK_OBJECT_TYPE_IMAGE); }
@ -88,6 +88,7 @@ public:
int width = 0;
int height = 0;
int mipLevels = 1;
int layerCount = 1;
void *Map(size_t offset, size_t size);
void Unmap();
@ -989,7 +990,7 @@ inline VulkanFramebuffer::~VulkanFramebuffer()
/////////////////////////////////////////////////////////////////////////////
inline VulkanImage::VulkanImage(VulkanDevice *device, VkImage image, VmaAllocation allocation, int width, int height, int mipLevels) : image(image), width(width), height(height), mipLevels(mipLevels), device(device), allocation(allocation)
inline VulkanImage::VulkanImage(VulkanDevice *device, VkImage image, VmaAllocation allocation, int width, int height, int mipLevels, int layerCount) : image(image), width(width), height(height), mipLevels(mipLevels), layerCount(layerCount), device(device), allocation(allocation)
{
}

View file

@ -22,7 +22,7 @@
#include "vk_imagetransition.h"
void VkImageTransition::addImage(VkTextureImage *image, VkImageLayout targetLayout, bool undefinedSrcLayout)
void VkImageTransition::addImage(VkTextureImage *image, VkImageLayout targetLayout, bool undefinedSrcLayout, int baseMipLevel, int levelCount)
{
if (image->Layout == targetLayout)
return;
@ -91,7 +91,7 @@ void VkImageTransition::addImage(VkTextureImage *image, VkImageLayout targetLayo
I_FatalError("Unimplemented dst image layout transition\n");
}
barrier.addImage(image->Image.get(), undefinedSrcLayout ? VK_IMAGE_LAYOUT_UNDEFINED : image->Layout, targetLayout, srcAccess, dstAccess, aspectMask);
barrier.addImage(image->Image.get(), undefinedSrcLayout ? VK_IMAGE_LAYOUT_UNDEFINED : image->Layout, targetLayout, srcAccess, dstAccess, aspectMask, baseMipLevel, levelCount);
needbarrier = true;
image->Layout = targetLayout;
}

View file

@ -33,7 +33,7 @@ public:
class VkImageTransition
{
public:
void addImage(VkTextureImage *image, VkImageLayout targetLayout, bool undefinedSrcLayout);
void addImage(VkTextureImage *image, VkImageLayout targetLayout, bool undefinedSrcLayout, int baseMipLevel = 0, int levelCount = 1);
void execute(VulkanCommandBuffer *cmdbuffer);
private:

View file

@ -11156,9 +11156,14 @@ ExpEmit FxLocalArrayDeclaration::Emit(VMFunctionBuilder *build)
ClearDynamicArray(build);
}
auto zero = build->GetConstantInt(0);
auto elementSizeConst = build->GetConstantInt(static_cast<PArray *>(ValueType)->ElementSize);
auto arrOffsetReg = build->Registers[REGT_INT].Get(1);
build->Emit(OP_LK, arrOffsetReg, build->GetConstantInt(StackOffset));
int arrOffsetReg;
if (!isDynamicArray)
{
arrOffsetReg = build->Registers[REGT_POINTER].Get(1);
build->Emit(OP_ADDA_RK, arrOffsetReg, build->FramePointer.RegNum, build->GetConstantInt(StackOffset));
}
for (auto v : values)
{
@ -11166,6 +11171,7 @@ ExpEmit FxLocalArrayDeclaration::Emit(VMFunctionBuilder *build)
if (isDynamicArray)
{
emitval.Free(build);
continue;
}
@ -11178,61 +11184,48 @@ ExpEmit FxLocalArrayDeclaration::Emit(VMFunctionBuilder *build)
if (emitval.Konst)
{
auto constval = static_cast<FxConstant *>(v);
int regNum = build->Registers[regtype].Get(1);
auto regNum = build->Registers[regtype].Get(1);
switch (regtype)
{
default:
case REGT_INT:
build->Emit(OP_LK, regNum, build->GetConstantInt(constval->GetValue().GetInt()));
build->Emit(OP_SW_R, build->FramePointer.RegNum, regNum, arrOffsetReg);
build->Emit(OP_LK, regNum, emitval.RegNum);
build->Emit(OP_SW, arrOffsetReg, regNum, zero);
break;
case REGT_FLOAT:
build->Emit(OP_LKF, regNum, build->GetConstantFloat(constval->GetValue().GetFloat()));
build->Emit(OP_SDP_R, build->FramePointer.RegNum, regNum, arrOffsetReg);
build->Emit(OP_LKF, regNum, emitval.RegNum);
build->Emit(OP_SDP, arrOffsetReg, regNum, zero);
break;
case REGT_POINTER:
build->Emit(OP_LKP, regNum, build->GetConstantAddress(constval->GetValue().GetPointer()));
build->Emit(OP_SP_R, build->FramePointer.RegNum, regNum, arrOffsetReg);
build->Emit(OP_LKP, regNum, emitval.RegNum);
build->Emit(OP_SP, arrOffsetReg, regNum, zero);
break;
case REGT_STRING:
build->Emit(OP_LKS, regNum, build->GetConstantString(constval->GetValue().GetString()));
build->Emit(OP_SS_R, build->FramePointer.RegNum, regNum, arrOffsetReg);
build->Emit(OP_LKS, regNum, emitval.RegNum);
build->Emit(OP_SS, arrOffsetReg, regNum, zero);
break;
}
build->Registers[regtype].Return(regNum, 1);
emitval.Free(build);
build->Registers[regtype].Return(regNum, 1);
}
else
{
switch (regtype)
{
default:
case REGT_INT:
build->Emit(OP_SW_R, build->FramePointer.RegNum, emitval.RegNum, arrOffsetReg);
break;
case REGT_FLOAT:
build->Emit(OP_SDP_R, build->FramePointer.RegNum, emitval.RegNum, arrOffsetReg);
break;
case REGT_POINTER:
build->Emit(OP_SP_R, build->FramePointer.RegNum, emitval.RegNum, arrOffsetReg);
break;
case REGT_STRING:
build->Emit(OP_SS_R, build->FramePointer.RegNum, emitval.RegNum, arrOffsetReg);
break;
}
emitval.Free(build);
build->Emit(v->ValueType->GetStoreOp(), arrOffsetReg, emitval.RegNum, zero);
}
emitval.Free(build);
build->Emit(OP_ADD_RK, arrOffsetReg, arrOffsetReg, elementSizeConst);
if (!isDynamicArray)
{
build->Emit(OP_ADDA_RK, arrOffsetReg, arrOffsetReg, elementSizeConst);
}
}
if (!isDynamicArray)
{
build->Registers[REGT_POINTER].Return(arrOffsetReg, 1);
}
build->Registers[REGT_INT].Return(arrOffsetReg, 1);
return ExpEmit();
}

View file

@ -175,7 +175,7 @@ static int fieldcmp(const void * a, const void * b)
void InitImports()
{
auto fontstruct = NewStruct("FFont", nullptr, true);
auto fontstruct = NewStruct("Font", nullptr, true);
fontstruct->Size = sizeof(FFont);
fontstruct->Align = alignof(FFont);
NewPointer(fontstruct, false)->InstallHandlers(

View file

@ -272,4 +272,3 @@ struct AFuncDesc;
struct FieldDesc;
AFuncDesc *FindFunction(PContainerType *cls, const char * string);
FieldDesc *FindField(PContainerType *cls, const char * string);
//void SetImplicitArgs(TArray<PType*>* args, TArray<uint32_t>* argflags, TArray<FName>* argnames, PContainerType* cls, uint32_t funcflags, int useflags);

View file

@ -30,7 +30,7 @@
#include "v_video.h"
CVAR(Bool, gl_customshader, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL);
CVAR(Bool, gl_customshader, true, 0);
static IHardwareTexture* (*layercallback)(int layer, int translation);

View file

@ -320,6 +320,8 @@ public:
void NeedUpdate() { bNeedsUpdate = true; }
void SetUpdated(bool rendertype) { bNeedsUpdate = false; bFirstUpdate = false; bLastUpdateType = rendertype; }
void SetAspectRatio(double aspectScale, bool useTextureRatio) { aspectRatio = (float)aspectScale * (useTextureRatio? ((float)Width / Height) : 1); }
protected:
bool bLastUpdateType = false;

View file

@ -987,6 +987,8 @@ int SmackerDecoder::DecodeAudio(uint32_t size, SmackerAudioTrack &track)
return -1;
}
memset(h, 0, sizeof(HuffContext) * 4);
// Initialize
for (i = 0; i < (1 << (sampleBits + stereo)); i++) {
h[i].length = 256;
@ -1142,7 +1144,7 @@ uint32_t SmackerDecoder::GetAudioData(uint32_t trackIndex, int16_t *audioBuffer)
SmackerAudioTrack *track = &audioTracks[trackIndex];
if (track->bytesReadThisFrame) {
memcpy(audioBuffer, track->buffer, min(track->bufferSize, track->bytesReadThisFrame));
memcpy(audioBuffer, track->buffer, std::min(track->bufferSize, track->bytesReadThisFrame));
}
return track->bytesReadThisFrame;

View file

@ -56,12 +56,12 @@ extern FFastTrig fasttrig;
inline double fastcosbam(double v)
{
return fasttrig.cos(v);
return fasttrig.cos(xs_CRoundToUInt(v));
}
inline double fastsinbam(double v)
{
return fasttrig.sin(v);
return fasttrig.sin(xs_CRoundToUInt(v));
}
inline double fastcosdeg(double v)

View file

@ -44,3 +44,8 @@ double I_GetInputFrac(bool const synchronised, double const ticrate = GameTicRat
// Reset the last input check to after a lengthy operation
void I_ResetInputTime();
// Pause a bit.
// [RH] Despite the name, it apparently never waited for the VBL, even in
// the original DOS version (if the Heretic/Hexen source is any indicator).
void I_WaitVBL(int count);