- backend sync from gzdoom

This commit is contained in:
Rachael Alexanderson 2024-04-17 14:51:13 -04:00
parent 68ccf7a1c4
commit 090973f8d7
No known key found for this signature in database
GPG key ID: 26A8ACCE97115EE0
31 changed files with 707 additions and 243 deletions

View file

@ -1826,6 +1826,7 @@ void S_SetSoundPaused(int state)
if ((state || i_soundinbackground) && !pauseext)
{
if (!paused)
S_ResumeSound(true);
if (GSnd != nullptr)
{

View file

@ -822,9 +822,4 @@ bool FRemapTable::AddColors(int start, int count, const uint8_t*colors, int tran
}
// placeholder
FTranslationID R_FindCustomTranslation(FName name)
{
return NO_TRANSLATION;
}

View file

@ -294,6 +294,21 @@ bool FSerializer::BeginObject(const char *name)
//
//==========================================================================
bool FSerializer::HasKey(const char* name)
{
if (isReading())
{
return r->FindKey(name) != nullptr;
}
return false;
}
//==========================================================================
//
//
//
//==========================================================================
bool FSerializer::HasObject(const char* name)
{
if (isReading())

View file

@ -91,6 +91,7 @@ public:
void ReadObjects(bool hubtravel);
bool BeginObject(const char *name);
void EndObject();
bool HasKey(const char* name);
bool HasObject(const char* name);
bool BeginArray(const char *name);
void EndArray();
@ -245,6 +246,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundI
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 &mo, struct ModelOverride *def);
FSerializer &Serialize(FSerializer &arc, const char *key, struct AnimModelOverride &mo, struct AnimModelOverride *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);
@ -259,6 +261,16 @@ FSerializer &Serialize(FSerializer &arc, const char *key, T *&value, T **)
return arc;
}
template<class A, class B>
FSerializer &Serialize(FSerializer &arc, const char *key, std::pair<A, B> &value, std::pair<A, B> *def)
{
arc.BeginObject(key);
Serialize(arc, "first", value.first, def ? &def->first : nullptr);
Serialize(arc, "second", value.second, def ? &def->second : nullptr);
arc.EndObject();
return arc;
}
template<class T, class TT>
FSerializer &Serialize(FSerializer &arc, const char *key, TArray<T, TT> &value, TArray<T, TT> *def)
{

View file

@ -985,6 +985,7 @@ bool OpenDecompressor(FileReader& self, FileReader &parent, FileReader::Size len
// read everything into a MemoryArrayReader.
FileData data(nullptr, length);
fr->Read(data.writable(), length);
delete fr;
fr = new MemoryArrayReader(data);
}
else if ((flags & DCF_SEEKABLE))

View file

@ -36,6 +36,18 @@
#include <string.h>
#include <vector>
#ifndef _WIN32
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>
#include <fnmatch.h>
#include <sys/stat.h>
#include <dirent.h>
#endif
namespace FileSys {
enum
@ -63,14 +75,6 @@ enum
#ifndef _WIN32
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>
#include <fnmatch.h>
#include <sys/stat.h>
#include <dirent.h>
struct findstate_t
{
std::string path;

View file

@ -43,8 +43,6 @@
#include "texturemanager.h"
#include "modelrenderer.h"
TArray<FString> savedModelFiles;
TDeletingArray<FModel*> Models;
TArray<FSpriteModelFrame> SpriteModelFrames;
TMap<void*, FSpriteModelFrame> BaseSpriteModelFrames;
@ -160,7 +158,7 @@ unsigned FindModel(const char * path, const char * modelfile, bool silent)
for(unsigned i = 0; i< Models.Size(); i++)
{
if (!Models[i]->mFileName.CompareNoCase(fullname)) return i;
if (Models[i]->mFileName.CompareNoCase(fullname) == 0) return i;
}
auto len = fileSystem.FileLength(lump);
@ -236,6 +234,7 @@ unsigned FindModel(const char * path, const char * modelfile, bool silent)
}
// The vertex buffer cannot be initialized here because this gets called before OpenGL is initialized
model->mFileName = fullname;
model->mFilePath = {path, modelfile};
return Models.Push(model);
}

View file

@ -18,7 +18,7 @@ struct FSpriteModelFrame;
FTextureID LoadSkin(const char* path, const char* fn);
void FlushModels();
extern TArray<FString> savedModelFiles;
extern TDeletingArray<FModel*> Models;
extern TArray<FSpriteModelFrame> SpriteModelFrames;
extern TMap<void*, FSpriteModelFrame> BaseSpriteModelFrames;
@ -76,6 +76,7 @@ enum EFrameError
class FModel
{
public:
FModel();
virtual ~FModel();
@ -100,7 +101,9 @@ public:
void DestroyVertexBuffer();
bool hasSurfaces = false;
FString mFileName;
std::pair<FString, FString> mFilePath;
FSpriteModelFrame *baseFrame;
private:

View file

@ -164,6 +164,7 @@ FVoxel *R_LoadKVX(int lumpnum)
auto lump = fileSystem.ReadFile(lumpnum); // FileData adds an extra 0 byte to the end.
auto rawvoxel = lump.bytes();
int voxelsize = (int)(lump.size());
if (voxelsize <= 768 + 4) return nullptr;
// Oh, KVX, why couldn't you have a proper header? We'll just go through
// and collect each MIP level, doing lots of range checking, and if the

View file

@ -359,54 +359,49 @@ size_t DObject::PropagateMark()
const PClass *info = GetClass();
if (!PClass::bShutdown)
{
const size_t *offsets = info->FlatPointers;
if (offsets == NULL)
if (info->FlatPointers == nullptr)
{
const_cast<PClass *>(info)->BuildFlatPointers();
offsets = info->FlatPointers;
}
while (*offsets != ~(size_t)0)
{
GC::Mark((DObject **)((uint8_t *)this + *offsets));
offsets++;
info->BuildFlatPointers();
assert(info->FlatPointers);
}
offsets = info->ArrayPointers;
if (offsets == NULL)
for(size_t i = 0; i < info->FlatPointersSize; i++)
{
const_cast<PClass *>(info)->BuildArrayPointers();
offsets = info->ArrayPointers;
GC::Mark((DObject **)((uint8_t *)this + info->FlatPointers[i].first));
}
while (*offsets != ~(size_t)0)
if (info->ArrayPointers == nullptr)
{
auto aray = (TArray<DObject*>*)((uint8_t *)this + *offsets);
info->BuildArrayPointers();
assert(info->ArrayPointers);
}
for(size_t i = 0; i < info->ArrayPointersSize; i++)
{
auto aray = (TArray<DObject*>*)((uint8_t *)this + info->ArrayPointers[i].first);
for (auto &p : *aray)
{
GC::Mark(&p);
}
offsets++;
}
if (info->MapPointers == nullptr)
{
const std::pair<size_t,PType *> *maps = info->MapPointers;
if (maps == NULL)
{
const_cast<PClass *>(info)->BuildMapPointers();
maps = info->MapPointers;
info->BuildMapPointers();
assert(info->MapPointers);
}
while (maps->first != ~(size_t)0)
for(size_t i = 0; i < info->MapPointersSize; i++)
{
if(maps->second->RegType == REGT_STRING)
PMap * type = static_cast<PMap*>(info->MapPointers[i].second);
if(type->KeyType->RegType == REGT_STRING)
{ // FString,DObject*
PropagateMarkMap((ZSMap<FString,DObject*>*)((uint8_t *)this + maps->first));
PropagateMarkMap((ZSMap<FString,DObject*>*)((uint8_t *)this + info->MapPointers[i].first));
}
else
{ // uint32_t,DObject*
PropagateMarkMap((ZSMap<uint32_t,DObject*>*)((uint8_t *)this + maps->first));
PropagateMarkMap((ZSMap<uint32_t,DObject*>*)((uint8_t *)this + info->MapPointers[i].first));
}
maps++;
}
}
return info->Size;
}
@ -419,46 +414,116 @@ size_t DObject::PropagateMark()
//
//==========================================================================
size_t DObject::PointerSubstitution (DObject *old, DObject *notOld)
template<typename M>
static void MapPointerSubstitution(M *map, size_t &changed, DObject *old, DObject *notOld, const bool shouldSwap)
{
const PClass *info = GetClass();
const size_t *offsets = info->FlatPointers;
size_t changed = 0;
if (offsets == NULL)
TMapIterator<typename M::KeyType, DObject*> it(*map);
typename M::Pair * p;
while(it.NextPair(p))
{
const_cast<PClass *>(info)->BuildFlatPointers();
offsets = info->FlatPointers;
}
while (*offsets != ~(size_t)0)
if (p->Value == old)
{
if (*(DObject **)((uint8_t *)this + *offsets) == old)
if (shouldSwap)
{
*(DObject **)((uint8_t *)this + *offsets) = notOld;
p->Value = notOld;
changed++;
}
offsets++;
else if (p->Value != nullptr)
{
p->Value = nullptr;
changed++;
}
}
}
}
size_t DObject::PointerSubstitution (DObject *old, DObject *notOld, bool nullOnFail)
{
const PClass *info = GetClass();
size_t changed = 0;
if (info->FlatPointers == nullptr)
{
info->BuildFlatPointers();
assert(info->FlatPointers);
}
offsets = info->ArrayPointers;
if (offsets == NULL)
for(size_t i = 0; i < info->FlatPointersSize; i++)
{
const_cast<PClass *>(info)->BuildArrayPointers();
offsets = info->ArrayPointers;
size_t offset = info->FlatPointers[i].first;
auto& obj = *(DObject**)((uint8_t*)this + offset);
if (obj == old)
{
// If a pointer's type is null, that means it's native and anything native is safe to swap
// around due to its inherit type expansiveness.
if (info->FlatPointers[i].second == nullptr || notOld->IsKindOf(info->FlatPointers[i].second->PointedClass()))
{
obj = notOld;
changed++;
}
while (*offsets != ~(size_t)0)
else if (nullOnFail && obj != nullptr)
{
auto aray = (TArray<DObject*>*)((uint8_t *)this + *offsets);
obj = nullptr;
changed++;
}
}
}
if (info->ArrayPointers == nullptr)
{
info->BuildArrayPointers();
assert(info->ArrayPointers);
}
for(size_t i = 0; i < info->ArrayPointersSize; i++)
{
const bool isType = notOld->IsKindOf(static_cast<PObjectPointer*>(info->ArrayPointers[i].second->ElementType)->PointedClass());
if (!isType && !nullOnFail)
continue;
auto aray = (TArray<DObject*>*)((uint8_t*)this + info->ArrayPointers[i].first);
for (auto &p : *aray)
{
if (p == old)
{
if (isType)
{
p = notOld;
changed++;
}
else if (p != nullptr)
{
p = nullptr;
changed++;
}
}
}
offsets++;
}
if (info->MapPointers == nullptr)
{
info->BuildMapPointers();
assert(info->MapPointers);
}
for(size_t i = 0; i < info->MapPointersSize; i++)
{
PMap * type = static_cast<PMap*>(info->MapPointers[i].second);
const bool isType = notOld->IsKindOf(static_cast<PObjectPointer*>(type->ValueType)->PointedClass());
if (!isType && !nullOnFail)
continue;
if(type->KeyType->RegType == REGT_STRING)
{ // FString,DObject*
MapPointerSubstitution((ZSMap<FString,DObject*>*)((uint8_t *)this + info->MapPointers[i].first), changed, old, notOld, isType);
}
else
{ // uint32_t,DObject*
MapPointerSubstitution((ZSMap<uint32_t,DObject*>*)((uint8_t *)this + info->MapPointers[i].first), changed, old, notOld, isType);
}
}
return changed;
}

View file

@ -246,7 +246,7 @@ public:
inline int* IntArray(FName field);
// This is only needed for swapping out PlayerPawns and absolutely nothing else!
virtual size_t PointerSubstitution (DObject *old, DObject *notOld);
virtual size_t PointerSubstitution (DObject *old, DObject *notOld, bool nullOnFail);
PClass *GetClass() const
{

View file

@ -214,6 +214,9 @@ class TObjPtr
mutable DObject *o;
};
public:
TObjPtr() = default;
TObjPtr(T t) : pp(t) {}
constexpr TObjPtr<T>& operator=(T q) noexcept
{

View file

@ -80,9 +80,7 @@ DEFINE_GLOBAL(WP_NOCHANGE);
// PRIVATE DATA DEFINITIONS ------------------------------------------------
// A harmless non-nullptr FlatPointer for classes without pointers.
static const size_t TheEnd = ~(size_t)0;
static const std::pair<size_t,PType *> TheMapEnd = {~(size_t)0 , nullptr};
static const std::pair<size_t,PType *> TheEnd = {~(size_t)0 , nullptr};
//==========================================================================
//
@ -669,7 +667,7 @@ PClass *PClass::FindClassTentative(FName name)
//
//==========================================================================
int PClass::FindVirtualIndex(FName name, PFunction::Variant *variant, PFunction *parentfunc, bool exactReturnType)
int PClass::FindVirtualIndex(FName name, PFunction::Variant *variant, PFunction *parentfunc, bool exactReturnType, bool ignorePointerReadOnly)
{
auto proto = variant->Proto;
for (unsigned i = 0; i < Virtuals.Size(); i++)
@ -688,11 +686,25 @@ int PClass::FindVirtualIndex(FName name, PFunction::Variant *variant, PFunction
for (unsigned a = 1; a < proto->ArgumentTypes.Size(); a++)
{
if (proto->ArgumentTypes[a] != vproto->ArgumentTypes[a])
{
if(ignorePointerReadOnly && proto->ArgumentTypes[a]->isPointer() && vproto->ArgumentTypes[a]->isPointer())
{
PPointer *ppa = proto->ArgumentTypes[a]->toPointer();
PPointer *ppb = vproto->ArgumentTypes[a]->toPointer();
if(ppa->PointedType != ppb->PointedType)
{
fail = true;
break;
}
}
else
{
fail = true;
break;
}
}
}
if (fail) continue;
for (unsigned a = 0; a < proto->ReturnTypes.Size(); a++)
@ -752,28 +764,46 @@ PSymbol *PClass::FindSymbol(FName symname, bool searchparents) const
//
//==========================================================================
void PClass::BuildFlatPointers ()
void PClass::BuildFlatPointers() const
{
using pairType = std::pair<size_t, PObjectPointer *>;
if (FlatPointers != nullptr)
{ // Already built: Do nothing.
return;
}
else if (ParentClass == nullptr)
{ // No parent (i.e. DObject: FlatPointers is the same as Pointers.
if (Pointers == nullptr)
{ // No pointers: Make FlatPointers a harmless non-nullptr.
FlatPointers = &TheEnd;
}
else
{
FlatPointers = Pointers;
}
}
else
TArray<pairType> NativePointers;
if (Pointers != nullptr)
{
ParentClass->BuildFlatPointers ();
for (size_t i = 0; Pointers[i] != ~(size_t)0; i++)
{
NativePointers.Push({Pointers[i], nullptr}); // native pointers have a null type
}
}
TArray<size_t> ScriptPointers;
if (ParentClass == nullptr)
{ // No parent (i.e. DObject): FlatPointers is the same as Pointers.
if (NativePointers.Size() == 0)
{ // No pointers: Make FlatPointers a harmless non-nullptr.
FlatPointers = (pairType*)(&TheEnd);
FlatPointersSize = 0;
}
else
{
pairType *flat = (pairType*)ClassDataAllocator.Alloc(sizeof(pairType) * NativePointers.Size());
memcpy(flat, NativePointers.Data(), sizeof(pairType) * NativePointers.Size());
FlatPointers = flat;
FlatPointersSize = NativePointers.Size();
}
}
else
{
ParentClass->BuildFlatPointers();
TArray<pairType> ScriptPointers;
// Collect all pointers in scripted fields. These are not part of the Pointers list.
for (auto field : Fields)
@ -784,43 +814,31 @@ void PClass::BuildFlatPointers ()
}
}
if (Pointers == nullptr && ScriptPointers.Size() == 0)
if (NativePointers.Size() == 0 && ScriptPointers.Size() == 0)
{ // No new pointers: Just use the same FlatPointers as the parent.
FlatPointers = ParentClass->FlatPointers;
FlatPointersSize = ParentClass->FlatPointersSize;
}
else
{ // New pointers: Create a new FlatPointers array and add them.
int numPointers, numSuperPointers;
if (Pointers != nullptr)
{
// Count pointers defined by this class.
for (numPointers = 0; Pointers[numPointers] != ~(size_t)0; numPointers++)
{
}
}
else numPointers = 0;
// Count pointers defined by superclasses.
for (numSuperPointers = 0; ParentClass->FlatPointers[numSuperPointers] != ~(size_t)0; numSuperPointers++)
{ }
// Concatenate them into a new array
size_t *flat = (size_t*)ClassDataAllocator.Alloc(sizeof(size_t) * (numPointers + numSuperPointers + ScriptPointers.Size() + 1));
if (numSuperPointers > 0)
pairType *flat = (pairType*)ClassDataAllocator.Alloc(sizeof(pairType) * (ParentClass->FlatPointersSize + NativePointers.Size() + ScriptPointers.Size()));
if (ParentClass->FlatPointersSize > 0)
{
memcpy (flat, ParentClass->FlatPointers, sizeof(size_t)*numSuperPointers);
memcpy (flat, ParentClass->FlatPointers, sizeof(pairType) * ParentClass->FlatPointersSize);
}
if (numPointers > 0)
if (NativePointers.Size() > 0)
{
memcpy(flat + numSuperPointers, Pointers, sizeof(size_t)*numPointers);
memcpy(flat + ParentClass->FlatPointersSize, NativePointers.Data(), sizeof(pairType) * NativePointers.Size());
}
if (ScriptPointers.Size() > 0)
{
memcpy(flat + numSuperPointers + numPointers, &ScriptPointers[0], sizeof(size_t) * ScriptPointers.Size());
memcpy(flat + ParentClass->FlatPointersSize + NativePointers.Size(), &ScriptPointers[0], sizeof(pairType) * ScriptPointers.Size());
}
flat[numSuperPointers + numPointers + ScriptPointers.Size()] = ~(size_t)0;
FlatPointers = flat;
FlatPointersSize = ParentClass->FlatPointersSize + NativePointers.Size() + ScriptPointers.Size();
}
}
}
}
@ -833,21 +851,24 @@ void PClass::BuildFlatPointers ()
//
//==========================================================================
void PClass::BuildArrayPointers()
void PClass::BuildArrayPointers() const
{
using pairType = std::pair<size_t, PDynArray *>;
if (ArrayPointers != nullptr)
{ // Already built: Do nothing.
return;
}
else if (ParentClass == nullptr)
{ // No parent (i.e. DObject: FlatPointers is the same as Pointers.
ArrayPointers = &TheEnd;
{ // No parent (i.e. DObject): Make ArrayPointers a harmless non-nullptr.
ArrayPointers = (pairType*)(&TheEnd);
ArrayPointersSize = 0;
}
else
{
ParentClass->BuildArrayPointers();
TArray<size_t> ScriptPointers;
TArray<pairType> ScriptPointers;
// Collect all arrays to pointers in scripted fields.
for (auto field : Fields)
@ -861,28 +882,24 @@ void PClass::BuildArrayPointers()
if (ScriptPointers.Size() == 0)
{ // No new pointers: Just use the same ArrayPointers as the parent.
ArrayPointers = ParentClass->ArrayPointers;
ArrayPointersSize = ParentClass->ArrayPointersSize;
}
else
{ // New pointers: Create a new FlatPointers array and add them.
int numSuperPointers;
// Count pointers defined by superclasses.
for (numSuperPointers = 0; ParentClass->ArrayPointers[numSuperPointers] != ~(size_t)0; numSuperPointers++)
{
}
{ // New pointers: Create a new ArrayPointers array and add them.
// Concatenate them into a new array
size_t *flat = (size_t*)ClassDataAllocator.Alloc(sizeof(size_t) * (numSuperPointers + ScriptPointers.Size() + 1));
if (numSuperPointers > 0)
pairType *flat = (pairType*)ClassDataAllocator.Alloc(sizeof(pairType) * (ParentClass->ArrayPointersSize + ScriptPointers.Size()));
if (ParentClass->ArrayPointersSize > 0)
{
memcpy(flat, ParentClass->ArrayPointers, sizeof(size_t)*numSuperPointers);
memcpy(flat, ParentClass->ArrayPointers, sizeof(pairType) * ParentClass->ArrayPointersSize);
}
if (ScriptPointers.Size() > 0)
{
memcpy(flat + numSuperPointers, &ScriptPointers[0], sizeof(size_t) * ScriptPointers.Size());
memcpy(flat + ParentClass->ArrayPointersSize, ScriptPointers.Data(), sizeof(pairType) * ScriptPointers.Size());
}
flat[numSuperPointers + ScriptPointers.Size()] = ~(size_t)0;
ArrayPointers = flat;
ArrayPointersSize = ParentClass->ArrayPointersSize + ScriptPointers.Size();
}
}
}
@ -895,21 +912,24 @@ void PClass::BuildArrayPointers()
//
//==========================================================================
void PClass::BuildMapPointers()
void PClass::BuildMapPointers() const
{
using pairType = std::pair<size_t, PMap *>;
if (MapPointers != nullptr)
{ // Already built: Do nothing.
return;
}
else if (ParentClass == nullptr)
{ // No parent (i.e. DObject: FlatPointers is the same as Pointers.
MapPointers = &TheMapEnd;
{ // No parent (i.e. DObject): Make MapPointers a harmless non-nullptr.
MapPointers = (pairType*)(&TheEnd);
MapPointersSize = 0;
}
else
{
ParentClass->BuildMapPointers();
TArray<std::pair<size_t,PType *>> ScriptPointers;
TArray<pairType> ScriptPointers;
// Collect all arrays to pointers in scripted fields.
for (auto field : Fields)
@ -923,28 +943,23 @@ void PClass::BuildMapPointers()
if (ScriptPointers.Size() == 0)
{ // No new pointers: Just use the same ArrayPointers as the parent.
MapPointers = ParentClass->MapPointers;
MapPointersSize = ParentClass->MapPointersSize;
}
else
{ // New pointers: Create a new FlatPointers array and add them.
int numSuperPointers;
// Count pointers defined by superclasses.
for (numSuperPointers = 0; ParentClass->MapPointers[numSuperPointers].first != ~(size_t)0; numSuperPointers++)
{
}
// Concatenate them into a new array
std::pair<size_t,PType *> *flat = (std::pair<size_t,PType *>*)ClassDataAllocator.Alloc(sizeof(std::pair<size_t,PType *>) * (numSuperPointers + ScriptPointers.Size() + 1));
if (numSuperPointers > 0)
pairType *flat = (pairType*)ClassDataAllocator.Alloc(sizeof(pairType) * (ParentClass->MapPointersSize + ScriptPointers.Size()));
if (ParentClass->MapPointersSize > 0)
{
memcpy(flat, ParentClass->MapPointers, sizeof(std::pair<size_t,PType *>)*numSuperPointers);
memcpy(flat, ParentClass->MapPointers, sizeof(pairType) * ParentClass->MapPointersSize);
}
if (ScriptPointers.Size() > 0)
{
memcpy(flat + numSuperPointers, &ScriptPointers[0], sizeof(std::pair<size_t,PType *>) * ScriptPointers.Size());
memcpy(flat + ParentClass->MapPointersSize, ScriptPointers.Data(), sizeof(pairType) * ScriptPointers.Size());
}
flat[numSuperPointers + ScriptPointers.Size()] = TheMapEnd;
MapPointers = flat;
MapPointersSize = ParentClass->MapPointersSize + ScriptPointers.Size();
}
}
}

View file

@ -27,6 +27,9 @@ class PClassType;
struct FNamespaceManager;
class PSymbol;
class PField;
class PObjectPointer;
class PDynArray;
class PMap;
enum
{
@ -43,7 +46,7 @@ public:
void InitializeSpecials(void* addr, void* defaults, TArray<FTypeAndOffset> PClass::* Inits);
void WriteAllFields(FSerializer &ar, const void *addr) const;
bool ReadAllFields(FSerializer &ar, void *addr) const;
int FindVirtualIndex(FName name, PFunction::Variant *variant, PFunction *parentfunc, bool exactReturnType);
int FindVirtualIndex(FName name, PFunction::Variant *variant, PFunction *parentfunc, bool exactReturnType, bool ignorePointerReadOnly);
PSymbol *FindSymbol(FName symname, bool searchparents) const;
PField *AddField(FName name, PType *type, uint32_t flags, int fileno = 0);
void InitializeDefaults();
@ -53,10 +56,15 @@ public:
// Per-class information -------------------------------------
PClass *ParentClass = nullptr; // the class this class derives from
const size_t *Pointers = nullptr; // object pointers defined by this class *only*
const size_t *FlatPointers = nullptr; // object pointers defined by this class and all its superclasses; not initialized by default
const size_t *ArrayPointers = nullptr; // dynamic arrays containing object pointers.
const std::pair<size_t,PType *> *MapPointers = nullptr; // maps containing object pointers.
const size_t * Pointers = nullptr; // native object pointers defined by this class *only*
mutable size_t FlatPointersSize = 0;
mutable const std::pair<size_t, PObjectPointer*> * FlatPointers = nullptr; // object pointers defined by this class and all its superclasses; not initialized by default.
mutable size_t ArrayPointersSize = 0;
mutable const std::pair<size_t, PDynArray *> * ArrayPointers = nullptr; // dynamic arrays containing object pointers.
mutable size_t MapPointersSize = 0;
mutable const std::pair<size_t, PMap *> * MapPointers = nullptr; // maps containing object pointers.
uint8_t *Defaults = nullptr;
uint8_t *Meta = nullptr; // Per-class static script data
unsigned Size = sizeof(DObject);
@ -86,9 +94,11 @@ public:
PClass *CreateDerivedClass(FName name, unsigned int size, bool *newlycreated = nullptr, int fileno = 0);
void InitializeActorInfo();
void BuildFlatPointers();
void BuildArrayPointers();
void BuildMapPointers();
void BuildFlatPointers() const;
void BuildArrayPointers() const;
void BuildMapPointers() const;
void DestroySpecials(void *addr);
void DestroyMeta(void *addr);
const PClass *NativeClass() const;

View file

@ -32,6 +32,7 @@
*/
#include "i_common.h"
#include "c_cvars.h"
#include <fnmatch.h>
#include <sys/sysctl.h>
@ -40,7 +41,7 @@
#include "st_console.h"
#include "v_text.h"
EXTERN_CVAR(Bool, longsavemessages)
double PerfToSec, PerfToMillisec;
void CalculateCPUSpeed()
@ -188,6 +189,7 @@ void I_OpenShellFolder(const char* folder)
NSString *currentpath = [filemgr currentDirectoryPath];
[filemgr changeCurrentDirectoryPath:[NSString stringWithUTF8String:folder]];
if (longsavemessages)
Printf("Opening folder: %s\n", folder);
std::system("open .");
[filemgr changeCurrentDirectoryPath:currentpath];

View file

@ -77,6 +77,7 @@ int I_PickIWad_Cocoa (WadStuff *wads, int numwads, bool showwin, int defaultiwad
double PerfToSec, PerfToMillisec;
CVAR(Bool, con_printansi, true, CVAR_GLOBALCONFIG|CVAR_ARCHIVE);
CVAR(Bool, con_4bitansi, false, CVAR_GLOBALCONFIG|CVAR_ARCHIVE);
EXTERN_CVAR(Bool, longsavemessages)
extern FStartupScreen *StartWindow;
@ -372,13 +373,17 @@ void I_OpenShellFolder(const char* infolder)
if (!chdir(infolder))
{
if (longsavemessages)
Printf("Opening folder: %s\n", infolder);
std::system("xdg-open .");
chdir(curdir);
}
else
{
if (longsavemessages)
Printf("Unable to open directory '%s\n", infolder);
else
Printf("Unable to open requested directory\n");
}
free(curdir);
}

View file

@ -95,8 +95,6 @@ CUSTOM_CVAR(Bool, gl_es, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCA
Printf("This won't take effect until " GAMENAME " is restarted.\n");
}
CVAR (Int, vid_adapter, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(String, vid_sdl_render_driver, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{
Printf("This won't take effect until " GAMENAME " is restarted.\n");
@ -120,29 +118,61 @@ namespace Priv
bool vulkanEnabled;
bool softpolyEnabled;
bool fullscreenSwitch;
int numberOfDisplays;
SDL_Rect* displayBounds = nullptr;
void updateDisplayInfo()
{
Priv::numberOfDisplays = SDL_GetNumVideoDisplays();
if (Priv::numberOfDisplays <= 0) {
Printf("%sWrong number of displays detected.\n", TEXTCOLOR_BOLD);
return;
}
Printf("Number of detected displays %d .\n", Priv::numberOfDisplays);
if (Priv::displayBounds != nullptr) {
free(Priv::displayBounds);
}
Priv::displayBounds = (SDL_Rect*) calloc(Priv::numberOfDisplays, sizeof(SDL_Rect));
for (int i=0; i < Priv::numberOfDisplays; i++) {
if (0 != SDL_GetDisplayBounds(i, &Priv::displayBounds[i])) {
Printf("%sError getting display %d size: %s\n", TEXTCOLOR_BOLD, i, SDL_GetError());
if (i == 0) {
free(Priv::displayBounds);
displayBounds = nullptr;
}
Priv::numberOfDisplays = i;
return;
}
}
}
void CreateWindow(uint32_t extraFlags)
{
assert(Priv::window == nullptr);
// Set default size
SDL_Rect bounds;
SDL_GetDisplayBounds(vid_adapter, &bounds);
// Get displays and default display size
updateDisplayInfo();
// TODO control better when updateDisplayInfo fails
SDL_Rect* bounds = &displayBounds[vid_adapter % numberOfDisplays];
if (win_w <= 0 || win_h <= 0)
{
win_w = bounds.w * 8 / 10;
win_h = bounds.h * 8 / 10;
win_w = bounds->w * 8 / 10;
win_h = bounds->h * 8 / 10;
}
int xWindowPos = (win_x <= 0) ? SDL_WINDOWPOS_CENTERED_DISPLAY(vid_adapter) : win_x;
int yWindowPos = (win_y <= 0) ? SDL_WINDOWPOS_CENTERED_DISPLAY(vid_adapter) : win_y;
Printf("Creating window [%dx%d] on adapter %d\n", (*win_w), (*win_h), (*vid_adapter));
FString caption;
caption.Format(GAMENAME " %s (%s)", GetVersionString(), GetGitTime());
const uint32_t windowFlags = (win_maximized ? SDL_WINDOW_MAXIMIZED : 0) | SDL_WINDOW_RESIZABLE | extraFlags;
Priv::window = SDL_CreateWindow(caption.GetChars(),
(win_x <= 0) ? SDL_WINDOWPOS_CENTERED_DISPLAY(vid_adapter) : win_x,
(win_y <= 0) ? SDL_WINDOWPOS_CENTERED_DISPLAY(vid_adapter) : win_y,
win_w, win_h, windowFlags);
Priv::window = SDL_CreateWindow(caption.GetChars(), xWindowPos, yWindowPos, win_w, win_h, windowFlags);
if (Priv::window != nullptr)
{
@ -159,6 +189,11 @@ namespace Priv
SDL_DestroyWindow(Priv::window);
Priv::window = nullptr;
if (Priv::displayBounds != nullptr) {
free(Priv::displayBounds);
Priv::displayBounds = nullptr;
}
}
void SetupPixelFormat(int multisample, const int *glver)
@ -194,12 +229,70 @@ namespace Priv
}
}
CUSTOM_CVAR(Int, vid_adapter, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{
if (Priv::window != nullptr) {
// Get displays and default display size
Priv::updateDisplayInfo();
int display = (*self) % Priv::numberOfDisplays;
// TODO control better when updateDisplayInfo fails
SDL_Rect* bounds = &Priv::displayBounds[vid_adapter % Priv::numberOfDisplays];
if (win_w <= 0 || win_h <= 0)
{
win_w = bounds->w * 8 / 10;
win_h = bounds->h * 8 / 10;
}
// Forces to set to the ini this vars to -1, so +vid_adapter keeps working the next time that the game it's launched
win_x = -1;
win_y = -1;
if ((SDL_GetWindowFlags(Priv::window) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0) {
// TODO This not works. For some reason keeps stuck on the previus screen
/*
SDL_DisplayMode currentDisplayMode;
SDL_GetWindowDisplayMode(Priv::window, &currentDisplayMode);
currentDisplayMode.w = win_w;
currentDisplayMode.h = win_h;
if ( 0 != SDL_SetWindowDisplayMode(Priv::window, &currentDisplayMode)) {
Printf("A problem occured trying to change of display %s\n", SDL_GetError());
}
*/
// TODO This workaround also isn't working
/*
SDL_SetWindowFullscreen(Priv::window, 0);
SDL_SetWindowSize(Priv::window, win_w, win_h);
SDL_SetWindowPosition(Priv::window, bounds->x , bounds->y);
SDL_SetWindowFullscreen(Priv::window, SDL_WINDOW_FULLSCREEN_DESKTOP);
*/
Printf("Changing adapter on fullscreen, isn't full supported by SDL. Instead try to switch to windowed mode, change the adapter and then switch again to fullscreen.\n");
} else {
SDL_SetWindowSize(Priv::window, win_w, win_h);
SDL_SetWindowPosition(Priv::window, SDL_WINDOWPOS_CENTERED_DISPLAY(display), SDL_WINDOWPOS_CENTERED_DISPLAY(display));
}
display = SDL_GetWindowDisplayIndex(Priv::window);
if (display >= 0) {
Printf("New display is %d\n", display );
} else {
Printf("A problem occured trying to change of display %s\n", SDL_GetError());
}
}
}
class SDLVideo : public IVideo
{
public:
SDLVideo ();
~SDLVideo ();
void DumpAdapters();
DFrameBuffer *CreateFrameBuffer ();
private:
@ -270,6 +363,22 @@ SDLVideo::~SDLVideo ()
#endif
}
void SDLVideo::DumpAdapters()
{
Priv::updateDisplayInfo();
for (int i=0; i < Priv::numberOfDisplays; i++) {
Printf("%s%d. [%dx%d @ (%d,%d)]\n",
vid_adapter == i ? TEXTCOLOR_BOLD : "",
i,
Priv::displayBounds[i].w,
Priv::displayBounds[i].h,
Priv::displayBounds[i].x,
Priv::displayBounds[i].y
);
}
}
DFrameBuffer *SDLVideo::CreateFrameBuffer ()
{
SystemBaseFrameBuffer *fb = nullptr;
@ -415,6 +524,7 @@ void SystemBaseFrameBuffer::SetWindowSize(int w, int h)
SDL_GetWindowPosition(Priv::window, &x, &y);
win_x = x;
win_y = y;
}
}

View file

@ -110,6 +110,8 @@ EXTERN_CVAR (Bool, use_mouse)
static int WheelDelta;
extern bool CursorState;
void SetCursorState(bool visible);
extern BOOL paused;
static bool noidle = false;
@ -415,7 +417,7 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
case WM_SETCURSOR:
if (!CursorState)
{
SetCursor(NULL); // turn off window cursor
SetCursorState(false); // turn off window cursor
return TRUE; // Prevent Windows from setting cursor to window class cursor
}
else

View file

@ -131,7 +131,7 @@ enum EMouseMode
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
static void SetCursorState(bool visible);
void SetCursorState(bool visible);
static FMouse *CreateWin32Mouse();
static FMouse *CreateDInputMouse();
static FMouse *CreateRawMouse();
@ -191,7 +191,7 @@ CUSTOM_CVAR (Int, in_mouse, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL)
static bool mouse_shown = true;
static void SetCursorState(bool visible)
void SetCursorState(bool visible)
{
CursorState = visible || !m_hidepointer;
if (GetForegroundWindow() == mainwindow.GetHandle())
@ -297,6 +297,12 @@ void I_CheckNativeMouse(bool preferNative, bool eventhandlerresult)
{
BlockMouseMove = 3;
Mouse->Ungrab();
if(!mouse_shown)
{
ShowCursor(true);
mouse_shown = true;
}
}
else
{

View file

@ -114,6 +114,7 @@ static HCURSOR CreateBitmapCursor(int xhot, int yhot, HBITMAP and_mask, HBITMAP
EXTERN_CVAR (Bool, queryiwad);
// Used on welcome/IWAD screen.
EXTERN_CVAR (Int, vid_preferbackend)
EXTERN_CVAR(Bool, longsavemessages)
extern HANDLE StdOut;
extern bool FancyStdOut;
@ -824,13 +825,17 @@ void I_OpenShellFolder(const char* infolder)
}
else if (SetCurrentDirectoryW(WideString(infolder).c_str()))
{
if (longsavemessages)
Printf("Opening folder: %s\n", infolder);
ShellExecuteW(NULL, L"open", L"explorer.exe", L".", NULL, SW_SHOWNORMAL);
SetCurrentDirectoryW(curdir.Data());
}
else
{
if (longsavemessages)
Printf("Unable to open directory '%s\n", infolder);
else
Printf("Unable to open requested directory\n");
}
}

View file

@ -81,7 +81,7 @@ CUSTOM_CVAR(Int, gl_pipeline_depth, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_N
Printf("Changing the pipeline depth requires a restart for " GAMENAME ".\n");
}
CUSTOM_CVAR(Int, vid_maxfps, 200, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Int, vid_maxfps, 500, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
{
if (self < GameTicRate && self != 0)
{

View file

@ -173,6 +173,7 @@ void VkCommandBufferManager::WaitForCommands(bool finish, bool uploadOnly)
if (finish)
{
if (!fb->GetVSync())
fb->FPSLimit();
fb->GetFramebufferManager()->QueuePresent();
}

View file

@ -291,23 +291,21 @@ bool AreCompatiblePointerTypes(PType *dest, PType *source, bool forcompare)
if (!forcompare && fromtype->IsConst && !totype->IsConst) return false;
// A type is always compatible to itself.
if (fromtype == totype) return true;
// Pointers to different types are only compatible if both point to an object and the source type is a child of the destination type.
if (source->isObjectPointer() && dest->isObjectPointer())
{
{ // Pointers to different types are only compatible if both point to an object and the source type is a child of the destination type.
auto fromcls = static_cast<PObjectPointer*>(source)->PointedClass();
auto tocls = static_cast<PObjectPointer*>(dest)->PointedClass();
if (forcompare && tocls->IsDescendantOf(fromcls)) return true;
return (fromcls->IsDescendantOf(tocls));
}
// The same rules apply to class pointers. A child type can be assigned to a variable of a parent type.
if (source->isClassPointer() && dest->isClassPointer())
{
else if (source->isClassPointer() && dest->isClassPointer())
{ // The same rules apply to class pointers. A child type can be assigned to a variable of a parent type.
auto fromcls = static_cast<PClassPointer*>(source)->ClassRestriction;
auto tocls = static_cast<PClassPointer*>(dest)->ClassRestriction;
if (forcompare && tocls->IsDescendantOf(fromcls)) return true;
return (fromcls->IsDescendantOf(tocls));
}
if(source->isFunctionPointer() && dest->isFunctionPointer())
else if(source->isFunctionPointer() && dest->isFunctionPointer())
{
auto from = static_cast<PFunctionPointer*>(source);
auto to = static_cast<PFunctionPointer*>(dest);
@ -315,6 +313,10 @@ bool AreCompatiblePointerTypes(PType *dest, PType *source, bool forcompare)
return to->PointedType == TypeVoid || (AreCompatibleFnPtrTypes((PPrototype *)to->PointedType, (PPrototype *)from->PointedType) && from->ArgFlags == to->ArgFlags && FScopeBarrier::CheckSidesForFunctionPointer(from->Scope, to->Scope));
}
else if(source->isRealPointer() && dest->isRealPointer())
{
return fromtype->PointedType == totype->PointedType;
}
}
return false;
}
@ -1940,6 +1942,12 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx)
{
bool writable;
basex->RequestAddress(ctx, &writable);
if(!writable && !ValueType->toPointer()->IsConst && ctx.Version >= MakeVersion(4, 12))
{
ScriptPosition.Message(MSG_ERROR, "Trying to assign readonly value to writable type.");
}
basex->ValueType = ValueType;
auto x = basex;
basex = nullptr;
@ -8739,6 +8747,12 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
if (Self->ValueType->isRealPointer())
{
auto pointedType = Self->ValueType->toPointer()->PointedType;
if(pointedType && pointedType->isStruct() && Self->ValueType->toPointer()->IsConst && ctx.Version >= MakeVersion(4, 12))
{
isreadonly = true;
}
if (pointedType && (pointedType->isDynArray() || pointedType->isMap() || pointedType->isMapIterator()))
{
Self = new FxOutVarDereference(Self, Self->ScriptPosition);
@ -9268,7 +9282,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
return nullptr;
}
}
else if (Self->ValueType->isStruct())
else if (Self->ValueType->isStruct() && !isreadonly)
{
bool writable;
@ -9528,6 +9542,8 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
auto &argflags = Function->Variants[0].ArgFlags;
auto *defaults = FnPtrCall ? nullptr : &Function->Variants[0].Implementation->DefaultArgs;
if(FnPtrCall) static_cast<VMScriptFunction*>(ctx.Function->Variants[0].Implementation)->blockJit = true;
int implicit = Function->GetImplicitArgs();
if (!CheckAccessibility(ctx.Version))

View file

@ -196,15 +196,15 @@ void PType::SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset>
//
//==========================================================================
void PType::SetPointer(void *base, unsigned offset, TArray<size_t> *stroffs)
void PType::SetPointer(void *base, unsigned offset, TArray<std::pair<size_t, PObjectPointer *>> *stroffs)
{
}
void PType::SetPointerArray(void *base, unsigned offset, TArray<size_t> *stroffs)
void PType::SetPointerArray(void *base, unsigned offset, TArray<std::pair<size_t, PDynArray *>> *stroffs)
{
}
void PType::SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t,PType *>> *ptrofs)
void PType::SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t, PMap *>> *ptrofs)
{
}
@ -1575,10 +1575,10 @@ PObjectPointer::PObjectPointer(PClass *cls, bool isconst)
//
//==========================================================================
void PObjectPointer::SetPointer(void *base, unsigned offset, TArray<size_t> *special)
void PObjectPointer::SetPointer(void *base, unsigned offset, TArray<std::pair<size_t, PObjectPointer *>> *special)
{
// Add to the list of pointers for this class.
special->Push(offset);
special->Push({offset, this});
}
//==========================================================================
@ -1706,7 +1706,7 @@ bool PClassPointer::isCompatible(PType *type)
//
//==========================================================================
void PClassPointer::SetPointer(void *base, unsigned offset, TArray<size_t> *special)
void PClassPointer::SetPointer(void *base, unsigned offset, TArray<std::pair<size_t, PObjectPointer *>> *special)
{
}
@ -1908,7 +1908,7 @@ void PArray::SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset>
//
//==========================================================================
void PArray::SetPointer(void *base, unsigned offset, TArray<size_t> *special)
void PArray::SetPointer(void *base, unsigned offset, TArray<std::pair<size_t, PObjectPointer *>> *special)
{
for (unsigned i = 0; i < ElementCount; ++i)
{
@ -1922,7 +1922,7 @@ void PArray::SetPointer(void *base, unsigned offset, TArray<size_t> *special)
//
//==========================================================================
void PArray::SetPointerArray(void *base, unsigned offset, TArray<size_t> *special)
void PArray::SetPointerArray(void *base, unsigned offset, TArray<std::pair<size_t, PDynArray *>> *special)
{
if (ElementType->isStruct() || ElementType->isDynArray())
{
@ -1939,7 +1939,7 @@ void PArray::SetPointerArray(void *base, unsigned offset, TArray<size_t> *specia
//
//==========================================================================
void PArray::SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t,PType *>> *special)
void PArray::SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t, PMap *>> *special)
{
if(ElementType->isStruct() || ElementType->isMap())
{
@ -2254,12 +2254,12 @@ void PDynArray::SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffs
//
//==========================================================================
void PDynArray::SetPointerArray(void *base, unsigned offset, TArray<size_t> *special)
void PDynArray::SetPointerArray(void *base, unsigned offset, TArray<std::pair<size_t, PDynArray *>> *special)
{
if (ElementType->isObjectPointer())
{
// Add to the list of pointer arrays for this class.
special->Push(offset);
special->Push({offset, this});
}
}
@ -2524,12 +2524,12 @@ void PMap::SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *
//
//==========================================================================
void PMap::SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t,PType *>> *special)
void PMap::SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t, PMap *>> *special)
{
if (ValueType->isObjectPointer())
{
// Add to the list of pointer arrays for this class.
special->Push(std::make_pair(offset,KeyType));
special->Push(std::make_pair(offset, this));
}
}
@ -3264,7 +3264,7 @@ void PStruct::SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset
//
//==========================================================================
void PStruct::SetPointer(void *base, unsigned offset, TArray<size_t> *special)
void PStruct::SetPointer(void *base, unsigned offset, TArray<std::pair<size_t, PObjectPointer *>> *special)
{
auto it = Symbols.GetIterator();
PSymbolTable::MapType::Pair *pair;
@ -3284,7 +3284,7 @@ void PStruct::SetPointer(void *base, unsigned offset, TArray<size_t> *special)
//
//==========================================================================
void PStruct::SetPointerArray(void *base, unsigned offset, TArray<size_t> *special)
void PStruct::SetPointerArray(void *base, unsigned offset, TArray<std::pair<size_t, PDynArray *>> *special)
{
auto it = Symbols.GetIterator();
PSymbolTable::MapType::Pair *pair;
@ -3304,7 +3304,7 @@ void PStruct::SetPointerArray(void *base, unsigned offset, TArray<size_t> *speci
//
//==========================================================================
void PStruct::SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t,PType *>> *special)
void PStruct::SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t, PMap *>> *special)
{
auto it = Symbols.GetIterator();
PSymbolTable::MapType::Pair *pair;

View file

@ -68,8 +68,11 @@ class PPointer;
class PClassPointer;
class PFunctionPointer;
class PArray;
class PDynArray;
class PMap;
class PStruct;
class PClassType;
class PObjectPointer;
struct ZCC_ExprConstant;
class PType : public PTypeBase
@ -129,9 +132,9 @@ public:
// initialization when the object is created and destruction when the
// object is destroyed.
virtual void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *special=NULL);
virtual void SetPointer(void *base, unsigned offset, TArray<size_t> *ptrofs = NULL);
virtual void SetPointerArray(void *base, unsigned offset, TArray<size_t> *ptrofs = NULL);
virtual void SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t,PType *>> *ptrofs = NULL);
virtual void SetPointer(void *base, unsigned offset, TArray<std::pair<size_t, PObjectPointer *>> *ptrofs = NULL);
virtual void SetPointerArray(void *base, unsigned offset, TArray<std::pair<size_t, PDynArray *>> *ptrofs = NULL);
virtual void SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t, PMap *>> *ptrofs = NULL);
// Initialize the value, if needed (e.g. strings)
virtual void InitializeValue(void *addr, const void *def) const;
@ -455,7 +458,7 @@ public:
void WriteValue(FSerializer &ar, const char *key, const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key, void *addr) const override;
void SetPointer(void *base, unsigned offset, TArray<size_t> *special = NULL) override;
void SetPointer(void *base, unsigned offset, TArray<std::pair<size_t, PObjectPointer *>> *special = NULL) override;
PClass *PointedClass() const;
};
@ -471,7 +474,7 @@ public:
void WriteValue(FSerializer &ar, const char *key, const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key, void *addr) const override;
void SetPointer(void *base, unsigned offset, TArray<size_t> *special = NULL) override;
void SetPointer(void *base, unsigned offset, TArray<std::pair<size_t, PObjectPointer *>> *special = NULL) override;
bool IsMatch(intptr_t id1, intptr_t id2) const override;
void GetTypeIDs(intptr_t &id1, intptr_t &id2) const override;
};
@ -503,9 +506,9 @@ public:
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *special) override;
void SetPointer(void *base, unsigned offset, TArray<size_t> *special) override;
void SetPointerArray(void *base, unsigned offset, TArray<size_t> *ptrofs = NULL) override;
void SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t,PType *>> *ptrofs = NULL) override;
void SetPointer(void *base, unsigned offset, TArray<std::pair<size_t, PObjectPointer *>> *special) override;
void SetPointerArray(void *base, unsigned offset, TArray<std::pair<size_t, PDynArray *>> *ptrofs = NULL) override;
void SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t, PMap *>> *ptrofs = NULL) override;
};
class PStaticArray : public PArray
@ -535,7 +538,7 @@ public:
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *specials) override;
void InitializeValue(void *addr, const void *def) const override;
void DestroyValue(void *addr) const override;
void SetPointerArray(void *base, unsigned offset, TArray<size_t> *ptrofs = NULL) override;
void SetPointerArray(void *base, unsigned offset, TArray<std::pair<size_t, PDynArray *>> *ptrofs = NULL) override;
};
class PMap : public PCompoundType
@ -579,7 +582,7 @@ public:
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *specials) override;
void InitializeValue(void *addr, const void *def) const override;
void DestroyValue(void *addr) const override;
void SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t,PType *>> *ptrofs) override;
void SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t, PMap *>> *ptrofs) override;
};
@ -653,9 +656,9 @@ public:
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *specials) override;
void SetPointer(void *base, unsigned offset, TArray<size_t> *specials) override;
void SetPointerArray(void *base, unsigned offset, TArray<size_t> *special) override;
void SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t,PType *>> *ptrofs) override;
void SetPointer(void *base, unsigned offset, TArray<std::pair<size_t, PObjectPointer *>> *specials) override;
void SetPointerArray(void *base, unsigned offset, TArray<std::pair<size_t, PDynArray *>> *special) override;
void SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t, PMap *>> *ptrofs) override;
};
class PPrototype : public PCompoundType

View file

@ -43,6 +43,11 @@
FSharedStringArena VMStringConstants;
static bool ShouldWrapPointer(PType * type)
{
return ((type->isStruct() && type != TypeVector2 && type != TypeVector3 && type != TypeVector4 && type != TypeQuaternion && type != TypeFVector2 && type != TypeFVector3 && type != TypeFVector4 && type != TypeFQuaternion) || type->isDynArray() || type->isMap() || type->isMapIterator());
}
int GetIntConst(FxExpression *ex, FCompileContext &ctx)
{
ex = new FxIntCast(ex, false);
@ -2049,8 +2054,17 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n
} while( (t = (ZCC_Type *)t->SiblingNext) != fn->RetType);
if(auto *t = fn->Params; t != nullptr) do {
args.Push(DetermineType(outertype, field, name, t->Type, false, false));
argflags.Push(t->Flags == ZCC_Out ? VARF_Out : 0);
PType * tt = DetermineType(outertype, field, name, t->Type, false, false);
int flags = 0;
if (ShouldWrapPointer(tt))
{
tt = NewPointer(tt);
flags = VARF_Ref;
}
args.Push(tt);
argflags.Push(t->Flags == ZCC_Out ? VARF_Out|flags : flags);
} while( (t = (ZCC_FuncPtrParamDecl *) t->SiblingNext) != fn->Params);
auto proto = NewPrototype(returns,args);
@ -2550,7 +2564,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
{
auto type = DetermineType(c->Type(), p, f->Name, p->Type, false, false);
int flags = 0;
if ((type->isStruct() && type != TypeVector2 && type != TypeVector3 && type != TypeVector4 && type != TypeQuaternion && type != TypeFVector2 && type != TypeFVector3 && type != TypeFVector4 && type != TypeFQuaternion) || type->isDynArray() || type->isMap() || type->isMapIterator())
if (ShouldWrapPointer(type))
{
// Structs are being passed by pointer, but unless marked 'out' that pointer must be readonly.
type = NewPointer(type /*, !(p->Flags & ZCC_Out)*/);
@ -2785,7 +2799,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
auto parentfunc = clstype->ParentClass? dyn_cast<PFunction>(clstype->ParentClass->VMType->Symbols.FindSymbol(sym->SymbolName, true)) : nullptr;
int virtindex = clstype->FindVirtualIndex(sym->SymbolName, &sym->Variants[0], parentfunc, exactReturnType);
int virtindex = clstype->FindVirtualIndex(sym->SymbolName, &sym->Variants[0], parentfunc, exactReturnType, sym->SymbolName == FName("SpecialBounceHit") && mVersion < MakeVersion(4, 12));
// specifying 'override' is necessary to prevent one of the biggest problem spots with virtual inheritance: Mismatching argument types.
if (varflags & VARF_Override)
{
@ -2867,7 +2881,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
}
else if (forclass)
{
int virtindex = clstype->FindVirtualIndex(sym->SymbolName, &sym->Variants[0], nullptr, exactReturnType);
int virtindex = clstype->FindVirtualIndex(sym->SymbolName, &sym->Variants[0], nullptr, exactReturnType, sym->SymbolName == FName("SpecialBounceHit") && mVersion < MakeVersion(4, 12));
if (virtindex != -1)
{
Error(f, "Function %s attempts to override parent function without 'override' qualifier", FName(f->Name).GetChars());

View file

@ -279,6 +279,8 @@ static bool CanJit(VMScriptFunction *func)
// Asmjit has a 256 register limit. Stay safely away from it as the jit compiler uses a few for temporaries as well.
// Any function exceeding the limit will use the VM - a fair punishment to someone for writing a function so bloated ;)
if(func->blockJit) return false;
int maxregs = 200;
if (func->NumRegA + func->NumRegD + func->NumRegF + func->NumRegS < maxregs)
return true;

View file

@ -474,6 +474,8 @@ public:
VM_UBYTE NumArgs; // Number of arguments this function takes
TArray<FTypeAndOffset> SpecialInits; // list of all contents on the extra stack which require construction and destruction
bool blockJit = false; // function triggers Jit bugs, block compilation until bugs are fixed
void InitExtra(void *addr);
void DestroyExtra(void *addr);
int AllocExtraStack(PType *type);

View file

@ -654,9 +654,11 @@ void FStartScreen::NetProgress(int count)
void FStartScreen::Render(bool force)
{
static uint64_t minwaittime = 30;
auto nowtime = I_msTime();
// Do not refresh too often. This function gets called a lot more frequently than the screen can update.
if (nowtime - screen->FrameTime > 30 || force)
if (nowtime - screen->FrameTime > minwaittime || force)
{
screen->FrameTime = nowtime;
screen->BeginFrame();
@ -689,6 +691,9 @@ void FStartScreen::Render(bool force)
screen->Update();
twod->OnFrameDone();
}
auto newtime = I_msTime();
if ((newtime - nowtime) * 2.0 > minwaittime) // slow down drawing the start screen if we're on a slow GPU!
minwaittime = (newtime - nowtime) * 2.0;
}
FImageSource* CreateStartScreenTexture(FBitmap& srcdata);

View file

@ -3,9 +3,9 @@
#include "tarray.h"
#include "hw_ihwtexture.h"
#include "palettecontainer.h"
#include "hw_ihwtexture.h" // Note: this cannot be a forward declaration due to the inlined delete statement below.
struct FTextureBuffer;
class IHardwareTexture;
enum ECreateTexBufferFlags
{
@ -34,7 +34,7 @@ private:
void Delete()
{
if (hwTexture) delete hwTexture;
delete hwTexture;
hwTexture = nullptr;
}
@ -148,11 +148,11 @@ public:
{
for (auto& tt : hwDefTex)
{
if (!tt.isMarkedForPreache()) tt.MarkForPrecache(false);
tt.MarkForPrecache(false);
}
for (auto& tt : hwTex_Translated)
{
if (!tt.isMarkedForPreache()) tt.MarkForPrecache(false);
tt.MarkForPrecache(false);
}
}

View file

@ -55,6 +55,7 @@
#include <utility>
#include <iterator>
#include <algorithm>
#include <functional>
#if !defined(_WIN32)
#include <inttypes.h> // for intptr_t
@ -355,6 +356,105 @@ public:
return i;
}
// !!! THIS REQUIRES AN ELEMENT TYPE THAT'S COMPARABLE WITH THE LT OPERATOR !!!
bool IsSorted()
{
for(unsigned i = 1; i < Count; i++)
{
if(Array[i] < Array[i-1]) return false;
}
return true;
}
template<typename Func>
bool IsSorted(Func &&lt)
{
for(unsigned i = 1; i < Count; i++)
{
if(std::invoke(lt, Array[i], Array[i-1])) return false;
}
return true;
}
// !!! THIS REQUIRES A SORTED OR EMPTY ARRAY !!!
// !!! AND AN ELEMENT TYPE THAT'S COMPARABLE WITH THE LT OPERATOR !!!
//
// exact = false returns the closest match, to be used for, ex., insertions, exact = true returns Size() when no match, like Find does
unsigned int SortedFind(const T& item, bool exact = true) const
{
if(Count == 0) return 0;
if(Count == 1) return (item < Array[0]) ? 0 : 1;
unsigned int lo = 0;
unsigned int hi = Count - 1;
while(lo <= hi)
{
int mid = lo + ((hi - lo) / 2);
if(Array[mid] < item)
{
lo = mid + 1;
}
else if(item < Array[mid])
{
hi = mid - 1;
}
else
{
return mid;
}
}
if(exact)
{
return Count;
}
else
{
return (lo == Count || (item < Array[lo])) ? lo : lo + 1;
}
}
// !!! THIS REQUIRES A SORTED OR EMPTY ARRAY !!!
//
// exact = false returns the closest match, to be used for, ex., insertions, exact = true returns Size() when no match, like Find does
template<typename Func>
unsigned int SortedFind(const T& item, Func &&lt, bool exact = true) const
{
if(Count == 0) return 0;
if(Count == 1) return lt(item, Array[0]) ? 0 : 1;
unsigned int lo = 0;
unsigned int hi = Count - 1;
while(lo <= hi)
{
int mid = lo + ((hi - lo) / 2);
if(std::invoke(lt, Array[mid], item))
{
lo = mid + 1;
}
else if(std::invoke(lt, item, Array[mid]))
{
if(mid == 0) break; // prevent negative overflow due to unsigned numbers
hi = mid - 1;
}
else
{
return mid;
}
}
if(exact)
{
return Count;
}
else
{
return (lo == Count || std::invoke(lt, item, Array[lo])) ? lo : lo + 1;
}
}
bool Contains(const T& item) const
{
unsigned int i;
@ -367,12 +467,24 @@ public:
}
template<class Func>
unsigned int FindEx(Func compare) const
bool Contains(const T& item, Func &&compare) const
{
unsigned int i;
for(i = 0;i < Count;++i)
{
if(std::invoke(compare, Array[i], item))
return true;
}
return false;
}
template<class Func>
unsigned int FindEx(Func &&compare) const
{
unsigned int i;
for (i = 0; i < Count; ++i)
{
if (compare(Array[i]))
if (std::invoke(compare, Array[i]))
break;
}
return i;
@ -462,6 +574,50 @@ public:
return f;
}
unsigned SortedAddUnique(const T& obj)
{
auto f = SortedFind(obj, true);
if (f == Size()) Push(obj);
return f;
}
template<typename Func>
unsigned SortedAddUnique(const T& obj, Func &&lt)
{
auto f = SortedFind(obj, std::forward<Func>(lt), true);
if (f == Size()) Push(obj);
return f;
}
bool SortedDelete(const T& obj)
{
auto f = SortedFind(obj, true);
if (f == Size())
{
Delete(f);
return true;
}
else
{
return false;
}
}
template<typename Func>
bool SortedDelete(const T& obj, Func &&lt)
{
auto f = SortedFind(obj, std::forward<Func>(lt), true);
if (f == Size())
{
Delete(f);
return true;
}
else
{
return false;
}
}
bool Pop ()
{
if (Count > 0)
@ -542,6 +698,17 @@ public:
}
}
void SortedInsert (const T &item)
{
Insert (SortedFind (item, false), item);
}
template<typename Func>
void SortedInsert (const T &item, Func &&lt)
{
Insert (SortedFind (item, std::forward<Func>(lt), false), item);
}
void ShrinkToFit ()
{
if (Most > Count)