mirror of
https://github.com/ZDoom/Raze.git
synced 2024-11-15 00:42:08 +00:00
backend update from GZDoom.
This commit is contained in:
parent
80fe0788c9
commit
c0d166c307
74 changed files with 1496 additions and 392 deletions
|
@ -337,7 +337,7 @@ static ZMusic_MidiSource GetMIDISource(const char *fn)
|
|||
}
|
||||
|
||||
auto data = wlump.Read();
|
||||
auto source = ZMusic_CreateMIDISource(data.data(), data.size(), type);
|
||||
auto source = ZMusic_CreateMIDISource(data.bytes(), data.size(), type);
|
||||
|
||||
if (source == nullptr)
|
||||
{
|
||||
|
|
|
@ -215,10 +215,10 @@ FileReader FZipPatReader::OpenFile(const char *name)
|
|||
FileReader fr;
|
||||
if (resf != nullptr)
|
||||
{
|
||||
auto lump = resf->FindLump(name);
|
||||
if (lump != nullptr)
|
||||
auto lump = resf->FindEntry(name);
|
||||
if (lump >= 0)
|
||||
{
|
||||
return lump->NewReader();
|
||||
return resf->GetEntryReader(lump);
|
||||
}
|
||||
}
|
||||
fr.OpenFile(name);
|
||||
|
@ -367,10 +367,10 @@ void FSoundFontManager::ProcessOneFile(const char* fn)
|
|||
auto zip = FResourceFile::OpenResourceFile(fn, true);
|
||||
if (zip != nullptr)
|
||||
{
|
||||
if (zip->LumpCount() > 1) // Anything with just one lump cannot possibly be a packed GUS patch set so skip it right away and simplify the lookup code
|
||||
if (zip->EntryCount() > 1) // Anything with just one lump cannot possibly be a packed GUS patch set so skip it right away and simplify the lookup code
|
||||
{
|
||||
auto zipl = zip->FindLump("timidity.cfg");
|
||||
if (zipl != nullptr)
|
||||
auto zipl = zip->FindEntry("timidity.cfg");
|
||||
if (zipl >= 0)
|
||||
{
|
||||
// It seems like this is what we are looking for
|
||||
FSoundFontInfo sft = { fb, fbe, fn, SF_GUS };
|
||||
|
|
|
@ -1141,7 +1141,7 @@ SoundHandle OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int length, int def
|
|||
return retval;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> data;
|
||||
TArray<uint8_t> data;
|
||||
unsigned total = 0;
|
||||
unsigned got;
|
||||
|
||||
|
|
|
@ -216,7 +216,7 @@ private:
|
|||
|
||||
// Checks if a copy of this sound is already playing.
|
||||
bool CheckSingular(FSoundID sound_id);
|
||||
virtual std::vector<uint8_t> ReadSound(int lumpnum) = 0;
|
||||
virtual TArray<uint8_t> ReadSound(int lumpnum) = 0;
|
||||
|
||||
protected:
|
||||
virtual bool CheckSoundLimit(sfxinfo_t* sfx, const FVector3& pos, int near_limit, float limit_range, int sourcetype, const void* actor, int channel, float attenuation);
|
||||
|
|
|
@ -218,6 +218,9 @@ public:
|
|||
|
||||
void* GetExtraDataPointer();
|
||||
|
||||
int pnum = -1;
|
||||
FName userinfoName;
|
||||
|
||||
protected:
|
||||
virtual void DoSet (UCVarValue value, ECVarType type) = 0;
|
||||
virtual void InstantiateZSCVar()
|
||||
|
|
|
@ -153,7 +153,7 @@ class AnmPlayer : public MoviePlayer
|
|||
{
|
||||
// This doesn't need its own class type
|
||||
anim_t anim;
|
||||
std::vector<uint8_t> buffer;
|
||||
FileSys::ResourceData buffer;
|
||||
int numframes = 0;
|
||||
int curframe = 1;
|
||||
int frametime = 0;
|
||||
|
@ -171,9 +171,10 @@ public:
|
|||
memcpy(frameTicks, frameticks, 3 * sizeof(int));
|
||||
flags = flags_;
|
||||
buffer = fr.ReadPadded(1);
|
||||
if (buffer.size() < 4) return;
|
||||
fr.Close();
|
||||
|
||||
if (ANIM_LoadAnim(&anim, buffer.data(), buffer.size() - 1) < 0)
|
||||
if (ANIM_LoadAnim(&anim, buffer.bytes(), buffer.size() - 1) < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ struct SystemCallbacks
|
|||
bool (*OkForLocalization)(FTextureID, const char*);
|
||||
FConfigFile* (*GetConfig)();
|
||||
bool (*WantEscape)();
|
||||
FTranslationID(*RemapTranslation)(FTranslationID trans);
|
||||
};
|
||||
|
||||
extern SystemCallbacks sysCallbacks;
|
||||
|
|
|
@ -10,6 +10,7 @@ xx(Object)
|
|||
xx(Actor)
|
||||
xx(Class)
|
||||
xx(Thinker)
|
||||
xx(VisualThinker)
|
||||
xx(Crosshairs)
|
||||
|
||||
xx(Untranslated)
|
||||
|
@ -134,6 +135,10 @@ xx(FVector3)
|
|||
xx(FVector4)
|
||||
xx(FQuat)
|
||||
xx(let)
|
||||
xx(BlockThingsIterator)
|
||||
xx(BlockLinesIterator)
|
||||
xx(ActorIterator)
|
||||
xx(ThinkerIterator)
|
||||
|
||||
xx(Min)
|
||||
xx(Max)
|
||||
|
|
|
@ -150,7 +150,7 @@ bool FScanner::OpenFile (const char *name)
|
|||
auto filebuff = fr.Read();
|
||||
if (filebuff.size() == 0 && filesize > 0) return false;
|
||||
|
||||
ScriptBuffer = FString((const char *)filebuff.data(), filesize);
|
||||
ScriptBuffer = FString(filebuff.string(), filesize);
|
||||
ScriptName = name; // This is used for error messages so the full file name is preferable
|
||||
LumpNum = -1;
|
||||
PrepareScript ();
|
||||
|
|
|
@ -71,12 +71,10 @@ public:
|
|||
void Open(const char *lumpname);
|
||||
bool OpenFile(const char *filename);
|
||||
void OpenMem(const char *name, const char *buffer, int size);
|
||||
void OpenMem(const char *name, const TArray<uint8_t> &buffer)
|
||||
{
|
||||
OpenMem(name, (const char*)buffer.Data(), buffer.Size());
|
||||
}
|
||||
void OpenMem(const char* name, const std::vector<uint8_t>& buffer)
|
||||
template<class T>
|
||||
void OpenMem(const char* name, const T& buffer)
|
||||
{
|
||||
static_assert(sizeof(typename T::value_type) == 1);
|
||||
OpenMem(name, (const char*)buffer.data(), (int)buffer.size());
|
||||
}
|
||||
void OpenString(const char *name, FString buffer);
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#include "texturemanager.h"
|
||||
#include "base64.h"
|
||||
#include "vm.h"
|
||||
#include "i_interface.h"
|
||||
|
||||
using namespace FileSys;
|
||||
|
||||
|
@ -1207,7 +1208,14 @@ FSerializer& Serialize(FSerializer& arc, const char* key, FTranslationID& value,
|
|||
int v = value.index();
|
||||
int* defv = (int*)defval;
|
||||
Serialize(arc, key, v, defv);
|
||||
value = FTranslationID::fromInt(v);
|
||||
|
||||
if (arc.isReading())
|
||||
{
|
||||
// allow games to alter the loaded value to handle dynamic lists.
|
||||
if (sysCallbacks.RemapTranslation) value = sysCallbacks.RemapTranslation(FTranslationID::fromInt(v));
|
||||
else value = FTranslationID::fromInt(v);
|
||||
}
|
||||
|
||||
return arc;
|
||||
}
|
||||
|
||||
|
@ -1749,6 +1757,19 @@ void SerializeFunctionPointer(FSerializer &arc, const char *key, FunctionPointer
|
|||
}
|
||||
}
|
||||
|
||||
bool FSerializer::ReadOptionalInt(const char * key, int &into)
|
||||
{
|
||||
if(!isReading()) return false;
|
||||
|
||||
auto val = r->FindKey(key);
|
||||
if(val && val->IsInt())
|
||||
{
|
||||
into = val->GetInt();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#include "renderstyle.h"
|
||||
FSerializer& Serialize(FSerializer& arc, const char* key, FRenderStyle& style, FRenderStyle* def)
|
||||
{
|
||||
|
|
|
@ -108,6 +108,10 @@ public:
|
|||
FSerializer &AddString(const char *key, const char *charptr);
|
||||
const char *GetString(const char *key);
|
||||
FSerializer &ScriptNum(const char *key, int &num);
|
||||
|
||||
|
||||
bool ReadOptionalInt(const char * key, int &into);
|
||||
|
||||
bool isReading() const
|
||||
{
|
||||
return r != nullptr;
|
||||
|
@ -240,7 +244,8 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FName &value, FName *d
|
|||
FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundID *def);
|
||||
FSerializer &Serialize(FSerializer &arc, const char *key, FString &sid, FString *def);
|
||||
FSerializer &Serialize(FSerializer &arc, const char *key, NumericValue &sid, NumericValue *def);
|
||||
FSerializer &Serialize(FSerializer &arc, const char *key, struct ModelOverride &sid, struct ModelOverride *def);
|
||||
FSerializer &Serialize(FSerializer &arc, const char *key, struct ModelOverride &mo, struct ModelOverride *def);
|
||||
FSerializer &Serialize(FSerializer &arc, const char *key, struct AnimOverride &ao, struct AnimOverride *def);
|
||||
FSerializer& Serialize(FSerializer& arc, const char* key, FTranslationID& value, FTranslationID* defval);
|
||||
|
||||
void SerializeFunctionPointer(FSerializer &arc, const char *key, FunctionPointerValue *&p);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 1998-2008 Randy Heit
|
||||
** Copyright 2005-2008 Christoph Oelckers
|
||||
** Copyright 2005-2023 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
|
@ -90,6 +90,84 @@ enum
|
|||
|
||||
class FileReader;
|
||||
|
||||
// an opaque memory buffer to the file's content. Can either own the memory or just point to an external buffer.
|
||||
class ResourceData
|
||||
{
|
||||
void* memory;
|
||||
size_t length;
|
||||
bool owned;
|
||||
|
||||
public:
|
||||
using value_type = uint8_t;
|
||||
ResourceData() { memory = nullptr; length = 0; owned = true; }
|
||||
const void* data() const { return memory; }
|
||||
size_t size() const { return length; }
|
||||
const char* string() const { return (const char*)memory; }
|
||||
const uint8_t* bytes() const { return (const uint8_t*)memory; }
|
||||
|
||||
ResourceData& operator = (const ResourceData& copy)
|
||||
{
|
||||
if (owned && memory) free(memory);
|
||||
length = copy.length;
|
||||
owned = copy.owned;
|
||||
if (owned)
|
||||
{
|
||||
memory = malloc(length);
|
||||
memcpy(memory, copy.memory, length);
|
||||
}
|
||||
else memory = copy.memory;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ResourceData& operator = (ResourceData&& copy) noexcept
|
||||
{
|
||||
if (owned && memory) free(memory);
|
||||
length = copy.length;
|
||||
owned = copy.owned;
|
||||
memory = copy.memory;
|
||||
copy.memory = nullptr;
|
||||
copy.length = 0;
|
||||
copy.owned = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ResourceData(const ResourceData& copy)
|
||||
{
|
||||
memory = nullptr;
|
||||
*this = copy;
|
||||
}
|
||||
|
||||
~ResourceData()
|
||||
{
|
||||
if (owned && memory) free(memory);
|
||||
}
|
||||
|
||||
void* allocate(size_t len)
|
||||
{
|
||||
if (!owned) memory = nullptr;
|
||||
length = len;
|
||||
owned = true;
|
||||
memory = realloc(memory, length);
|
||||
return memory;
|
||||
}
|
||||
|
||||
void set(const void* mem, size_t len)
|
||||
{
|
||||
memory = (void*)mem;
|
||||
length = len;
|
||||
owned = false;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
if (owned && memory) free(memory);
|
||||
memory = nullptr;
|
||||
length = 0;
|
||||
owned = true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class FileReaderInterface
|
||||
{
|
||||
public:
|
||||
|
@ -171,10 +249,12 @@ public:
|
|||
mReader = nullptr;
|
||||
}
|
||||
|
||||
bool OpenFile(const char *filename, Size start = 0, Size length = -1);
|
||||
bool OpenFile(const char *filename, Size start = 0, Size length = -1, bool buffered = false);
|
||||
bool OpenFilePart(FileReader &parent, Size start, Size length);
|
||||
bool OpenMemory(const void *mem, Size length); // read directly from the buffer
|
||||
bool OpenMemoryArray(const void *mem, Size length); // read from a copy of the buffer.
|
||||
bool OpenMemoryArray(std::vector<uint8_t>& data); // take the given array
|
||||
bool OpenMemoryArray(ResourceData& data); // take the given array
|
||||
bool OpenMemoryArray(std::function<bool(std::vector<uint8_t>&)> getter); // read contents to a buffer and return a reader to it
|
||||
bool OpenDecompressor(FileReader &parent, Size length, int method, bool seekable, bool exceptions = false); // creates a decompressor stream. 'seekable' uses a buffered version so that the Seek and Tell methods can be used.
|
||||
|
||||
|
@ -193,33 +273,34 @@ public:
|
|||
return mReader->Read(buffer, len);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Read(size_t len)
|
||||
ResourceData Read(size_t len)
|
||||
{
|
||||
std::vector<uint8_t> buffer(len);
|
||||
ResourceData buffer;
|
||||
if (len > 0)
|
||||
{
|
||||
Size length = mReader->Read(&buffer[0], len);
|
||||
buffer.resize((size_t)length);
|
||||
Size length = mReader->Read(buffer.allocate(len), len);
|
||||
if ((size_t)length < len) buffer.allocate(length);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Read()
|
||||
ResourceData Read()
|
||||
{
|
||||
return Read(GetLength());
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ReadPadded(size_t padding)
|
||||
ResourceData ReadPadded(size_t padding)
|
||||
{
|
||||
auto len = GetLength();
|
||||
std::vector<uint8_t> buffer(len + padding);
|
||||
ResourceData buffer;
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
Size length = mReader->Read(&buffer[0], len);
|
||||
auto p = (char*)buffer.allocate(len + padding);
|
||||
Size length = mReader->Read(p, len);
|
||||
if (length < len) buffer.clear();
|
||||
else memset(buffer.data() + len, 0, padding);
|
||||
else memset(p + len, 0, padding);
|
||||
}
|
||||
else buffer[0] = 0;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
@ -353,13 +434,13 @@ protected:
|
|||
class BufferWriter : public FileWriter
|
||||
{
|
||||
protected:
|
||||
TArray<unsigned char> mBuffer;
|
||||
std::vector<unsigned char> mBuffer;
|
||||
public:
|
||||
|
||||
BufferWriter() {}
|
||||
virtual size_t Write(const void *buffer, size_t len) override;
|
||||
TArray<unsigned char> *GetBuffer() { return &mBuffer; }
|
||||
TArray<unsigned char>&& TakeBuffer() { return std::move(mBuffer); }
|
||||
std::vector<unsigned char> *GetBuffer() { return &mBuffer; }
|
||||
std::vector<unsigned char>&& TakeBuffer() { return std::move(mBuffer); }
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -174,7 +174,6 @@ public:
|
|||
int AddFromBuffer(const char* name, const char* type, char* data, int size, int id, int flags);
|
||||
FileReader* GetFileReader(int wadnum); // Gets a FileReader object to the entire WAD
|
||||
void InitHashChains();
|
||||
FResourceLump* GetFileAt(int no);
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
@ -88,8 +88,8 @@ enum ELumpFlags
|
|||
// This holds a compresed Zip entry with all needed info to decompress it.
|
||||
struct FCompressedBuffer
|
||||
{
|
||||
unsigned mSize;
|
||||
unsigned mCompressedSize;
|
||||
size_t mSize;
|
||||
size_t mCompressedSize;
|
||||
int mMethod;
|
||||
int mZipFlags;
|
||||
unsigned mCRC32;
|
||||
|
@ -110,18 +110,34 @@ struct FCompressedBuffer
|
|||
|
||||
struct FResourceLump
|
||||
{
|
||||
protected:
|
||||
friend class FResourceFile;
|
||||
friend class FWadFile; // this still needs direct access.
|
||||
friend class FileData;
|
||||
friend class FileSystem;
|
||||
friend class FLumpFile;
|
||||
friend class FLumpReader;
|
||||
friend class FGrpFile;
|
||||
friend class F7ZFile;
|
||||
friend class FSSIFile;
|
||||
friend class FWHResFile;
|
||||
friend class FZipFile;
|
||||
friend class FPakFile;
|
||||
friend class FRFFFile;
|
||||
friend class FDirectory;
|
||||
friend int lumpcmp(const void* a, const void* b);
|
||||
|
||||
|
||||
int LumpSize;
|
||||
int RefCount;
|
||||
protected:
|
||||
//protected:
|
||||
const char* FullName;
|
||||
public:
|
||||
//public:
|
||||
uint8_t Flags;
|
||||
char * Cache;
|
||||
FResourceFile * Owner;
|
||||
|
||||
public:
|
||||
FResourceLump()
|
||||
{
|
||||
Cache = NULL;
|
||||
|
@ -129,9 +145,12 @@ public:
|
|||
Flags = 0;
|
||||
RefCount = 0;
|
||||
FullName = "";
|
||||
LumpSize = 0;
|
||||
}
|
||||
|
||||
virtual ~FResourceLump();
|
||||
|
||||
protected:
|
||||
|
||||
virtual FileReader *GetReader();
|
||||
virtual FileReader NewReader();
|
||||
virtual int GetFileOffset() { return -1; }
|
||||
|
@ -157,9 +176,9 @@ protected:
|
|||
class FResourceFile
|
||||
{
|
||||
public:
|
||||
protected:
|
||||
FileReader Reader;
|
||||
const char* FileName;
|
||||
protected:
|
||||
uint32_t NumLumps;
|
||||
char Hash[48];
|
||||
StringPool* stringpool;
|
||||
|
@ -186,15 +205,61 @@ public:
|
|||
static FResourceFile *OpenDirectory(const char *filename, LumpFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, StringPool* sp = nullptr);
|
||||
virtual ~FResourceFile();
|
||||
// If this FResourceFile represents a directory, the Reader object is not usable so don't return it.
|
||||
FileReader *GetReader() { return Reader.isOpen()? &Reader : nullptr; }
|
||||
uint32_t LumpCount() const { return NumLumps; }
|
||||
FileReader *GetContainerReader() { return Reader.isOpen()? &Reader : nullptr; }
|
||||
const char* GetFileName() const { return FileName; }
|
||||
uint32_t GetFirstEntry() const { return FirstLump; }
|
||||
void SetFirstLump(uint32_t f) { FirstLump = f; }
|
||||
const char* GetHash() const { return Hash; }
|
||||
|
||||
|
||||
virtual FResourceLump *GetLump(int no) = 0;
|
||||
FResourceLump *FindLump(const char *name);
|
||||
|
||||
int EntryCount() const { return NumLumps; }
|
||||
int FindEntry(const char* name);
|
||||
|
||||
size_t Length(int entry)
|
||||
{
|
||||
auto l = GetLump(entry);
|
||||
return l ? l->LumpSize : -1;
|
||||
}
|
||||
|
||||
FileReader GetEntryReader(int entry, bool newreader = true)
|
||||
{
|
||||
auto l = GetLump(entry);
|
||||
return l ? l->NewReader() : FileReader();
|
||||
}
|
||||
|
||||
int GetEntryFlags(int entry)
|
||||
{
|
||||
auto l = GetLump(entry);
|
||||
return l ? l->Flags : 0;
|
||||
}
|
||||
|
||||
ResourceData Read(int entry)
|
||||
{
|
||||
auto fr = GetEntryReader(entry, false);
|
||||
return fr.Read();
|
||||
}
|
||||
|
||||
const char* getName(int entry)
|
||||
{
|
||||
auto l = GetLump(entry);
|
||||
return l ? l->FullName : nullptr;
|
||||
}
|
||||
FCompressedBuffer GetRawData(int entry)
|
||||
{
|
||||
auto l = GetLump(entry);
|
||||
if (!l) return {};
|
||||
return l->GetRawData();
|
||||
}
|
||||
|
||||
FileReader Destroy()
|
||||
{
|
||||
auto fr = std::move(Reader);
|
||||
delete this;
|
||||
return fr;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -367,8 +367,7 @@ FResourceFile *Check7Z(const char *filename, FileReader &file, LumpFilterInfo* f
|
|||
auto rf = new F7ZFile(filename, file, sp);
|
||||
if (rf->Open(filter, Printf)) return rf;
|
||||
|
||||
file = std::move(rf->Reader); // to avoid destruction of reader
|
||||
delete rf;
|
||||
file = rf->Destroy();
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
|
|
@ -145,9 +145,7 @@ FResourceFile *CheckGRP(const char *filename, FileReader &file, LumpFilterInfo*
|
|||
{
|
||||
auto rf = new FGrpFile(filename, file, sp);
|
||||
if (rf->Open(filter)) return rf;
|
||||
|
||||
file = std::move(rf->Reader); // to avoid destruction of reader
|
||||
delete rf;
|
||||
file = rf->Destroy();
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
|
|
@ -89,8 +89,7 @@ FResourceFile *CheckLump(const char *filename, FileReader &file, LumpFilterInfo*
|
|||
// always succeeds
|
||||
auto rf = new FLumpFile(filename, file, sp);
|
||||
if (rf->Open(filter)) return rf;
|
||||
file = std::move(rf->Reader); // to avoid destruction of reader
|
||||
delete rf;
|
||||
file = rf->Destroy();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -138,9 +138,7 @@ FResourceFile *CheckPak(const char *filename, FileReader &file, LumpFilterInfo*
|
|||
{
|
||||
auto rf = new FPakFile(filename, file, sp);
|
||||
if (rf->Open(filter)) return rf;
|
||||
|
||||
file = std::move(rf->Reader); // to avoid destruction of reader
|
||||
delete rf;
|
||||
file = rf->Destroy();
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
|
|
@ -252,9 +252,7 @@ FResourceFile *CheckRFF(const char *filename, FileReader &file, LumpFilterInfo*
|
|||
{
|
||||
auto rf = new FRFFFile(filename, file, sp);
|
||||
if (rf->Open(filter)) return rf;
|
||||
|
||||
file = std::move(rf->Reader); // to avoid destruction of reader
|
||||
delete rf;
|
||||
file = rf->Destroy();
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
|
|
@ -46,7 +46,7 @@ class FSSIFile : public FUncompressedFile
|
|||
{
|
||||
public:
|
||||
FSSIFile(const char * filename, FileReader &file, StringPool* sp);
|
||||
bool Open(int version, int lumpcount, LumpFilterInfo* filter);
|
||||
bool Open(int version, int EntryCount, LumpFilterInfo* filter);
|
||||
};
|
||||
|
||||
|
||||
|
@ -68,13 +68,13 @@ FSSIFile::FSSIFile(const char *filename, FileReader &file, StringPool* sp)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FSSIFile::Open(int version, int lumpcount, LumpFilterInfo*)
|
||||
bool FSSIFile::Open(int version, int EntryCount, LumpFilterInfo*)
|
||||
{
|
||||
NumLumps = lumpcount*2;
|
||||
Lumps.Resize(lumpcount*2);
|
||||
NumLumps = EntryCount*2;
|
||||
Lumps.Resize(EntryCount*2);
|
||||
|
||||
|
||||
int32_t j = (version == 2 ? 267 : 254) + (lumpcount * 121);
|
||||
int32_t j = (version == 2 ? 267 : 254) + (EntryCount * 121);
|
||||
for (uint32_t i = 0; i < NumLumps; i+=2)
|
||||
{
|
||||
char fn[13];
|
||||
|
@ -147,8 +147,7 @@ FResourceFile* CheckSSI(const char* filename, FileReader& file, LumpFilterInfo*
|
|||
}
|
||||
auto ssi = new FSSIFile(filename, file, sp);
|
||||
if (ssi->Open(version, numfiles, filter)) return ssi;
|
||||
file = std::move(ssi->Reader); // to avoid destruction of reader
|
||||
delete ssi;
|
||||
file = ssi->Destroy();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
|
|
|
@ -76,8 +76,8 @@ public:
|
|||
{
|
||||
if(!Compressed)
|
||||
{
|
||||
Owner->Reader.Seek(Position, FileReader::SeekSet);
|
||||
return &Owner->Reader;
|
||||
Owner->GetContainerReader()->Seek(Position, FileReader::SeekSet);
|
||||
return Owner->GetContainerReader();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ public:
|
|||
{
|
||||
if(!Compressed)
|
||||
{
|
||||
const char * buffer = Owner->Reader.GetBuffer();
|
||||
const char * buffer = Owner->GetContainerReader()->GetBuffer();
|
||||
|
||||
if (buffer != NULL)
|
||||
{
|
||||
|
@ -96,20 +96,20 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
Owner->Reader.Seek(Position, FileReader::SeekSet);
|
||||
Owner->GetContainerReader()->Seek(Position, FileReader::SeekSet);
|
||||
Cache = new char[LumpSize];
|
||||
|
||||
if(Compressed)
|
||||
{
|
||||
FileReader lzss;
|
||||
if (lzss.OpenDecompressor(Owner->Reader, LumpSize, METHOD_LZSS, false, true))
|
||||
if (lzss.OpenDecompressor(*Owner->GetContainerReader(), LumpSize, METHOD_LZSS, false, true))
|
||||
{
|
||||
lzss.Read(Cache, LumpSize);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto read = Owner->Reader.Read(Cache, LumpSize);
|
||||
auto read = Owner->GetContainerReader()->Read(Cache, LumpSize);
|
||||
if (read != LumpSize)
|
||||
{
|
||||
throw FileSystemException("only read %d of %d bytes", (int)read, (int)LumpSize);
|
||||
|
@ -478,8 +478,7 @@ FResourceFile *CheckWad(const char *filename, FileReader &file, LumpFilterInfo*
|
|||
auto rf = new FWadFile(filename, file, sp);
|
||||
if (rf->Open(filter, Printf)) return rf;
|
||||
|
||||
file = std::move(rf->Reader); // to avoid destruction of reader
|
||||
delete rf;
|
||||
file = rf->Destroy();
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
|
|
@ -136,8 +136,7 @@ FResourceFile *CheckWHRes(const char *filename, FileReader &file, LumpFilterInfo
|
|||
}
|
||||
auto rf = new FWHResFile(filename, file, sp);
|
||||
if (rf->Open(filter)) return rf;
|
||||
file = std::move(rf->Reader); // to avoid destruction of reader
|
||||
delete rf;
|
||||
file = rf->Destroy();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace FileSys {
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
static bool UncompressZipLump(char *Cache, FileReader &Reader, int Method, int LumpSize, int CompressedSize, int GPFlags, bool exceptions)
|
||||
static bool UncompressZipLump(char *Cache, FileReader &Reader, int Method, ptrdiff_t LumpSize, ptrdiff_t CompressedSize, int GPFlags, bool exceptions)
|
||||
{
|
||||
switch (Method)
|
||||
{
|
||||
|
@ -79,7 +79,7 @@ static bool UncompressZipLump(char *Cache, FileReader &Reader, int Method, int L
|
|||
case METHOD_IMPLODE:
|
||||
{
|
||||
FZipExploder exploder;
|
||||
if (exploder.Explode((unsigned char*)Cache, LumpSize, Reader, CompressedSize, GPFlags) == -1)
|
||||
if (exploder.Explode((unsigned char*)Cache, (unsigned)LumpSize, Reader, (unsigned)CompressedSize, GPFlags) == -1)
|
||||
{
|
||||
// decompression failed so zero the cache.
|
||||
memset(Cache, 0, LumpSize);
|
||||
|
@ -89,7 +89,7 @@ static bool UncompressZipLump(char *Cache, FileReader &Reader, int Method, int L
|
|||
|
||||
case METHOD_SHRINK:
|
||||
{
|
||||
ShrinkLoop((unsigned char *)Cache, LumpSize, Reader, CompressedSize);
|
||||
ShrinkLoop((unsigned char *)Cache, (unsigned)LumpSize, Reader, (unsigned)CompressedSize);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -445,8 +445,8 @@ FCompressedBuffer FZipLump::GetRawData()
|
|||
{
|
||||
FCompressedBuffer cbuf = { (unsigned)LumpSize, (unsigned)CompressedSize, Method, GPFlags, CRC32, new char[CompressedSize] };
|
||||
if (NeedFileStart) SetLumpAddress();
|
||||
Owner->Reader.Seek(Position, FileReader::SeekSet);
|
||||
Owner->Reader.Read(cbuf.mBuffer, CompressedSize);
|
||||
Owner->GetContainerReader()->Seek(Position, FileReader::SeekSet);
|
||||
Owner->GetContainerReader()->Read(cbuf.mBuffer, CompressedSize);
|
||||
return cbuf;
|
||||
}
|
||||
|
||||
|
@ -464,8 +464,8 @@ void FZipLump::SetLumpAddress()
|
|||
FZipLocalFileHeader localHeader;
|
||||
int skiplen;
|
||||
|
||||
Owner->Reader.Seek(Position, FileReader::SeekSet);
|
||||
Owner->Reader.Read(&localHeader, sizeof(localHeader));
|
||||
Owner->GetContainerReader()->Seek(Position, FileReader::SeekSet);
|
||||
Owner->GetContainerReader()->Read(&localHeader, sizeof(localHeader));
|
||||
skiplen = LittleShort(localHeader.NameLength) + LittleShort(localHeader.ExtraLength);
|
||||
Position += sizeof(localHeader) + skiplen;
|
||||
NeedFileStart = false;
|
||||
|
@ -484,8 +484,8 @@ FileReader *FZipLump::GetReader()
|
|||
if (Method == METHOD_STORED)
|
||||
{
|
||||
if (NeedFileStart) SetLumpAddress();
|
||||
Owner->Reader.Seek(Position, FileReader::SeekSet);
|
||||
return &Owner->Reader;
|
||||
Owner->GetContainerReader()->Seek(Position, FileReader::SeekSet);
|
||||
return Owner->GetContainerReader();
|
||||
}
|
||||
else return NULL;
|
||||
}
|
||||
|
@ -501,7 +501,7 @@ int FZipLump::FillCache()
|
|||
if (NeedFileStart) SetLumpAddress();
|
||||
const char *buffer;
|
||||
|
||||
if (Method == METHOD_STORED && (buffer = Owner->Reader.GetBuffer()) != NULL)
|
||||
if (Method == METHOD_STORED && (buffer = Owner->GetContainerReader()->GetBuffer()) != NULL)
|
||||
{
|
||||
// This is an in-memory file so the cache can point directly to the file's data.
|
||||
Cache = const_cast<char*>(buffer) + Position;
|
||||
|
@ -509,9 +509,9 @@ int FZipLump::FillCache()
|
|||
return -1;
|
||||
}
|
||||
|
||||
Owner->Reader.Seek(Position, FileReader::SeekSet);
|
||||
Owner->GetContainerReader()->Seek(Position, FileReader::SeekSet);
|
||||
Cache = new char[LumpSize];
|
||||
UncompressZipLump(Cache, Owner->Reader, Method, LumpSize, CompressedSize, GPFlags, true);
|
||||
UncompressZipLump(Cache, *Owner->GetContainerReader(), Method, LumpSize, CompressedSize, GPFlags, true);
|
||||
RefCount = 1;
|
||||
return 1;
|
||||
}
|
||||
|
@ -548,9 +548,7 @@ FResourceFile *CheckZip(const char *filename, FileReader &file, LumpFilterInfo*
|
|||
{
|
||||
auto rf = new FZipFile(filename, file, sp);
|
||||
if (rf->Open(filter, Printf)) return rf;
|
||||
|
||||
file = std::move(rf->Reader); // to avoid destruction of reader
|
||||
delete rf;
|
||||
file = rf->Destroy();
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
@ -606,8 +604,8 @@ static int AppendToZip(FileWriter *zip_file, const FCompressedBuffer &content, s
|
|||
local.ModDate = LittleShort(dostime.first);
|
||||
local.ModTime = LittleShort(dostime.second);
|
||||
local.CRC32 = content.mCRC32;
|
||||
local.UncompressedSize = LittleLong(content.mSize);
|
||||
local.CompressedSize = LittleLong(content.mCompressedSize);
|
||||
local.UncompressedSize = LittleLong((unsigned)content.mSize);
|
||||
local.CompressedSize = LittleLong((unsigned)content.mCompressedSize);
|
||||
local.NameLength = LittleShort((unsigned short)strlen(content.filename));
|
||||
local.ExtraLength = 0;
|
||||
|
||||
|
@ -648,8 +646,8 @@ int AppendCentralDirectory(FileWriter *zip_file, const FCompressedBuffer &conten
|
|||
dir.ModTime = LittleShort(dostime.first);
|
||||
dir.ModDate = LittleShort(dostime.second);
|
||||
dir.CRC32 = content.mCRC32;
|
||||
dir.CompressedSize32 = LittleLong(content.mCompressedSize);
|
||||
dir.UncompressedSize32 = LittleLong(content.mSize);
|
||||
dir.CompressedSize32 = LittleLong((unsigned)content.mCompressedSize);
|
||||
dir.UncompressedSize32 = LittleLong((unsigned)content.mSize);
|
||||
dir.NameLength = LittleShort((unsigned short)strlen(content.filename));
|
||||
dir.ExtraLength = 0;
|
||||
dir.CommentLength = 0;
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
*/
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include "files_internal.h"
|
||||
|
||||
namespace FileSys {
|
||||
|
@ -285,7 +286,7 @@ ptrdiff_t MemoryReader::Seek(ptrdiff_t offset, int origin)
|
|||
|
||||
ptrdiff_t MemoryReader::Read(void *buffer, ptrdiff_t len)
|
||||
{
|
||||
if (len>Length - FilePos) len = Length - FilePos;
|
||||
if (len > Length - FilePos) len = Length - FilePos;
|
||||
if (len<0) len = 0;
|
||||
memcpy(buffer, bufptr + FilePos, len);
|
||||
FilePos += len;
|
||||
|
@ -322,40 +323,37 @@ char *MemoryReader::Gets(char *strbuf, ptrdiff_t len)
|
|||
return strbuf;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// MemoryArrayReader
|
||||
//
|
||||
// reads data from an array of memory
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class MemoryArrayReader : public MemoryReader
|
||||
int BufferingReader::FillBuffer(ptrdiff_t newpos)
|
||||
{
|
||||
std::vector<uint8_t> buf;
|
||||
|
||||
public:
|
||||
MemoryArrayReader(const char *buffer, ptrdiff_t length)
|
||||
if (newpos > Length) newpos = Length;
|
||||
if (newpos < bufferpos) return 0;
|
||||
auto read = baseReader->Read(&buf[bufferpos], newpos - bufferpos);
|
||||
bufferpos += read;
|
||||
if (bufferpos == Length)
|
||||
{
|
||||
if (length > 0)
|
||||
{
|
||||
buf.resize(length);
|
||||
memcpy(&buf[0], buffer, length);
|
||||
}
|
||||
UpdateBuffer();
|
||||
// we have read the entire file, so delete our data provider.
|
||||
baseReader.reset();
|
||||
}
|
||||
return read == newpos - bufferpos ? 0 : -1;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> &GetArray() { return buf; }
|
||||
|
||||
void UpdateBuffer()
|
||||
{
|
||||
bufptr = (const char*)buf.data();
|
||||
FilePos = 0;
|
||||
Length = buf.size();
|
||||
}
|
||||
};
|
||||
ptrdiff_t BufferingReader::Seek(ptrdiff_t offset, int origin)
|
||||
{
|
||||
if (-1 == MemoryReader::Seek(offset, origin)) return -1;
|
||||
return FillBuffer(FilePos);
|
||||
}
|
||||
|
||||
ptrdiff_t BufferingReader::Read(void* buffer, ptrdiff_t len)
|
||||
{
|
||||
if (FillBuffer(FilePos + len) < 0) return 0;
|
||||
return MemoryReader::Read(buffer, len);
|
||||
}
|
||||
|
||||
char* BufferingReader::Gets(char* strbuf, ptrdiff_t len)
|
||||
{
|
||||
if (FillBuffer(FilePos + len) < 0) return nullptr;
|
||||
return MemoryReader::Gets(strbuf, len);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -365,7 +363,7 @@ public:
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FileReader::OpenFile(const char *filename, FileReader::Size start, FileReader::Size length)
|
||||
bool FileReader::OpenFile(const char *filename, FileReader::Size start, FileReader::Size length, bool buffered)
|
||||
{
|
||||
auto reader = new StdFileReader;
|
||||
if (!reader->Open(filename, start, length))
|
||||
|
@ -374,7 +372,8 @@ bool FileReader::OpenFile(const char *filename, FileReader::Size start, FileRead
|
|||
return false;
|
||||
}
|
||||
Close();
|
||||
mReader = reader;
|
||||
if (buffered) mReader = new BufferingReader(reader);
|
||||
else mReader = reader;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -396,13 +395,27 @@ bool FileReader::OpenMemory(const void *mem, FileReader::Size length)
|
|||
bool FileReader::OpenMemoryArray(const void *mem, FileReader::Size length)
|
||||
{
|
||||
Close();
|
||||
mReader = new MemoryArrayReader((const char *)mem, length);
|
||||
mReader = new MemoryArrayReader<std::vector<uint8_t>>((const char *)mem, length);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileReader::OpenMemoryArray(std::vector<uint8_t>& data)
|
||||
{
|
||||
Close();
|
||||
if (data.size() > 0) mReader = new MemoryArrayReader<std::vector<uint8_t>>(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileReader::OpenMemoryArray(ResourceData& data)
|
||||
{
|
||||
Close();
|
||||
if (data.size() > 0) mReader = new MemoryArrayReader<ResourceData>(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileReader::OpenMemoryArray(std::function<bool(std::vector<uint8_t>&)> getter)
|
||||
{
|
||||
auto reader = new MemoryArrayReader(nullptr, 0);
|
||||
auto reader = new MemoryArrayReader<std::vector<uint8_t>>(nullptr, 0);
|
||||
if (getter(reader->GetArray()))
|
||||
{
|
||||
Close();
|
||||
|
@ -494,7 +507,8 @@ size_t FileWriter::Printf(const char *fmt, ...)
|
|||
|
||||
size_t BufferWriter::Write(const void *buffer, size_t len)
|
||||
{
|
||||
unsigned int ofs = mBuffer.Reserve((unsigned)len);
|
||||
size_t ofs = mBuffer.size();
|
||||
mBuffer.resize(ofs + len);
|
||||
memcpy(&mBuffer[ofs], buffer, len);
|
||||
return len;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "fs_files.h"
|
||||
|
||||
namespace FileSys {
|
||||
|
@ -28,4 +29,71 @@ public:
|
|||
virtual const char *GetBuffer() const override { return bufptr; }
|
||||
};
|
||||
|
||||
class BufferingReader : public MemoryReader
|
||||
{
|
||||
std::vector<uint8_t> buf;
|
||||
std::unique_ptr<FileReaderInterface> baseReader;
|
||||
ptrdiff_t bufferpos = 0;
|
||||
|
||||
int FillBuffer(ptrdiff_t newpos);
|
||||
public:
|
||||
BufferingReader(FileReaderInterface* base)
|
||||
: baseReader(base)
|
||||
{
|
||||
}
|
||||
|
||||
ptrdiff_t Seek(ptrdiff_t offset, int origin) override;
|
||||
ptrdiff_t Read(void* buffer, ptrdiff_t len) override;
|
||||
char* Gets(char* strbuf, ptrdiff_t len) override;
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// MemoryArrayReader
|
||||
//
|
||||
// reads data from an array of memory
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
template<class T>
|
||||
class MemoryArrayReader : public MemoryReader
|
||||
{
|
||||
T buf;
|
||||
|
||||
public:
|
||||
MemoryArrayReader()
|
||||
{
|
||||
FilePos = 0;
|
||||
Length = 0;
|
||||
}
|
||||
|
||||
MemoryArrayReader(const char* buffer, ptrdiff_t length)
|
||||
{
|
||||
if (length > 0)
|
||||
{
|
||||
buf.resize(length);
|
||||
memcpy(&buf[0], buffer, length);
|
||||
}
|
||||
UpdateBuffer();
|
||||
}
|
||||
|
||||
MemoryArrayReader(T& buffer)
|
||||
{
|
||||
buf = std::move(buffer);
|
||||
UpdateBuffer();
|
||||
}
|
||||
|
||||
std::vector<uint8_t>& GetArray() { return buf; }
|
||||
|
||||
void UpdateBuffer()
|
||||
{
|
||||
bufptr = (const char*)buf.data();
|
||||
FilePos = 0;
|
||||
Length = buf.size();
|
||||
}
|
||||
};
|
||||
|
||||
bool OpenMemoryArray(std::vector<uint8_t>& data); // take the given array
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -404,14 +404,14 @@ void FileSystem::AddFile (const char *filename, FileReader *filer, LumpFilterInf
|
|||
if (resfile != NULL)
|
||||
{
|
||||
if (Printf)
|
||||
Printf(FSMessageLevel::Message, "adding %s, %d lumps\n", filename, resfile->LumpCount());
|
||||
Printf(FSMessageLevel::Message, "adding %s, %d lumps\n", filename, resfile->EntryCount());
|
||||
|
||||
uint32_t lumpstart = (uint32_t)FileInfo.size();
|
||||
|
||||
resfile->SetFirstLump(lumpstart);
|
||||
for (uint32_t i=0; i < resfile->LumpCount(); i++)
|
||||
for (int i = 0; i < resfile->EntryCount(); i++)
|
||||
{
|
||||
FResourceLump *lump = resfile->GetLump(i);
|
||||
FResourceLump* lump = resfile->GetLump(i);
|
||||
FileInfo.resize(FileInfo.size() + 1);
|
||||
FileSystem::LumpRecord* lump_p = &FileInfo.back();
|
||||
lump_p->SetFromLump((int)Files.size(), lump, stringpool);
|
||||
|
@ -419,15 +419,15 @@ void FileSystem::AddFile (const char *filename, FileReader *filer, LumpFilterInf
|
|||
|
||||
Files.push_back(resfile);
|
||||
|
||||
for (uint32_t i=0; i < resfile->LumpCount(); i++)
|
||||
for (int i = 0; i < resfile->EntryCount(); i++)
|
||||
{
|
||||
FResourceLump *lump = resfile->GetLump(i);
|
||||
if (lump->Flags & LUMPF_EMBEDDED)
|
||||
int flags = resfile->GetEntryFlags(i);
|
||||
if (flags & LUMPF_EMBEDDED)
|
||||
{
|
||||
std::string path = filename;
|
||||
path += ':';
|
||||
path += lump->getName();
|
||||
auto embedded = lump->NewReader();
|
||||
path += resfile->getName(i);
|
||||
auto embedded = resfile->GetEntryReader(i, true);
|
||||
AddFile(path.c_str(), &embedded, filter, Printf, hashfile);
|
||||
}
|
||||
}
|
||||
|
@ -454,13 +454,12 @@ void FileSystem::AddFile (const char *filename, FileReader *filer, LumpFilterInf
|
|||
else
|
||||
fprintf(hashfile, "file: %s, Directory structure\n", filename);
|
||||
|
||||
for (uint32_t i = 0; i < resfile->LumpCount(); i++)
|
||||
for (int i = 0; i < resfile->EntryCount(); i++)
|
||||
{
|
||||
FResourceLump *lump = resfile->GetLump(i);
|
||||
|
||||
if (!(lump->Flags & LUMPF_EMBEDDED))
|
||||
int flags = resfile->GetEntryFlags(i);
|
||||
if (!(flags & LUMPF_EMBEDDED))
|
||||
{
|
||||
auto reader = lump->NewReader();
|
||||
auto reader = resfile->GetEntryReader(i, true);
|
||||
md5Hash(filereader, cksum);
|
||||
|
||||
for (size_t j = 0; j < sizeof(cksum); ++j)
|
||||
|
@ -468,7 +467,7 @@ void FileSystem::AddFile (const char *filename, FileReader *filer, LumpFilterInf
|
|||
snprintf(cksumout + (j * 2), 3, "%02X", cksum[j]);
|
||||
}
|
||||
|
||||
fprintf(hashfile, "file: %s, lump: %s, hash: %s, size: %d\n", filename, lump->getName(), cksumout, lump->LumpSize);
|
||||
fprintf(hashfile, "file: %s, lump: %s, hash: %s, size: %llu\n", filename, resfile->getName(i), cksumout, (uint64_t)resfile->Length(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1421,7 +1420,7 @@ FileReader *FileSystem::GetFileReader(int rfnum)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return Files[rfnum]->GetReader();
|
||||
return Files[rfnum]->GetContainerReader();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -1441,7 +1440,7 @@ const char *FileSystem::GetResourceFileName (int rfnum) const noexcept
|
|||
return NULL;
|
||||
}
|
||||
|
||||
name = Files[rfnum]->FileName;
|
||||
name = Files[rfnum]->GetFileName();
|
||||
slash = strrchr (name, '/');
|
||||
return (slash != nullptr && slash[1] != 0) ? slash+1 : name;
|
||||
}
|
||||
|
@ -1473,7 +1472,7 @@ int FileSystem::GetLastEntry (int rfnum) const noexcept
|
|||
return 0;
|
||||
}
|
||||
|
||||
return Files[rfnum]->GetFirstEntry() + Files[rfnum]->LumpCount() - 1;
|
||||
return Files[rfnum]->GetFirstEntry() + Files[rfnum]->EntryCount() - 1;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -1488,7 +1487,7 @@ int FileSystem::GetEntryCount (int rfnum) const noexcept
|
|||
return 0;
|
||||
}
|
||||
|
||||
return Files[rfnum]->LumpCount();
|
||||
return Files[rfnum]->EntryCount();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1507,7 +1506,7 @@ const char *FileSystem::GetResourceFileFullName (int rfnum) const noexcept
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
return Files[rfnum]->FileName;
|
||||
return Files[rfnum]->GetFileName();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1592,15 +1591,5 @@ static void PrintLastError (FileSystemMessageFunc Printf)
|
|||
}
|
||||
#endif
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// NBlood style lookup functions
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FResourceLump* FileSystem::GetFileAt(int no)
|
||||
{
|
||||
return FileInfo[no].lump;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -157,7 +157,7 @@ static bool IsWadInFolder(const FResourceFile* const archive, const char* const
|
|||
return false;
|
||||
}
|
||||
|
||||
const auto dirName = ExtractBaseName(archive->FileName);
|
||||
const auto dirName = ExtractBaseName(archive->GetFileName());
|
||||
const auto fileName = ExtractBaseName(resPath, true);
|
||||
const std::string filePath = dirName + '/' + fileName;
|
||||
|
||||
|
@ -242,7 +242,7 @@ void *FResourceLump::Lock()
|
|||
catch (const FileSystemException& err)
|
||||
{
|
||||
// enrich the message with info about this lump.
|
||||
throw FileSystemException("%s, file '%s': %s", getName(), Owner->FileName, err.what());
|
||||
throw FileSystemException("%s, file '%s': %s", getName(), Owner->GetFileName(), err.what());
|
||||
}
|
||||
}
|
||||
return Cache;
|
||||
|
@ -360,13 +360,13 @@ int lumpcmp(const void * a, const void * b)
|
|||
//
|
||||
// Generates a hash identifier for use in file identification.
|
||||
// Potential uses are mod-wide compatibility settings or localization add-ons.
|
||||
// This only hashes the lump directory but not the actual content
|
||||
// This only hashes the directory but not the actual content
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FResourceFile::GenerateHash()
|
||||
{
|
||||
// hash the lump directory after sorting
|
||||
// hash the directory after sorting
|
||||
using namespace FileSys::md5;
|
||||
|
||||
auto n = snprintf(Hash, 48, "%08X-%04X-", (unsigned)Reader.GetLength(), NumLumps);
|
||||
|
@ -377,9 +377,10 @@ void FResourceFile::GenerateHash()
|
|||
uint8_t digest[16];
|
||||
for(uint32_t i = 0; i < NumLumps; i++)
|
||||
{
|
||||
auto lump = GetLump(i);
|
||||
md5_append(&state, (const uint8_t*)lump->FullName, (unsigned)strlen(lump->FullName) + 1);
|
||||
md5_append(&state, (const uint8_t*)&lump->LumpSize, 4);
|
||||
auto name = getName(i);
|
||||
auto size = Length(i);
|
||||
md5_append(&state, (const uint8_t*)name, (unsigned)strlen(name) + 1);
|
||||
md5_append(&state, (const uint8_t*)&size, sizeof(size));
|
||||
}
|
||||
md5_finish(&state, digest);
|
||||
for (auto c : digest)
|
||||
|
@ -618,17 +619,16 @@ bool FResourceFile::FindPrefixRange(const char* filter, void *lumps, size_t lump
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
FResourceLump *FResourceFile::FindLump(const char *name)
|
||||
int FResourceFile::FindEntry(const char *name)
|
||||
{
|
||||
for (unsigned i = 0; i < NumLumps; i++)
|
||||
{
|
||||
FResourceLump *lump = GetLump(i);
|
||||
if (!stricmp(name, lump->FullName))
|
||||
if (!stricmp(name, getName(i)))
|
||||
{
|
||||
return lump;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
return -1;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -639,8 +639,8 @@ FResourceLump *FResourceFile::FindLump(const char *name)
|
|||
|
||||
FileReader *FUncompressedLump::GetReader()
|
||||
{
|
||||
Owner->Reader.Seek(Position, FileReader::SeekSet);
|
||||
return &Owner->Reader;
|
||||
Owner->GetContainerReader()->Seek(Position, FileReader::SeekSet);
|
||||
return Owner->GetContainerReader();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -651,7 +651,7 @@ FileReader *FUncompressedLump::GetReader()
|
|||
|
||||
int FUncompressedLump::FillCache()
|
||||
{
|
||||
const char * buffer = Owner->Reader.GetBuffer();
|
||||
const char * buffer = Owner->GetContainerReader()->GetBuffer();
|
||||
|
||||
if (buffer != NULL)
|
||||
{
|
||||
|
@ -661,10 +661,10 @@ int FUncompressedLump::FillCache()
|
|||
return -1;
|
||||
}
|
||||
|
||||
Owner->Reader.Seek(Position, FileReader::SeekSet);
|
||||
Owner->GetContainerReader()->Seek(Position, FileReader::SeekSet);
|
||||
Cache = new char[LumpSize];
|
||||
|
||||
auto read = Owner->Reader.Read(Cache, LumpSize);
|
||||
auto read = Owner->GetContainerReader()->Read(Cache, LumpSize);
|
||||
if (read != LumpSize)
|
||||
{
|
||||
throw FileSystemException("only read %d of %d bytes", (int)read, (int)LumpSize);
|
||||
|
|
|
@ -58,12 +58,12 @@ struct HexDataSource
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void ParseDefinition(FileSys::FResourceLump* font)
|
||||
void ParseDefinition(FResourceFile* resf, int index)
|
||||
{
|
||||
FScanner sc;
|
||||
|
||||
auto data = font->Lock();
|
||||
sc.OpenMem("newconsolefont.hex", (const char*)data, font->Size());
|
||||
auto data = resf->Read(index);
|
||||
sc.OpenMem("newconsolefont.hex", data.string(), data.size());
|
||||
sc.SetCMode(true);
|
||||
glyphdata.Push(0); // ensure that index 0 can be used as 'not present'.
|
||||
while (sc.GetString())
|
||||
|
@ -97,7 +97,6 @@ struct HexDataSource
|
|||
lumb = i * 255 / 17;
|
||||
SmallPal[i] = PalEntry(255, lumb, lumb, lumb);
|
||||
}
|
||||
font->Unlock();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -440,8 +439,8 @@ void LoadHexFont(const char* filename)
|
|||
{
|
||||
auto resf = FResourceFile::OpenResourceFile(filename);
|
||||
if (resf == nullptr) I_FatalError("Unable to open %s", filename);
|
||||
auto hexfont = resf->FindLump("newconsolefont.hex");
|
||||
if (hexfont == nullptr) I_FatalError("Unable to find newconsolefont.hex in %s", filename);
|
||||
hexdata.ParseDefinition(hexfont);
|
||||
auto hexfont = resf->FindEntry("newconsolefont.hex");
|
||||
if (hexfont < 0) I_FatalError("Unable to find newconsolefont.hex in %s", filename);
|
||||
hexdata.ParseDefinition(resf, hexfont);
|
||||
delete resf;
|
||||
}
|
||||
|
|
|
@ -297,37 +297,26 @@ unsigned FSavegameManagerBase::ExtractSaveData(int index)
|
|||
!node->bOldVersion &&
|
||||
(resf = FResourceFile::OpenResourceFile(node->Filename.GetChars(), true)) != nullptr)
|
||||
{
|
||||
auto info = resf->FindLump("info.json");
|
||||
if (info == nullptr)
|
||||
auto info = resf->FindEntry("info.json");
|
||||
if (info < 0)
|
||||
{
|
||||
// this should not happen because the file has already been verified.
|
||||
return index;
|
||||
}
|
||||
|
||||
void* data = info->Lock();
|
||||
auto data = resf->Read(info);
|
||||
FSerializer arc;
|
||||
if (!arc.OpenReader((const char*)data, info->LumpSize))
|
||||
if (!arc.OpenReader(data.string(), data.size()))
|
||||
{
|
||||
info->Unlock();
|
||||
return index;
|
||||
}
|
||||
info->Unlock();
|
||||
|
||||
SaveCommentString = ExtractSaveComment(arc);
|
||||
|
||||
auto pic = resf->FindLump("savepic.png");
|
||||
if (pic != nullptr)
|
||||
auto pic = resf->FindEntry("savepic.png");
|
||||
if (pic >= 0)
|
||||
{
|
||||
FileReader picreader;
|
||||
|
||||
picreader.OpenMemoryArray([=](std::vector<uint8_t> &array)
|
||||
{
|
||||
auto cache = pic->Lock();
|
||||
array.resize(pic->LumpSize);
|
||||
memcpy(&array[0], cache, pic->LumpSize);
|
||||
pic->Unlock();
|
||||
return true;
|
||||
});
|
||||
FileReader picreader = resf->GetEntryReader(pic);
|
||||
PNGHandle *png = M_VerifyPNG(picreader);
|
||||
if (png != nullptr)
|
||||
{
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
TArray<FString> savedModelFiles;
|
||||
TDeletingArray<FModel*> Models;
|
||||
TArray<FSpriteModelFrame> SpriteModelFrames;
|
||||
TMap<void*, FSpriteModelFrame> BaseSpriteModelFrames;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include "matrix.h"
|
||||
#include "palettecontainer.h"
|
||||
#include "TRS.h"
|
||||
#include "tarray.h"
|
||||
#include "name.h"
|
||||
|
||||
class DBoneComponents;
|
||||
class FModelRenderer;
|
||||
|
@ -19,6 +21,7 @@ void FlushModels();
|
|||
extern TArray<FString> savedModelFiles;
|
||||
extern TDeletingArray<FModel*> Models;
|
||||
extern TArray<FSpriteModelFrame> SpriteModelFrames;
|
||||
extern TMap<void*, FSpriteModelFrame> BaseSpriteModelFrames;
|
||||
|
||||
#define MD3_MAX_SURFACES 32
|
||||
#define MIN_MODELS 4
|
||||
|
@ -72,13 +75,20 @@ public:
|
|||
virtual ~FModel();
|
||||
|
||||
virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length) = 0;
|
||||
|
||||
virtual int FindFrame(const char * name, bool nodefault = false) = 0;
|
||||
|
||||
// [RL0] these are used for decoupled iqm animations
|
||||
virtual int FindFirstFrame(FName name) { return FErr_NotFound; }
|
||||
virtual int FindLastFrame(FName name) { return FErr_NotFound; }
|
||||
virtual double FindFramerate(FName name) { return FErr_NotFound; }
|
||||
|
||||
virtual void RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frame, int frame2, double inter, FTranslationID translation, const FTextureID* surfaceskinids, const TArray<VSMatrix>& boneData, int boneStartPosition) = 0;
|
||||
virtual void BuildVertexBuffer(FModelRenderer *renderer) = 0;
|
||||
virtual void AddSkins(uint8_t *hitlist, const FTextureID* surfaceskinids) = 0;
|
||||
virtual float getAspectFactor(float vscale) { return 1.f; }
|
||||
virtual const TArray<TRS>* AttachAnimationData() { return nullptr; };
|
||||
virtual const TArray<VSMatrix> CalculateBones(int frame1, int frame2, double inter, const TArray<TRS>* animationData, DBoneComponents* bones, int index) { return {}; };
|
||||
virtual const TArray<VSMatrix> CalculateBones(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const TArray<TRS>* animationData, DBoneComponents* bones, int index) { return {}; };
|
||||
|
||||
void SetVertexBuffer(int type, IModelVertexBuffer *buffer) { mVBuf[type] = buffer; }
|
||||
IModelVertexBuffer *GetVertexBuffer(int type) const { return mVBuf[type]; }
|
||||
|
@ -86,7 +96,8 @@ public:
|
|||
|
||||
bool hasSurfaces = false;
|
||||
FString mFileName;
|
||||
|
||||
|
||||
FSpriteModelFrame *baseFrame;
|
||||
private:
|
||||
IModelVertexBuffer *mVBuf[NumModelRendererTypes];
|
||||
};
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "matrix.h"
|
||||
#include "common/rendering/i_modelvertexbuffer.h"
|
||||
#include "m_swap.h"
|
||||
#include "name.h"
|
||||
|
||||
class DBoneComponents;
|
||||
|
||||
|
@ -112,11 +113,14 @@ public:
|
|||
|
||||
bool Load(const char* fn, int lumpnum, const char* buffer, int length) override;
|
||||
int FindFrame(const char* name, bool nodefault) override;
|
||||
int FindFirstFrame(FName name) override;
|
||||
int FindLastFrame(FName name) override;
|
||||
double FindFramerate(FName name) override;
|
||||
void RenderFrame(FModelRenderer* renderer, FGameTexture* skin, int frame, int frame2, double inter, FTranslationID translation, const FTextureID* surfaceskinids, const TArray<VSMatrix>& boneData, int boneStartPosition) override;
|
||||
void BuildVertexBuffer(FModelRenderer* renderer) override;
|
||||
void AddSkins(uint8_t* hitlist, const FTextureID* surfaceskinids) override;
|
||||
const TArray<TRS>* AttachAnimationData() override;
|
||||
const TArray<VSMatrix> CalculateBones(int frame1, int frame2, double inter, const TArray<TRS>* animationData, DBoneComponents* bones, int index) override;
|
||||
const TArray<VSMatrix> CalculateBones(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const TArray<TRS>* animationData, DBoneComponents* bones, int index) override;
|
||||
|
||||
private:
|
||||
void LoadGeometry();
|
||||
|
@ -129,6 +133,9 @@ private:
|
|||
void LoadBlendWeights(IQMFileReader& reader, const IQMVertexArray& vertexArray);
|
||||
|
||||
int mLumpNum = -1;
|
||||
|
||||
TMap<FName, int> NamedAnimations;
|
||||
|
||||
TArray<IQMMesh> Meshes;
|
||||
TArray<IQMTriangle> Triangles;
|
||||
TArray<IQMAdjacency> Adjacency;
|
||||
|
|
|
@ -137,9 +137,12 @@ bool IQMModel::Load(const char* path, int lumpnum, const char* buffer, int lengt
|
|||
}
|
||||
|
||||
reader.SeekTo(ofs_anims);
|
||||
for (IQMAnim& anim : Anims)
|
||||
for(int i = 0; i < Anims.Size(); i++)
|
||||
{
|
||||
IQMAnim& anim = Anims[i];
|
||||
anim.Name = reader.ReadName(text);
|
||||
NamedAnimations.Insert(anim.Name, i);
|
||||
|
||||
anim.FirstFrame = reader.ReadUInt32();
|
||||
anim.NumFrames = reader.ReadUInt32();
|
||||
anim.Framerate = reader.ReadFloat();
|
||||
|
@ -445,6 +448,27 @@ int IQMModel::FindFrame(const char* name, bool nodefault)
|
|||
return FErr_NotFound;
|
||||
}
|
||||
|
||||
int IQMModel::FindFirstFrame(FName name)
|
||||
{
|
||||
int * nam = NamedAnimations.CheckKey(name);
|
||||
if(nam) return Anims[*nam].FirstFrame;
|
||||
return FErr_NotFound;
|
||||
}
|
||||
|
||||
int IQMModel::FindLastFrame(FName name)
|
||||
{
|
||||
int * nam = NamedAnimations.CheckKey(name);
|
||||
if(nam) return Anims[*nam].FirstFrame + Anims[*nam].NumFrames;
|
||||
return FErr_NotFound;
|
||||
}
|
||||
|
||||
double IQMModel::FindFramerate(FName name)
|
||||
{
|
||||
int * nam = NamedAnimations.CheckKey(name);
|
||||
if(nam) return Anims[*nam].Framerate;
|
||||
return FErr_NotFound;
|
||||
}
|
||||
|
||||
void IQMModel::RenderFrame(FModelRenderer* renderer, FGameTexture* skin, int frame1, int frame2, double inter, FTranslationID translation, const FTextureID* surfaceskinids, const TArray<VSMatrix>& boneData, int boneStartPosition)
|
||||
{
|
||||
renderer->SetupFrame(this, 0, 0, NumVertices, boneData, boneStartPosition);
|
||||
|
@ -517,7 +541,26 @@ const TArray<TRS>* IQMModel::AttachAnimationData()
|
|||
return &TRSData;
|
||||
}
|
||||
|
||||
const TArray<VSMatrix> IQMModel::CalculateBones(int frame1, int frame2, double inter, const TArray<TRS>* animationData, DBoneComponents* boneComponentData, int index)
|
||||
static TRS InterpolateBone(const TRS &from, const TRS &to, float t, float invt)
|
||||
{
|
||||
TRS bone;
|
||||
|
||||
bone.translation = from.translation * invt + to.translation * t;
|
||||
bone.rotation = from.rotation * invt;
|
||||
|
||||
if ((bone.rotation | to.rotation * t) < 0)
|
||||
{
|
||||
bone.rotation.X *= -1; bone.rotation.Y *= -1; bone.rotation.Z *= -1; bone.rotation.W *= -1;
|
||||
}
|
||||
|
||||
bone.rotation += to.rotation * t;
|
||||
bone.rotation.MakeUnit();
|
||||
bone.scaling = from.scaling * invt + to.scaling * t;
|
||||
|
||||
return bone;
|
||||
}
|
||||
|
||||
const TArray<VSMatrix> IQMModel::CalculateBones(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const TArray<TRS>* animationData, DBoneComponents* boneComponentData, int index)
|
||||
{
|
||||
const TArray<TRS>& animationFrames = animationData ? *animationData : TRSData;
|
||||
if (Joints.Size() > 0)
|
||||
|
@ -534,8 +577,13 @@ const TArray<VSMatrix> IQMModel::CalculateBones(int frame1, int frame2, double i
|
|||
|
||||
int offset1 = frame1 * numbones;
|
||||
int offset2 = frame2 * numbones;
|
||||
float t = (float)inter;
|
||||
float invt = 1.0f - t;
|
||||
|
||||
int offset1_1 = frame1_prev * numbones;
|
||||
int offset2_1 = frame2_prev * numbones;
|
||||
|
||||
float invt = 1.0f - inter;
|
||||
float invt1 = 1.0f - inter1_prev;
|
||||
float invt2 = 1.0f - inter2_prev;
|
||||
|
||||
float swapYZ[16] = { 0.0f };
|
||||
swapYZ[0 + 0 * 4] = 1.0f;
|
||||
|
@ -547,19 +595,26 @@ const TArray<VSMatrix> IQMModel::CalculateBones(int frame1, int frame2, double i
|
|||
TArray<bool> modifiedBone(numbones, true);
|
||||
for (int i = 0; i < numbones; i++)
|
||||
{
|
||||
TRS bone;
|
||||
TRS from = animationFrames[offset1 + i];
|
||||
TRS to = animationFrames[offset2 + i];
|
||||
TRS prev;
|
||||
|
||||
bone.translation = from.translation * invt + to.translation * t;
|
||||
bone.rotation = from.rotation * invt;
|
||||
if ((bone.rotation | to.rotation * t) < 0)
|
||||
if(frame1 >= 0 && (frame1_prev >= 0 || inter1_prev < 0))
|
||||
{
|
||||
bone.rotation.X *= -1; bone.rotation.Y *= -1; bone.rotation.Z *= -1; bone.rotation.W *= -1;
|
||||
prev = inter1_prev < 0 ? animationFrames[offset1 + i] : InterpolateBone(animationFrames[offset1_1 + i], animationFrames[offset1 + i], inter1_prev, invt1);
|
||||
}
|
||||
|
||||
TRS next;
|
||||
|
||||
if(frame2 >= 0 && (frame2_prev >= 0 || inter2_prev < 0))
|
||||
{
|
||||
next = inter2_prev < 0 ? animationFrames[offset2 + i] : InterpolateBone(animationFrames[offset2_1 + i], animationFrames[offset2 + i], inter2_prev, invt2);
|
||||
}
|
||||
|
||||
TRS bone;
|
||||
|
||||
if(frame1 >= 0 || inter < 0)
|
||||
{
|
||||
bone = inter < 0 ? animationFrames[offset1 + i] : InterpolateBone(prev, next , inter, invt);
|
||||
}
|
||||
bone.rotation += to.rotation * t;
|
||||
bone.rotation.MakeUnit();
|
||||
bone.scaling = from.scaling * invt + to.scaling * t;
|
||||
|
||||
if (Joints[i].Parent >= 0 && modifiedBone[Joints[i].Parent])
|
||||
{
|
||||
|
|
|
@ -179,8 +179,6 @@ public: \
|
|||
|
||||
#include "dobjgc.h"
|
||||
|
||||
class AActor;
|
||||
|
||||
class DObject
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -210,8 +210,8 @@ class TObjPtr
|
|||
{
|
||||
union
|
||||
{
|
||||
T pp;
|
||||
DObject *o;
|
||||
mutable T pp;
|
||||
mutable DObject *o;
|
||||
};
|
||||
public:
|
||||
|
||||
|
@ -273,16 +273,22 @@ public:
|
|||
{
|
||||
return GC::ReadBarrier(pp);
|
||||
}
|
||||
constexpr bool operator!=(T u) noexcept
|
||||
|
||||
constexpr const T operator->() const noexcept
|
||||
{
|
||||
return GC::ReadBarrier(pp);
|
||||
}
|
||||
|
||||
constexpr bool operator!=(T u) const noexcept
|
||||
{
|
||||
return GC::ReadBarrier(o) != u;
|
||||
}
|
||||
constexpr bool operator==(T u) noexcept
|
||||
constexpr bool operator==(T u) const noexcept
|
||||
{
|
||||
return GC::ReadBarrier(o) == u;
|
||||
}
|
||||
|
||||
constexpr bool operator==(TObjPtr<T> u) noexcept
|
||||
constexpr bool operator==(TObjPtr<T> u) const noexcept
|
||||
{
|
||||
return ForceGet() == u.ForceGet();
|
||||
}
|
||||
|
|
|
@ -218,20 +218,21 @@ void RedrawProgressBar(int CurPos, int MaxPos)
|
|||
CleanProgressBar();
|
||||
struct winsize sizeOfWindow;
|
||||
ioctl(STDOUT_FILENO, TIOCGWINSZ, &sizeOfWindow);
|
||||
int windowColClamped = std::min((int)sizeOfWindow.ws_col, 512);
|
||||
double progVal = std::clamp((double)CurPos / (double)MaxPos,0.0,1.0);
|
||||
int curProgVal = std::clamp(int(sizeOfWindow.ws_col * progVal),0,(int)sizeOfWindow.ws_col);
|
||||
int curProgVal = std::clamp(int(windowColClamped * progVal),0,windowColClamped);
|
||||
|
||||
char progressBuffer[512];
|
||||
memset(progressBuffer,'.',512);
|
||||
progressBuffer[sizeOfWindow.ws_col - 1] = 0;
|
||||
progressBuffer[windowColClamped - 1] = 0;
|
||||
int lengthOfStr = 0;
|
||||
|
||||
while (curProgVal-- > 0)
|
||||
{
|
||||
progressBuffer[lengthOfStr++] = '=';
|
||||
if (lengthOfStr >= sizeOfWindow.ws_col - 1) break;
|
||||
if (lengthOfStr >= windowColClamped - 1) break;
|
||||
}
|
||||
fprintf(stdout, "\0337\033[%d;%dH\033[2K[%s\033[%d;%dH]\0338", sizeOfWindow.ws_row, 0, progressBuffer, sizeOfWindow.ws_row, sizeOfWindow.ws_col);
|
||||
fprintf(stdout, "\0337\033[%d;%dH\033[2K[%s\033[%d;%dH]\0338", sizeOfWindow.ws_row, 0, progressBuffer, sizeOfWindow.ws_row, windowColClamped);
|
||||
fflush(stdout);
|
||||
ProgressBarCurPos = CurPos;
|
||||
ProgressBarMaxPos = MaxPos;
|
||||
|
|
|
@ -850,37 +850,6 @@ FString I_GetLongPathName(const FString &shortpath)
|
|||
return longpath;
|
||||
}
|
||||
|
||||
#ifdef _USING_V110_SDK71_
|
||||
//==========================================================================
|
||||
//
|
||||
// _stat64i32
|
||||
//
|
||||
// Work around an issue where stat() function doesn't work
|
||||
// with Windows XP compatible toolset.
|
||||
// It uses GetFileInformationByHandleEx() which requires Windows Vista.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int _wstat64i32(const wchar_t *path, struct _stat64i32 *buffer)
|
||||
{
|
||||
WIN32_FILE_ATTRIBUTE_DATA data;
|
||||
if(!GetFileAttributesExW(path, GetFileExInfoStandard, &data))
|
||||
return -1;
|
||||
|
||||
buffer->st_ino = 0;
|
||||
buffer->st_mode = ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? S_IFDIR : S_IFREG)|
|
||||
((data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? S_IREAD : S_IREAD|S_IWRITE);
|
||||
buffer->st_dev = buffer->st_rdev = 0;
|
||||
buffer->st_nlink = 1;
|
||||
buffer->st_uid = 0;
|
||||
buffer->st_gid = 0;
|
||||
buffer->st_size = data.nFileSizeLow;
|
||||
buffer->st_atime = (*(uint64_t*)&data.ftLastAccessTime) / 10000000 - 11644473600LL;
|
||||
buffer->st_mtime = (*(uint64_t*)&data.ftLastWriteTime) / 10000000 - 11644473600LL;
|
||||
buffer->st_ctime = (*(uint64_t*)&data.ftCreationTime) / 10000000 - 11644473600LL;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct NumaNode
|
||||
{
|
||||
|
|
|
@ -104,6 +104,7 @@ CUSTOM_CVAR(Int, vid_preferbackend, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_N
|
|||
#ifdef HAVE_GLES2
|
||||
case 3:
|
||||
case 2:
|
||||
self = 2;
|
||||
Printf("Selecting OpenGLES 2.0 backend...\n");
|
||||
break;
|
||||
#endif
|
||||
|
@ -122,7 +123,7 @@ CUSTOM_CVAR(Int, vid_preferbackend, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_N
|
|||
int V_GetBackend()
|
||||
{
|
||||
int v = vid_preferbackend;
|
||||
if (v == 3) v = 2;
|
||||
if (v == 3) vid_preferbackend = v = 2;
|
||||
else if (v < 0 || v > 3) v = 0;
|
||||
return v;
|
||||
}
|
||||
|
|
|
@ -2728,7 +2728,7 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx)
|
|||
{
|
||||
FArgumentList args;
|
||||
args.Push(Right);
|
||||
auto call = new FxMemberFunctionCall(Base, NAME_Copy, args, ScriptPosition);
|
||||
auto call = new FxMemberFunctionCall(Base, NAME_Copy, std::move(args), ScriptPosition);
|
||||
Right = Base = nullptr;
|
||||
delete this;
|
||||
return call->Resolve(ctx);
|
||||
|
@ -2756,7 +2756,7 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx)
|
|||
{
|
||||
FArgumentList args;
|
||||
args.Push(Right);
|
||||
auto call = new FxMemberFunctionCall(Base, NAME_Copy, args, ScriptPosition);
|
||||
auto call = new FxMemberFunctionCall(Base, NAME_Copy, std::move(args), ScriptPosition);
|
||||
Right = Base = nullptr;
|
||||
delete this;
|
||||
return call->Resolve(ctx);
|
||||
|
@ -3826,6 +3826,16 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx)
|
|||
delete left;
|
||||
left = x;
|
||||
}
|
||||
else if (left->IsNumeric() && right->ValueType == TypeTranslationID && ctx.Version < MakeVersion(4, 12))
|
||||
{
|
||||
right = new FxTypeCast(right, TypeSInt32, true);
|
||||
SAFE_RESOLVE(right, ctx);
|
||||
}
|
||||
else if (right->IsNumeric() && left->ValueType == TypeTranslationID && ctx.Version < MakeVersion(4, 12))
|
||||
{
|
||||
left = new FxTypeCast(left, TypeSInt32, true);
|
||||
SAFE_RESOLVE(left, ctx);
|
||||
}
|
||||
|
||||
if (left->ValueType == TypeString || right->ValueType == TypeString)
|
||||
{
|
||||
|
@ -4118,6 +4128,17 @@ FxExpression *FxCompareEq::Resolve(FCompileContext& ctx)
|
|||
delete left;
|
||||
left = x;
|
||||
}
|
||||
else if (left->IsNumeric() && right->ValueType == TypeTranslationID && ctx.Version < MakeVersion(4, 12))
|
||||
{
|
||||
right = new FxIntCast(right, true, true);
|
||||
SAFE_RESOLVE(right, ctx);
|
||||
}
|
||||
else if (right->IsNumeric() && left->ValueType == TypeTranslationID && ctx.Version < MakeVersion(4, 12))
|
||||
{
|
||||
left = new FxTypeCast(left, TypeSInt32, true);
|
||||
SAFE_RESOLVE(left, ctx);
|
||||
}
|
||||
|
||||
// Special cases: Compare strings and names with names, sounds, colors, state labels and class types.
|
||||
// These are all types a string can be implicitly cast into, so for convenience, so they should when doing a comparison.
|
||||
if ((left->ValueType == TypeString || left->ValueType == TypeName) &&
|
||||
|
@ -8181,7 +8202,7 @@ static bool CheckFunctionCompatiblity(FScriptPosition &ScriptPosition, PFunction
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
FxFunctionCall::FxFunctionCall(FName methodname, FName rngname, FArgumentList &args, const FScriptPosition &pos)
|
||||
FxFunctionCall::FxFunctionCall(FName methodname, FName rngname, FArgumentList &&args, const FScriptPosition &pos)
|
||||
: FxExpression(EFX_FunctionCall, pos)
|
||||
{
|
||||
MethodName = methodname;
|
||||
|
@ -8608,7 +8629,7 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
FxMemberFunctionCall::FxMemberFunctionCall(FxExpression *self, FName methodname, FArgumentList &args, const FScriptPosition &pos)
|
||||
FxMemberFunctionCall::FxMemberFunctionCall(FxExpression *self, FName methodname, FArgumentList &&args, const FScriptPosition &pos)
|
||||
: FxExpression(EFX_MemberFunctionCall, pos)
|
||||
{
|
||||
Self = self;
|
||||
|
@ -9153,7 +9174,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
|||
if (a->IsMap())
|
||||
{
|
||||
// Copy and Move must turn their parameter into a pointer to the backing struct type.
|
||||
auto o = static_cast<PMapIterator*>(a->ValueType);
|
||||
auto o = static_cast<PMap*>(a->ValueType);
|
||||
auto backingtype = o->BackingType;
|
||||
if (mapKeyType != o->KeyType || mapValueType != o->ValueType)
|
||||
{
|
||||
|
@ -11361,12 +11382,14 @@ ExpEmit FxForLoop::Emit(VMFunctionBuilder *build)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
FxForEachLoop::FxForEachLoop(FName vn, FxExpression* arrayvar, FxExpression* arrayvar2, FxExpression* code, const FScriptPosition& pos)
|
||||
: FxLoopStatement(EFX_ForEachLoop, pos), loopVarName(vn), Array(arrayvar), Array2(arrayvar2), Code(code)
|
||||
FxForEachLoop::FxForEachLoop(FName vn, FxExpression* arrayvar, FxExpression* arrayvar2, FxExpression* arrayvar3, FxExpression* arrayvar4, FxExpression* code, const FScriptPosition& pos)
|
||||
: FxLoopStatement(EFX_ForEachLoop, pos), loopVarName(vn), Array(arrayvar), Array2(arrayvar2), Array3(arrayvar3), Array4(arrayvar4), Code(code)
|
||||
{
|
||||
ValueType = TypeVoid;
|
||||
if (Array != nullptr) Array->NeedResult = false;
|
||||
if (Array2 != nullptr) Array2->NeedResult = false;
|
||||
if (Array3 != nullptr) Array3->NeedResult = false;
|
||||
if (Array4 != nullptr) Array4->NeedResult = false;
|
||||
if (Code != nullptr) Code->NeedResult = false;
|
||||
}
|
||||
|
||||
|
@ -11374,57 +11397,347 @@ FxForEachLoop::~FxForEachLoop()
|
|||
{
|
||||
SAFE_DELETE(Array);
|
||||
SAFE_DELETE(Array2);
|
||||
SAFE_DELETE(Array3);
|
||||
SAFE_DELETE(Array4);
|
||||
SAFE_DELETE(Code);
|
||||
}
|
||||
|
||||
extern bool IsGameSpecificForEachLoop(FxForEachLoop *);
|
||||
extern FxExpression * ResolveGameSpecificForEachLoop(FxForEachLoop *);
|
||||
|
||||
FxExpression* FxForEachLoop::DoResolve(FCompileContext& ctx)
|
||||
{
|
||||
CHECKRESOLVED();
|
||||
SAFE_RESOLVE(Array, ctx);
|
||||
SAFE_RESOLVE(Array2, ctx);
|
||||
SAFE_RESOLVE(Array3, ctx);
|
||||
SAFE_RESOLVE(Array4, ctx);
|
||||
|
||||
// Instead of writing a new code generator for this, convert this into
|
||||
//
|
||||
// int @size = array.Size();
|
||||
// for(int @i = 0; @i < @size; @i++)
|
||||
// {
|
||||
// let var = array[i];
|
||||
// body
|
||||
// }
|
||||
// and let the existing 'for' loop code sort out the rest.
|
||||
|
||||
FName sizevar = "@size";
|
||||
FName itvar = "@i";
|
||||
FArgumentList al;
|
||||
auto block = new FxCompoundStatement(ScriptPosition);
|
||||
auto arraysize = new FxMemberFunctionCall(Array, NAME_Size, al, ScriptPosition);
|
||||
auto size = new FxLocalVariableDeclaration(TypeSInt32, sizevar, arraysize, 0, ScriptPosition);
|
||||
auto it = new FxLocalVariableDeclaration(TypeSInt32, itvar, new FxConstant(0, ScriptPosition), 0, ScriptPosition);
|
||||
block->Add(size);
|
||||
block->Add(it);
|
||||
if(Array->ValueType->isMap() || Array->ValueType->isMapIterator())
|
||||
{
|
||||
auto mapLoop = new FxTwoArgForEachLoop(NAME_None, loopVarName, Array, Array2, Array3, Array4, Code, ScriptPosition);
|
||||
Array = Array2 = Array3 = Array4 = Code = nullptr;
|
||||
delete this;
|
||||
return mapLoop->Resolve(ctx);
|
||||
}
|
||||
else if(IsGameSpecificForEachLoop(this))
|
||||
{
|
||||
return ResolveGameSpecificForEachLoop(this)->Resolve(ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Instead of writing a new code generator for this, convert this into
|
||||
//
|
||||
// int @size = array.Size();
|
||||
// for(int @i = 0; @i < @size; @i++)
|
||||
// {
|
||||
// let var = array[i];
|
||||
// body
|
||||
// }
|
||||
// and let the existing 'for' loop code sort out the rest.
|
||||
|
||||
auto cit = new FxLocalVariable(it, ScriptPosition);
|
||||
auto csiz = new FxLocalVariable(size, ScriptPosition);
|
||||
auto comp = new FxCompareRel('<', cit, csiz); // new FxIdentifier(itvar, ScriptPosition), new FxIdentifier(sizevar, ScriptPosition));
|
||||
FName sizevar = "@size";
|
||||
FName itvar = "@i";
|
||||
|
||||
auto iit = new FxLocalVariable(it, ScriptPosition);
|
||||
auto bump = new FxPreIncrDecr(iit, TK_Incr);
|
||||
auto block = new FxCompoundStatement(ScriptPosition);
|
||||
auto arraysize = new FxMemberFunctionCall(Array, NAME_Size, {}, ScriptPosition);
|
||||
auto size = new FxLocalVariableDeclaration(TypeSInt32, sizevar, arraysize, 0, ScriptPosition);
|
||||
auto it = new FxLocalVariableDeclaration(TypeSInt32, itvar, new FxConstant(0, ScriptPosition), 0, ScriptPosition);
|
||||
block->Add(size);
|
||||
block->Add(it);
|
||||
|
||||
auto ait = new FxLocalVariable(it, ScriptPosition);
|
||||
auto access = new FxArrayElement(Array2, ait, true); // Note: Array must be a separate copy because these nodes cannot share the same element.
|
||||
auto cit = new FxLocalVariable(it, ScriptPosition);
|
||||
auto csiz = new FxLocalVariable(size, ScriptPosition);
|
||||
auto comp = new FxCompareRel('<', cit, csiz); // new FxIdentifier(itvar, ScriptPosition), new FxIdentifier(sizevar, ScriptPosition));
|
||||
|
||||
auto assign = new FxLocalVariableDeclaration(TypeAuto, loopVarName, access, 0, ScriptPosition);
|
||||
auto body = new FxCompoundStatement(ScriptPosition);
|
||||
body->Add(assign);
|
||||
body->Add(Code);
|
||||
auto forloop = new FxForLoop(nullptr, comp, bump, body, ScriptPosition);
|
||||
block->Add(forloop);
|
||||
Array2 = Array = nullptr;
|
||||
Code = nullptr;
|
||||
delete this;
|
||||
return block->Resolve(ctx);
|
||||
auto iit = new FxLocalVariable(it, ScriptPosition);
|
||||
auto bump = new FxPreIncrDecr(iit, TK_Incr);
|
||||
|
||||
auto ait = new FxLocalVariable(it, ScriptPosition);
|
||||
auto access = new FxArrayElement(Array2, ait, true); // Note: Array must be a separate copy because these nodes cannot share the same element.
|
||||
|
||||
auto assign = new FxLocalVariableDeclaration(TypeAuto, loopVarName, access, 0, ScriptPosition);
|
||||
auto body = new FxCompoundStatement(ScriptPosition);
|
||||
body->Add(assign);
|
||||
body->Add(Code);
|
||||
auto forloop = new FxForLoop(nullptr, comp, bump, body, ScriptPosition);
|
||||
block->Add(forloop);
|
||||
Array2 = Array = nullptr;
|
||||
Code = nullptr;
|
||||
delete this;
|
||||
return block->Resolve(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxMapForEachLoop
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxTwoArgForEachLoop::FxTwoArgForEachLoop(FName kv, FName vv, FxExpression* mapexpr, FxExpression* mapexpr2, FxExpression* mapexpr3, FxExpression* mapexpr4, FxExpression* code, const FScriptPosition& pos)
|
||||
: FxExpression(EFX_TwoArgForEachLoop,pos), keyVarName(kv), valueVarName(vv), MapExpr(mapexpr), MapExpr2(mapexpr2), MapExpr3(mapexpr3), MapExpr4(mapexpr4), Code(code)
|
||||
{
|
||||
ValueType = TypeVoid;
|
||||
if (MapExpr != nullptr) MapExpr->NeedResult = false;
|
||||
if (MapExpr2 != nullptr) MapExpr2->NeedResult = false;
|
||||
if (MapExpr3 != nullptr) MapExpr3->NeedResult = false;
|
||||
if (MapExpr4 != nullptr) MapExpr4->NeedResult = false;
|
||||
if (Code != nullptr) Code->NeedResult = false;
|
||||
}
|
||||
|
||||
FxTwoArgForEachLoop::~FxTwoArgForEachLoop()
|
||||
{
|
||||
SAFE_DELETE(MapExpr);
|
||||
SAFE_DELETE(MapExpr2);
|
||||
SAFE_DELETE(MapExpr3);
|
||||
SAFE_DELETE(MapExpr4);
|
||||
SAFE_DELETE(Code);
|
||||
}
|
||||
|
||||
extern bool HasGameSpecificTwoArgForEachLoopTypeNames();
|
||||
extern const char * GetGameSpecificTwoArgForEachLoopTypeNames();
|
||||
extern bool IsGameSpecificTwoArgForEachLoop(FxTwoArgForEachLoop *);
|
||||
extern FxExpression * ResolveGameSpecificTwoArgForEachLoop(FxTwoArgForEachLoop *);
|
||||
|
||||
FxExpression *FxTwoArgForEachLoop::Resolve(FCompileContext &ctx)
|
||||
{
|
||||
CHECKRESOLVED();
|
||||
SAFE_RESOLVE(MapExpr, ctx);
|
||||
SAFE_RESOLVE(MapExpr2, ctx);
|
||||
SAFE_RESOLVE(MapExpr3, ctx);
|
||||
SAFE_RESOLVE(MapExpr4, ctx);
|
||||
|
||||
bool is_iterator = false;
|
||||
|
||||
if(IsGameSpecificTwoArgForEachLoop(this))
|
||||
{
|
||||
return ResolveGameSpecificTwoArgForEachLoop(this)->Resolve(ctx);
|
||||
}
|
||||
else if(!(MapExpr->ValueType->isMap() || (is_iterator = MapExpr->ValueType->isMapIterator())))
|
||||
{
|
||||
if(HasGameSpecificTwoArgForEachLoopTypeNames())
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "foreach( k, v : m ) - 'm' must be %s a map, or a map iterator, but is a %s", GetGameSpecificTwoArgForEachLoopTypeNames(), MapExpr->ValueType->DescriptiveName());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "foreach( k, v : m ) - 'm' must be a map or a map iterator, but is a %s", MapExpr->ValueType->DescriptiveName());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else if(valueVarName == NAME_None)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "missing value for foreach( k, v : m )");
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
auto block = new FxCompoundStatement(ScriptPosition);
|
||||
|
||||
auto valType = is_iterator ? static_cast<PMapIterator*>(MapExpr->ValueType)->ValueType : static_cast<PMap*>(MapExpr->ValueType)->ValueType;
|
||||
auto keyType = is_iterator ? static_cast<PMapIterator*>(MapExpr->ValueType)->KeyType : static_cast<PMap*>(MapExpr->ValueType)->KeyType;
|
||||
|
||||
auto v = new FxLocalVariableDeclaration(valType, valueVarName, nullptr, 0, ScriptPosition);
|
||||
block->Add(v);
|
||||
|
||||
if(keyVarName != NAME_None)
|
||||
{
|
||||
auto k = new FxLocalVariableDeclaration(keyType, keyVarName, nullptr, 0, ScriptPosition);
|
||||
block->Add(k);
|
||||
}
|
||||
|
||||
|
||||
if(MapExpr->ValueType->isMapIterator())
|
||||
{
|
||||
/*
|
||||
{
|
||||
KeyType k;
|
||||
ValueType v;
|
||||
if(it.ReInit()) while(it.Next())
|
||||
{
|
||||
k = it.GetKey();
|
||||
v = it.GetValue();
|
||||
body
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
auto inner_block = new FxCompoundStatement(ScriptPosition);
|
||||
|
||||
if(keyVarName != NAME_None)
|
||||
{
|
||||
inner_block->Add(new FxAssign(new FxIdentifier(keyVarName, ScriptPosition), new FxMemberFunctionCall(MapExpr, "GetKey", {}, ScriptPosition), true));
|
||||
}
|
||||
|
||||
inner_block->Add(new FxAssign(new FxIdentifier(valueVarName, ScriptPosition), new FxMemberFunctionCall(MapExpr2, "GetValue", {}, ScriptPosition), true));
|
||||
inner_block->Add(Code);
|
||||
|
||||
auto reInit = new FxMemberFunctionCall(MapExpr3, "ReInit", {}, ScriptPosition);
|
||||
block->Add(new FxIfStatement(reInit, new FxWhileLoop(new FxMemberFunctionCall(MapExpr4, "Next", {}, ScriptPosition), inner_block, ScriptPosition), nullptr, ScriptPosition));
|
||||
|
||||
MapExpr = MapExpr2 = MapExpr3 = MapExpr4 = Code = nullptr;
|
||||
delete this;
|
||||
return block->Resolve(ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
{
|
||||
KeyType k;
|
||||
ValueType v;
|
||||
MapIterator<KeyType, ValueType> @it;
|
||||
@it.Init(map);
|
||||
while(@it.Next())
|
||||
{
|
||||
k = @it.GetKey();
|
||||
v = @it.GetValue();
|
||||
body
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
PType * itType = NewMapIterator(keyType, valType);
|
||||
auto it = new FxLocalVariableDeclaration(itType, "@it", nullptr, 0, ScriptPosition);
|
||||
block->Add(it);
|
||||
|
||||
FArgumentList al_map;
|
||||
al_map.Push(MapExpr);
|
||||
|
||||
block->Add(new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "Init", std::move(al_map), ScriptPosition));
|
||||
|
||||
auto inner_block = new FxCompoundStatement(ScriptPosition);
|
||||
|
||||
if(keyVarName != NAME_None)
|
||||
{
|
||||
inner_block->Add(new FxAssign(new FxIdentifier(keyVarName, ScriptPosition), new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "GetKey", {}, ScriptPosition), true));
|
||||
}
|
||||
inner_block->Add(new FxAssign(new FxIdentifier(valueVarName, ScriptPosition), new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "GetValue", {}, ScriptPosition), true));
|
||||
inner_block->Add(Code);
|
||||
|
||||
block->Add(new FxWhileLoop(new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "Next", {}, ScriptPosition), inner_block, ScriptPosition));
|
||||
|
||||
delete MapExpr2;
|
||||
delete MapExpr3;
|
||||
delete MapExpr4;
|
||||
MapExpr = MapExpr2 = MapExpr3 = MapExpr4 = Code = nullptr;
|
||||
delete this;
|
||||
return block->Resolve(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxThreeArgForEachLoop
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxThreeArgForEachLoop::FxThreeArgForEachLoop(FName vv, FName pv, FName fv, FxExpression* blockiteartorexpr, FxExpression* code, const FScriptPosition& pos)
|
||||
: FxExpression(EFX_ThreeArgForEachLoop, pos), varVarName(vv), posVarName(pv), flagsVarName(fv), BlockIteratorExpr(blockiteartorexpr), Code(code)
|
||||
{
|
||||
ValueType = TypeVoid;
|
||||
if (BlockIteratorExpr != nullptr) BlockIteratorExpr->NeedResult = false;
|
||||
if (Code != nullptr) Code->NeedResult = false;
|
||||
}
|
||||
|
||||
FxThreeArgForEachLoop::~FxThreeArgForEachLoop()
|
||||
{
|
||||
SAFE_DELETE(BlockIteratorExpr);
|
||||
SAFE_DELETE(Code);
|
||||
}
|
||||
|
||||
extern bool HasGameSpecificThreeArgForEachLoopTypeNames();
|
||||
extern const char * GetGameSpecificThreeArgForEachLoopTypeNames();
|
||||
extern bool IsGameSpecificThreeArgForEachLoop(FxThreeArgForEachLoop *);
|
||||
extern FxExpression * ResolveGameSpecificThreeArgForEachLoop(FxThreeArgForEachLoop *);
|
||||
|
||||
FxExpression *FxThreeArgForEachLoop::Resolve(FCompileContext &ctx)
|
||||
{
|
||||
CHECKRESOLVED();
|
||||
SAFE_RESOLVE(BlockIteratorExpr, ctx);
|
||||
|
||||
|
||||
if(IsGameSpecificThreeArgForEachLoop(this))
|
||||
{
|
||||
return ResolveGameSpecificThreeArgForEachLoop(this)->Resolve(ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
//put any non-game-specific typed for-each loops here
|
||||
}
|
||||
|
||||
if(HasGameSpecificThreeArgForEachLoopTypeNames())
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "foreach( a, b, c : it ) - 'it' must be % but is a %s", GetGameSpecificThreeArgForEachLoopTypeNames(), BlockIteratorExpr->ValueType->DescriptiveName());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "foreach( a, b, c : it ) - three-arg foreach loops not supported");
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxCastForEachLoop
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxTypedForEachLoop::FxTypedForEachLoop(FName cv, FName vv, FxExpression* castiteartorexpr, FxExpression* code, const FScriptPosition& pos)
|
||||
: FxExpression(EFX_TypedForEachLoop, pos), className(cv), varName(vv), Expr(castiteartorexpr), Code(code)
|
||||
{
|
||||
ValueType = TypeVoid;
|
||||
if (Expr != nullptr) Expr->NeedResult = false;
|
||||
if (Code != nullptr) Code->NeedResult = false;
|
||||
}
|
||||
|
||||
FxTypedForEachLoop::~FxTypedForEachLoop()
|
||||
{
|
||||
SAFE_DELETE(Expr);
|
||||
SAFE_DELETE(Code);
|
||||
}
|
||||
|
||||
extern bool HasGameSpecificTypedForEachLoopTypeNames();
|
||||
extern const char * GetGameSpecificTypedForEachLoopTypeNames();
|
||||
extern bool IsGameSpecificTypedForEachLoop(FxTypedForEachLoop *);
|
||||
extern FxExpression * ResolveGameSpecificTypedForEachLoop(FxTypedForEachLoop *);
|
||||
|
||||
FxExpression *FxTypedForEachLoop::Resolve(FCompileContext &ctx)
|
||||
{
|
||||
CHECKRESOLVED();
|
||||
SAFE_RESOLVE(Expr, ctx);
|
||||
|
||||
if(IsGameSpecificTypedForEachLoop(this))
|
||||
{
|
||||
return ResolveGameSpecificTypedForEachLoop(this)->Resolve(ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
//put any non-game-specific typed for-each loops here
|
||||
}
|
||||
|
||||
if(HasGameSpecificTypedForEachLoopTypeNames())
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "foreach(Type var : it ) - 'it' must be % but is a %s",GetGameSpecificTypedForEachLoopTypeNames(), Expr->ValueType->DescriptiveName());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "foreach(Type var : it ) - typed foreach loops not supported");
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -12267,8 +12580,7 @@ FxExpression *FxLocalVariableDeclaration::Resolve(FCompileContext &ctx)
|
|||
if (IsDynamicArray())
|
||||
{
|
||||
auto stackVar = new FxStackVariable(ValueType, StackOffset, ScriptPosition);
|
||||
FArgumentList argsList;
|
||||
clearExpr = new FxMemberFunctionCall(stackVar, "Clear", argsList, ScriptPosition);
|
||||
clearExpr = new FxMemberFunctionCall(stackVar, "Clear", {}, ScriptPosition);
|
||||
SAFE_RESOLVE(clearExpr, ctx);
|
||||
}
|
||||
|
||||
|
@ -12586,10 +12898,9 @@ FxExpression *FxLocalArrayDeclaration::Resolve(FCompileContext &ctx)
|
|||
else
|
||||
{
|
||||
FArgumentList argsList;
|
||||
argsList.Clear();
|
||||
argsList.Push(v);
|
||||
|
||||
FxExpression *funcCall = new FxMemberFunctionCall(stackVar, NAME_Push, argsList, (const FScriptPosition) v->ScriptPosition);
|
||||
FxExpression *funcCall = new FxMemberFunctionCall(stackVar, NAME_Push, std::move(argsList), (const FScriptPosition) v->ScriptPosition);
|
||||
SAFE_RESOLVE(funcCall, ctx);
|
||||
|
||||
v = funcCall;
|
||||
|
|
|
@ -275,6 +275,9 @@ enum EFxType
|
|||
EFX_DoWhileLoop,
|
||||
EFX_ForLoop,
|
||||
EFX_ForEachLoop,
|
||||
EFX_TwoArgForEachLoop,
|
||||
EFX_ThreeArgForEachLoop,
|
||||
EFX_TypedForEachLoop,
|
||||
EFX_JumpStatement,
|
||||
EFX_ReturnStatement,
|
||||
EFX_ClassTypeCast,
|
||||
|
@ -1621,7 +1624,7 @@ public:
|
|||
FName MethodName;
|
||||
FArgumentList ArgList;
|
||||
|
||||
FxFunctionCall(FName methodname, FName rngname, FArgumentList &args, const FScriptPosition &pos);
|
||||
FxFunctionCall(FName methodname, FName rngname, FArgumentList &&args, const FScriptPosition &pos);
|
||||
~FxFunctionCall();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
};
|
||||
|
@ -1638,10 +1641,11 @@ class FxMemberFunctionCall : public FxExpression
|
|||
FxExpression *Self;
|
||||
FName MethodName;
|
||||
FArgumentList ArgList;
|
||||
bool ResolveSelf;
|
||||
|
||||
public:
|
||||
|
||||
FxMemberFunctionCall(FxExpression *self, FName methodname, FArgumentList &args, const FScriptPosition &pos);
|
||||
FxMemberFunctionCall(FxExpression *self, FName methodname, FArgumentList &&args, const FScriptPosition &pos);
|
||||
~FxMemberFunctionCall();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
};
|
||||
|
@ -2069,17 +2073,83 @@ public:
|
|||
|
||||
class FxForEachLoop : public FxLoopStatement
|
||||
{
|
||||
public:
|
||||
FName loopVarName;
|
||||
FxExpression* Array;
|
||||
FxExpression* Array2;
|
||||
FxExpression* Array3;
|
||||
FxExpression* Array4;
|
||||
FxExpression* Code;
|
||||
|
||||
public:
|
||||
FxForEachLoop(FName vn, FxExpression* arrayvar, FxExpression* arrayvar2, FxExpression* code, const FScriptPosition& pos);
|
||||
FxForEachLoop(FName vn, FxExpression* arrayvar, FxExpression* arrayvar2, FxExpression* arrayvar3, FxExpression* arrayvar4, FxExpression* code, const FScriptPosition& pos);
|
||||
~FxForEachLoop();
|
||||
FxExpression* DoResolve(FCompileContext&);
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxTwoArgForEachLoop
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FxTwoArgForEachLoop : public FxExpression
|
||||
{
|
||||
public:
|
||||
FName keyVarName;
|
||||
FName valueVarName;
|
||||
FxExpression* MapExpr;
|
||||
FxExpression* MapExpr2;
|
||||
FxExpression* MapExpr3;
|
||||
FxExpression* MapExpr4;
|
||||
FxExpression* Code;
|
||||
|
||||
FxTwoArgForEachLoop(FName kv, FName vv, FxExpression* mapexpr, FxExpression* mapexpr2, FxExpression* mapexpr3, FxExpression* mapexpr4, FxExpression* code, const FScriptPosition& pos);
|
||||
~FxTwoArgForEachLoop();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
//ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxThreeArgForEachLoop
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FxThreeArgForEachLoop : public FxExpression
|
||||
{
|
||||
public:
|
||||
FName varVarName;
|
||||
FName posVarName;
|
||||
FName flagsVarName;
|
||||
FxExpression* BlockIteratorExpr;
|
||||
FxExpression* Code;
|
||||
|
||||
FxThreeArgForEachLoop(FName vv, FName pv, FName fv, FxExpression* blockiteartorexpr, FxExpression* code, const FScriptPosition& pos);
|
||||
~FxThreeArgForEachLoop();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
//ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxTypedForEachLoop
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FxTypedForEachLoop : public FxExpression
|
||||
{
|
||||
public:
|
||||
FName className;
|
||||
FName varName;
|
||||
FxExpression* Expr;
|
||||
FxExpression* Code;
|
||||
|
||||
FxTypedForEachLoop(FName cv, FName vv, FxExpression* castiteartorexpr, FxExpression* code, const FScriptPosition& pos);
|
||||
~FxTypedForEachLoop();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
//ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxJumpStatement
|
||||
|
|
|
@ -41,6 +41,9 @@
|
|||
|
||||
CVAR(Bool, strictdecorate, false, CVAR_GLOBALCONFIG | CVAR_ARCHIVE)
|
||||
|
||||
EXTERN_CVAR(Bool, vm_jit)
|
||||
EXTERN_CVAR(Bool, vm_jit_aot)
|
||||
|
||||
struct VMRemap
|
||||
{
|
||||
uint8_t altOp, kReg, kType;
|
||||
|
@ -928,6 +931,13 @@ void FFunctionBuildList::Build()
|
|||
disasmdump.Write(sfunc, item.PrintableName);
|
||||
|
||||
sfunc->Unsafe = ctx.Unsafe;
|
||||
|
||||
#if HAVE_VM_JIT
|
||||
if(vm_jit && vm_jit_aot)
|
||||
{
|
||||
sfunc->JitCompile();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
catch (CRecoverableError &err)
|
||||
{
|
||||
|
@ -1094,8 +1104,6 @@ void FunctionCallEmitter::AddParameterStringConst(const FString &konst)
|
|||
});
|
||||
}
|
||||
|
||||
EXTERN_CVAR(Bool, vm_jit)
|
||||
|
||||
ExpEmit FunctionCallEmitter::EmitCall(VMFunctionBuilder *build, TArray<ExpEmit> *ReturnRegs)
|
||||
{
|
||||
unsigned paramcount = 0;
|
||||
|
|
|
@ -147,6 +147,24 @@ VMFunction *FindVMFunction(PClass *cls, const char *name)
|
|||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Find an action function in AActor's table from a qualified name
|
||||
// This cannot search in structs. sorry. :(
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
VMFunction* FindVMFunction( const char* name)
|
||||
{
|
||||
auto p = strchr(name, '.');
|
||||
if (p == nullptr) return nullptr;
|
||||
std::string clsname(name, p - name);
|
||||
auto cls = PClass::FindClass(clsname.c_str());
|
||||
if (cls == nullptr) return nullptr;
|
||||
return FindVMFunction(cls, p + 1);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Sorting helpers
|
||||
|
|
|
@ -42,6 +42,8 @@
|
|||
#include "textureid.h"
|
||||
#include "maps.h"
|
||||
#include "palettecontainer.h"
|
||||
#include "texturemanager.h"
|
||||
#include "i_interface.h"
|
||||
|
||||
|
||||
FTypeTable TypeTable;
|
||||
|
@ -1659,7 +1661,8 @@ PClassPointer::PClassPointer(PClass *restrict)
|
|||
loadOp = OP_LP;
|
||||
storeOp = OP_SP;
|
||||
Flags |= TYPE_ClassPointer;
|
||||
mVersion = restrict->VMType->mVersion;
|
||||
if (restrict) mVersion = restrict->VMType->mVersion;
|
||||
else mVersion = 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -2549,9 +2552,63 @@ static void PMapValueWriter(FSerializer &ar, const M *map, const PMap *m)
|
|||
}
|
||||
else if constexpr(std::is_same_v<typename M::KeyType,uint32_t>)
|
||||
{
|
||||
FString key;
|
||||
key.Format("%u",p->Key);
|
||||
m->ValueType->WriteValue(ar,key.GetChars(),static_cast<const void *>(&p->Value));
|
||||
if(m->KeyType->Flags & 8 /*TYPE_IntNotInt*/)
|
||||
{
|
||||
if(m->KeyType == TypeName)
|
||||
{
|
||||
m->ValueType->WriteValue(ar,FName(ENamedName(p->Key)).GetChars(),static_cast<const void *>(&p->Value));
|
||||
}
|
||||
else if(m->KeyType == TypeSound)
|
||||
{
|
||||
m->ValueType->WriteValue(ar,soundEngine->GetSoundName(FSoundID::fromInt(p->Key)),static_cast<const void *>(&p->Value));
|
||||
}
|
||||
else if(m->KeyType == TypeTextureID)
|
||||
{
|
||||
if(!!(p->Key & 0x8000000))
|
||||
{ // invalid
|
||||
m->ValueType->WriteValue(ar,"invalid",static_cast<const void *>(&p->Value));
|
||||
}
|
||||
else if(p->Key == 0 || p->Key >= TexMan.NumTextures())
|
||||
{ // null
|
||||
m->ValueType->WriteValue(ar,"null",static_cast<const void *>(&p->Value));
|
||||
}
|
||||
else
|
||||
{
|
||||
FTextureID tid;
|
||||
tid.SetIndex(p->Key);
|
||||
FGameTexture *tex = TexMan.GetGameTexture(tid);
|
||||
int lump = tex->GetSourceLump();
|
||||
unsigned useType = static_cast<unsigned>(tex->GetUseType());
|
||||
|
||||
FString name;
|
||||
|
||||
if (TexMan.GetLinkedTexture(lump) == tex)
|
||||
{
|
||||
name = fileSystem.GetFileFullName(lump);
|
||||
}
|
||||
else
|
||||
{
|
||||
name = tex->GetName().GetChars();
|
||||
}
|
||||
|
||||
name.AppendFormat(":%u",useType);
|
||||
|
||||
m->ValueType->WriteValue(ar,name.GetChars(),static_cast<const void *>(&p->Value));
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // bool/color/enum/sprite/translationID
|
||||
FString key;
|
||||
key.Format("%u",p->Key);
|
||||
m->ValueType->WriteValue(ar,key.GetChars(),static_cast<const void *>(&p->Value));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FString key;
|
||||
key.Format("%u",p->Key);
|
||||
m->ValueType->WriteValue(ar,key.GetChars(),static_cast<const void *>(&p->Value));
|
||||
}
|
||||
}
|
||||
//else unknown key type
|
||||
}
|
||||
|
@ -2584,20 +2641,85 @@ static bool PMapValueReader(FSerializer &ar, M *map, const PMap *m)
|
|||
const char * k;
|
||||
while((k = ar.GetKey()))
|
||||
{
|
||||
typename M::ValueType * val;
|
||||
typename M::ValueType * val = nullptr;
|
||||
if constexpr(std::is_same_v<typename M::KeyType,FString>)
|
||||
{
|
||||
val = &map->InsertNew(k);
|
||||
}
|
||||
else if constexpr(std::is_same_v<typename M::KeyType,uint32_t>)
|
||||
{
|
||||
FString s(k);
|
||||
if(!s.IsInt())
|
||||
if(m->KeyType->Flags & 8 /*TYPE_IntNotInt*/)
|
||||
{
|
||||
ar.EndObject();
|
||||
return false;
|
||||
if(m->KeyType == TypeName)
|
||||
{
|
||||
val = &map->InsertNew(FName(k).GetIndex());
|
||||
}
|
||||
else if(m->KeyType == TypeSound)
|
||||
{
|
||||
val = &map->InsertNew(S_FindSound(k).index());
|
||||
}
|
||||
else if(m->KeyType == TypeTextureID)
|
||||
{
|
||||
FString s(k);
|
||||
FTextureID tex;
|
||||
if(s.Compare("invalid") == 0)
|
||||
{
|
||||
tex.SetInvalid();
|
||||
}
|
||||
else if(s.Compare("null") == 0)
|
||||
{
|
||||
tex.SetNull();
|
||||
}
|
||||
else
|
||||
{
|
||||
ptrdiff_t sep = s.LastIndexOf(":");
|
||||
if(sep < 0)
|
||||
{
|
||||
ar.EndObject();
|
||||
return false;
|
||||
}
|
||||
FString texName = s.Left(sep);
|
||||
FString useType = s.Mid(sep + 1);
|
||||
|
||||
tex = TexMan.GetTextureID(texName.GetChars(), (ETextureType) useType.ToULong());
|
||||
}
|
||||
val = &map->InsertNew(tex.GetIndex());
|
||||
}
|
||||
else if(m->KeyType == TypeTranslationID)
|
||||
{
|
||||
FString s(k);
|
||||
if(!s.IsInt())
|
||||
{
|
||||
ar.EndObject();
|
||||
return false;
|
||||
}
|
||||
int v = s.ToULong();
|
||||
|
||||
if (sysCallbacks.RemapTranslation) v = sysCallbacks.RemapTranslation(FTranslationID::fromInt(v)).index();
|
||||
|
||||
val = &map->InsertNew(v);
|
||||
}
|
||||
else
|
||||
{ // bool/color/enum/sprite
|
||||
FString s(k);
|
||||
if(!s.IsInt())
|
||||
{
|
||||
ar.EndObject();
|
||||
return false;
|
||||
}
|
||||
val = &map->InsertNew(static_cast<uint32_t>(s.ToULong()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FString s(k);
|
||||
if(!s.IsInt())
|
||||
{
|
||||
ar.EndObject();
|
||||
return false;
|
||||
}
|
||||
val = &map->InsertNew(static_cast<uint32_t>(s.ToULong()));
|
||||
}
|
||||
val = &map->InsertNew(static_cast<uint32_t>(s.ToULong()));
|
||||
}
|
||||
if (!m->ValueType->ReadValue(ar,nullptr,static_cast<void*>(val)))
|
||||
{
|
||||
|
|
|
@ -742,6 +742,7 @@ extern PPointer *TypeVoidPtr;
|
|||
extern PPointer* TypeRawFunction;
|
||||
extern PPointer* TypeVMFunction;
|
||||
|
||||
|
||||
inline FString &DObject::StringVar(FName field)
|
||||
{
|
||||
return *(FString*)ScriptVar(field, TypeString);
|
||||
|
|
|
@ -983,6 +983,53 @@ static void PrintArrayIterationStmt(FLispString &out, const ZCC_TreeNode *node)
|
|||
out.Close();
|
||||
}
|
||||
|
||||
static void PrintTwoArgIterationStmt(FLispString &out, const ZCC_TreeNode *node)
|
||||
{
|
||||
auto inode = (ZCC_TwoArgIterationStmt *)node;
|
||||
out.Break();
|
||||
out.Open("map-iteration-stmt");
|
||||
PrintVarName(out, inode->ItKey);
|
||||
out.Break();
|
||||
PrintVarName(out, inode->ItValue);
|
||||
out.Break();
|
||||
PrintNodes(out, inode->ItMap);
|
||||
out.Break();
|
||||
PrintNodes(out, inode->LoopStatement);
|
||||
out.Close();
|
||||
}
|
||||
|
||||
static void PrintThreeArgIterationStmt(FLispString &out, const ZCC_TreeNode *node)
|
||||
{
|
||||
auto inode = (ZCC_ThreeArgIterationStmt *)node;
|
||||
out.Break();
|
||||
out.Open("block-iteration-stmt");
|
||||
PrintVarName(out, inode->ItVar);
|
||||
out.Break();
|
||||
PrintVarName(out, inode->ItPos);
|
||||
out.Break();
|
||||
PrintVarName(out, inode->ItFlags);
|
||||
out.Break();
|
||||
PrintNodes(out, inode->ItBlock);
|
||||
out.Break();
|
||||
PrintNodes(out, inode->LoopStatement);
|
||||
out.Close();
|
||||
}
|
||||
|
||||
static void PrintTypedIterationStmt(FLispString &out, const ZCC_TreeNode *node)
|
||||
{
|
||||
auto inode = (ZCC_TypedIterationStmt *)node;
|
||||
out.Break();
|
||||
out.Open("cast-iteration-stmt");
|
||||
PrintVarName(out, inode->ItType);
|
||||
out.Break();
|
||||
PrintVarName(out, inode->ItVar);
|
||||
out.Break();
|
||||
PrintNodes(out, inode->ItExpr);
|
||||
out.Break();
|
||||
PrintNodes(out, inode->LoopStatement);
|
||||
out.Close();
|
||||
}
|
||||
|
||||
static const NodePrinterFunc TreeNodePrinter[] =
|
||||
{
|
||||
PrintIdentifier,
|
||||
|
@ -1050,6 +1097,9 @@ static const NodePrinterFunc TreeNodePrinter[] =
|
|||
PrintMixinDef,
|
||||
PrintMixinStmt,
|
||||
PrintArrayIterationStmt,
|
||||
PrintTwoArgIterationStmt,
|
||||
PrintThreeArgIterationStmt,
|
||||
PrintTypedIterationStmt,
|
||||
};
|
||||
|
||||
FString ZCC_PrintAST(const ZCC_TreeNode *root)
|
||||
|
|
|
@ -378,6 +378,15 @@ flag_def(X) ::= FLAGDEF(T) IDENTIFIER(A) COLON IDENTIFIER(B) COMMA INTCONST(C) S
|
|||
X = def;
|
||||
}
|
||||
|
||||
flag_def(X) ::= FLAGDEF(T) INTERNAL IDENTIFIER(A) COLON IDENTIFIER(B) COMMA INTCONST(C) SEMICOLON.
|
||||
{
|
||||
NEW_AST_NODE(FlagDef,def,T);
|
||||
def->NodeName = A.Name();
|
||||
def->RefName = B.Name();
|
||||
def->BitValue = C.Int | 0x10000;
|
||||
X = def;
|
||||
}
|
||||
|
||||
|
||||
identifier_list(X) ::= IDENTIFIER(A).
|
||||
{
|
||||
|
@ -437,6 +446,7 @@ struct_member(X) ::= declarator(A). { X = A; /*X-overwrites-A*/ }
|
|||
struct_member(X) ::= enum_def(A). { X = A; /*X-overwrites-A*/ }
|
||||
struct_member(X) ::= const_def(A). { X = A; /*X-overwrites-A*/ }
|
||||
struct_member(X) ::= staticarray_statement(A). { X = A; /*X-overwrites-A*/ }
|
||||
struct_member(X) ::= flag_def(A). { X = A; /*X-overwrites-A*/ }
|
||||
|
||||
/*----- Constant Definition ------*/
|
||||
/* Like UnrealScript, a constant's type is implied by its value's type. */
|
||||
|
@ -1946,6 +1956,9 @@ statement(X) ::= expression_statement(A) SEMICOLON. { X = A; /*X-overwrites-A*/
|
|||
statement(X) ::= selection_statement(X).
|
||||
statement(X) ::= iteration_statement(X).
|
||||
statement(X) ::= array_iteration_statement(X).
|
||||
statement(X) ::= two_arg_iteration_statement(X).
|
||||
statement(X) ::= three_arg_iteration_statement(X).
|
||||
statement(X) ::= typed_iteration_statement(X).
|
||||
statement(X) ::= jump_statement(X).
|
||||
statement(X) ::= assign_statement(A) SEMICOLON. { X = A; /*X-overwrites-A*/ }
|
||||
statement(X) ::= assign_decl_statement(A) SEMICOLON.{ X = A; /*X-overwrites-A*/ }
|
||||
|
@ -2115,6 +2128,43 @@ array_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(IN) COLON expr(
|
|||
X = iter;
|
||||
}
|
||||
|
||||
%type two_arg_iteration_statement{ZCC_Statement *}
|
||||
|
||||
two_arg_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(KEY) COMMA variable_name(VAL) COLON expr(EX) RPAREN statement(ST).
|
||||
{
|
||||
NEW_AST_NODE(TwoArgIterationStmt, iter, T);
|
||||
iter->ItKey = KEY;
|
||||
iter->ItValue = VAL;
|
||||
iter->ItMap = EX;
|
||||
iter->LoopStatement = ST;
|
||||
X = iter;
|
||||
}
|
||||
|
||||
%type three_arg_iteration_statement{ZCC_Statement *}
|
||||
|
||||
three_arg_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(VAR) COMMA variable_name(POS) COMMA variable_name(FLAGS) COLON expr(EX) RPAREN statement(ST).
|
||||
{
|
||||
NEW_AST_NODE(ThreeArgIterationStmt, iter, T);
|
||||
iter->ItVar = VAR;
|
||||
iter->ItPos = POS;
|
||||
iter->ItFlags = FLAGS;
|
||||
iter->ItBlock = EX;
|
||||
iter->LoopStatement = ST;
|
||||
X = iter;
|
||||
}
|
||||
|
||||
%type typed_iteration_statement{ZCC_Statement *}
|
||||
|
||||
typed_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(TYPE) variable_name(VAR) COLON expr(EX) RPAREN statement(ST).
|
||||
{
|
||||
NEW_AST_NODE(TypedIterationStmt, iter, T);
|
||||
iter->ItType = TYPE;
|
||||
iter->ItVar = VAR;
|
||||
iter->ItExpr = EX;
|
||||
iter->LoopStatement = ST;
|
||||
X = iter;
|
||||
}
|
||||
|
||||
while_or_until(X) ::= WHILE(T).
|
||||
{
|
||||
X.Int = ZCC_WHILE;
|
||||
|
|
|
@ -57,6 +57,13 @@ double GetFloatConst(FxExpression *ex, FCompileContext &ctx)
|
|||
return ex ? static_cast<FxConstant*>(ex)->GetValue().GetFloat() : 0;
|
||||
}
|
||||
|
||||
VMFunction* GetFuncConst(FxExpression* ex, FCompileContext& ctx)
|
||||
{
|
||||
ex = new FxTypeCast(ex, TypeVMFunction, false);
|
||||
ex = ex->Resolve(ctx);
|
||||
return static_cast<VMFunction*>(ex ? static_cast<FxConstant*>(ex)->GetValue().GetPointer() : nullptr);
|
||||
}
|
||||
|
||||
const char * ZCCCompiler::GetStringConst(FxExpression *ex, FCompileContext &ctx)
|
||||
{
|
||||
ex = new FxStringCast(ex);
|
||||
|
@ -452,6 +459,11 @@ void ZCCCompiler::ProcessStruct(ZCC_Struct *cnode, PSymbolTreeNode *treenode, ZC
|
|||
}
|
||||
break;
|
||||
|
||||
case AST_FlagDef:
|
||||
cls->FlagDefs.Push(static_cast<ZCC_FlagDef*>(node));
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
assert(0 && "Unhandled AST node type");
|
||||
break;
|
||||
|
@ -2987,12 +2999,12 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast, bool substitute)
|
|||
{
|
||||
case AST_ExprID:
|
||||
// The function name is a simple identifier.
|
||||
return new FxFunctionCall(static_cast<ZCC_ExprID *>(fcall->Function)->Identifier, NAME_None, ConvertNodeList(args, fcall->Parameters), *ast);
|
||||
return new FxFunctionCall(static_cast<ZCC_ExprID *>(fcall->Function)->Identifier, NAME_None, std::move(ConvertNodeList(args, fcall->Parameters)), *ast);
|
||||
|
||||
case AST_ExprMemberAccess:
|
||||
{
|
||||
auto ema = static_cast<ZCC_ExprMemberAccess *>(fcall->Function);
|
||||
return new FxMemberFunctionCall(ConvertNode(ema->Left, true), ema->Right, ConvertNodeList(args, fcall->Parameters), *ast);
|
||||
return new FxMemberFunctionCall(ConvertNode(ema->Left, true), ema->Right, std::move(ConvertNodeList(args, fcall->Parameters)), *ast);
|
||||
}
|
||||
|
||||
case AST_ExprBinary:
|
||||
|
@ -3002,7 +3014,7 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast, bool substitute)
|
|||
auto binary = static_cast<ZCC_ExprBinary *>(fcall->Function);
|
||||
if (binary->Left->NodeType == AST_ExprID && binary->Right->NodeType == AST_ExprID)
|
||||
{
|
||||
return new FxFunctionCall(static_cast<ZCC_ExprID *>(binary->Left)->Identifier, static_cast<ZCC_ExprID *>(binary->Right)->Identifier, ConvertNodeList(args, fcall->Parameters), *ast);
|
||||
return new FxFunctionCall(static_cast<ZCC_ExprID *>(binary->Left)->Identifier, static_cast<ZCC_ExprID *>(binary->Right)->Identifier, std::move(ConvertNodeList(args, fcall->Parameters)), *ast);
|
||||
}
|
||||
}
|
||||
// fall through if this isn't an array access node.
|
||||
|
@ -3376,10 +3388,45 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast, bool substitute)
|
|||
auto iter = static_cast<ZCC_ArrayIterationStmt*>(ast);
|
||||
auto var = iter->ItName->Name;
|
||||
FxExpression* const itArray = ConvertNode(iter->ItArray);
|
||||
FxExpression* const itArray2 = ConvertNode(iter->ItArray); // the handler needs two copies of this - here's the easiest place to create them.
|
||||
FxExpression* const itArray2 = ConvertNode(iter->ItArray);
|
||||
FxExpression* const itArray3 = ConvertNode(iter->ItArray);
|
||||
FxExpression* const itArray4 = ConvertNode(iter->ItArray); // the handler needs copies of this - here's the easiest place to create them.
|
||||
FxExpression* const body = ConvertImplicitScopeNode(ast, iter->LoopStatement);
|
||||
return new FxForEachLoop(iter->ItName->Name, itArray, itArray2, body, *ast);
|
||||
return new FxForEachLoop(iter->ItName->Name, itArray, itArray2, itArray3, itArray4, body, *ast);
|
||||
}
|
||||
|
||||
case AST_TwoArgIterationStmt:
|
||||
{
|
||||
auto iter = static_cast<ZCC_TwoArgIterationStmt*>(ast);
|
||||
auto key = iter->ItKey->Name;
|
||||
auto var = iter->ItValue->Name;
|
||||
FxExpression* const itMap = ConvertNode(iter->ItMap);
|
||||
FxExpression* const itMap2 = ConvertNode(iter->ItMap);
|
||||
FxExpression* const itMap3 = ConvertNode(iter->ItMap);
|
||||
FxExpression* const itMap4 = ConvertNode(iter->ItMap);
|
||||
FxExpression* const body = ConvertImplicitScopeNode(ast, iter->LoopStatement);
|
||||
return new FxTwoArgForEachLoop(key, var, itMap, itMap2, itMap3, itMap4, body, *ast);
|
||||
}
|
||||
|
||||
case AST_ThreeArgIterationStmt:
|
||||
{
|
||||
auto iter = static_cast<ZCC_ThreeArgIterationStmt*>(ast);
|
||||
auto var = iter->ItVar->Name;
|
||||
auto pos = iter->ItPos->Name;
|
||||
auto flags = iter->ItFlags->Name;
|
||||
FxExpression* const itBlock = ConvertNode(iter->ItBlock);
|
||||
FxExpression* const body = ConvertImplicitScopeNode(ast, iter->LoopStatement);
|
||||
return new FxThreeArgForEachLoop(var, pos, flags, itBlock, body, *ast);
|
||||
}
|
||||
|
||||
case AST_TypedIterationStmt:
|
||||
{
|
||||
auto iter = static_cast<ZCC_TypedIterationStmt*>(ast);
|
||||
auto cls = iter->ItType->Name;
|
||||
auto var = iter->ItVar->Name;
|
||||
FxExpression* const itExpr = ConvertNode(iter->ItExpr);
|
||||
FxExpression* const body = ConvertImplicitScopeNode(ast, iter->LoopStatement);
|
||||
return new FxTypedForEachLoop(cls, var, itExpr, body, *ast);
|
||||
}
|
||||
|
||||
case AST_IterationStmt:
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
struct Baggage;
|
||||
struct FPropertyInfo;
|
||||
class AActor;
|
||||
class FxExpression;
|
||||
typedef TDeletingArray<FxExpression*> FArgumentList;
|
||||
|
||||
|
@ -23,6 +22,7 @@ struct ZCC_StructWork
|
|||
TArray<ZCC_VarDeclarator *> Fields;
|
||||
TArray<ZCC_FuncDeclarator *> Functions;
|
||||
TArray<ZCC_StaticArrayStatement *> Arrays;
|
||||
TArray<ZCC_FlagDef*> FlagDefs;
|
||||
|
||||
ZCC_StructWork()
|
||||
{
|
||||
|
|
|
@ -1177,6 +1177,46 @@ ZCC_TreeNode *TreeNodeDeepCopy_Internal(ZCC_AST *ast, ZCC_TreeNode *orig, bool c
|
|||
break;
|
||||
}
|
||||
|
||||
case AST_TwoArgIterationStmt:
|
||||
{
|
||||
TreeNodeDeepCopy_Start(TwoArgIterationStmt);
|
||||
|
||||
// ZCC_TwoArgIterationStmt
|
||||
copy->ItKey = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItKey, true, copiedNodesList));
|
||||
copy->ItValue = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItValue, true, copiedNodesList));
|
||||
copy->LoopStatement = static_cast<ZCC_Statement*>(TreeNodeDeepCopy_Internal(ast, origCasted->LoopStatement, true, copiedNodesList));
|
||||
copy->ItMap = static_cast<ZCC_Expression*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItMap, true, copiedNodesList));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case AST_ThreeArgIterationStmt:
|
||||
{
|
||||
TreeNodeDeepCopy_Start(ThreeArgIterationStmt);
|
||||
|
||||
// ZCC_TwoArgIterationStmt
|
||||
copy->ItVar = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItVar, true, copiedNodesList));
|
||||
copy->ItPos = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItPos, true, copiedNodesList));
|
||||
copy->ItFlags = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItFlags, true, copiedNodesList));
|
||||
copy->LoopStatement = static_cast<ZCC_Statement*>(TreeNodeDeepCopy_Internal(ast, origCasted->LoopStatement, true, copiedNodesList));
|
||||
copy->ItBlock = static_cast<ZCC_Expression*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItBlock, true, copiedNodesList));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case AST_TypedIterationStmt:
|
||||
{
|
||||
TreeNodeDeepCopy_Start(TypedIterationStmt);
|
||||
|
||||
// ZCC_TwoArgIterationStmt
|
||||
copy->ItType = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItType, true, copiedNodesList));
|
||||
copy->ItVar = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItVar, true, copiedNodesList));
|
||||
copy->LoopStatement = static_cast<ZCC_Statement*>(TreeNodeDeepCopy_Internal(ast, origCasted->LoopStatement, true, copiedNodesList));
|
||||
copy->ItExpr = static_cast<ZCC_Expression*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItExpr, true, copiedNodesList));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case AST_IfStmt:
|
||||
{
|
||||
TreeNodeDeepCopy_Start(IfStmt);
|
||||
|
|
|
@ -145,6 +145,9 @@ enum EZCCTreeNodeType
|
|||
AST_MixinDef,
|
||||
AST_MixinStmt,
|
||||
AST_ArrayIterationStmt,
|
||||
AST_TwoArgIterationStmt,
|
||||
AST_ThreeArgIterationStmt,
|
||||
AST_TypedIterationStmt,
|
||||
|
||||
NUM_AST_NODE_TYPES
|
||||
};
|
||||
|
@ -532,6 +535,31 @@ struct ZCC_ArrayIterationStmt : ZCC_Statement
|
|||
ZCC_Statement* LoopStatement;
|
||||
};
|
||||
|
||||
struct ZCC_TwoArgIterationStmt : ZCC_Statement
|
||||
{
|
||||
ZCC_VarName* ItKey;
|
||||
ZCC_VarName* ItValue;
|
||||
ZCC_Expression* ItMap;
|
||||
ZCC_Statement* LoopStatement;
|
||||
};
|
||||
|
||||
struct ZCC_ThreeArgIterationStmt : ZCC_Statement
|
||||
{
|
||||
ZCC_VarName* ItVar;
|
||||
ZCC_VarName* ItPos;
|
||||
ZCC_VarName* ItFlags;
|
||||
ZCC_Expression* ItBlock;
|
||||
ZCC_Statement* LoopStatement;
|
||||
};
|
||||
|
||||
struct ZCC_TypedIterationStmt : ZCC_Statement
|
||||
{
|
||||
ZCC_VarName* ItType;
|
||||
ZCC_VarName* ItVar;
|
||||
ZCC_Expression* ItExpr;
|
||||
ZCC_Statement* LoopStatement;
|
||||
};
|
||||
|
||||
struct ZCC_IfStmt : ZCC_Statement
|
||||
{
|
||||
ZCC_Expression *Condition;
|
||||
|
|
|
@ -724,6 +724,11 @@ struct AFuncDesc
|
|||
extern FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr; \
|
||||
MSVC_FSEG FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr GCC_FSEG = &VMField_##cls##_##scriptname;
|
||||
|
||||
#define DEFINE_FIELD_NAMED_UNSIZED(cls, name, scriptname) \
|
||||
static const FieldDesc VMField_##cls##_##scriptname = { #cls, #scriptname, (unsigned)myoffsetof(cls, name), ~0u, 0 }; \
|
||||
extern FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr; \
|
||||
MSVC_FSEG FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr GCC_FSEG = &VMField_##cls##_##scriptname;
|
||||
|
||||
#define DEFINE_FIELD_BIT(cls, name, scriptname, bitval) \
|
||||
static const FieldDesc VMField_##cls##_##scriptname = { #cls, #scriptname, (unsigned)myoffsetof(cls, name), (unsigned)sizeof(cls::name), bitval }; \
|
||||
extern FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr; \
|
||||
|
@ -792,6 +797,7 @@ class AActor;
|
|||
class PFunction;
|
||||
|
||||
VMFunction *FindVMFunction(PClass *cls, const char *name);
|
||||
VMFunction* FindVMFunction(const char* name);
|
||||
#define DECLARE_VMFUNC(cls, name) static VMFunction *name; if (name == nullptr) name = FindVMFunction(RUNTIME_CLASS(cls), #name);
|
||||
|
||||
FString FStringFormat(VM_ARGS, int offset = 0);
|
||||
|
|
|
@ -54,8 +54,14 @@ CUSTOM_CVAR(Bool, vm_jit, true, CVAR_NOINITCALL)
|
|||
Printf("You must restart " GAMENAME " for this change to take effect.\n");
|
||||
Printf("This cvar is currently not saved. You must specify it on the command line.");
|
||||
}
|
||||
CUSTOM_CVAR(Bool, vm_jit_aot, true, CVAR_NOINITCALL)
|
||||
{
|
||||
Printf("You must restart " GAMENAME " for this change to take effect.\n");
|
||||
Printf("This cvar is currently not saved. You must specify it on the command line.");
|
||||
}
|
||||
#else
|
||||
CVAR(Bool, vm_jit, false, CVAR_NOINITCALL|CVAR_NOSET)
|
||||
CVAR(Bool, vm_jit_aot, false, CVAR_NOINITCALL|CVAR_NOSET)
|
||||
FString JitCaptureStackTrace(int framesToSkip, bool includeNativeFrames, int maxFrames) { return FString(); }
|
||||
void JitRelease() {}
|
||||
#endif
|
||||
|
@ -282,6 +288,25 @@ static bool CanJit(VMScriptFunction *func)
|
|||
return false;
|
||||
}
|
||||
|
||||
void VMScriptFunction::JitCompile()
|
||||
{
|
||||
if(!(VarFlags & VARF_Abstract))
|
||||
{
|
||||
#ifdef HAVE_VM_JIT
|
||||
if (vm_jit && CanJit(this))
|
||||
{
|
||||
ScriptCall = ::JitCompile(this);
|
||||
if (!ScriptCall)
|
||||
ScriptCall = VMExec;
|
||||
}
|
||||
else
|
||||
#endif // HAVE_VM_JIT
|
||||
{
|
||||
ScriptCall = VMExec;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int VMScriptFunction::FirstScriptCall(VMFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret)
|
||||
{
|
||||
// [Player701] Check that we aren't trying to call an abstract function.
|
||||
|
@ -291,18 +316,8 @@ int VMScriptFunction::FirstScriptCall(VMFunction *func, VMValue *params, int num
|
|||
{
|
||||
ThrowAbortException(X_OTHER, "attempt to call abstract function %s.", func->PrintableName);
|
||||
}
|
||||
#ifdef HAVE_VM_JIT
|
||||
if (vm_jit && CanJit(static_cast<VMScriptFunction*>(func)))
|
||||
{
|
||||
func->ScriptCall = JitCompile(static_cast<VMScriptFunction*>(func));
|
||||
if (!func->ScriptCall)
|
||||
func->ScriptCall = VMExec;
|
||||
}
|
||||
else
|
||||
#endif // HAVE_VM_JIT
|
||||
{
|
||||
func->ScriptCall = VMExec;
|
||||
}
|
||||
|
||||
static_cast<VMScriptFunction*>(func)->JitCompile();
|
||||
|
||||
return func->ScriptCall(func, params, numparams, ret, numret);
|
||||
}
|
||||
|
|
|
@ -481,4 +481,6 @@ public:
|
|||
|
||||
private:
|
||||
static int FirstScriptCall(VMFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret);
|
||||
void JitCompile();
|
||||
friend class FFunctionBuildList;
|
||||
};
|
||||
|
|
|
@ -72,9 +72,10 @@ FImageSource *AnmImage_TryCreate(FileReader & file, int lumpnum)
|
|||
if (memcmp(check, "LPF ", 4)) return nullptr;
|
||||
file.Seek(0, FileReader::SeekSet);
|
||||
auto buffer = file.ReadPadded(1);
|
||||
if (buffer.size() < 4) return nullptr;
|
||||
|
||||
std::unique_ptr<anim_t> anim = std::make_unique<anim_t>(); // note that this struct is very large and should not go onto the stack!
|
||||
if (ANIM_LoadAnim(anim.get(), buffer.data(), buffer.size() - 1) < 0)
|
||||
if (ANIM_LoadAnim(anim.get(), buffer.bytes(), buffer.size() - 1) < 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -161,7 +161,7 @@ void FPCXTexture::ReadPCX1bit (uint8_t *dst, FileReader & lump, PCXHeader *hdr)
|
|||
uint8_t rle_value = 0;
|
||||
|
||||
auto srcp = lump.Read(lump.GetLength() - sizeof(PCXHeader));
|
||||
uint8_t * src = srcp.data();
|
||||
const uint8_t * src = srcp.bytes();
|
||||
|
||||
for (y = 0; y < Height; ++y)
|
||||
{
|
||||
|
@ -211,7 +211,7 @@ void FPCXTexture::ReadPCX4bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr)
|
|||
TArray<uint8_t> colorIndex(Width, true);
|
||||
|
||||
auto srcp = lump.Read(lump.GetLength() - sizeof(PCXHeader));
|
||||
uint8_t * src = srcp.data();
|
||||
const uint8_t * src = srcp.bytes();
|
||||
|
||||
for (y = 0; y < Height; ++y)
|
||||
{
|
||||
|
@ -265,7 +265,7 @@ void FPCXTexture::ReadPCX8bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr)
|
|||
int y, bytes;
|
||||
|
||||
auto srcp = lump.Read(lump.GetLength() - sizeof(PCXHeader));
|
||||
uint8_t * src = srcp.data();
|
||||
const uint8_t * src = srcp.bytes();
|
||||
|
||||
for (y = 0; y < Height; ++y)
|
||||
{
|
||||
|
@ -306,7 +306,7 @@ void FPCXTexture::ReadPCX24bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr
|
|||
int bytes;
|
||||
|
||||
auto srcp = lump.Read(lump.GetLength() - sizeof(PCXHeader));
|
||||
uint8_t * src = srcp.data();
|
||||
const uint8_t * src = srcp.bytes();
|
||||
|
||||
for (y = 0; y < Height; ++y)
|
||||
{
|
||||
|
|
|
@ -65,9 +65,9 @@ FImageSource *WebPImage_TryCreate(FileReader &file, int lumpnum)
|
|||
file.Seek(0, FileReader::SeekSet);
|
||||
auto bytes = file.Read();
|
||||
|
||||
if (WebPGetInfo(bytes.data(), bytes.size(), &width, &height))
|
||||
if (WebPGetInfo(bytes.bytes(), bytes.size(), &width, &height))
|
||||
{
|
||||
WebPData data{ bytes.data(), bytes.size() };
|
||||
WebPData data{ bytes.bytes(), bytes.size() };
|
||||
WebPData chunk_data;
|
||||
auto mux = WebPMuxCreate(&data, 0);
|
||||
if (mux)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
enum class ETextureType : uint8_t
|
||||
{
|
||||
Any,
|
||||
|
@ -28,6 +30,7 @@ class FTextureID
|
|||
|
||||
public:
|
||||
FTextureID() = default;
|
||||
FTextureID(std::nullptr_t) : texnum(0) {}
|
||||
bool isNull() const { return texnum == 0; }
|
||||
bool isValid() const { return texnum > 0; }
|
||||
bool Exists() const { return texnum >= 0; }
|
||||
|
|
|
@ -657,6 +657,44 @@ public:
|
|||
std::swap(Most, other.Most);
|
||||
}
|
||||
|
||||
// aliases with STL compliant names to allow using TArrays with templates designed for STL containers
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return Count;
|
||||
}
|
||||
|
||||
T* data() const
|
||||
{
|
||||
return Data();
|
||||
}
|
||||
|
||||
T& front() const
|
||||
{
|
||||
return *Data();
|
||||
}
|
||||
|
||||
T& back() const
|
||||
{
|
||||
return Last();
|
||||
}
|
||||
|
||||
void resize(size_t i)
|
||||
{
|
||||
Resize(i);
|
||||
}
|
||||
|
||||
void push_back(T& elem)
|
||||
{
|
||||
Push(elem);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
T *Array;
|
||||
unsigned int Count;
|
||||
|
|
|
@ -519,3 +519,19 @@ void SetRazeCompileEnvironment()
|
|||
compileEnvironment.CheckSpecialMember = CheckForMemberDefault;
|
||||
compileEnvironment.CheckCustomGlobalFunctions = ResolveGlobalCustomFunction;
|
||||
}
|
||||
|
||||
// todo: clean up this mess
|
||||
extern bool HasGameSpecificTwoArgForEachLoopTypeNames() { return false; }
|
||||
extern const char* GetGameSpecificTwoArgForEachLoopTypeNames() { return ""; }
|
||||
extern bool IsGameSpecificTwoArgForEachLoop(FxTwoArgForEachLoop*) { return false; }
|
||||
extern FxExpression* ResolveGameSpecificTwoArgForEachLoop(FxTwoArgForEachLoop*) { return nullptr; }
|
||||
extern bool HasGameSpecificThreeArgForEachLoopTypeNames() { return false; }
|
||||
extern const char* GetGameSpecificThreeArgForEachLoopTypeNames() { return ""; }
|
||||
extern bool IsGameSpecificThreeArgForEachLoop(FxThreeArgForEachLoop*) { return false; }
|
||||
extern FxExpression* ResolveGameSpecificThreeArgForEachLoop(FxThreeArgForEachLoop*) { return nullptr; }
|
||||
extern bool HasGameSpecificTypedForEachLoopTypeNames() { return false; }
|
||||
extern const char* GetGameSpecificTypedForEachLoopTypeNames() { return ""; }
|
||||
extern bool IsGameSpecificTypedForEachLoop(FxTypedForEachLoop*) { return false; }
|
||||
extern FxExpression* ResolveGameSpecificTypedForEachLoop(FxTypedForEachLoop*) { return nullptr; }
|
||||
extern bool IsGameSpecificForEachLoop(FxForEachLoop*) { return false; }
|
||||
extern FxExpression* ResolveGameSpecificForEachLoop(FxForEachLoop*) { return nullptr; }
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "findfile.h"
|
||||
#include "palutil.h"
|
||||
#include "startupinfo.h"
|
||||
#include "files.h"
|
||||
|
||||
using namespace FileSys;
|
||||
|
||||
|
@ -153,6 +154,7 @@ static std::vector<std::string> ParseGameInfo(std::vector<std::string>& pwads, c
|
|||
|
||||
static std::vector<std::string> CheckGameInfo(std::vector<std::string>& pwads)
|
||||
{
|
||||
#if 1
|
||||
// scan the list of WADs backwards to find the last one that contains a GAMEINFO lump
|
||||
for (int i = (int)pwads.size() - 1; i >= 0; i--)
|
||||
{
|
||||
|
@ -180,18 +182,18 @@ static std::vector<std::string> CheckGameInfo(std::vector<std::string>& pwads)
|
|||
else
|
||||
resfile = FResourceFile::OpenDirectory(filename);
|
||||
|
||||
FName gameinfo = "GAMEINFO.TXT";
|
||||
if (resfile != NULL)
|
||||
const char* gameinfo = "GAMEINFO.TXT";
|
||||
if (resfile != nullptr)
|
||||
{
|
||||
uint32_t cnt = resfile->LumpCount();
|
||||
uint32_t cnt = resfile->EntryCount();
|
||||
for (int c = cnt - 1; c >= 0; c--)
|
||||
{
|
||||
FResourceLump* lmp = resfile->GetLump(c);
|
||||
|
||||
if (FName(lmp->getName(), true) == gameinfo)
|
||||
if (!stricmp(resfile->getName(c), gameinfo))
|
||||
{
|
||||
// Found one!
|
||||
auto bases = ParseGameInfo(pwads, resfile->FileName, (const char*)lmp->Lock(), lmp->LumpSize);
|
||||
auto data = resfile->Read(c);
|
||||
auto wadname = resfile->GetFileName();
|
||||
auto bases = ParseGameInfo(pwads, wadname, data.string(), (int)data.size());
|
||||
delete resfile;
|
||||
return bases;
|
||||
}
|
||||
|
@ -199,6 +201,7 @@ static std::vector<std::string> CheckGameInfo(std::vector<std::string>& pwads)
|
|||
delete resfile;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return std::vector<std::string>();
|
||||
}
|
||||
|
||||
|
@ -445,8 +448,8 @@ void InitFileSystem(TArray<GrpEntry>& groups)
|
|||
FILE* f = fopen("filesystem.dir", "wb");
|
||||
for (int num = 0; num < fileSystem.GetNumEntries(); num++)
|
||||
{
|
||||
auto fd = fileSystem.GetFileAt(num);
|
||||
fprintf(f, "%.50s %60s %d\n", fd->getName(), fileSystem.GetResourceFileFullName(fileSystem.GetFileContainer(num)), fd->Size());
|
||||
auto fd = fileSystem.FileLength(num);
|
||||
fprintf(f, "%.50s %60s %d\n", fileSystem.GetFileFullName(num), fileSystem.GetResourceFileFullName(fileSystem.GetFileContainer(num)), fd);
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
|
|
@ -320,7 +320,7 @@ CCMD(md4sum)
|
|||
{
|
||||
auto data = fr.Read();
|
||||
uint8_t digest[16];
|
||||
md4once(data.data(), (uint32_t)data.size(), digest);
|
||||
md4once(data.bytes(), (uint32_t)data.size(), digest);
|
||||
for (int j = 0; j < 16; ++j)
|
||||
{
|
||||
Printf("%02x", digest[j]);
|
||||
|
|
|
@ -547,7 +547,7 @@ void loadMap(const char* filename, int flags, DVector3* pos, int16_t* ang, secto
|
|||
fr.Seek(0, FileReader::SeekSet);
|
||||
auto buffer = fr.Read();
|
||||
uint8_t md4[16];
|
||||
md4once(buffer.data(), (unsigned)buffer.size(), md4);
|
||||
md4once(buffer.bytes(), (unsigned)buffer.size(), md4);
|
||||
PostProcessLevel(md4, filename, sprites);
|
||||
loadMapHack(filename, md4, sprites);
|
||||
setWallSectors();
|
||||
|
@ -589,7 +589,7 @@ static void Decrypt(void* to_, const void* from_, int len, int key)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
static void P_LoadBloodMapWalls(uint8_t* data, size_t len, TArray<walltype>& lwalls)
|
||||
static void P_LoadBloodMapWalls(const uint8_t* data, size_t len, TArray<walltype>& lwalls)
|
||||
{
|
||||
uint8_t infoBlock[37];
|
||||
int mapver = data[5];
|
||||
|
@ -698,7 +698,7 @@ TArray<walltype> loadMapWalls(const char* filename)
|
|||
if (isBlood())
|
||||
{
|
||||
auto data = fr.Read();
|
||||
P_LoadBloodMapWalls(data.data(), data.size(), lwalls);
|
||||
P_LoadBloodMapWalls(data.bytes(), data.size(), lwalls);
|
||||
return lwalls;
|
||||
}
|
||||
|
||||
|
|
|
@ -71,14 +71,14 @@ void FSavegameManager::ReadSaveStrings()
|
|||
FResourceFile *savegame = FResourceFile::OpenResourceFile(entry.FilePath.c_str(), true);
|
||||
if (savegame != nullptr)
|
||||
{
|
||||
FResourceLump *info = savegame->FindLump("info.json");
|
||||
if (info == nullptr)
|
||||
auto info = savegame->FindEntry("info.json");
|
||||
if (info < 0)
|
||||
{
|
||||
// savegame info not found. This is not a savegame so leave it alone.
|
||||
delete savegame;
|
||||
continue;
|
||||
}
|
||||
auto fr = info->NewReader();
|
||||
auto fr = savegame->GetEntryReader(info, true);
|
||||
FString title;
|
||||
int check = G_ValidateSavegame(fr, &title, true);
|
||||
fr.Close();
|
||||
|
|
|
@ -125,7 +125,7 @@ void paletteLoadFromDisk(void)
|
|||
unsigned length = numshades * 256;
|
||||
auto buffer = fil.Read(length);
|
||||
if (buffer.size() != length) return;
|
||||
lookups.setTable(0, buffer.data());
|
||||
lookups.setTable(0, buffer.bytes());
|
||||
|
||||
paletteloaded |= PALETTE_SHADE | PALETTE_TRANSLUC;
|
||||
}
|
||||
|
|
|
@ -89,10 +89,13 @@ void S_SetReverb(int strength)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
std::vector<uint8_t> RazeSoundEngine::ReadSound(int lumpnum)
|
||||
TArray<uint8_t> RazeSoundEngine::ReadSound(int lumpnum)
|
||||
{
|
||||
auto wlump = fileSystem.OpenFileReader(lumpnum);
|
||||
return wlump.Read();
|
||||
TArray<uint8_t> buffer(wlump.GetLength(), true);
|
||||
auto len = wlump.Read(buffer.data(), buffer.size());
|
||||
buffer.Resize(len);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -47,5 +47,5 @@ public:
|
|||
virtual bool SourceIsActor(FSoundChan* chan) { return chan->SourceType == SOURCE_Actor; }
|
||||
virtual int SoundSourceIndex(FSoundChan* chan) { return 0; }
|
||||
virtual void SetSource(FSoundChan* chan, int index) {}
|
||||
std::vector<uint8_t> ReadSound(int lumpnum) override;
|
||||
TArray<uint8_t> ReadSound(int lumpnum) override;
|
||||
};
|
||||
|
|
|
@ -136,13 +136,13 @@ bool ReadSavegame(const char* name)
|
|||
|
||||
if (savereader != nullptr)
|
||||
{
|
||||
auto lump = savereader->FindLump("info.json");
|
||||
if (!lump)
|
||||
auto lump = savereader->FindEntry("info.json");
|
||||
if (lump < 0)
|
||||
{
|
||||
delete savereader;
|
||||
return false;
|
||||
}
|
||||
auto file = lump->NewReader();
|
||||
auto file = savereader->GetEntryReader(lump);
|
||||
if (G_ValidateSavegame(file, nullptr, false) <= 0)
|
||||
{
|
||||
delete savereader;
|
||||
|
@ -150,18 +150,17 @@ bool ReadSavegame(const char* name)
|
|||
}
|
||||
file.Close();
|
||||
|
||||
auto info = savereader->FindLump("session.json");
|
||||
if (info == nullptr)
|
||||
auto info = savereader->FindEntry("session.json");
|
||||
if (info < 0)
|
||||
{
|
||||
delete savereader;
|
||||
return false;
|
||||
}
|
||||
|
||||
void* data = info->Lock();
|
||||
auto data = savereader->Read(info);
|
||||
FRazeSerializer arc;
|
||||
if (!arc.OpenReader((const char*)data, info->LumpSize))
|
||||
if (!arc.OpenReader(data.string(), data.size()))
|
||||
{
|
||||
info->Unlock();
|
||||
delete savereader;
|
||||
return false;
|
||||
}
|
||||
|
@ -171,7 +170,6 @@ bool ReadSavegame(const char* name)
|
|||
SerializeSession(arc);
|
||||
g_nextskill = gi->GetCurrentSkill();
|
||||
arc.Close();
|
||||
info->Unlock();
|
||||
delete savereader;
|
||||
|
||||
// this can only be done after the load is complete
|
||||
|
@ -247,7 +245,7 @@ bool WriteSavegame(const char* filename, const char *name)
|
|||
M_FinishPNG(&savepic);
|
||||
|
||||
auto picdata = savepic.GetBuffer();
|
||||
FileSys::FCompressedBuffer bufpng = { picdata->Size(), picdata->Size(), FileSys::METHOD_STORED, 0, static_cast<unsigned int>(crc32(0, &(*picdata)[0], picdata->Size())), (char*)&(*picdata)[0] };
|
||||
FileSys::FCompressedBuffer bufpng = { picdata->size(), picdata->size(), FileSys::METHOD_STORED, 0, static_cast<unsigned int>(crc32(0, &(*picdata)[0], picdata->size())), (char*)&(*picdata)[0] };
|
||||
|
||||
TArray<FileSys::FCompressedBuffer> savegame_content;
|
||||
TArray<FString> savegame_filenames;
|
||||
|
|
|
@ -628,10 +628,10 @@ TArray<GrpInfo> ParseAllGrpInfos(TArray<FileEntry>& filelist)
|
|||
engine_res.reset(FResourceFile::OpenResourceFile(baseres, true));
|
||||
if (engine_res)
|
||||
{
|
||||
auto basegrp = engine_res->FindLump("engine/grpinfo.txt");
|
||||
if (basegrp)
|
||||
auto basegrp = engine_res->FindEntry("engine/grpinfo.txt");
|
||||
if (basegrp >= 0)
|
||||
{
|
||||
auto fr = basegrp->NewReader();
|
||||
auto fr = engine_res->GetEntryReader(basegrp, true);
|
||||
if (fr.isOpen())
|
||||
{
|
||||
groups = ParseGrpInfo("engine/grpinfo.txt", fr, CRCMap);
|
||||
|
@ -787,7 +787,7 @@ TArray<GrpEntry> GrpScan()
|
|||
bool ok = true;
|
||||
for (auto &lump : grp->mustcontain)
|
||||
{
|
||||
if (!resf->FindLump(lump.GetChars()))
|
||||
if (resf->FindEntry(lump.GetChars()) < 0)
|
||||
{
|
||||
ok = false;
|
||||
break;
|
||||
|
|
|
@ -560,7 +560,7 @@ FStateLabels *FStateDefinitions::CreateStateLabelList(TArray<FStateDefine> & sta
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
void FStateDefinitions::InstallStates(PClassActor *info, AActor *defaults)
|
||||
void FStateDefinitions::InstallStates(PClassActor *info, DCoreActor *defaults)
|
||||
{
|
||||
if (defaults == nullptr)
|
||||
{
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
|
||||
#include "dobject.h"
|
||||
|
||||
class DCoreActor;
|
||||
struct Baggage;
|
||||
class FScanner;
|
||||
struct FActorInfo;
|
||||
|
@ -238,7 +239,7 @@ public:
|
|||
void SetStateLabel(const char *statename, FState *state, uint8_t defflags = SDF_STATE);
|
||||
void AddStateLabel(const char *statename);
|
||||
int GetStateLabelIndex (FName statename);
|
||||
void InstallStates(PClassActor *info, AActor *defaults);
|
||||
void InstallStates(PClassActor *info, DCoreActor *defaults);
|
||||
int FinishStates(PClassActor *actor);
|
||||
|
||||
void MakeStateDefines(const PClassActor *cls);
|
||||
|
|
|
@ -613,11 +613,11 @@ void dbLoadMap(const char* pPath, DVector3& pos, short* pAngle, sectortype** cur
|
|||
fr.Seek(0, FileReader::SeekSet);
|
||||
auto buffer = fr.Read();
|
||||
uint8_t md4[16];
|
||||
md4once(buffer.data(), (unsigned)buffer.size(), md4);
|
||||
md4once(buffer.bytes(), (unsigned)buffer.size(), md4);
|
||||
PostProcessLevel(md4, mapname, sprites);
|
||||
loadMapHack(mapname.GetChars(), md4, sprites);
|
||||
|
||||
if (CalcCRC32(buffer.data(), (unsigned)buffer.size() - 4) != nCRC)
|
||||
if (CalcCRC32(buffer.bytes(), (unsigned)buffer.size() - 4) != nCRC)
|
||||
{
|
||||
I_Error("%s: Map File does not match CRC", mapname.GetChars());
|
||||
}
|
||||
|
|
|
@ -144,7 +144,7 @@ public:
|
|||
auto wbuffer = audio.samples + audio.nWrite * kSampleSize;
|
||||
for (int i = 0; i < 2205; i++)
|
||||
{
|
||||
wbuffer[i] = (buffer[i] - 128) << 8;
|
||||
wbuffer[i] = (buffer.bytes()[i] - 128) << 8;
|
||||
}
|
||||
audio.nWrite++;
|
||||
if (audio.nWrite >= numAudioBlocks) audio.nWrite = 0;
|
||||
|
|
|
@ -67,26 +67,25 @@ static bool tokenready; // only true if UnGetToken was ju
|
|||
==============
|
||||
*/
|
||||
|
||||
std::vector<uint8_t> LoadScriptFile(const char *filename)
|
||||
TArray<uint8_t> LoadScriptFile(const char *filename)
|
||||
{
|
||||
TArray<uint8_t> ret;
|
||||
FileReader fp;
|
||||
|
||||
if (!(fp = fileSystem.OpenFileReader(filename)).isOpen())
|
||||
{
|
||||
// If there's no script file, forget it.
|
||||
return std::vector<uint8_t>();
|
||||
return ret;
|
||||
}
|
||||
|
||||
auto scriptbuffer = fp.Read();
|
||||
|
||||
if (scriptbuffer.size() != 0)
|
||||
ret.Resize(fp.GetLength() + 1);
|
||||
if (fp.Read(ret.Data(), fp.GetLength()) < fp.GetLength())
|
||||
{
|
||||
scriptbuffer.push_back(0);
|
||||
scriptline = 1;
|
||||
endofscript = false;
|
||||
tokenready = false;
|
||||
}
|
||||
return scriptbuffer;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue