- Backend update from GZDoom

* scriptable CVARs.
* GLES update
* various ZScript improvements.
This commit is contained in:
Christoph Oelckers 2023-02-11 12:06:58 +01:00
parent 565f1ed416
commit 8c99d7b034
31 changed files with 1022 additions and 276 deletions

View file

@ -45,6 +45,7 @@
#include "findfile.h"
#include "i_interface.h"
#include "configfile.h"
#include "printf.h"
//==========================================================================
//
@ -447,6 +448,7 @@ const FSoundFontInfo *FSoundFontManager::FindSoundFont(const char *name, int all
// an empty name will pick the first one in a compatible format.
if (allowed & sfi.type && (name == nullptr || *name == 0 || !sfi.mName.CompareNoCase(name) || !sfi.mNameExt.CompareNoCase(name)))
{
DPrintf(DMSG_NOTIFY, "Found compatible soundfont %s\n", sfi.mNameExt.GetChars());
return &sfi;
}
}
@ -455,6 +457,7 @@ const FSoundFontInfo *FSoundFontManager::FindSoundFont(const char *name, int all
{
if (allowed & sfi.type)
{
DPrintf(DMSG_NOTIFY, "Unable to find %s soundfont. Falling back to %s\n", name, sfi.mNameExt.GetChars());
return &sfi;
}
}

View file

@ -45,6 +45,14 @@
#include "palutil.h"
#include "i_interface.h"
#include "dobject.h"
#include "dobjtype.h"
#include "dobjgc.h"
#include "vm.h"
#include "doomstat.h"
struct FLatchedValue
{
@ -215,13 +223,11 @@ FBaseCVar::~FBaseCVar ()
void FBaseCVar::SetCallback(void (*callback)(FBaseCVar&))
{
m_Callback = callback;
m_UseCallback = true;
}
void FBaseCVar::ClearCallback()
{
m_Callback = nullptr;
m_UseCallback = false;
}
void FBaseCVar::SetExtraDataPointer(void *pointer)
@ -296,6 +302,7 @@ bool FBaseCVar::ToBool (UCVarValue value, ECVarType type)
case CVAR_Bool:
return value.Bool;
case CVAR_Color:
case CVAR_Int:
return !!value.Int;
@ -325,6 +332,7 @@ int FBaseCVar::ToInt (UCVarValue value, ECVarType type)
switch (type)
{
case CVAR_Bool: res = (int)value.Bool; break;
case CVAR_Color:
case CVAR_Int: res = value.Int; break;
#if __GNUC__ <= 2
case CVAR_Float: tmp = value.Float; res = (int)tmp; break;
@ -353,6 +361,7 @@ float FBaseCVar::ToFloat (UCVarValue value, ECVarType type)
case CVAR_Bool:
return (float)value.Bool;
case CVAR_Color:
case CVAR_Int:
return (float)value.Int;
@ -382,6 +391,7 @@ const char *FBaseCVar::ToString (UCVarValue value, ECVarType type)
case CVAR_String:
return value.String;
case CVAR_Color:
case CVAR_Int:
mysnprintf (cstrbuf, countof(cstrbuf), "%i", value.Int);
break;
@ -603,6 +613,34 @@ void FBaseCVar::EnableCallbacks ()
}
}
void FBaseCVar::InitZSCallbacks ()
{
CVarMap::Iterator it(cvarMap);
CVarMap::Pair *pair;
while (it.NextPair(pair))
{
auto cvar = pair->Value;
if (cvar->Flags & CVAR_ZS_CUSTOM)
{
cvar->InstantiateZSCVar();
}
}
GC::AddMarkerFunc(FBaseCVar::MarkZSCallbacks);
}
void FBaseCVar::MarkZSCallbacks () {
CVarMap::Iterator it(cvarMap);
CVarMap::Pair *pair;
while (it.NextPair(pair))
{
auto cvar = pair->Value;
if (cvar->Flags & CVAR_ZS_CUSTOM)
{
cvar->MarkZSCVar();
}
}
}
void FBaseCVar::DisableCallbacks ()
{
m_UseCallback = false;
@ -1432,6 +1470,21 @@ FBaseCVar *C_CreateCVar(const char *var_name, ECVarType var_type, uint32_t flags
}
}
FBaseCVar * C_CreateZSCustomCVar(const char *var_name, ECVarType var_type, uint32_t flags, FName className)
{
assert(FindCVar(var_name, NULL) == NULL);
flags |= CVAR_AUTO | CVAR_ZS_CUSTOM;
switch (var_type)
{
case CVAR_Bool: return new FZSBoolCVar(var_name, 0, flags, className);
case CVAR_Int: return new FZSIntCVar(var_name, 0, flags, className);
case CVAR_Float: return new FZSFloatCVar(var_name, 0, flags, className);
case CVAR_String: return new FZSStringCVar(var_name, NULL, flags, className);
case CVAR_Color: return new FZSColorCVar(var_name, 0, flags, className);
default: return NULL;
}
}
void UnlatchCVars (void)
{
for (const FLatchedValue& var : LatchedValues)
@ -1737,3 +1790,305 @@ CCMD(listcvarswithoutdescription)
{
C_ListCVarsWithoutDescription();
}
//===========================================================================
//
// FZSIntCVar
//
//===========================================================================
FZSIntCVar::FZSIntCVar(const char *name, int def, uint32_t flags, FName _className, const char* descr)
: FIntCVar(name,def,flags,nullptr,descr) , cvarName(name) , className(_className)
{ customCVarHandler = nullptr; }
void FZSIntCVar::CallCVarCallback(FZSIntCVar &self)
{
if (!self.customCVarHandler) {
I_Error("Handler for CustomIntCVar '%s' of class '%s' was Destroyed", self.cvarName.GetChars(), self.className.GetChars());
}
IFVIRTUALPTRNAME(self.customCVarHandler, "CustomIntCVar", ModifyValue)
{
VMValue param[] = { self.customCVarHandler.Get() , self.cvarName.GetIndex() , self.Value };
VMReturn ret(&self.Value);
VMCall(func, param, 3, &ret, 1);
}
}
void FZSIntCVar::InstantiateZSCVar()
{
static PClass * baseClass = PClass::FindClass("CustomIntCVar");
assert(baseClass);
PClass * classPtr = PClass::FindClass(className);
if (!classPtr || !classPtr->IsDescendantOf(baseClass))
{
I_Error("Instantiating CVar '%s': Class '%s' %s",cvarName.GetChars(), className.GetChars(), (classPtr ? "is not a descendant of CustomIntCVar" : "does not exist"));
}
customCVarHandler = classPtr->CreateNew();
SetCallback(reinterpret_cast<void (*)(FBaseCVar &)>(CallCVarCallback));
}
void FZSIntCVar::MarkZSCVar()
{
GC::Mark(customCVarHandler);
}
UCVarValue FZSIntCVar::GenericZSCVarCallback(UCVarValue value, ECVarType type) {
int val = ToInt(value, type);
IFVIRTUALPTRNAME(customCVarHandler, "CustomIntCVar", ModifyValue)
{
VMValue param[] = { customCVarHandler.Get() , cvarName.GetIndex() , val };
VMReturn ret(&val);
VMCall(func, param, 3, &ret, 1);
}
UCVarValue v;
v.Int = val;
return v;
}
//===========================================================================
//
// FZSFloatCVar
//
//===========================================================================
FZSFloatCVar::FZSFloatCVar(const char *name, float def, uint32_t flags, FName _className, const char* descr)
: FFloatCVar(name,def,flags,nullptr,descr) , cvarName(name) , className(_className)
{ customCVarHandler = nullptr; }
void FZSFloatCVar::CallCVarCallback(FZSFloatCVar &self)
{
if (!self.customCVarHandler) {
I_Error("Handler for CustomFloatCVar '%s' of class '%s' was Destroyed", self.cvarName.GetChars(), self.className.GetChars());
}
IFVIRTUALPTRNAME(self.customCVarHandler, "CustomFloatCVar", ModifyValue)
{
VMValue param[] = { self.customCVarHandler.Get() , self.cvarName.GetIndex() , (double) self.Value };
double v;
VMReturn ret(&v);
VMCall(func, param, 3, &ret, 1);
self.Value = (float) v;
}
}
void FZSFloatCVar::InstantiateZSCVar()
{
static PClass * baseClass = PClass::FindClass("CustomFloatCVar");
assert(baseClass);
PClass * classPtr = PClass::FindClass(className);
if (!classPtr || !classPtr->IsDescendantOf(baseClass))
{
I_Error("Instantiating CVar '%s': Class '%s' %s", cvarName.GetChars(), className.GetChars(), (classPtr ? "is not a descendant of CustomFloatCVar" : "does not exist"));
}
customCVarHandler = classPtr->CreateNew();
SetCallback(reinterpret_cast<void (*)(FBaseCVar &)>(CallCVarCallback));
}
void FZSFloatCVar::MarkZSCVar()
{
GC::Mark(customCVarHandler);
}
UCVarValue FZSFloatCVar::GenericZSCVarCallback(UCVarValue value, ECVarType type) {
float val = ToFloat(value, type);
IFVIRTUALPTRNAME(customCVarHandler, "CustomFloatCVar", ModifyValue)
{
VMValue param[] = { customCVarHandler.Get() , cvarName.GetIndex() , (double) val };
double v;
VMReturn ret(&v);
VMCall(func, param, 3, &ret, 1);
val = (float) v;
}
UCVarValue v;
v.Float = val;
return v;
}
//===========================================================================
//
// FZSStringCVar
//
//===========================================================================
FZSStringCVar::FZSStringCVar(const char *name, const char * def, uint32_t flags, FName _className, const char* descr)
: FStringCVar(name,def,flags,nullptr,descr) , cvarName(name) , className(_className)
{ customCVarHandler = nullptr; }
void FZSStringCVar::CallCVarCallback(FZSStringCVar &self)
{
if (!self.customCVarHandler) {
I_Error("Handler for CustomStringCVar '%s' of class '%s' was Destroyed", self.cvarName.GetChars(), self.className.GetChars());
}
IFVIRTUALPTRNAME(self.customCVarHandler, "CustomStringCVar", ModifyValue)
{
VMValue param[] = { self.customCVarHandler.Get() , self.cvarName.GetIndex() , &self.mValue };
VMReturn ret(&self.mValue);
VMCall(func, param, 3, &ret, 1);
}
}
void FZSStringCVar::InstantiateZSCVar()
{
static PClass * baseClass = PClass::FindClass("CustomStringCVar");
assert(baseClass);
PClass * classPtr = PClass::FindClass(className);
if (!classPtr || !classPtr->IsDescendantOf(baseClass))
{
I_Error("Instantiating CVar '%s': Class '%s' %s", cvarName.GetChars(), className.GetChars(), (classPtr ? "is not a descendant of CustomStringCVar" : "does not exist"));
}
customCVarHandler = classPtr->CreateNew();
SetCallback(reinterpret_cast<void (*)(FBaseCVar &)>(CallCVarCallback));
}
void FZSStringCVar::MarkZSCVar()
{
GC::Mark(customCVarHandler);
}
UCVarValue FZSStringCVar::GenericZSCVarCallback(UCVarValue value, ECVarType type) {
FString val = ToString(value, type);
IFVIRTUALPTRNAME(customCVarHandler, "CustomStringCVar", ModifyValue)
{
VMValue param[] = { customCVarHandler.Get() , cvarName.GetIndex() , &val };
VMReturn ret(&val);
VMCall(func, param, 3, &ret, 1);
}
char * str = new char[val.Len() + 1];
memcpy(str, val.GetChars(), val.Len() * sizeof(char));
str[val.Len()] = '\0';
UCVarValue v;
v.String = str;
return v;
}
//===========================================================================
//
// FZSBoolCVar
//
//===========================================================================
FZSBoolCVar::FZSBoolCVar(const char *name, bool def, uint32_t flags, FName _className, const char* descr)
: FBoolCVar(name,def,flags,nullptr,descr) , cvarName(name) , className(_className)
{ customCVarHandler = nullptr; }
void FZSBoolCVar::CallCVarCallback(FZSBoolCVar &self)
{
if (!self.customCVarHandler) {
I_Error("Handler for CustomBoolCVar '%s' of class '%s' was Destroyed", self.cvarName.GetChars(), self.className.GetChars());
}
IFVIRTUALPTRNAME(self.customCVarHandler, "CustomBoolCVar", ModifyValue)
{
VMValue param[] = { self.customCVarHandler.Get() , self.cvarName.GetIndex() , self.Value };
int v;
VMReturn ret(&v);
VMCall(func, param, 3, &ret, 1);
self.Value = v;
}
}
void FZSBoolCVar::InstantiateZSCVar()
{
static PClass * baseClass = PClass::FindClass("CustomBoolCVar");
assert(baseClass);
PClass * classPtr = PClass::FindClass(className);
if (!classPtr || !classPtr->IsDescendantOf(baseClass))
{
I_Error("Instantiating CVar '%s': Class '%s' %s", cvarName.GetChars(), className.GetChars(), (classPtr ? "is not a descendant of CustomBoolCVar" : "does not exist"));
}
customCVarHandler = classPtr->CreateNew();
SetCallback(reinterpret_cast<void (*)(FBaseCVar &)>(CallCVarCallback));
}
void FZSBoolCVar::MarkZSCVar()
{
GC::Mark(customCVarHandler);
}
UCVarValue FZSBoolCVar::GenericZSCVarCallback(UCVarValue value, ECVarType type) {
bool val = ToFloat(value, type);
IFVIRTUALPTRNAME(customCVarHandler, "CustomBoolCVar", ModifyValue)
{
VMValue param[] = { customCVarHandler.Get() , cvarName.GetIndex() , val };
int v;
VMReturn ret(&v);
VMCall(func, param, 3, &ret, 1);
val = v;
}
UCVarValue v;
v.Bool = val;
return v;
}
//===========================================================================
//
// FZSColorCVar
//
//===========================================================================
FZSColorCVar::FZSColorCVar(const char *name, int def, uint32_t flags, FName _className, const char* descr)
: FColorCVar(name,def,flags,nullptr,descr) , cvarName(name) , className(_className)
{ customCVarHandler = nullptr; }
void FZSColorCVar::CallCVarCallback(FZSColorCVar &self)
{
if (!self.customCVarHandler) {
I_Error("Handler for CustomColorCVar '%s' of class '%s' was Destroyed", self.cvarName.GetChars(), self.className.GetChars());
}
IFVIRTUALPTRNAME(self.customCVarHandler, "CustomColorCVar", ModifyValue)
{
VMValue param[] = { self.customCVarHandler.Get() , self.cvarName.GetIndex() , self.Value };
VMReturn ret(&self.Value);
VMCall(func, param, 3, &ret, 1);
}
}
void FZSColorCVar::InstantiateZSCVar()
{
static PClass * baseClass = PClass::FindClass("CustomColorCVar");
assert(baseClass);
PClass * classPtr = PClass::FindClass(className);
if (!classPtr || !classPtr->IsDescendantOf(baseClass))
{
I_Error("Instantiating CVar '%s': Class '%s' %s", cvarName.GetChars(), className.GetChars(), (classPtr ? "is not a descendant of CustomColorCVar" : "does not exist"));
}
customCVarHandler = classPtr->CreateNew();
SetCallback(reinterpret_cast<void (*)(FBaseCVar &)>(CallCVarCallback));
}
void FZSColorCVar::MarkZSCVar()
{
GC::Mark(customCVarHandler);
}
UCVarValue FZSColorCVar::GenericZSCVarCallback(UCVarValue value, ECVarType type) {
int val = ToInt(value, type);
IFVIRTUALPTRNAME(customCVarHandler, "CustomColorCVar", ModifyValue)
{
VMValue param[] = { customCVarHandler.Get() , cvarName.GetIndex() , val };
VMReturn ret(&val);
VMCall(func, param, 3, &ret, 1);
}
UCVarValue v;
v.Int = val;
return v;
}

View file

@ -37,6 +37,7 @@
#include "tarray.h"
#include "autosegs.h"
#include "name.h"
#include "dobjgc.h"
class FSerializer; // this needs to go away.
/*
@ -49,29 +50,31 @@ CVARS (console variables)
enum
{
CVAR_ARCHIVE = 1, // set to cause it to be saved to config.
CVAR_USERINFO = 1 << 1, // added to userinfo when changed.
CVAR_SERVERINFO = 1 << 2, // added to serverinfo when changed.
CVAR_NOSET = 1 << 3, // don't allow change from console at all,
// but can be set from the command line.
CVAR_LATCH = 1 << 4, // save changes until server restart.
CVAR_UNSETTABLE = 1 << 5, // can unset this var from console.
CVAR_DEMOSAVE = 1 << 6, // save the value of this cvar in a demo.
CVAR_ISDEFAULT = 1 << 7, // is cvar unchanged since creation?
CVAR_AUTO = 1 << 8, // allocated; needs to be freed when destroyed.
CVAR_NOINITCALL = 1 << 9, // don't call callback at game start.
CVAR_GLOBALCONFIG = 1 << 10, // cvar is saved to global config section.
CVAR_VIDEOCONFIG = 1 << 11, // cvar is saved to video config section (not implemented).
CVAR_NOSAVE = 1 << 12, // when used with CVAR_SERVERINFO, do not save var to savegame
// and config.
CVAR_MOD = 1 << 13, // cvar was defined by a mod.
CVAR_IGNORE = 1 << 14, // do not send cvar across the network/inaccesible from ACS
// (dummy mod cvar).
CVAR_CHEAT = 1 << 15, // can be set only when sv_cheats is enabled.
CVAR_UNSAFECONTEXT = 1 << 16, // cvar value came from unsafe context.
CVAR_VIRTUAL = 1 << 17, // do not invoke the callback recursively so it can be used to
// mirror an external variable.
CVAR_CONFIG_ONLY = 1 << 18, // do not save var to savegame and do not send it across network.
CVAR_ARCHIVE = 1, // set to cause it to be saved to config.
CVAR_USERINFO = 1 << 1, // added to userinfo when changed.
CVAR_SERVERINFO = 1 << 2, // added to serverinfo when changed.
CVAR_NOSET = 1 << 3, // don't allow change from console at all,
// but can be set from the command line.
CVAR_LATCH = 1 << 4, // save changes until server restart.
CVAR_UNSETTABLE = 1 << 5, // can unset this var from console.
CVAR_DEMOSAVE = 1 << 6, // save the value of this cvar in a demo.
CVAR_ISDEFAULT = 1 << 7, // is cvar unchanged since creation?
CVAR_AUTO = 1 << 8, // allocated; needs to be freed when destroyed.
CVAR_NOINITCALL = 1 << 9, // don't call callback at game start.
CVAR_GLOBALCONFIG = 1 << 10, // cvar is saved to global config section.
CVAR_VIDEOCONFIG = 1 << 11, // cvar is saved to video config section (not implemented).
CVAR_NOSAVE = 1 << 12, // when used with CVAR_SERVERINFO, do not save var to savegame
// and config.
CVAR_MOD = 1 << 13, // cvar was defined by a mod.
CVAR_IGNORE = 1 << 14, // do not send cvar across the network/inaccesible from ACS
// (dummy mod cvar).
CVAR_CHEAT = 1 << 15, // can be set only when sv_cheats is enabled.
CVAR_UNSAFECONTEXT = 1 << 16, // cvar value came from unsafe context.
CVAR_VIRTUAL = 1 << 17, // do not invoke the callback recursively so it can be used to
// mirror an external variable.
CVAR_CONFIG_ONLY = 1 << 18, // do not save var to savegame and do not send it across network.
CVAR_ZS_CUSTOM = 1 << 19, // Custom CVar backed by a ZScript class
CVAR_ZS_CUSTOM_CLONE = 1 << 20, // Clone of a Custom ZScript CVar
};
enum ECVarType
@ -182,12 +185,20 @@ public:
virtual UCVarValue GetFavoriteRepDefault (ECVarType *type) const = 0;
virtual void SetGenericRepDefault (UCVarValue value, ECVarType type) = 0;
virtual UCVarValue GenericZSCVarCallback(UCVarValue value, ECVarType type)
{ // not valid for cvars that aren't custom zscript cvars, doesn't modify the actual cvar directly, just transforms the value
// FZSStringCVar allocates a buffer for the returned string that must be freed by the caller
return 0;
}
FBaseCVar &operator= (const FBaseCVar &var)
{ UCVarValue val; ECVarType type; val = var.GetFavoriteRep (&type); SetGenericRep (val, type); return *this; }
static void EnableNoSet (); // enable the honoring of CVAR_NOSET
static void EnableCallbacks ();
static void DisableCallbacks ();
static void InitZSCallbacks ();
static void MarkZSCallbacks ();
static void ResetColors (); // recalc color cvars' indices after screen change
static void ListVars (const char *filter, bool plain);
@ -209,6 +220,10 @@ public:
protected:
virtual void DoSet (UCVarValue value, ECVarType type) = 0;
virtual void InstantiateZSCVar()
{}
virtual void MarkZSCVar()
{}
static bool ToBool (UCVarValue value, ECVarType type);
static int ToInt (UCVarValue value, ECVarType type);
@ -278,6 +293,7 @@ FBaseCVar *GetCVar(int playernum, const char *cvarname);
// Create a new cvar with the specified name and type
FBaseCVar *C_CreateCVar(const char *var_name, ECVarType var_type, uint32_t flags);
FBaseCVar *C_CreateZSCustomCVar(const char *var_name, ECVarType var_type, uint32_t flags, FName className);
// Called from G_InitNew()
void UnlatchCVars (void);
@ -482,6 +498,76 @@ protected:
int BitNum;
};
class FZSIntCVar : public FIntCVar
{
TObjPtr<DObject*> customCVarHandler;
FName cvarName;
FName className;
static void CallCVarCallback(FZSIntCVar &);
public:
FZSIntCVar(const char *name, int def, uint32_t flags, FName className, const char* descr = nullptr);
void InstantiateZSCVar() override;
void MarkZSCVar() override;
UCVarValue GenericZSCVarCallback(UCVarValue value, ECVarType type) override;
};
class FZSFloatCVar : public FFloatCVar
{
TObjPtr<DObject*> customCVarHandler;
FName cvarName;
FName className;
static void CallCVarCallback(FZSFloatCVar &);
public:
FZSFloatCVar(const char *name, float def, uint32_t flags, FName className, const char* descr = nullptr);
void InstantiateZSCVar() override;
void MarkZSCVar() override;
UCVarValue GenericZSCVarCallback(UCVarValue value, ECVarType type) override;
};
class FZSStringCVar : public FStringCVar
{
TObjPtr<DObject*> customCVarHandler;
FName cvarName;
FName className;
static void CallCVarCallback(FZSStringCVar &);
public:
FZSStringCVar(const char *name, const char * def, uint32_t flags, FName className, const char* descr = nullptr);
void InstantiateZSCVar() override;
void MarkZSCVar() override;
UCVarValue GenericZSCVarCallback(UCVarValue value, ECVarType type) override;
};
class FZSBoolCVar : public FBoolCVar
{
TObjPtr<DObject*> customCVarHandler;
FName cvarName;
FName className;
static void CallCVarCallback(FZSBoolCVar &);
public:
FZSBoolCVar(const char *name, bool def, uint32_t flags, FName className, const char* descr = nullptr);
void InstantiateZSCVar() override;
void MarkZSCVar() override;
UCVarValue GenericZSCVarCallback(UCVarValue value, ECVarType type) override;
};
class FZSColorCVar : public FColorCVar
{
TObjPtr<DObject*> customCVarHandler;
FName cvarName;
FName className;
static void CallCVarCallback(FZSColorCVar &);
public:
FZSColorCVar(const char *name, int def, uint32_t flags, FName className, const char* descr = nullptr);
void InstantiateZSCVar() override;
void MarkZSCVar() override;
UCVarValue GenericZSCVarCallback(UCVarValue value, ECVarType type) override;
};
class FBoolCVarRef
{
FBoolCVar* ref;

View file

@ -29,7 +29,7 @@ CVAR(Bool, vid_fps, false, 0)
EXTERN_CVAR(Bool, ui_generic)
CUSTOM_CVAR(String, language, "auto", CVAR_ARCHIVE | CVAR_NOINITCALL /* | CVAR_GLOBALCONFIG*/)
CUSTOM_CVAR(String, language, "auto", CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG)
{
GStrings.UpdateLanguage(self);
UpdateGenericUI(ui_generic);

View file

@ -167,10 +167,12 @@ xx(Insert)
xx(InsertNew)
xx(Remove)
xx(Get)
xx(GetIfExists)
xx(GetValue)
xx(GetKey)
xx(SetValue)
xx(CheckKey)
xx(CheckValue)
xx(Value)
xx(Copy)
xx(Move)
@ -185,6 +187,8 @@ xx(Exists)
xx(SetInvalid)
xx(SetNull)
xx(Key)
xx(Index)
xx(Find)
// color channels
xx(a)

View file

@ -531,7 +531,7 @@ void PClass::Derive(PClass *newclass, FName name)
//
//==========================================================================
PClass *PClass::CreateDerivedClass(FName name, unsigned int size, bool *newlycreated)
PClass *PClass::CreateDerivedClass(FName name, unsigned int size, bool *newlycreated, int fileno)
{
assert(size >= Size);
PClass *type;
@ -571,7 +571,7 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size, bool *newlycre
type->Size = size;
if (size != TentativeClass)
{
NewClassType(type);
NewClassType(type, fileno);
if (newlycreated) *newlycreated = true;
type->Virtuals = Virtuals;
}
@ -591,13 +591,13 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size, bool *newlycre
//
//==========================================================================
PField *PClass::AddField(FName name, PType *type, uint32_t flags)
PField *PClass::AddField(FName name, PType *type, uint32_t flags, int fileno)
{
PField *field;
if (!(flags & VARF_Meta))
{
unsigned oldsize = Size;
field = VMType->Symbols.AddField(name, type, flags, Size);
field = VMType->Symbols.AddField(name, type, flags, Size, nullptr, fileno);
// Only initialize the defaults if they have already been created.
// For ZScript this is not the case, it will first define all fields before
@ -612,7 +612,7 @@ PField *PClass::AddField(FName name, PType *type, uint32_t flags)
{
// Same as above, but a different data storage.
unsigned oldsize = MetaSize;
field = VMType->Symbols.AddField(name, type, flags, MetaSize);
field = VMType->Symbols.AddField(name, type, flags, MetaSize, nullptr, fileno);
if (field != nullptr && !(flags & VARF_Native) && Meta != nullptr)
{

View file

@ -45,7 +45,7 @@ public:
bool ReadAllFields(FSerializer &ar, void *addr) const;
int FindVirtualIndex(FName name, PFunction::Variant *variant, PFunction *parentfunc, bool exactReturnType);
PSymbol *FindSymbol(FName symname, bool searchparents) const;
PField *AddField(FName name, PType *type, uint32_t flags);
PField *AddField(FName name, PType *type, uint32_t flags, int fileno = 0);
void InitializeDefaults();
static void StaticInit();
@ -80,7 +80,7 @@ public:
~PClass();
void InsertIntoHash(bool native);
DObject *CreateNew();
PClass *CreateDerivedClass(FName name, unsigned int size, bool *newlycreated = nullptr);
PClass *CreateDerivedClass(FName name, unsigned int size, bool *newlycreated = nullptr, int fileno = 0);
void InitializeActorInfo();
void BuildFlatPointers();

View file

@ -85,6 +85,8 @@
// The main window's title.
#ifdef _M_X64
#define X64 " 64-bit"
#elif _M_ARM64
#define X64 " ARM-64"
#else
#define X64 ""
#endif

View file

@ -17,6 +17,8 @@
#ifdef _M_X64
#define X64 " 64-bit"
#elif _M_ARM64
#define X64 " ARM-64"
#else
#define X64 ""
#endif

View file

@ -196,10 +196,12 @@ static void SetCursorState(bool visible)
{
if (CursorState)
{
ShowCursor(1);
SetCursor((HCURSOR)(intptr_t)GetClassLongPtr(mainwindow.GetHandle(), GCLP_HCURSOR));
}
else
{
ShowCursor(0);
SetCursor(NULL);
}
}

View file

@ -90,7 +90,7 @@ bool IsPortable()
}
// A portable INI means that this storage location should also be portable if the file can be written to.
FStringf path("%s" GAMENAME "_portable.ini", progdir.GetChars());
FStringf path("%s" GAMENAMELOWERCASE "_portable.ini", progdir.GetChars());
if (FileExists(path))
{
file = CreateFile(path.WideString().c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL,

View file

@ -388,6 +388,7 @@ BOOL CALLBACK IWADBoxCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lPa
break;
#ifdef HAVE_GLES2
case 2:
case 3:
SendDlgItemMessage( hDlg, IDC_WELCOME_VULKAN4, BM_SETCHECK, BST_CHECKED, 0 );
break;
#endif

View file

@ -234,8 +234,7 @@ void GLBuffer::Resize(size_t newsize)
void GLBuffer::GPUDropSync()
{
#if !(USE_GLES2) // Only applicable when running on desktop for now
if (gles.useMappedBuffers && glFenceSync && glClientWaitSync)
if (gles.glesMode > GLES_MODE_GLES && gles.useMappedBuffers && glFenceSync && glDeleteSync)
{
if (mGLSync != NULL)
{
@ -244,13 +243,11 @@ void GLBuffer::GPUDropSync()
mGLSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
}
#endif
}
void GLBuffer::GPUWaitSync()
{
#if !(USE_GLES2) // Only applicable when running on desktop for now
if (gles.useMappedBuffers && glFenceSync && glClientWaitSync)
if (gles.glesMode > GLES_MODE_GLES && gles.useMappedBuffers && glDeleteSync && glClientWaitSync)
{
GLenum status = glClientWaitSync(mGLSync, GL_SYNC_FLUSH_COMMANDS_BIT, 1000 * 1000 * 50); // Wait for a max of 50ms...
@ -263,7 +260,6 @@ void GLBuffer::GPUWaitSync()
mGLSync = NULL;
}
#endif
}
@ -318,7 +314,7 @@ void GLVertexBuffer::Bind(int *offsets)
glVertexAttribPointer(i, attrinf.size, attrinf.format, attrinf.normalize, (GLsizei)mStride, (void*)(intptr_t)ofs);
else
{
if (gles.gles3Features)
if (gles.glesMode >= GLES_MODE_OGL3)
glVertexAttribIPointer(i, attrinf.size, attrinf.format, (GLsizei)mStride, (void*)(intptr_t)ofs);
}
}

View file

@ -130,44 +130,47 @@ unsigned int FHardwareTexture::CreateTexture(unsigned char * buffer, int w, int
int sourcetype;
#if USE_GLES2
if (glTextureBytes == 1)
if (gles.glesMode == GLES_MODE_GLES)
{
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
sourcetype = GL_ALPHA;
texformat = GL_ALPHA;
if (glTextureBytes == 1)
{
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
sourcetype = GL_ALPHA;
texformat = GL_ALPHA;
}
else
{
sourcetype = GL_BGRA; // These two must be the same
texformat = GL_BGRA;
}
}
else
{
sourcetype = GL_BGRA;
texformat = GL_BGRA;
if (glTextureBytes == 1) //Use Red channel instread becuase Alpha does not work in OpenGL, swizzle later
{
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
sourcetype = GL_RED;
texformat = GL_RED;
}
else
{
sourcetype = GL_BGRA;
texformat = GL_RGBA;
}
}
#else
if (glTextureBytes == 1)
{
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
sourcetype = GL_RED;
texformat = GL_RED;
}
else
{
sourcetype = GL_BGRA;
texformat = GL_RGBA;
}
#endif
glTexImage2D(GL_TEXTURE_2D, 0, texformat, rw, rh, 0, sourcetype, GL_UNSIGNED_BYTE, buffer);
#if !(USE_GLES2)
// The shader is using the alpha channel instead of red, this work on GLES but not on GL
// So the texture uses GL_RED and this swizzels the red channel into the alpha channel
if (glTextureBytes == 1)
if (gles.glesMode != GLES_MODE_GLES)
{
GLint swizzleMask[] = { GL_ZERO, GL_ZERO, GL_ZERO, GL_RED };
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
// The shader is using the alpha channel instead of red, this work on GLES but not on GL
// So the texture uses GL_RED and this swizzels the red channel into the alpha channel
if (glTextureBytes == 1)
{
GLint swizzleMask[] = { GL_ZERO, GL_ZERO, GL_ZERO, GL_RED };
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
}
}
#endif
if (deletebuffer && buffer) free(buffer);

View file

@ -346,7 +346,7 @@ bool FGLRenderState::ApplyShader()
activeShader->cur->muLightRange.Set(range);
}
if (gles.gles3Features)
if (gles.glesMode >= GLES_MODE_OGL3)
{
// Upload bone data
// NOTE, this is pretty inefficient, it will be reloading the same data over and over in a single frame

View file

@ -12,50 +12,16 @@ EXTERN_CVAR(Bool, gl_customshader);
void setGlVersion(double glv);
#if USE_GLES2
#if USE_GLAD_LOADER
PFNGLMAPBUFFERRANGEEXTPROC glMapBufferRange = NULL;
PFNGLUNMAPBUFFEROESPROC glUnmapBuffer = NULL;
PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer = NULL;
PFNGLFENCESYNCPROC glFenceSync = NULL;
PFNGLCLIENTWAITSYNCPROC glClientWaitSync = NULL;
PFNGLDELETESYNCPROC glDeleteSync = NULL;
#ifdef __ANDROID__
#include <dlfcn.h>
static void* LoadGLES2Proc(const char* name)
{
static void *glesLib = NULL;
if(!glesLib)
{
int flags = RTLD_LOCAL | RTLD_NOW;
glesLib = dlopen("libGLESv2_CM.so", flags);
if(!glesLib)
{
glesLib = dlopen("libGLESv2.so", flags);
}
if(!glesLib)
{
glesLib = dlopen("libGLESv2.so.2", flags);
}
}
void * ret = NULL;
ret = dlsym(glesLib, name);
if(!ret)
{
//LOGI("Failed to load: %s", name);
}
else
{
//LOGI("Loaded %s func OK", name);
}
return ret;
}
#elif defined _WIN32
#if defined _WIN32
#include <windows.h>
@ -80,9 +46,38 @@ static void* LoadGLES2Proc(const char* name)
}
}
#else
#include <dlfcn.h>
static void* LoadGLES2Proc(const char* name)
{
static void* glesLib = NULL;
if (!glesLib)
{
int flags = RTLD_LOCAL | RTLD_NOW;
glesLib = dlopen("libGLESv2_CM.so", flags);
if (!glesLib)
{
glesLib = dlopen("libGLESv2.so", flags);
}
if (!glesLib)
{
glesLib = dlopen("libGLESv2.so.2", flags);
}
}
void* ret = NULL;
ret = dlsym(glesLib, name);
return ret;
}
#endif
#endif // USE_GLES2
#endif // USE_GLAD_LOADER
static TArray<FString> m_Extensions;
@ -126,7 +121,7 @@ namespace OpenGLESRenderer
void InitGLES()
{
#if USE_GLES2
#if USE_GLAD_LOADER
if (!gladLoadGLES2Loader(&LoadGLES2Proc))
{
@ -136,6 +131,10 @@ namespace OpenGLESRenderer
glMapBufferRange = (PFNGLMAPBUFFERRANGEEXTPROC)LoadGLES2Proc("glMapBufferRange");
glUnmapBuffer = (PFNGLUNMAPBUFFEROESPROC)LoadGLES2Proc("glUnmapBuffer");
glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC)LoadGLES2Proc("glVertexAttribIPointer");
glFenceSync = (PFNGLFENCESYNCPROC)LoadGLES2Proc("glFenceSync");
glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC)LoadGLES2Proc("glClientWaitSync");
glDeleteSync = (PFNGLDELETESYNCPROC)LoadGLES2Proc("glDeleteSync");
#else
static bool first = true;
@ -161,48 +160,78 @@ namespace OpenGLESRenderer
{
Printf(" %s\n", m_Extensions[i].GetChars());
}
const char* glVersionStr = (const char*)glGetString(GL_VERSION);
double glVersion = strtod(glVersionStr, NULL);
Printf("GL Version parsed = %f\n", glVersion);
gles.flags = RFL_NO_CLIP_PLANES;
gles.useMappedBuffers = gles_use_mapped_buffer;
gles.forceGLSLv100 = gles_force_glsl_v100;
gles.maxlights = gles_max_lights_per_surface;
gles.numlightvectors = (gles.maxlights * LIGHT_VEC4_NUM);
gles.modelstring = (char*)glGetString(GL_RENDERER);
gles.vendorstring = (char*)glGetString(GL_VENDOR);
gl_customshader = false;
gl_customshader = false; // Disable user shaders for GLES renderer
GLint maxTextureSize[1];
glGetIntegerv(GL_MAX_TEXTURE_SIZE, maxTextureSize);
gles.max_texturesize = maxTextureSize[0];
Printf("GL_MAX_TEXTURE_SIZE: %d\n", gles.max_texturesize);
#if USE_GLES2
gles.gles3Features = false; // Enales IQM bones
gles.shaderVersionString = "100";
gles.depthStencilAvailable = CheckExtension("GL_OES_packed_depth_stencil");
gles.npotAvailable = CheckExtension("GL_OES_texture_npot");
gles.depthClampAvailable = CheckExtension("GL_EXT_depth_clamp");
gles.anistropicFilterAvailable = CheckExtension("GL_EXT_texture_filter_anisotropic");
#else
gles.gles3Features = true;
gles.shaderVersionString = "330";
gles.depthStencilAvailable = true;
gles.npotAvailable = true;
gles.useMappedBuffers = true;
gles.depthClampAvailable = true;
gles.anistropicFilterAvailable = true;
#endif
// Check if running on a GLES device, version string will start with 'OpenGL ES'
if (!strncmp(glVersionStr, "OpenGL ES", strlen("OpenGL ES")))
{
gles.glesMode = GLES_MODE_GLES;
}
else // Else runnning on Desktop, check OpenGL version is 3 or above
{
if (glVersion > 3.29)
gles.glesMode = GLES_MODE_OGL3; // 3.3 or above
else
gles.glesMode = GLES_MODE_OGL2; // Below 3.3
}
gles.numlightvectors = (gles.maxlights * LIGHT_VEC4_NUM);
const char* glversion = (const char*)glGetString(GL_VERSION);
setGlVersion( strtod(glversion, NULL));
if (gles.glesMode == GLES_MODE_GLES)
{
Printf("GLES choosing mode: GLES_MODE_GLES\n");
gles.shaderVersionString = "100";
gles.depthStencilAvailable = CheckExtension("GL_OES_packed_depth_stencil");
gles.npotAvailable = CheckExtension("GL_OES_texture_npot");
gles.depthClampAvailable = CheckExtension("GL_EXT_depth_clamp");
gles.anistropicFilterAvailable = CheckExtension("GL_EXT_texture_filter_anisotropic");
}
else if (gles.glesMode == GLES_MODE_OGL2)
{
Printf("GLES choosing mode: GLES_MODE_OGL2\n");
gles.shaderVersionString = "100";
gles.depthStencilAvailable = true;
gles.npotAvailable = true;
gles.useMappedBuffers = true;
gles.depthClampAvailable = true;
gles.anistropicFilterAvailable = true;
}
else if (gles.glesMode == GLES_MODE_OGL3)
{
Printf("GLES choosing mode: GLES_MODE_OGL3\n");
gles.shaderVersionString = "330";
gles.depthStencilAvailable = true;
gles.npotAvailable = true;
gles.useMappedBuffers = true;
gles.depthClampAvailable = true;
gles.anistropicFilterAvailable = true;
}
setGlVersion(glVersion);
}
}

View file

@ -23,32 +23,47 @@
#include <sys/stat.h>
#include <fcntl.h>
#define USE_GLES2 0 // For Desktop PC leave as 0, it will use the exisiting OpenGL context creationg code but run with the GLES2 renderer
// Set to 1 for when comipling for a real GLES device
#define USE_GLAD_LOADER 0 // Set to 1 to use the GLAD loader, otherwise use noramal GZDoom loader for PC
#if (USE_GLES2)
#if (USE_GLAD_LOADER)
#include "glad/glad.h"
// Below are used extensions for GLES
typedef void* (APIENTRYP PFNGLMAPBUFFERRANGEEXTPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
GLAPI PFNGLMAPBUFFERRANGEEXTPROC glMapBufferRange;
// Below are used extensions for GLES
typedef void* (APIENTRYP PFNGLMAPBUFFERRANGEEXTPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
GLAPI PFNGLMAPBUFFERRANGEEXTPROC glMapBufferRange;
typedef GLboolean(APIENTRYP PFNGLUNMAPBUFFEROESPROC)(GLenum target);
GLAPI PFNGLUNMAPBUFFEROESPROC glUnmapBuffer;
typedef GLboolean(APIENTRYP PFNGLUNMAPBUFFEROESPROC)(GLenum target);
GLAPI PFNGLUNMAPBUFFEROESPROC glUnmapBuffer;
typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void* pointer);
GLAPI PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer;
typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void* pointer);
GLAPI PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer;
typedef GLsync(APIENTRYP PFNGLFENCESYNCPROC)(GLenum condition, GLbitfield flags);
GLAPI PFNGLFENCESYNCPROC glFenceSync;
typedef GLenum(APIENTRYP PFNGLCLIENTWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout);
GLAPI PFNGLCLIENTWAITSYNCPROC glClientWaitSync;
typedef void (APIENTRYP PFNGLDELETESYNCPROC)(GLsync sync);
GLAPI PFNGLDELETESYNCPROC glDeleteSync;
#define GL_DEPTH24_STENCIL8 0x88F0
#define GL_MAP_PERSISTENT_BIT 0x0040
#define GL_MAP_READ_BIT 0x0001
#define GL_MAP_WRITE_BIT 0x0002
#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020
#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008
#define GL_BGRA 0x80E1
#define GL_DEPTH_CLAMP 0x864F
#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
#define GL_INT_2_10_10_10_REV 0x8D9F
#define GL_RED 0x1903
#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46
#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117
#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001
#define GL_ALREADY_SIGNALED 0x911A
#define GL_CONDITION_SATISFIED 0x911C
#define GL_DEPTH24_STENCIL8 0x88F0
#define GL_MAP_PERSISTENT_BIT 0x0040
#define GL_MAP_READ_BIT 0x0001
#define GL_MAP_WRITE_BIT 0x0002
#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020
#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008
#define GL_BGRA 0x80E1
#define GL_DEPTH_CLAMP 0x864F
#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
#define GL_INT_2_10_10_10_REV 0x8D9F
#else
#include "gl_load/gl_load.h"
#endif
@ -66,6 +81,13 @@ GLAPI PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer;
namespace OpenGLESRenderer
{
enum
{
GLES_MODE_GLES = 0,
GLES_MODE_OGL2 = 1,
GLES_MODE_OGL3 = 2,
};
struct RenderContextGLES
{
unsigned int flags;
@ -77,7 +99,7 @@ namespace OpenGLESRenderer
bool forceGLSLv100;
bool depthClampAvailable;
bool anistropicFilterAvailable;
bool gles3Features;
int glesMode;
const char* shaderVersionString;
int max_texturesize;
char* vendorstring;

View file

@ -96,6 +96,7 @@ void HWViewpointBuffer::Set2D(FRenderState &di, int width, int height, int pll)
matrices.mProjectionMatrix.ortho(0, (float)width, (float)height, 0, -1.0f, 1.0f);
matrices.CalcDependencies();
CheckSize();
mBuffer->Map();
memcpy(((char*)mBuffer->Memory()) + mUploadIndex * mBlockAlign, &matrices, sizeof(matrices));
mBuffer->Unmap();
@ -125,6 +126,8 @@ void HWViewpointBuffer::Clear()
if (needNewPipeline)
{
mLastMappedIndex = UINT_MAX;
mPipelinePos++;
mPipelinePos %= mPipelineNbr;
}

View file

@ -177,12 +177,9 @@ void FCompileContext::CheckReturn(PPrototype *proto, FScriptPosition &pos)
}
}
// [ZZ] I find it really dumb that something called CheckReadOnly returns false for readonly. renamed.
bool FCompileContext::CheckWritable(int flags)
bool FCompileContext::IsWritable(int flags, int checkFileNo)
{
if (!(flags & VARF_ReadOnly)) return false;
if (!(flags & VARF_InternalAccess)) return true;
return fileSystem.GetFileContainer(Lump) != 0;
return !(flags & VARF_ReadOnly) || ((flags & VARF_InternalAccess) && fileSystem.GetFileContainer(Lump) == checkFileNo);
}
FxLocalVariableDeclaration *FCompileContext::FindLocalVariable(FName name)
@ -277,6 +274,14 @@ bool AreCompatiblePointerTypes(PType *dest, PType *source, bool forcompare)
{
auto fromtype = source->toPointer();
auto totype = dest->toPointer();
// implicit pointer casts
if( fromtype->isClassPointer() && !totype->isClassPointer() ) totype->toClassPointer(fromtype); // just to make sure they're compatible pointer types
else if( !fromtype->isClassPointer() && totype->isClassPointer() ) fromtype->toClassPointer(totype); // just to make sure they're compatible pointer types
else if( fromtype->PointedType != totype->PointedType )
{
auto res = fromtype->PointedType->toClass(totype->PointedType);
if(!res || res != totype->PointedType) return false;
}
// null pointers can be assigned to everything, everything can be assigned to void pointers.
if (fromtype == nullptr || totype == TypeVoidPtr) return true;
// when comparing const-ness does not matter.
@ -6730,7 +6735,7 @@ FxExpression *FxLocalVariable::Resolve(FCompileContext &ctx)
bool FxLocalVariable::RequestAddress(FCompileContext &ctx, bool *writable)
{
AddressRequested = true;
if (writable != nullptr) *writable = !ctx.CheckWritable(Variable->VarFlags);
if (writable != nullptr) *writable = ctx.IsWritable(Variable->VarFlags);
return true;
}
@ -6885,7 +6890,7 @@ FxGlobalVariable::FxGlobalVariable(PField* mem, const FScriptPosition &pos)
bool FxGlobalVariable::RequestAddress(FCompileContext &ctx, bool *writable)
{
AddressRequested = true;
if (writable != nullptr) *writable = AddressWritable && !ctx.CheckWritable(membervar->Flags);
if (writable != nullptr) *writable = AddressWritable && ctx.IsWritable(membervar->Flags, membervar->mDefFileNo);
return true;
}
@ -7078,7 +7083,7 @@ FxStackVariable::~FxStackVariable()
bool FxStackVariable::RequestAddress(FCompileContext &ctx, bool *writable)
{
AddressRequested = true;
if (writable != nullptr) *writable = AddressWritable && !ctx.CheckWritable(membervar->Flags);
if (writable != nullptr) *writable = AddressWritable && ctx.IsWritable(membervar->Flags, membervar->mDefFileNo);
return true;
}
@ -7180,7 +7185,7 @@ bool FxStructMember::RequestAddress(FCompileContext &ctx, bool *writable)
else if (writable != nullptr)
{
// [ZZ] original check.
bool bWritable = (AddressWritable && !ctx.CheckWritable(membervar->Flags) &&
bool bWritable = (AddressWritable && ctx.IsWritable(membervar->Flags, membervar->mDefFileNo) &&
(!classx->ValueType->isPointer() || !classx->ValueType->toPointer()->IsConst));
// [ZZ] implement write barrier between different scopes
if (bWritable)
@ -8508,6 +8513,11 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
}
else
{
if (PFunction **Override; ctx.Version >= MakeVersion(4, 11, 0) && (Override = static_cast<PDynArray*>(Self->ValueType)->FnOverrides.CheckKey(MethodName)))
{
afd_override = *Override;
}
auto elementType = static_cast<PDynArray*>(Self->ValueType)->ElementType;
Self->ValueType = static_cast<PDynArray*>(Self->ValueType)->BackingType;
bool isDynArrayObj = elementType->isObjectPointer();

View file

@ -101,7 +101,7 @@ struct FCompileContext
void HandleJumps(int token, FxExpression *handler);
void CheckReturn(PPrototype *proto, FScriptPosition &pos);
bool CheckWritable(int flags);
bool IsWritable(int flags, int checkFileNo = 0);
FxLocalVariableDeclaration *FindLocalVariable(FName name);
};

View file

@ -108,7 +108,7 @@ template<typename T>
using expand_types_vm =
std::conditional_t<std::is_same_v<T, uint8_t> || std::is_same_v<T, uint16_t>, uint32_t , /* expand 8/16-bit to 32-bit */
std::conditional_t<std::is_same_v<T, float> , double , /* expand float to double */
std::conditional_t<std::is_same_v<T, FString> , const FString & , T>>>; /* change String to String ref */
std::conditional_t<std::is_same_v<T, FString> , const FString & , T>>>; /* change String to String ref */
template<typename M> unsigned int MapCountUsed(M * self)
{
@ -118,13 +118,22 @@ template<typename M> unsigned int MapCountUsed(M * self)
template<typename M> expand_types_vm<typename M::ValueType> MapGet(M * self,expand_types_vm<typename M::KeyType> key)
{
typename M::ValueType * v = self->CheckKey(key);
if (v) {
return *v;
if (v)
{
if constexpr(std::is_same_v<typename M::ValueType, DObject*>)
{
return GC::ReadBarrier(*v);
}
else
{
return *v;
}
}
else
{
typename M::ValueType n {};
self->Insert(key,n);
self->info->rev++; // invalidate iterators
return n;
}
}
@ -139,6 +148,38 @@ template<typename M> void MapGetString(M * self,expand_types_vm<typename M::KeyT
{
out = FString();
self->Insert(key,out);
self->info->rev++; // invalidate iterators
}
}
template<typename M> expand_types_vm<typename M::ValueType> MapGetIfExists(M * self,expand_types_vm<typename M::KeyType> key)
{
typename M::ValueType * v = self->CheckKey(key);
if (v) {
if constexpr(std::is_same_v<typename M::ValueType, DObject*>)
{
return GC::ReadBarrier(*v);
}
else
{
return *v;
}
}
else
{
return {};
}
}
template<typename M> void MapGetIfExistsString(M * self,expand_types_vm<typename M::KeyType> key, FString &out)
{
FString * v = self->CheckKey(key);
if (v) {
out = *v;
}
else
{
out = FString();
}
}
@ -147,6 +188,37 @@ template<typename M> int MapCheckKey(M * self, expand_types_vm<typename M::KeyTy
return self->CheckKey(key) != nullptr;
}
template<typename M> expand_types_vm<typename M::ValueType> MapCheckValue(M * self,expand_types_vm<typename M::KeyType> key, int &exists)
{
typename M::ValueType * v = self->CheckKey(key);
if ((exists = !!v)) {
if constexpr(std::is_same_v<typename M::ValueType, DObject*>)
{
return GC::ReadBarrier(*v);
}
else
{
return *v;
}
}
else
{
return {};
}
}
template<typename M> void MapCheckValueString(M * self,expand_types_vm<typename M::KeyType> key, FString &out, int &exists)
{
FString * v = self->CheckKey(key);
if ((exists = !!v)) {
out = *v;
}
else
{
out = FString();
}
}
//==========================================================================
//
@ -238,7 +310,14 @@ template<typename I> void MapIteratorGetKeyString(I * self, FString &out)
template<typename I> expand_types_vm<typename I::ValueType> MapIteratorGetValue(I * self)
{
return self->GetValue();
if constexpr(std::is_same_v<typename I::ValueType, DObject*>)
{
return GC::ReadBarrier(self->GetValue());
}
else
{
return self->GetValue();
}
}
template<typename I> void MapIteratorGetValueString(I * self, FString &out)
@ -272,6 +351,25 @@ template<typename I> void MapIteratorSetValue(I * self, expand_types_vm<typename
//
//==========================================================================
template<int N, typename T, typename U> void SetValType(T & ret,U & val){
if constexpr(std::is_same_v<U, DObject*>)
{
ret[N].SetObject(val);
}
else if constexpr(std::is_same_v<U, void*>)
{
ret[N].SetPointer(val);
}
else if constexpr(std::is_same_v<U, uint32_t>)
{
ret[N].SetInt(val);
}
else if constexpr(std::is_same_v<U, double>)
{
ret[N].SetFloat(val);
}
}
#define PARAM_VOIDPOINTER(X) PARAM_POINTER( X , void )
#define PARAM_OBJPOINTER(X) PARAM_OBJECT( X , DObject )
@ -345,6 +443,23 @@ template<typename I> void MapIteratorSetValue(I * self, expand_types_vm<typename
PARAM_SELF_STRUCT_PROLOGUE( name ); \
PARAM_KEY( key ); \
ACTION_RETURN_VALUE( MapGet(self, key) ); \
} \
DEFINE_ACTION_FUNCTION_NATIVE( name, GetIfExists, MapGetIfExists< name >) \
{ \
PARAM_SELF_STRUCT_PROLOGUE( name ); \
PARAM_KEY( key ); \
ACTION_RETURN_VALUE( MapGetIfExists(self, key) ); \
} \
DEFINE_ACTION_FUNCTION_NATIVE( name, CheckValue, MapCheckValue< name >) \
{ \
PARAM_SELF_STRUCT_PROLOGUE( name ); \
PARAM_KEY( key ); \
int exists; \
expand_types_vm<value_type> out; \
out = MapCheckValue(self, key, exists); \
if (numret > 1) ret[1].SetInt(exists); \
if (numret > 0) SetValType<0>(ret, out); \
return numret; \
}
#define DEF_MAP_X_S( name, key_type, PARAM_KEY ) \
@ -356,6 +471,25 @@ template<typename I> void MapIteratorSetValue(I * self, expand_types_vm<typename
FString out; \
MapGetString(self, key, out); \
ACTION_RETURN_STRING( out ); \
} \
DEFINE_ACTION_FUNCTION_NATIVE( name, GetIfExists, MapGetIfExistsString< name >) \
{ \
PARAM_SELF_STRUCT_PROLOGUE( name ); \
PARAM_KEY( key ); \
FString out; \
MapGetIfExistsString(self, key, out); \
ACTION_RETURN_STRING( out ); \
} \
DEFINE_ACTION_FUNCTION_NATIVE( name, CheckValue, MapCheckValueString< name >) \
{ \
PARAM_SELF_STRUCT_PROLOGUE( name ); \
PARAM_KEY( key ); \
int exists; \
FString out; \
MapCheckValueString(self, key, out, exists); \
if (numret > 1) ret[1].SetInt(exists); \
if (numret > 0) ret[0].SetString(out); \
return numret; \
}
#define COMMA ,

View file

@ -211,6 +211,7 @@ void FScopeBarrier::AddFlags(int flags1, int flags2, const char* name)
// these are for vmexec.h
void FScopeBarrier::ValidateNew(PClass* cls, int outerside)
{
if (cls->VMType == nullptr) ThrowAbortException(X_OTHER,"Cannot instantiate invalid class %s", cls->TypeName.GetChars());
int innerside = FScopeBarrier::SideFromObjectFlags(cls->VMType->ScopeFlags);
if ((outerside != innerside) && (innerside != FScopeBarrier::Side_PlainData)) // "cannot construct ui class ... from data context"
ThrowAbortException(X_OTHER, "Cannot construct %s class %s from %s context", FScopeBarrier::StringFromSide(innerside), cls->TypeName.GetChars(), FScopeBarrier::StringFromSide(outerside));

View file

@ -137,7 +137,6 @@ PField::PField()
{
}
PField::PField(FName name, PType *type, uint32_t flags, size_t offset, int bitvalue)
: PSymbol(name), Offset(offset), Type(type), Flags(flags)
{
@ -331,10 +330,12 @@ PSymbol *PSymbolTable::AddSymbol (PSymbol *sym)
//
//==========================================================================
PField *PSymbolTable::AddField(FName name, PType *type, uint32_t flags, unsigned &Size, unsigned *Align)
PField *PSymbolTable::AddField(FName name, PType *type, uint32_t flags, unsigned &Size, unsigned *Align, int fileno)
{
PField *field = Create<PField>(name, type, flags);
field->mDefFileNo = fileno;
// The new field is added to the end of this struct, alignment permitting.
field->Offset = (Size + (type->Align - 1)) & ~(type->Align - 1);
@ -365,10 +366,12 @@ PField *PSymbolTable::AddField(FName name, PType *type, uint32_t flags, unsigned
//
//==========================================================================
PField *PSymbolTable::AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue)
PField *PSymbolTable::AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue, int fileno)
{
PField *field = Create<PField>(name, type, flags | VARF_Native | VARF_Transient, address, bitvalue);
field->mDefFileNo = fileno;
if (AddSymbol(field) == nullptr)
{ // name is already in use
field->Destroy();

View file

@ -78,6 +78,7 @@ public:
uint32_t Flags;
int BitValue;
FString DeprecationMessage;
int mDefFileNo = 0;
protected:
PField();
};
@ -212,8 +213,8 @@ struct PSymbolTable
// a symbol with the same name is already in the table. This symbol is
// not copied and will be freed when the symbol table is destroyed.
PSymbol *AddSymbol (PSymbol *sym);
PField *AddField(FName name, PType *type, uint32_t flags, unsigned &Size, unsigned *Align = nullptr);
PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue);
PField *AddField(FName name, PType *type, uint32_t flags, unsigned &Size, unsigned *Align = nullptr, int fileno = 0);
PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue, int fileno = 0);
bool ReadFields(FSerializer &ar, void *addr, const char *TypeName) const;
void WriteFields(FSerializer &ar, const void *addr, const void *def = nullptr) const;

View file

@ -1985,12 +1985,114 @@ PStaticArray *NewStaticArray(PType *type)
//
//==========================================================================
enum OverrideFunctionRetType {
OFN_RET_VOID,
OFN_RET_VAL,
OFN_RET_KEY,
OFN_RET_BOOL,
OFN_RET_VAL_BOOL,
OFN_RET_INT,
};
enum OverrideFunctionArgType {
OFN_ARG_VOID,
OFN_ARG_KEY,
OFN_ARG_VAL,
OFN_ARG_KEY_VAL,
OFN_ARG_ELEM,
OFN_ARG_INT_ELEM,
};
template<OverrideFunctionRetType RetType, OverrideFunctionArgType ArgType , int ExtraFlags = 0, class MT>
void CreateOverrideFunction(MT *self, FName name)
{
auto Fn = Create<PFunction>(self->BackingType, name);
auto NativeFn = FindFunction(self->BackingType, name.GetChars());
assert(NativeFn);
assert(NativeFn->VMPointer);
TArray<PType*> ret;
TArray<PType*> args;
TArray<uint32_t> argflags;
TArray<FName> argnames;
if constexpr(RetType == OFN_RET_VAL)
{
ret.Push(self->ValueType);
}
else if constexpr(RetType == OFN_RET_KEY)
{
ret.Push(self->KeyType);
}
else if constexpr(RetType == OFN_RET_BOOL)
{
ret.Push(TypeBool);
}
else if constexpr(RetType == OFN_RET_VAL_BOOL)
{
ret.Push(self->ValueType);
ret.Push(TypeBool);
}
else if constexpr(RetType == OFN_RET_INT)
{
ret.Push(TypeSInt32);
}
args.Push(NewPointer(self->BackingType));
argnames.Push(NAME_self);
argflags.Push(VARF_Implicit | VARF_ReadOnly);
if constexpr(ArgType == OFN_ARG_KEY)
{
args.Push(self->KeyType);
argflags.Push(0);
argnames.Push(NAME_Key);
}
else if constexpr(ArgType == OFN_ARG_VAL)
{
args.Push(self->ValueType);
argflags.Push(0);
argnames.Push(NAME_Value);
}
else if constexpr(ArgType == OFN_ARG_KEY_VAL)
{
args.Push(self->KeyType);
args.Push(self->ValueType);
argflags.Push(0);
argflags.Push(0);
argnames.Push(NAME_Key);
argnames.Push(NAME_Value);
}
else if constexpr(ArgType == OFN_ARG_ELEM)
{
args.Push(self->ElementType);
argflags.Push(0);
argnames.Push(NAME_Item);
}
else if constexpr(ArgType == OFN_ARG_INT_ELEM)
{
args.Push(TypeSInt32);
args.Push(self->ElementType);
argflags.Push(0);
argflags.Push(0);
argnames.Push(NAME_Index);
argnames.Push(NAME_Item);
}
Fn->AddVariant(NewPrototype(ret, args), argflags, argnames, *NativeFn->VMPointer, VARF_Method | VARF_Native | ExtraFlags, SUF_ACTOR | SUF_OVERLAY | SUF_WEAPON | SUF_ITEM);
self->FnOverrides.Insert(name, Fn);
}
PDynArray::PDynArray(PType *etype,PStruct *backing)
: ElementType(etype), BackingType(backing)
{
mDescriptiveName.Format("DynArray<%s>", etype->DescriptiveName());
Size = sizeof(FArray);
Align = alignof(FArray);
CreateOverrideFunction<OFN_RET_INT , OFN_ARG_ELEM , VARF_ReadOnly> (this, NAME_Find);
CreateOverrideFunction<OFN_RET_INT , OFN_ARG_ELEM > (this, NAME_Push);
CreateOverrideFunction<OFN_RET_VOID , OFN_ARG_INT_ELEM > (this, NAME_Insert);
}
//==========================================================================
@ -2226,89 +2328,19 @@ PDynArray *NewDynArray(PType *type)
//
//==========================================================================
enum OverrideFunctionRetType {
OFN_RET_VOID,
OFN_RET_VAL,
OFN_RET_KEY,
OFN_RET_BOOL,
};
enum OverrideFunctionArgType {
OFN_ARG_VOID,
OFN_ARG_KEY,
OFN_ARG_VAL,
OFN_ARG_KEY_VAL,
};
template<class MT, OverrideFunctionRetType RetType, OverrideFunctionArgType ArgType >
void CreateOverrideFunction(MT *self, FName name)
{
auto Fn = Create<PFunction>(self->BackingType, name);
auto NativeFn = FindFunction(self->BackingType, name.GetChars());
assert(NativeFn);
assert(NativeFn->VMPointer);
TArray<PType*> ret;
TArray<PType*> args;
TArray<uint32_t> argflags;
TArray<FName> argnames;
if constexpr(RetType == OFN_RET_VAL)
{
ret.Push(self->ValueType);
}
else if constexpr(RetType == OFN_RET_KEY)
{
ret.Push(self->KeyType);
}
else if constexpr(RetType == OFN_RET_BOOL)
{
ret.Push(TypeBool);
}
args.Push(NewPointer(self->BackingType));
argnames.Push(NAME_self);
argflags.Push(VARF_Implicit | VARF_ReadOnly);
if constexpr(ArgType == OFN_ARG_KEY)
{
args.Push(self->KeyType);
argflags.Push(0);
argnames.Push(NAME_Key);
}
else if constexpr(ArgType == OFN_ARG_VAL)
{
args.Push(self->ValueType);
argflags.Push(0);
argnames.Push(NAME_Value);
}
else if constexpr(ArgType == OFN_ARG_KEY_VAL)
{
args.Push(self->KeyType);
args.Push(self->ValueType);
argflags.Push(0);
argflags.Push(0);
argnames.Push(NAME_Key);
argnames.Push(NAME_Value);
}
Fn->AddVariant(NewPrototype(ret, args), argflags, argnames, *NativeFn->VMPointer, VARF_Method | VARF_Native,SUF_ACTOR | SUF_OVERLAY | SUF_WEAPON | SUF_ITEM);
self->FnOverrides.Insert(name, Fn);
}
PMap::PMap(PType *keytype, PType *valtype, PStruct *backing, int backing_class)
: KeyType(keytype), ValueType(valtype), BackingType(backing), BackingClass((decltype(BackingClass)) backing_class)
{
mDescriptiveName.Format("Map<%s, %s>", keytype->DescriptiveName(), valtype->DescriptiveName());
Size = sizeof(ZSFMap);
Align = alignof(ZSFMap);
CreateOverrideFunction<PMap, OFN_RET_VAL, OFN_ARG_KEY>(this, NAME_Get);
CreateOverrideFunction<PMap, OFN_RET_BOOL, OFN_ARG_KEY>(this, NAME_CheckKey);
CreateOverrideFunction<PMap, OFN_RET_VOID, OFN_ARG_KEY_VAL>(this, NAME_Insert);
CreateOverrideFunction<PMap, OFN_RET_VOID, OFN_ARG_KEY>(this, NAME_InsertNew);
CreateOverrideFunction<PMap, OFN_RET_VOID, OFN_ARG_KEY>(this, NAME_Remove);
CreateOverrideFunction< OFN_RET_VAL , OFN_ARG_KEY > (this, NAME_Get);
CreateOverrideFunction< OFN_RET_VAL , OFN_ARG_KEY , VARF_ReadOnly> (this, NAME_GetIfExists);
CreateOverrideFunction< OFN_RET_BOOL , OFN_ARG_KEY , VARF_ReadOnly> (this, NAME_CheckKey);
CreateOverrideFunction< OFN_RET_VAL_BOOL , OFN_ARG_KEY , VARF_ReadOnly> (this, NAME_CheckValue);
CreateOverrideFunction< OFN_RET_VOID , OFN_ARG_KEY_VAL > (this, NAME_Insert);
CreateOverrideFunction< OFN_RET_VOID , OFN_ARG_KEY > (this, NAME_InsertNew);
CreateOverrideFunction< OFN_RET_VOID , OFN_ARG_KEY > (this, NAME_Remove);
}
//==========================================================================
@ -2770,9 +2802,9 @@ PMapIterator::PMapIterator(PType *keytype, PType *valtype, PStruct *backing, int
mDescriptiveName.Format("MapIterator<%s, %s>", keytype->DescriptiveName(), valtype->DescriptiveName());
Size = sizeof(ZSFMap);
Align = alignof(ZSFMap);
CreateOverrideFunction<PMapIterator, OFN_RET_KEY, OFN_ARG_VOID>(this, NAME_GetKey);
CreateOverrideFunction<PMapIterator, OFN_RET_VAL, OFN_ARG_VOID>(this, NAME_GetValue);
CreateOverrideFunction<PMapIterator, OFN_RET_VOID, OFN_ARG_VAL>(this, NAME_SetValue);
CreateOverrideFunction<OFN_RET_KEY, OFN_ARG_VOID>(this, NAME_GetKey);
CreateOverrideFunction<OFN_RET_VAL, OFN_ARG_VOID>(this, NAME_GetValue);
CreateOverrideFunction<OFN_RET_VOID, OFN_ARG_VAL>(this, NAME_SetValue);
}
//==========================================================================
@ -3009,12 +3041,13 @@ PMapIterator *NewMapIterator(PType *keyType, PType *valueType)
//
//==========================================================================
PStruct::PStruct(FName name, PTypeBase *outer, bool isnative)
PStruct::PStruct(FName name, PTypeBase *outer, bool isnative, int fileno)
: PContainerType(name, outer)
{
mDescriptiveName.Format("%sStruct<%s>", isnative? "Native" : "", name.GetChars());
Size = 0;
isNative = isnative;
mDefFileNo = fileno;
}
//==========================================================================
@ -3155,7 +3188,7 @@ PField *PStruct::AddField(FName name, PType *type, uint32_t flags)
PField *PStruct::AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue)
{
return Symbols.AddNativeField(name, type, address, flags, bitvalue);
return Symbols.AddNativeField(name, type, address, flags, bitvalue, mDefFileNo);
}
//==========================================================================
@ -3166,14 +3199,14 @@ PField *PStruct::AddNativeField(FName name, PType *type, size_t address, uint32_
//
//==========================================================================
PStruct *NewStruct(FName name, PTypeBase *outer, bool native)
PStruct *NewStruct(FName name, PTypeBase *outer, bool native, int fileno)
{
size_t bucket;
if (outer == nullptr) outer = Namespaces.GlobalNamespace;
PType *stype = TypeTable.FindType(NAME_Struct, (intptr_t)outer, name.GetIndex(), &bucket);
if (stype == nullptr)
{
stype = new PStruct(name, outer, native);
stype = new PStruct(name, outer, native, fileno);
TypeTable.AddType(stype, NAME_Struct, (intptr_t)outer, name.GetIndex(), bucket);
}
return static_cast<PStruct *>(stype);
@ -3271,7 +3304,7 @@ PPrototype *NewPrototype(const TArray<PType *> &rettypes, const TArray<PType *>
//
//==========================================================================
PClassType::PClassType(PClass *cls)
PClassType::PClassType(PClass *cls, int fileno)
{
assert(cls->VMType == nullptr);
Descriptor = cls;
@ -3284,6 +3317,7 @@ PClassType::PClassType(PClass *cls)
ScopeFlags = ParentType->ScopeFlags;
}
cls->VMType = this;
mDefFileNo = fileno;
mDescriptiveName.Format("Class<%s>", cls->TypeName.GetChars());
}
@ -3295,7 +3329,7 @@ PClassType::PClassType(PClass *cls)
PField *PClassType::AddField(FName name, PType *type, uint32_t flags)
{
return Descriptor->AddField(name, type, flags);
return Descriptor->AddField(name, type, flags, mDefFileNo);
}
//==========================================================================
@ -3306,7 +3340,7 @@ PField *PClassType::AddField(FName name, PType *type, uint32_t flags)
PField *PClassType::AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue)
{
auto field = Symbols.AddNativeField(name, type, address, flags, bitvalue);
auto field = Symbols.AddNativeField(name, type, address, flags, bitvalue, mDefFileNo);
if (field != nullptr) Descriptor->Fields.Push(field);
return field;
}
@ -3317,13 +3351,13 @@ PField *PClassType::AddNativeField(FName name, PType *type, size_t address, uint
//
//==========================================================================
PClassType *NewClassType(PClass *cls)
PClassType *NewClassType(PClass *cls, int fileno)
{
size_t bucket;
PType *ptype = TypeTable.FindType(NAME_Object, 0, cls->TypeName.GetIndex(), &bucket);
if (ptype == nullptr)
{
ptype = new PClassType(cls);
ptype = new PClassType(cls, fileno);
TypeTable.AddType(ptype, NAME_Object, 0, cls->TypeName.GetIndex(), bucket);
}
return static_cast<PClassType *>(ptype);

View file

@ -512,6 +512,8 @@ public:
PType *ElementType;
PStruct *BackingType;
TMap<FName,PFunction*> FnOverrides;
bool IsMatch(intptr_t id1, intptr_t id2) const override;
void GetTypeIDs(intptr_t &id1, intptr_t &id2) const override;
@ -596,13 +598,14 @@ public:
class PStruct : public PContainerType
{
public:
PStruct(FName name, PTypeBase *outer, bool isnative = false);
PStruct(FName name, PTypeBase *outer, bool isnative = false, int fileno = 0);
bool isNative;
bool isOrdered = false;
// Some internal structs require explicit construction and destruction of fields the VM cannot handle directly so use these two functions for it.
VMFunction *mConstructor = nullptr;
VMFunction *mDestructor = nullptr;
int mDefFileNo;
PField *AddField(FName name, PType *type, uint32_t flags=0) override;
PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags = 0, int bitvalue = 0) override;
@ -635,8 +638,9 @@ class PClassType : public PContainerType
public:
PClass *Descriptor;
PClassType *ParentType;
int mDefFileNo;
PClassType(PClass *cls = nullptr);
PClassType(PClass *cls = nullptr, int fileno = 0);
PField *AddField(FName name, PType *type, uint32_t flags = 0) override;
PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags = 0, int bitvalue = 0) override;
};
@ -657,9 +661,9 @@ PPointer *NewPointer(PType *type, bool isconst = false);
PPointer *NewPointer(PClass *type, bool isconst = false);
PClassPointer *NewClassPointer(PClass *restrict);
PEnum *NewEnum(FName name, PTypeBase *outer);
PStruct *NewStruct(FName name, PTypeBase *outer, bool native = false);
PStruct *NewStruct(FName name, PTypeBase *outer, bool native = false, int fileno = 0);
PPrototype *NewPrototype(const TArray<PType *> &rettypes, const TArray<PType *> &argtypes);
PClassType *NewClassType(PClass *cls);
PClassType *NewClassType(PClass *cls, int fileno);
// Built-in types -----------------------------------------------------------

View file

@ -720,11 +720,11 @@ void ZCCCompiler::CreateStructTypes()
}
else if (s->strct->Flags & ZCC_Native)
{
s->strct->Type = NewStruct(s->NodeName(), outer, true);
s->strct->Type = NewStruct(s->NodeName(), outer, true, AST.FileNo);
}
else
{
s->strct->Type = NewStruct(s->NodeName(), outer);
s->strct->Type = NewStruct(s->NodeName(), outer, false, AST.FileNo);
}
if (s->strct->Flags & ZCC_Version)
{
@ -832,7 +832,7 @@ void ZCCCompiler::CreateClassTypes()
{
DPrintf(DMSG_SPAMMY, "Registered %s as native with parent %s\n", me->TypeName.GetChars(), parent->TypeName.GetChars());
}
c->cls->Type = NewClassType(me);
c->cls->Type = NewClassType(me, AST.FileNo);
me->SourceLumpName = *c->cls->SourceName;
}
else
@ -844,14 +844,14 @@ void ZCCCompiler::CreateClassTypes()
{
Error(c->cls, "Parent class %s of %s not accessible to ZScript version %d.%d.%d", parent->TypeName.GetChars(), c->NodeName().GetChars(), mVersion.major, mVersion.minor, mVersion.revision);
}
auto newclass = parent->CreateDerivedClass(c->NodeName(), TentativeClass);
auto newclass = parent->CreateDerivedClass(c->NodeName(), TentativeClass, nullptr, AST.FileNo);
if (newclass == nullptr)
{
Error(c->cls, "Class name %s already exists", c->NodeName().GetChars());
}
else
{
c->cls->Type = NewClassType(newclass);
c->cls->Type = NewClassType(newclass, AST.FileNo);
DPrintf(DMSG_SPAMMY, "Created class %s with parent %s\n", c->Type()->TypeName.GetChars(), c->ClassType()->ParentClass->TypeName.GetChars());
}
}
@ -864,7 +864,7 @@ void ZCCCompiler::CreateClassTypes()
if (c->Type() == nullptr)
{
// create a placeholder so that the compiler can continue looking for errors.
c->cls->Type = NewClassType(parent->FindClassTentative(c->NodeName()));
c->cls->Type = NewClassType(parent->FindClassTentative(c->NodeName()), AST.FileNo);
}
if (c->cls->Flags & ZCC_Abstract)
@ -928,7 +928,7 @@ void ZCCCompiler::CreateClassTypes()
{
Error(c->cls, "Class %s has unknown base class %s", c->NodeName().GetChars(), FName(c->cls->ParentName->Id).GetChars());
// create a placeholder so that the compiler can continue looking for errors.
c->cls->Type = NewClassType(RUNTIME_CLASS(DObject)->FindClassTentative(c->NodeName()));
c->cls->Type = NewClassType(RUNTIME_CLASS(DObject)->FindClassTentative(c->NodeName()), AST.FileNo);
c->cls->Symbol = Create<PSymbolType>(c->NodeName(), c->Type());
OutNamespace->Symbols.AddSymbol(c->cls->Symbol);
Classes.Push(c);
@ -944,7 +944,7 @@ void ZCCCompiler::CreateClassTypes()
for (auto c : OrigClasses)
{
Error(c->cls, "Class %s has circular inheritance", FName(c->NodeName()).GetChars());
c->cls->Type = NewClassType(RUNTIME_CLASS(DObject)->FindClassTentative(c->NodeName()));
c->cls->Type = NewClassType(RUNTIME_CLASS(DObject)->FindClassTentative(c->NodeName()), AST.FileNo);
c->cls->Symbol = Create<PSymbolType>(c->NodeName(), c->Type());
OutNamespace->Symbols.AddSymbol(c->cls->Symbol);
Classes.Push(c);

View file

@ -407,6 +407,10 @@ PNamespace *ParseOneScript(const int baselump, ZCCParseState &state)
int lumpnum = baselump;
auto fileno = fileSystem.GetFileContainer(lumpnum);
FString file = fileSystem.GetFileFullPath(lumpnum);
state.FileNo = fileno;
if (TokenMap.CountUsed() == 0)
{
InitTokenMap();

View file

@ -628,6 +628,7 @@ struct ZCC_AST
FMemArena SyntaxArena;
struct ZCC_TreeNode *TopNode;
VersionInfo ParseVersion;
int FileNo;
};
struct ZCCParseState : public ZCC_AST

View file

@ -852,7 +852,22 @@ DEFINE_ACTION_FUNCTION(_CVar, SetInt)
PARAM_INT(val);
UCVarValue v;
v.Int = val;
self->SetGenericRep(v, CVAR_Int);
if(self->GetFlags() & CVAR_ZS_CUSTOM_CLONE)
{
auto realCVar = (FBaseCVar*)(self->GetExtraDataPointer());
assert(realCVar->GetFlags() & CVAR_ZS_CUSTOM);
v = realCVar->GenericZSCVarCallback(v, CVAR_Int);
self->SetGenericRep(v, realCVar->GetRealType());
if(realCVar->GetRealType() == CVAR_String) delete[] v.String;
}
else
{
self->SetGenericRep(v, CVAR_Int);
}
return 0;
}
@ -870,7 +885,22 @@ DEFINE_ACTION_FUNCTION(_CVar, SetFloat)
PARAM_FLOAT(val);
UCVarValue v;
v.Float = (float)val;
self->SetGenericRep(v, CVAR_Float);
if(self->GetFlags() & CVAR_ZS_CUSTOM_CLONE)
{
auto realCVar = (FBaseCVar*)(self->GetExtraDataPointer());
assert(realCVar->GetFlags() & CVAR_ZS_CUSTOM);
v = realCVar->GenericZSCVarCallback(v, CVAR_Float);
self->SetGenericRep(v, realCVar->GetRealType());
if(realCVar->GetRealType() == CVAR_String) delete[] v.String;
}
else
{
self->SetGenericRep(v, CVAR_Float);
}
return 0;
}
@ -889,7 +919,22 @@ DEFINE_ACTION_FUNCTION(_CVar, SetString)
PARAM_STRING(val);
UCVarValue v;
v.String = val.GetChars();
self->SetGenericRep(v, CVAR_String);
if(self->GetFlags() & CVAR_ZS_CUSTOM_CLONE)
{
auto realCVar = (FBaseCVar*)(self->GetExtraDataPointer());
assert(realCVar->GetFlags() & CVAR_ZS_CUSTOM);
v = realCVar->GenericZSCVarCallback(v, CVAR_String);
self->SetGenericRep(v, realCVar->GetRealType());
if(realCVar->GetRealType() == CVAR_String) delete[] v.String;
}
else
{
self->SetGenericRep(v, CVAR_String);
}
return 0;
}

View file

@ -849,6 +849,7 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret)
return 0;
}
auto p = o->GetClass();
if(p->Virtuals.Size() <= 0) ThrowAbortException(X_OTHER,"Attempted to call an invalid virtual function in class %s",p->TypeName.GetChars());
assert(C < p->Virtuals.Size());
reg.a[a] = p->Virtuals[C];
}