Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Simon 2023-02-16 22:10:57 +00:00
commit c9dc3c628f
582 changed files with 1055 additions and 292 deletions

View file

@ -151,6 +151,9 @@ if( NOT NO_OPENAL )
mark_as_advanced(CLEAR OPENAL_LIBRARY)
if( OPENAL_LIBRARY )
set( PROJECT_LIBRARIES ${OPENAL_LIBRARY} ${PROJECT_LIBRARIES} )
if( APPLE )
set( PROJECT_LIBRARIES ${PROJECT_LIBRARIES} "-framework AudioUnit -framework CoreAudio -framework ApplicationServices -framework AudioToolbox -framework CoreFoundation" )
endif()
else()
set( NO_OPENAL ON )
endif()

View file

@ -45,6 +45,7 @@
#include "findfile.h"
#include "i_interface.h"
#include "configfile.h"
#include "printf.h"
//==========================================================================
//
@ -456,6 +457,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;
}
}
@ -464,6 +466,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,13 @@
#include "palutil.h"
#include "i_interface.h"
#include "dobject.h"
#include "dobjtype.h"
#include "dobjgc.h"
#include "vm.h"
struct FLatchedValue
{
@ -215,13 +222,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 +301,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 +331,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 +360,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 +390,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 +612,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 +1469,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 +1789,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

@ -120,7 +120,7 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla
sc.MustGetValue(false);
GlobalKerning = sc.Number;
}
if (sc.Compare("Altfont"))
else if (sc.Compare("Altfont"))
{
sc.MustGetString();
AltFontName = sc.String;
@ -179,6 +179,11 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla
sc.ScriptError("Unknown translation type %s", sc.String);
}
}
else if (sc.Compare("lowercaselatinonly"))
{
lowercaselatinonly = true;
}
}
}
}
@ -755,7 +760,7 @@ int FFont::GetCharCode(int code, bool needpic) const
// Use different substitution logic based on the fonts content:
// In a font which has both upper and lower case, prefer unaccented small characters over capital ones.
// In a pure upper-case font, do not check for lower case replacements.
if (!MixedCase)
if (!MixedCase || (lowercaselatinonly && code >= 0x380 && code < 0x500))
{
// Try converting lowercase characters to uppercase.
if (myislower(code))

View file

@ -167,6 +167,7 @@ public:
forceremap = other.forceremap;
Chars = other.Chars;
Translations = other.Translations;
lowercaselatinonly = other.lowercaselatinonly;
Lump = other.Lump;
}
@ -189,6 +190,7 @@ protected:
bool noTranslate = false;
bool MixedCase = false;
bool forceremap = false;
bool lowercaselatinonly = false;
struct CharData
{
FGameTexture *OriginalPic = nullptr;

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

@ -119,12 +119,11 @@ void HWViewpointBuffer::Set2D(F2DDrawer *drawer, FRenderState &di, int width, in
SetViewpoint(di, &matrices);
return;
for (int n = 0; n < mPipelineNbr; n++)
{
mBufferPipeline[n]->Map();
memcpy(mBufferPipeline[n]->Memory(), &matrices, sizeof(matrices));
mBufferPipeline[n]->Unmap();
}
CheckSize();
mBuffer->Map();
memcpy(((char*)mBuffer->Memory()) + mUploadIndex * mBlockAlign, &matrices, sizeof(matrices));
mBuffer->Unmap();
mLastMappedIndex = -1;
}
@ -151,6 +150,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)
@ -6730,7 +6727,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 +6882,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 +7075,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 +7177,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 +8505,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];
}

View file

@ -554,6 +554,14 @@ bool WantEscape()
return gi->WantEscape();
}
EXTERN_CVAR(Int, duke_menufont)
void LanguageChanged(const char* lang)
{
duke_menufont->Callback();
}
void I_StartupJoysticks();
@ -600,7 +608,7 @@ int GameMain()
HudScaleChanged,
M_SetSpecialMenu,
OnMenuOpen,
nullptr,
LanguageChanged,
nullptr,
[]() ->FConfigFile* { return GameConfig; },
WantEscape,

View file

@ -43,6 +43,7 @@
FGameTexture* GetBaseForChar(FGameTexture* t);
void FontCharCreated(FGameTexture* base, FGameTexture* glyph);
EXTERN_CVAR(String, language)
FFont* IndexFont;
@ -55,8 +56,12 @@ CUSTOM_CVAR(Int, duke_menufont, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOIN
if (self < -1 || self > 1) self = -1;
else
{
// BigFont15 is Latin only, so for non-latin languages force BigFont13 until someone completes this font. (This lists all relevant European languages, regardless of support!)
if (!strnicmp(language, "ru", 2) || !strnicmp(language, "sr", 2) || !strnicmp(language, "bg", 2) || !strnicmp(language, "mk", 2) || !strnicmp(language, "uk", 2) || !strnicmp(language, "el", 2))
OriginalBigFont->CopyFrom(*BigFont13);
// Font info must be copied so that BigFont does not change its address.
if (self == 0 || (self == -1 && isPlutoPak())) OriginalBigFont->CopyFrom(*BigFont15);
else if (self == 0 || (self == -1 && isPlutoPak())) OriginalBigFont->CopyFrom(*BigFont15);
else if (self == 1 || (self == -1 && !isPlutoPak())) OriginalBigFont->CopyFrom(*BigFont13);
}
}

View file

@ -149,7 +149,8 @@ DDukeActor* spawninit_d(DDukeActor* actj, DDukeActor* act, TArray<DDukeActor*>*
switch (act->spr.picnum)
{
default:
CallInitialize(act);
if (!badguy(act) || commonEnemySetup(act, actj))
CallInitialize(act);
break;
case FOF:
act->spr.scale = DVector2(0, 0);

View file

@ -61,7 +61,8 @@ DDukeActor* spawninit_r(DDukeActor* actj, DDukeActor* act, TArray<DDukeActor*>*
{
default:
default_case:
CallInitialize(act);
if (!badguy(act) || commonEnemySetup(act, actj))
CallInitialize(act);
break;
case RTILE_RRTILE7936:
if (!isRRRA()) goto default_case;

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show more