Backend update from GZDoom.

This commit is contained in:
Christoph Oelckers 2024-10-09 15:25:44 +02:00
parent 27dc590931
commit b3a2523099
125 changed files with 1542 additions and 509 deletions

View file

@ -151,6 +151,7 @@ typedef enum EIntConfigKey_
zmusic_snd_mididevice,
zmusic_snd_outputrate,
zmusic_mod_preferredplayer,
NUM_ZMUSIC_INT_CONFIGS
} EIntConfigKey;

View file

@ -41,6 +41,7 @@
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cstdint>
#include <list>
#include <map>
#include <set>

View file

@ -120,6 +120,9 @@ include_directories(include include/zwidget src)
if(WIN32)
set(ZWIDGET_SOURCES ${ZWIDGET_SOURCES} ${ZWIDGET_WIN32_SOURCES})
add_definitions(-DUNICODE -D_UNICODE)
if(MINGW)
add_definitions(-DMINGW)
endif()
elseif(APPLE)
set(ZWIDGET_SOURCES ${ZWIDGET_SOURCES} ${ZWIDGET_COCOA_SOURCES})
set(ZWIDGET_LIBS ${CMAKE_DL_LIBS} -ldl)

View file

@ -18,6 +18,8 @@ LineEdit::LineEdit(Widget* parent) : Widget(parent)
LineEdit::~LineEdit()
{
delete timer;
delete scroll_timer;
}
bool LineEdit::IsReadOnly() const

View file

@ -28,6 +28,26 @@
#define RIDEV_INPUTSINK (0x100)
#endif
#ifdef MINGW
// MinGW's library doesn't contain a thunk for DwmDefWindowProc, so we need to create our own
BOOL DwmDefWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *plResult )
{
typedef BOOL(* dwmdwp)(HWND, UINT, WPARAM, LPARAM, LRESULT* );
BOOL result(FALSE);
HMODULE module = LoadLibrary( _T( "dwmapi.dll" ) );
if( module ) {
dwmdwp proc = reinterpret_cast<dwmdwp>( GetProcAddress( module, "DwmDefWindowProc" ) );
if( proc ) {
result = proc( hWnd, msg, wParam, lParam, plResult );
}
FreeLibrary(module);
}
return result;
}
#endif
static std::string from_utf16(const std::wstring& str)
{
if (str.empty()) return {};
@ -61,7 +81,7 @@ Win32Window::Win32Window(DisplayWindowHost* windowHost) : WindowHost(windowHost)
Windows.push_front(this);
WindowsIterator = Windows.begin();
WNDCLASSEX classdesc = {};
WNDCLASSEXW classdesc = {};
classdesc.cbSize = sizeof(WNDCLASSEX);
classdesc.hInstance = GetModuleHandle(0);
classdesc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
@ -74,7 +94,7 @@ Win32Window::Win32Window(DisplayWindowHost* windowHost) : WindowHost(windowHost)
// WS_CAPTION shows the caption (yay! actually a flag that does what it says it does!)
// WS_SYSMENU shows the min/max/close buttons
// WS_THICKFRAME makes the window resizable
CreateWindowEx(WS_EX_APPWINDOW | WS_EX_DLGMODALFRAME, L"ZWidgetWindow", L"", WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, 0, 0, 100, 100, 0, 0, GetModuleHandle(0), this);
CreateWindowExW(WS_EX_APPWINDOW | WS_EX_DLGMODALFRAME, L"ZWidgetWindow", L"", WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, 0, 0, 100, 100, 0, 0, GetModuleHandle(0), this);
/*
RAWINPUTDEVICE rid;
@ -387,6 +407,7 @@ void Win32Window::PresentBitmap(int width, int height, const uint32_t* pixels)
LRESULT Win32Window::OnWindowMessage(UINT msg, WPARAM wparam, LPARAM lparam)
{
LPARAM result = 0;
if (DwmDefWindowProc(WindowHandle, msg, wparam, lparam, &result))
return result;

View file

@ -2,7 +2,7 @@
#include "window/window.h"
#include <stdexcept>
#ifdef WIN32
#ifdef _WIN32
#include "win32/win32window.h"

View file

@ -13,4 +13,5 @@ add_library( bz2 STATIC
decompress.c
huffman.c
randtable.c )
link_libraries("-static")
target_link_libraries( bz2 )

View file

@ -1067,6 +1067,7 @@ set (PCH_SOURCES
common/textures/multipatchtexturebuilder.cpp
common/textures/skyboxtexture.cpp
common/textures/animtexture.cpp
common/textures/firetexture.cpp
common/textures/v_collection.cpp
common/textures/formats/automaptexture.cpp
common/textures/formats/brightmaptexture.cpp

View file

@ -592,6 +592,10 @@ void DShape2D::OnDestroy() {
void F2DDrawer::AddShape(FGameTexture* img, DShape2D* shape, DrawParms& parms)
{
// bail if shape is null (shouldn't happen but it might)
if (!shape)
ThrowAbortException(X_OTHER, "shape is null");
// [MK] bail out if vertex/coord array sizes are mismatched
if ( shape->mVertices.Size() != shape->mCoords.Size() )
ThrowAbortException(X_OTHER, "Mismatch in vertex/coord count: %u != %u", shape->mVertices.Size(), shape->mCoords.Size());

View file

@ -380,7 +380,7 @@ void DrawText(F2DDrawer *drawer, FFont* font, int normalcolor, double x, double
{
return;
}
const char *txt = (parms.localize && string[0] == '$') ? GStrings(&string[1]) : string;
const char *txt = (parms.localize && string[0] == '$') ? GStrings.GetString(&string[1]) : string;
DrawTextCommon(drawer, font, normalcolor, x, y, (const uint8_t*)string, parms);
}
@ -419,7 +419,7 @@ void DrawText(F2DDrawer *drawer, FFont *font, int normalcolor, double x, double
{
return;
}
const char *txt = (parms.localize && string[0] == '$') ? GStrings(&string[1]) : string.GetChars();
const char *txt = (parms.localize && string[0] == '$') ? GStrings.GetString(&string[1]) : string.GetChars();
DrawTextCommon(drawer, font, normalcolor, x, y, (uint8_t*)txt, parms);
}

View file

@ -74,6 +74,7 @@ float relative_volume = 1.f;
float saved_relative_volume = 1.0f; // this could be used to implement an ACS FadeMusic function
MusicVolumeMap MusicVolumes;
MidiDeviceMap MidiDevices;
TMap<int, int> ModPlayers;
static int DefaultFindMusic(const char* fn)
{
@ -93,6 +94,7 @@ EXTERN_CVAR(Float, fluid_gain)
CVAR(Bool, mus_calcgain, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // changing this will only take effect for the next song.
CVAR(Bool, mus_usereplaygain, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // changing this will only take effect for the next song.
CVAR(Int, mod_preferred_player, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)// toggle between libXMP and Dumb. Unlike other sound CVARs this is not directly mapped to ZMusic's config.
// CODE --------------------------------------------------------------------
@ -130,6 +132,24 @@ static FileReader OpenMusic(const char* musicname)
return reader;
}
bool MusicExists(const char* music_name)
{
if (music_name == nullptr)
return false;
if (FileExists(music_name))
return true;
else
{
int lumpnum;
lumpnum = mus_cb.FindMusic(music_name);
if (lumpnum == -1) lumpnum = fileSystem.CheckNumForName(music_name, FileSys::ns_music);
if (lumpnum != -1 && fileSystem.FileLength(lumpnum) != 0)
return true;
}
return false;
}
void S_SetMusicCallbacks(MusicCallbacks* cb)
{
mus_cb = *cb;
@ -751,6 +771,7 @@ bool S_ChangeMusic(const char* musicname, int order, bool looping, bool force)
{
int lumpnum = mus_cb.FindMusic(musicname);
MidiDeviceSetting* devp = MidiDevices.CheckKey(lumpnum);
int* mplay = ModPlayers.CheckKey(lumpnum);
auto volp = MusicVolumes.CheckKey(lumpnum);
if (volp)
@ -763,6 +784,12 @@ bool S_ChangeMusic(const char* musicname, int order, bool looping, bool force)
CheckReplayGain(musicname, devp ? (EMidiDevice)devp->device : MDEV_DEFAULT, devp ? devp->args.GetChars() : "");
}
auto mreader = GetMusicReader(reader); // this passes the file reader to the newly created wrapper.
int mod_player = mplay? *mplay : *mod_preferred_player;
int scratch;
// This config var is only effective when opening a music stream so there's no need for active synchronization. Setting it here is sufficient.
// Ideally this should have been a parameter to ZMusic_OpenSong, but that would have necessitated an API break.
ChangeMusicSettingInt(zmusic_mod_preferredplayer, mus_playing.handle, mod_player, &scratch);
mus_playing.handle = ZMusic_OpenSong(mreader, devp ? (EMidiDevice)devp->device : MDEV_DEFAULT, devp ? devp->args.GetChars() : "");
if (mus_playing.handle == nullptr)
{

View file

@ -45,6 +45,9 @@ bool S_StartMusic (const char *music_name);
// Start music using <music_name>, and set whether looping
bool S_ChangeMusic (const char *music_name, int order=0, bool looping=true, bool force=false);
// Check if <music_name> exists
bool MusicExists(const char* music_name);
void S_RestartMusic ();
void S_MIDIDeviceChanged(int newdev);
@ -71,6 +74,7 @@ struct MidiDeviceSetting
typedef TMap<int, MidiDeviceSetting> MidiDeviceMap;
typedef TMap<int, float> MusicVolumeMap;
extern TMap<int, int> ModPlayers;
extern MidiDeviceMap MidiDevices;
extern MusicVolumeMap MusicVolumes;
extern MusicCallbacks mus_cb;

View file

@ -598,6 +598,7 @@ OpenALSoundRenderer::OpenALSoundRenderer()
ALC.EXT_disconnect = !!alcIsExtensionPresent(Device, "ALC_EXT_disconnect");
ALC.SOFT_HRTF = !!alcIsExtensionPresent(Device, "ALC_SOFT_HRTF");
ALC.SOFT_pause_device = !!alcIsExtensionPresent(Device, "ALC_SOFT_pause_device");
ALC.SOFT_output_limiter = !!alcIsExtensionPresent(Device, "ALC_SOFT_output_limiter");
const ALCchar *current = NULL;
if(alcIsExtensionPresent(Device, "ALC_ENUMERATE_ALL_EXT"))
@ -634,6 +635,11 @@ OpenALSoundRenderer::OpenALSoundRenderer()
else
attribs.Push(ALC_DONT_CARE_SOFT);
}
if(ALC.SOFT_output_limiter)
{
attribs.Push(ALC_OUTPUT_LIMITER_SOFT);
attribs.Push(ALC_TRUE);
}
// Other attribs..?
attribs.Push(0);

View file

@ -80,7 +80,7 @@ CCMD (print)
Printf ("print <name>: Print a string from the string table\n");
return;
}
const char *str = GStrings[argv[1]];
const char *str = GStrings.CheckString(argv[1]);
if (str == NULL)
{
Printf ("%s unknown\n", argv[1]);
@ -304,7 +304,7 @@ CCMD(printlocalized)
return;
}
}
Printf("%s\n", GStrings(argv[1]));
Printf("%s\n", GStrings.GetString(argv[1]));
}
}

View file

@ -4,8 +4,15 @@
#include "startupinfo.h"
#include "c_cvars.h"
#include "gstrings.h"
#include "version.h"
static_assert(sizeof(void*) == 8, "32 builds are not supported");
static_assert(sizeof(void*) == 8,
"Only LP64/LLP64 builds are officially supported. "
"Please do not attempt to build for other platforms; "
"even if the program succeeds in a MAP01 smoke test, "
"there are e.g. known visual artifacts "
"<https://forum.zdoom.org/viewtopic.php?f=7&t=75673> "
"that lead to a bad user experience.");
// Some global engine variables taken out of the backend code.
FStartupScreen* StartWindow;
@ -23,7 +30,7 @@ bool pauseext;
FStartupInfo GameStartupInfo;
CVAR(Bool, queryiwad, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
CVAR(Bool, queryiwad, QUERYIWADDEFAULT, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
CVAR(String, defaultiwad, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
CVAR(Bool, vid_fps, false, 0)

View file

@ -31,7 +31,6 @@ struct SystemCallbacks
FString(*GetPlayerName)(int i);
bool (*DispatchEvent)(event_t* ev);
bool (*CheckGame)(const char* nm);
int (*GetGender)();
void (*MenuClosed)();
bool (*CheckMenudefOption)(const char* opt);
void (*ConsoleToggled)(int state);

View file

@ -907,7 +907,7 @@ static int PrivateNetOf(in_addr in)
{
return 0xC0A80000;
}
else if ((addr & 0xFFF00000) == 0xAC100000) // 172.16.0.0
else if ((addr & 0xFFFF0000) >= 0xAC100000 && (addr & 0xFFFF0000) <= 0xAC1F0000) // 172.16.0.0 - 172.31.0.0
{
return 0xAC100000;
}

View file

@ -120,16 +120,30 @@ bool M_LoadJoystickConfig(IJoystickConfig *joy)
{
return false;
}
assert(GameConfig);
value = GameConfig->GetValueForKey("Enabled");
if (value != NULL)
if (value)
{
joy->SetEnabled((bool)atoi(value));
}
if(joy->AllowsEnabledInBackground())
{
value = GameConfig->GetValueForKey("EnabledInBackground");
if (value)
{
joy->SetEnabledInBackground((bool)atoi(value));
}
}
value = GameConfig->GetValueForKey("Sensitivity");
if (value != NULL)
if (value)
{
joy->SetSensitivity((float)atof(value));
}
numaxes = joy->GetNumAxes();
for (int i = 0; i < numaxes; ++i)
{
@ -137,21 +151,21 @@ bool M_LoadJoystickConfig(IJoystickConfig *joy)
mysnprintf(key + axislen, countof(key) - axislen, "deadzone");
value = GameConfig->GetValueForKey(key);
if (value != NULL)
if (value)
{
joy->SetAxisDeadZone(i, (float)atof(value));
}
mysnprintf(key + axislen, countof(key) - axislen, "scale");
value = GameConfig->GetValueForKey(key);
if (value != NULL)
if (value)
{
joy->SetAxisScale(i, (float)atof(value));
}
mysnprintf(key + axislen, countof(key) - axislen, "map");
value = GameConfig->GetValueForKey(key);
if (value != NULL)
if (value)
{
EJoyAxis gameaxis = (EJoyAxis)atoi(value);
if (gameaxis < JOYAXIS_None || gameaxis >= NUM_JOYAXIS)
@ -185,6 +199,12 @@ void M_SaveJoystickConfig(IJoystickConfig *joy)
{
GameConfig->SetValueForKey("Enabled", "0");
}
if (!joy->AllowsEnabledInBackground() && joy->GetEnabledInBackground())
{
GameConfig->SetValueForKey("EnabledInBackground", "1");
}
if (!joy->IsSensitivityDefault())
{
mysnprintf(value, countof(value), "%g", joy->GetSensitivity());

View file

@ -39,6 +39,10 @@ struct IJoystickConfig
virtual bool GetEnabled() = 0;
virtual void SetEnabled(bool enabled) = 0;
virtual bool AllowsEnabledInBackground() = 0;
virtual bool GetEnabledInBackground() = 0;
virtual void SetEnabledInBackground(bool enabled) = 0;
// Used by the saver to not save properties that are at their defaults.
virtual bool IsSensitivityDefault() = 0;
virtual bool IsAxisDeadZoneDefault(int axis) = 0;

View file

@ -278,6 +278,8 @@ xx(BuiltinNameToClass)
xx(BuiltinClassCast)
xx(BuiltinFunctionPtrCast)
xx(BuiltinFindTranslation)
xx(HandleDeprecatedFlags)
xx(CheckDeprecatedFlags)
xx(ScreenJobRunner)
xx(Action)

View file

@ -197,6 +197,9 @@ void FSerializer::Close()
}
if (mErrors > 0)
{
if (mLumpName.IsNotEmpty())
I_Error("%d errors parsing JSON lump %s", mErrors, mLumpName.GetChars());
else
I_Error("%d errors parsing JSON", mErrors);
}
}
@ -331,6 +334,28 @@ bool FSerializer::HasObject(const char* name)
//
//==========================================================================
bool FSerializer::IsKeyNull(const char* name)
{
if (isReading())
{
auto val = r->FindKey(name);
if (val != nullptr)
{
if (val->IsNull())
{
return true;
}
}
}
return false;
}
//==========================================================================
//
//
//
//==========================================================================
void FSerializer::EndObject()
{
if (isWriting())

View file

@ -9,6 +9,7 @@
#include "palentry.h"
#include "name.h"
#include "dictionary.h"
#include "bonecomponents.h"
extern bool save_full;
@ -93,6 +94,7 @@ public:
void EndObject();
bool HasKey(const char* name);
bool HasObject(const char* name);
bool IsKeyNull(const char* name);
bool BeginArray(const char *name);
void EndArray();
unsigned GetSize(const char *group);
@ -224,6 +226,7 @@ public:
int mErrors = 0;
int mObjectErrors = 0;
FString mLumpName;
};
FSerializer& Serialize(FSerializer& arc, const char* key, char& value, char* defval);
@ -247,7 +250,8 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FString &sid, FString
FSerializer &Serialize(FSerializer &arc, const char *key, NumericValue &sid, NumericValue *def);
FSerializer &Serialize(FSerializer &arc, const char *key, struct ModelOverride &mo, struct ModelOverride *def);
FSerializer &Serialize(FSerializer &arc, const char *key, struct AnimModelOverride &mo, struct AnimModelOverride *def);
FSerializer &Serialize(FSerializer &arc, const char *key, struct AnimOverride &ao, struct AnimOverride *def);
FSerializer &Serialize(FSerializer &arc, const char *key, ModelAnim &ao, ModelAnim *def);
FSerializer &Serialize(FSerializer &arc, const char *key, ModelAnimFrame &ao, ModelAnimFrame *def);
FSerializer& Serialize(FSerializer& arc, const char* key, FTranslationID& value, FTranslationID* defval);
void SerializeFunctionPointer(FSerializer &arc, const char *key, FunctionPointerValue *&p);

View file

@ -47,29 +47,29 @@
//
//==========================================================================
void FStringTable::LoadStrings (FileSys::FileSystem& fileSystem_, const char *language)
void FStringTable::LoadStrings (FileSys::FileSystem& fileSystem, const char *language)
{
int lastlump, lump;
fileSystem = &fileSystem_;
allStrings.Clear();
lastlump = 0;
while ((lump = fileSystem->FindLump("LMACROS", &lastlump)) != -1)
while ((lump = fileSystem.FindLump("LMACROS", &lastlump)) != -1)
{
readMacros(lump);
auto lumpdata = fileSystem.ReadFile(lump);
readMacros(lumpdata.string(), lumpdata.size());
}
lastlump = 0;
while ((lump = fileSystem->FindLump ("LANGUAGE", &lastlump)) != -1)
while ((lump = fileSystem.FindLump ("LANGUAGE", &lastlump)) != -1)
{
auto lumpdata = fileSystem->ReadFile(lump);
auto lumpdata = fileSystem.ReadFile(lump);
auto filenum = fileSystem.GetFileContainer(lump);
if (!ParseLanguageCSV(lump, lumpdata.string(), lumpdata.size()))
LoadLanguage (lump, lumpdata.string(), lumpdata.size());
if (!ParseLanguageCSV(filenum, lumpdata.string(), lumpdata.size()))
LoadLanguage (filenum, lumpdata.string(), lumpdata.size());
}
UpdateLanguage(language);
allMacros.Clear();
fileSystem = nullptr;
}
@ -159,10 +159,9 @@ TArray<TArray<FString>> FStringTable::parseCSV(const char* buffer, size_t size)
//
//==========================================================================
bool FStringTable::readMacros(int lumpnum)
bool FStringTable::readMacros(const char* buffer, size_t size)
{
auto lumpdata = fileSystem->ReadFile(lumpnum);
auto data = parseCSV(lumpdata.string(), lumpdata.size());
auto data = parseCSV(buffer, size);
allMacros.Clear();
for (unsigned i = 1; i < data.Size(); i++)
@ -187,7 +186,7 @@ bool FStringTable::readMacros(int lumpnum)
//
//==========================================================================
bool FStringTable::ParseLanguageCSV(int lumpnum, const char* buffer, size_t size)
bool FStringTable::ParseLanguageCSV(int filenum, const char* buffer, size_t size)
{
if (size < 11) return false;
if (strnicmp(buffer, "default,", 8) && strnicmp(buffer, "identifier,", 11 )) return false;
@ -255,17 +254,18 @@ bool FStringTable::ParseLanguageCSV(int lumpnum, const char* buffer, size_t size
}
}
row[labelcol].StripLeftRight();
FName strName = row[labelcol].GetChars();
if (hasDefaultEntry)
{
DeleteForLabel(lumpnum, strName);
DeleteForLabel(filenum, strName);
}
for (auto &langentry : langrows)
{
auto str = row[langentry.first];
if (str.Len() > 0)
{
InsertString(lumpnum, langentry.second, strName, str);
InsertString(filenum, langentry.second, strName, str);
}
else
{
@ -409,11 +409,10 @@ void FStringTable::DeleteString(int langid, FName label)
//
//==========================================================================
void FStringTable::DeleteForLabel(int lumpnum, FName label)
void FStringTable::DeleteForLabel(int filenum, FName label)
{
decltype(allStrings)::Iterator it(allStrings);
decltype(allStrings)::Pair *pair;
auto filenum = fileSystem->GetFileContainer(lumpnum);
while (it.NextPair(pair))
{
@ -432,10 +431,10 @@ void FStringTable::DeleteForLabel(int lumpnum, FName label)
//
//==========================================================================
void FStringTable::InsertString(int lumpnum, int langid, FName label, const FString &string)
void FStringTable::InsertString(int filenum, int langid, FName label, const FString &string)
{
const char *strlangid = (const char *)&langid;
TableElement te = { fileSystem->GetFileContainer(lumpnum), { string, string, string, string } };
TableElement te = { filenum, { string, string, string, string } };
ptrdiff_t index;
while ((index = te.strings[0].IndexOf("@[")) >= 0)
{
@ -579,26 +578,33 @@ bool FStringTable::exists(const char *name)
//
//==========================================================================
const char *FStringTable::GetString(const char *name, uint32_t *langtable, int gender) const
const char *FStringTable::CheckString(const char *name, uint32_t *langtable, int gender) const
{
if (name == nullptr || *name == 0)
{
return nullptr;
}
if (gender == -1 && sysCallbacks.GetGender) gender = sysCallbacks.GetGender();
if (gender == -1) gender = defaultgender;
if (gender < 0 || gender > 3) gender = 0;
FName nm(name, true);
if (nm != NAME_None)
{
TableElement* bestItem = nullptr;
for (auto map : currentLanguageSet)
{
auto item = map.second->CheckKey(nm);
if (item)
{
if (bestItem && bestItem->filenum > item->filenum)
{
// prioritize content from later files, even if the language doesn't fully match.
// This is mainly for Dehacked content.
continue;
}
if (langtable) *langtable = map.first;
auto c = item->strings[gender].GetChars();
if (c && *c == '$' && c[1] == '$')
return GetString(c + 2, langtable, gender);
c = CheckString(c + 2, langtable, gender);
return c;
}
}
@ -608,7 +614,7 @@ const char *FStringTable::GetString(const char *name, uint32_t *langtable, int g
//==========================================================================
//
// Finds a string by name in a given language
// Finds a string by name in a given language without attempting any substitution
//
//==========================================================================
@ -618,7 +624,7 @@ const char *FStringTable::GetLanguageString(const char *name, uint32_t langtable
{
return nullptr;
}
if (gender == -1 && sysCallbacks.GetGender) gender = sysCallbacks.GetGender();
if (gender == -1) gender = defaultgender;
if (gender < 0 || gender > 3) gender = 0;
FName nm(name, true);
if (nm != NAME_None)
@ -655,9 +661,9 @@ bool FStringTable::MatchDefaultString(const char *name, const char *content) con
//
//==========================================================================
const char *FStringTable::operator() (const char *name) const
const char *FStringTable::GetString(const char *name) const
{
const char *str = operator[] (name);
const char *str = CheckString(name, nullptr);
return str ? str : name;
}

View file

@ -95,32 +95,29 @@ public:
const char *GetLanguageString(const char *name, uint32_t langtable, int gender = -1) const;
bool MatchDefaultString(const char *name, const char *content) const;
const char *GetString(const char *name, uint32_t *langtable, int gender = -1) const;
const char *operator() (const char *name) const; // Never returns NULL
const char* operator() (const FString& name) const { return operator()(name.GetChars()); }
const char *operator[] (const char *name) const
{
return GetString(name, nullptr);
}
const char *CheckString(const char *name, uint32_t *langtable = nullptr, int gender = -1) const;
const char* GetString(const char* name) const;
const char* GetString(const FString& name) const { return GetString(name.GetChars()); }
bool exists(const char *name);
void InsertString(int lumpnum, int langid, FName label, const FString& string);
void InsertString(int filenum, int langid, FName label, const FString& string);
void SetDefaultGender(int gender) { defaultgender = gender; }
private:
FileSys::FileSystem* fileSystem;
FString activeLanguage;
StringMacroMap allMacros;
LangMap allStrings;
TArray<std::pair<uint32_t, StringMap*>> currentLanguageSet;
int defaultgender = 0;
void LoadLanguage (int lumpnum, const char* buffer, size_t size);
TArray<TArray<FString>> parseCSV(const char* buffer, size_t size);
bool ParseLanguageCSV(int lumpnum, const char* buffer, size_t size);
bool ParseLanguageCSV(int filenum, const char* buffer, size_t size);
bool readMacros(int lumpnum);
bool readMacros(const char* buffer, size_t size);
void DeleteString(int langid, FName label);
void DeleteForLabel(int lumpnum, FName label);
void DeleteForLabel(int filenum, FName label);
static size_t ProcessEscapes (char *str);
public:
@ -138,7 +135,7 @@ public:
const char* localize(const char* str)
{
return *str == '$' ? operator()(str + 1) : str;
return *str == '$' ? GetString(str + 1) : str;
}
};

View file

@ -31,8 +31,6 @@
**
*/
namespace FileSys {
#ifdef _WIN32
#ifndef _WINNT_
@ -40,6 +38,8 @@ namespace FileSys {
#include <windows.h>
#endif
namespace FileSys {
class FInternalCriticalSection
{
public:
@ -82,6 +82,8 @@ void LeaveCriticalSection(FInternalCriticalSection *c)
#include <pthread.h>
namespace FileSys {
class FInternalCriticalSection
{
public:

View file

@ -106,7 +106,7 @@ int FDirectory::AddDirectory(const char *dirpath, LumpFilterInfo* filter, FileSy
if (mBasePath == nullptr)
{
// extract the base path from the first entry to cover changes made in ScanDirectory.
auto full = entry.FilePath.find(entry.FilePathRel);
auto full = entry.FilePath.rfind(entry.FilePathRel);
std::string path(entry.FilePath, 0, full);
mBasePath = stringpool->Strdup(path.c_str());
}

View file

@ -35,6 +35,7 @@
#include "fs_findfile.h"
#include <string.h>
#include <vector>
#include <sys/stat.h>
#ifndef _WIN32
@ -45,8 +46,6 @@
#endif
#include <unistd.h>
#include <fnmatch.h>
#include <sys/stat.h>
#include <dirent.h>
#endif

View file

@ -271,12 +271,12 @@ bool CheckFontComplete(FFont* font)
{
// Also check if the SmallFont contains all characters this language needs.
// If not, switch back to the original one.
return font->CanPrint(GStrings["REQUIRED_CHARACTERS"]);
return font->CanPrint(GStrings.CheckString("REQUIRED_CHARACTERS"));
}
void UpdateGenericUI(bool cvar)
{
auto switchstr = GStrings["USE_GENERIC_FONT"];
auto switchstr = GStrings.CheckString("USE_GENERIC_FONT");
generic_ui = (cvar || (switchstr && strtoll(switchstr, nullptr, 0)));
if (!generic_ui)
{
@ -311,7 +311,7 @@ void UpdateGenericUI(bool cvar)
}
}
// Turkish i crap. What a mess, just to save two code points... :(
switchstr = GStrings["REQUIRED_CHARACTERS"];
switchstr = GStrings.CheckString("REQUIRED_CHARACTERS");
special_i = switchstr && strstr(switchstr, "\xc4\xb0") != nullptr; // capital dotted i (İ).
if (special_i)
{

View file

@ -133,6 +133,26 @@ DEFINE_ACTION_FUNCTION(IJoystickConfig, SetEnabled)
return 0;
}
DEFINE_ACTION_FUNCTION(IJoystickConfig, AllowsEnabledInBackground)
{
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
ACTION_RETURN_BOOL(self->AllowsEnabledInBackground());
}
DEFINE_ACTION_FUNCTION(IJoystickConfig, GetEnabledInBackground)
{
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
ACTION_RETURN_BOOL(self->GetEnabledInBackground());
}
DEFINE_ACTION_FUNCTION(IJoystickConfig, SetEnabledInBackground)
{
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
PARAM_BOOL(enabled);
self->SetEnabledInBackground(enabled);
return 0;
}
void UpdateJoystickMenu(IJoystickConfig *selected)
{

View file

@ -84,7 +84,7 @@ int FSavegameManagerBase::RemoveSaveSlot(int index)
int listindex = SaveGames[0]->bNoDelete ? index - 1 : index;
if (listindex < 0) return index;
remove(SaveGames[index]->Filename.GetChars());
RemoveFile(SaveGames[index]->Filename.GetChars());
UnloadSaveData();
FSaveGameNode *file = SaveGames[index];
@ -274,7 +274,7 @@ DEFINE_ACTION_FUNCTION(FSavegameManager, DoSave)
unsigned FSavegameManagerBase::ExtractSaveData(int index)
{
FResourceFile *resf;
std::unique_ptr<FResourceFile> resf;
FSaveGameNode *node;
if (index == -1)
@ -295,7 +295,7 @@ unsigned FSavegameManagerBase::ExtractSaveData(int index)
(node = SaveGames[index]) &&
!node->Filename.IsEmpty() &&
!node->bOldVersion &&
(resf = FResourceFile::OpenResourceFile(node->Filename.GetChars(), true)) != nullptr)
( (resf.reset(FResourceFile::OpenResourceFile(node->Filename.GetChars(), true))), resf != nullptr))
{
auto info = resf->FindEntry("info.json");
if (info < 0)
@ -316,7 +316,8 @@ unsigned FSavegameManagerBase::ExtractSaveData(int index)
auto pic = resf->FindEntry("savepic.png");
if (pic >= 0)
{
FileReader picreader = resf->GetEntryReader(pic, FileSys::READER_NEW, FileSys::READERFLAG_SEEKABLE);
// This must use READER_CACHED or it will lock the savegame file.
FileReader picreader = resf->GetEntryReader(pic, FileSys::READER_CACHED, FileSys::READERFLAG_SEEKABLE);
PNGHandle *png = M_VerifyPNG(picreader);
if (png != nullptr)
{
@ -329,7 +330,6 @@ unsigned FSavegameManagerBase::ExtractSaveData(int index)
}
}
}
delete resf;
}
return index;
}
@ -470,7 +470,7 @@ DEFINE_ACTION_FUNCTION(FSavegameManager, GetSavegame)
void FSavegameManagerBase::InsertNewSaveNode()
{
NewSaveNode.SaveTitle = GStrings("NEWSAVE");
NewSaveNode.SaveTitle = GStrings.GetString("NEWSAVE");
NewSaveNode.bNoDelete = true;
SaveGames.Insert(0, &NewSaveNode);
}

View file

@ -4,6 +4,8 @@
#include "TRS.h"
#include "matrix.h"
#include <variant>
class DBoneComponents : public DObject
{
@ -14,3 +16,41 @@ public:
DBoneComponents() = default;
};
struct ModelAnimFrameInterp
{
float inter = -1.0f;
int frame1 = -1;
int frame2 = -1;
};
struct ModelAnimFramePrecalculatedIQM
{
TArray<TRS> precalcBones;
};
enum EModelAnimFlags
{
MODELANIM_NONE = 1 << 0, // no animation
MODELANIM_LOOP = 1 << 1, // animation loops, otherwise it stays on the last frame once it ends
};
struct ModelAnim
{
int firstFrame = 0;
int lastFrame = 0;
int loopFrame = 0;
float framerate = 0;
double startFrame = 0;
int flags = MODELANIM_NONE;
double startTic = 0; // when the current animation started (changing framerates counts as restarting) (or when animation starts if interpolating from previous animation)
double switchOffset = 0; // when the animation was changed -- where to interpolate the switch from
};
static_assert(sizeof(ModelAnim) == sizeof(double) * 6);
using ModelAnimFrame = std::variant<std::nullptr_t, ModelAnimFrameInterp, ModelAnimFramePrecalculatedIQM>;
double getCurrentFrame(const ModelAnim &anim, double tic, bool *looped);
void calcFrame(const ModelAnim &anim, double tic, ModelAnimFrameInterp &inter);
void calcFrames(const ModelAnim &curAnim, double tic, ModelAnimFrameInterp &to, float &inter);

View file

@ -9,6 +9,8 @@
#include "tarray.h"
#include "name.h"
#include "bonecomponents.h"
class DBoneComponents;
class FModelRenderer;
class FGameTexture;
@ -94,7 +96,10 @@ public:
virtual void AddSkins(uint8_t *hitlist, const FTextureID* surfaceskinids) = 0;
virtual float getAspectFactor(float vscale) { return 1.f; }
virtual const TArray<TRS>* AttachAnimationData() { return nullptr; };
virtual const TArray<VSMatrix> CalculateBones(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const TArray<TRS>* animationData, DBoneComponents* bones, int index) { return {}; };
virtual ModelAnimFrame PrecalculateFrame(const ModelAnimFrame &from, const ModelAnimFrameInterp &to, float inter, const TArray<TRS>* animationData, DBoneComponents* bones, int index) { return nullptr; };
virtual const TArray<VSMatrix> CalculateBones(const ModelAnimFrame &from, const ModelAnimFrameInterp &to, float inter, const TArray<TRS>* animationData, DBoneComponents* bones, int index) { return {}; };
void SetVertexBuffer(int type, IModelVertexBuffer *buffer) { mVBuf[type] = buffer; }
IModelVertexBuffer *GetVertexBuffer(int type) const { return mVBuf[type]; }

View file

@ -120,7 +120,12 @@ public:
void BuildVertexBuffer(FModelRenderer* renderer) override;
void AddSkins(uint8_t* hitlist, const FTextureID* surfaceskinids) override;
const TArray<TRS>* AttachAnimationData() override;
const TArray<VSMatrix> CalculateBones(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const TArray<TRS>* animationData, DBoneComponents* bones, int index) override;
ModelAnimFrame PrecalculateFrame(const ModelAnimFrame &from, const ModelAnimFrameInterp &to, float inter, const TArray<TRS>* animationData, DBoneComponents* bones, int index) override;
const TArray<VSMatrix> CalculateBones(const ModelAnimFrame &from, const ModelAnimFrameInterp &to, float inter, const TArray<TRS>* animationData, DBoneComponents* bones, int index) override;
ModelAnimFramePrecalculatedIQM CalculateFrameIQM(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const ModelAnimFramePrecalculatedIQM* precalculated, const TArray<TRS>* animationData, DBoneComponents* bones, int index);
const TArray<VSMatrix> CalculateBonesIQM(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const ModelAnimFramePrecalculatedIQM* precalculated, const TArray<TRS>* animationData, DBoneComponents* bones, int index);
private:
void LoadGeometry();

View file

@ -560,7 +560,108 @@ static TRS InterpolateBone(const TRS &from, const TRS &to, float t, float invt)
return bone;
}
const TArray<VSMatrix> IQMModel::CalculateBones(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const TArray<TRS>* animationData, DBoneComponents* boneComponentData, int index)
#include "printf.h"
ModelAnimFrame IQMModel::PrecalculateFrame(const ModelAnimFrame &from, const ModelAnimFrameInterp &to, float inter, const TArray<TRS>* animationData, DBoneComponents* bones, int index)
{
if(inter <= 0)
{
return CalculateFrameIQM(to.frame1, to.frame2, to.inter, 0, -1.f, 0, -1.f, nullptr, animationData, bones, index);
}
else if(std::holds_alternative<ModelAnimFrameInterp>(from))
{
auto &from_interp = std::get<ModelAnimFrameInterp>(from);
return CalculateFrameIQM(from_interp.frame2, to.frame2, inter, from_interp.frame1, from_interp.inter, to.frame1, to.inter, nullptr, animationData, bones, index);
}
else if(std::holds_alternative<ModelAnimFramePrecalculatedIQM>(from))
{
return CalculateFrameIQM(0, to.frame2, inter, 0, -1.f, to.frame1, to.inter, &std::get<ModelAnimFramePrecalculatedIQM>(from), animationData, bones, index);
}
else
{
return CalculateFrameIQM(to.frame1, to.frame2, to.inter, 0, -1.f, 0, -1.f, nullptr, animationData, bones, index);
}
}
const TArray<VSMatrix> IQMModel::CalculateBones(const ModelAnimFrame &from, const ModelAnimFrameInterp &to, float inter, const TArray<TRS>* animationData, DBoneComponents* bones, int index)
{
if(inter <= 0)
{
return CalculateBonesIQM(to.frame1, to.frame2, to.inter, 0, -1.f, 0, -1.f, nullptr, animationData, bones, index);
}
else if(std::holds_alternative<ModelAnimFrameInterp>(from))
{
auto &from_interp = std::get<ModelAnimFrameInterp>(from);
return CalculateBonesIQM(from_interp.frame2, to.frame2, inter, from_interp.frame1, from_interp.inter, to.frame1, to.inter, nullptr, animationData, bones, index);
}
else if(std::holds_alternative<ModelAnimFramePrecalculatedIQM>(from))
{
return CalculateBonesIQM(0, to.frame2, inter, 0, -1.f, to.frame1, to.inter, &std::get<ModelAnimFramePrecalculatedIQM>(from), animationData, bones, index);
}
else
{
return CalculateBonesIQM(to.frame1, to.frame2, to.inter, 0, -1.f, 0, -1.f, nullptr, animationData, bones, index);
}
}
ModelAnimFramePrecalculatedIQM IQMModel::CalculateFrameIQM(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const ModelAnimFramePrecalculatedIQM* precalculated, const TArray<TRS>* animationData, DBoneComponents* boneComponentData, int index)
{
ModelAnimFramePrecalculatedIQM out;
const TArray<TRS>& animationFrames = animationData ? *animationData : TRSData;
out.precalcBones.Resize(Joints.Size());
if (Joints.Size() > 0)
{
int numbones = Joints.SSize();
int offset1 = frame1 * numbones;
int offset2 = frame2 * numbones;
int offset1_1 = frame1_prev * numbones;
int offset2_1 = frame2_prev * numbones;
float invt = 1.0f - inter;
float invt1 = 1.0f - inter1_prev;
float invt2 = 1.0f - inter2_prev;
for (int i = 0; i < numbones; i++)
{
TRS prev;
if(precalculated)
{
prev = precalculated->precalcBones[i];
}
else
{
if(frame1 >= 0 && (frame1_prev >= 0 || inter1_prev < 0))
{
prev = inter1_prev <= 0 ? animationFrames[offset1 + i] : InterpolateBone(animationFrames[offset1_1 + i], animationFrames[offset1 + i], inter1_prev, invt1);
}
}
TRS next;
if(frame2 >= 0 && (frame2_prev >= 0 || inter2_prev < 0))
{
next = inter2_prev <= 0 ? animationFrames[offset2 + i] : InterpolateBone(animationFrames[offset2_1 + i], animationFrames[offset2 + i], inter2_prev, invt2);
}
if(frame1 >= 0 || inter < 0)
{
out.precalcBones[i] = inter < 0 ? animationFrames[offset1 + i] : InterpolateBone(prev, next , inter, invt);
}
}
}
return out;
}
const TArray<VSMatrix> IQMModel::CalculateBonesIQM(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const ModelAnimFramePrecalculatedIQM* precalculated, const TArray<TRS>* animationData, DBoneComponents* boneComponentData, int index)
{
const TArray<TRS>& animationFrames = animationData ? *animationData : TRSData;
if (Joints.Size() > 0)
@ -597,10 +698,17 @@ const TArray<VSMatrix> IQMModel::CalculateBones(int frame1, int frame2, float in
{
TRS prev;
if(precalculated)
{
prev = precalculated->precalcBones[i];
}
else
{
if(frame1 >= 0 && (frame1_prev >= 0 || inter1_prev < 0))
{
prev = inter1_prev <= 0 ? animationFrames[offset1 + i] : InterpolateBone(animationFrames[offset1_1 + i], animationFrames[offset1 + i], inter1_prev, invt1);
}
}
TRS next;

View file

@ -73,6 +73,9 @@ struct FVoxelDef
int VoxeldefIndex; // Needed by GZDoom
double Scale;
DAngle AngleOffset;// added to actor's angle to compensate for wrong-facing voxels
double xoffset;
double yoffset;
double zoffset;
bool PitchFromMomentum;
bool UseActorPitch;
bool UseActorRoll;

View file

@ -330,6 +330,7 @@ void DObject::Destroy ()
}
OnDestroy();
ObjectFlags = (ObjectFlags & ~OF_Fixed) | OF_EuthanizeMe;
GC::WriteBarrier(this);
}
DEFINE_ACTION_FUNCTION(DObject, Destroy)
@ -622,3 +623,165 @@ void *DObject::ScriptVar(FName field, PType *type)
// This is only for internal use so I_Error is fine.
I_Error("Variable %s not found in %s\n", field.GetChars(), cls->TypeName.GetChars());
}
//==========================================================================
//
//
//
//==========================================================================
void NetworkEntityManager::InitializeNetworkEntities()
{
if (!s_netEntities.Size())
s_netEntities.AppendFill(nullptr, NetIDStart); // Allocate the first 0-8 slots for the world and clients.
}
// Clients need special handling since they always go in slots 1 - MAXPLAYERS.
void NetworkEntityManager::SetClientNetworkEntity(DObject* mo, const unsigned int playNum)
{
// If resurrecting, we need to swap the corpse's position with the new pawn's
// position so it's no longer considered the client's body.
const uint32_t id = ClientNetIDStart + playNum;
DObject* const oldBody = s_netEntities[id];
if (oldBody != nullptr)
{
if (oldBody == mo)
return;
const uint32_t curID = mo->GetNetworkID();
s_netEntities[curID] = oldBody;
oldBody->ClearNetworkID();
oldBody->SetNetworkID(curID);
mo->ClearNetworkID();
}
else
{
RemoveNetworkEntity(mo); // Free up its current id.
}
s_netEntities[id] = mo;
mo->SetNetworkID(id);
}
void NetworkEntityManager::AddNetworkEntity(DObject* const ent)
{
if (ent->IsNetworked())
return;
// Slot 0 is reserved for the world.
// Clients go in the first 1 - MAXPLAYERS slots
// Everything else is first come first serve.
uint32_t id = WorldNetID;
if (s_openNetIDs.Size())
{
s_openNetIDs.Pop(id);
s_netEntities[id] = ent;
}
else
{
id = s_netEntities.Push(ent);
}
ent->SetNetworkID(id);
}
void NetworkEntityManager::RemoveNetworkEntity(DObject* const ent)
{
if (!ent->IsNetworked())
return;
const uint32_t id = ent->GetNetworkID();
if (id == WorldNetID)
return;
assert(s_netEntities[id] == ent);
if (id >= NetIDStart)
s_openNetIDs.Push(id);
s_netEntities[id] = nullptr;
ent->ClearNetworkID();
}
DObject* NetworkEntityManager::GetNetworkEntity(const uint32_t id)
{
if (id == WorldNetID || id >= s_netEntities.Size())
return nullptr;
return s_netEntities[id];
}
//==========================================================================
//
//
//
//==========================================================================
void DObject::SetNetworkID(const uint32_t id)
{
if (!IsNetworked())
{
ObjectFlags |= OF_Networked;
_networkID = id;
}
}
void DObject::ClearNetworkID()
{
ObjectFlags &= ~OF_Networked;
_networkID = NetworkEntityManager::WorldNetID;
}
void DObject::EnableNetworking(const bool enable)
{
if (enable)
NetworkEntityManager::AddNetworkEntity(this);
else
NetworkEntityManager::RemoveNetworkEntity(this);
}
void DObject::RemoveFromNetwork()
{
NetworkEntityManager::RemoveNetworkEntity(this);
}
static unsigned int GetNetworkID(DObject* const self)
{
return self->GetNetworkID();
}
DEFINE_ACTION_FUNCTION_NATIVE(DObject, GetNetworkID, GetNetworkID)
{
PARAM_SELF_PROLOGUE(DObject);
ACTION_RETURN_INT(self->GetNetworkID());
}
static void EnableNetworking(DObject* const self, const bool enable)
{
self->EnableNetworking(enable);
}
DEFINE_ACTION_FUNCTION_NATIVE(DObject, EnableNetworking, EnableNetworking)
{
PARAM_SELF_PROLOGUE(DObject);
PARAM_BOOL(enable);
self->EnableNetworking(enable);
return 0;
}
static DObject* GetNetworkEntity(const unsigned int id)
{
return NetworkEntityManager::GetNetworkEntity(id);
}
DEFINE_ACTION_FUNCTION_NATIVE(DObject, GetNetworkEntity, GetNetworkEntity)
{
PARAM_PROLOGUE;
PARAM_UINT(id);
ACTION_RETURN_OBJECT(NetworkEntityManager::GetNetworkEntity(id));
}

View file

@ -487,4 +487,25 @@ inline T *&DObject::PointerVar(FName field)
return *(T**)ScriptVar(field, nullptr); // pointer check is more tricky and for the handful of uses in the DECORATE parser not worth the hassle.
}
class NetworkEntityManager
{
private:
inline static TArray<DObject*> s_netEntities = {};
inline static TArray<uint32_t> s_openNetIDs = {};
public:
NetworkEntityManager() = delete;
static constexpr uint32_t WorldNetID = 0u;
static constexpr uint32_t ClientNetIDStart = 1u;
inline static uint32_t NetIDStart;// = MAXPLAYERS + 1u;
static void InitializeNetworkEntities();
static void SetClientNetworkEntity(DObject* mo, const unsigned int playNum);
static void AddNetworkEntity(DObject* const ent);
static void RemoveNetworkEntity(DObject* const ent);
static DObject* GetNetworkEntity(const uint32_t id);
};
#endif //__DOBJECT_H__

View file

@ -107,6 +107,10 @@ public:
virtual bool GetEnabled();
virtual void SetEnabled(bool enabled);
bool AllowsEnabledInBackground() { return false; }
bool GetEnabledInBackground() { return false; }
void SetEnabledInBackground(bool enabled) {}
virtual void SetDefaultConfig();
virtual FString GetIdentifier();

View file

@ -122,7 +122,7 @@ void I_ShowFatalError(const char *message)
}
int I_PickIWad(WadStuff* const wads, const int numwads, const bool showwin, const int defaultiwad, int&)
int I_PickIWad(WadStuff* const wads, const int numwads, const bool showwin, const int defaultiwad, int&, FString&)
{
if (!showwin)
{

View file

@ -38,7 +38,7 @@ void I_PrintStr (const char *str);
void I_SetIWADInfo ();
// Pick from multiple IWADs to use
int I_PickIWad (WadStuff *wads, int numwads, bool queryiwad, int defaultiwad, int&);
int I_PickIWad (WadStuff *wads, int numwads, bool queryiwad, int defaultiwad, int&, FString &);
// [RH] Checks the registry for Steam's install path, so we can scan its
// directories for IWADs if the user purchased any through Steam.

View file

@ -167,6 +167,10 @@ public:
Enabled = enabled;
}
bool AllowsEnabledInBackground() { return false; }
bool GetEnabledInBackground() { return false; }
void SetEnabledInBackground(bool enabled) {}
FString GetIdentifier()
{
char id[16];

View file

@ -298,7 +298,7 @@ void I_PrintStr(const char *cp)
if (StartWindow) RedrawProgressBar(ProgressBarCurPos,ProgressBarMaxPos);
}
int I_PickIWad (WadStuff *wads, int numwads, bool showwin, int defaultiwad, int& autoloadflags)
int I_PickIWad (WadStuff *wads, int numwads, bool showwin, int defaultiwad, int& autoloadflags, FString &extraArgs)
{
if (!showwin)
{
@ -308,7 +308,7 @@ int I_PickIWad (WadStuff *wads, int numwads, bool showwin, int defaultiwad, int&
#ifdef __APPLE__
return I_PickIWad_Cocoa (wads, numwads, showwin, defaultiwad);
#else
return LauncherWindow::ExecModal(wads, numwads, defaultiwad, &autoloadflags);
return LauncherWindow::ExecModal(wads, numwads, defaultiwad, &autoloadflags, &extraArgs);
#endif
}

View file

@ -183,6 +183,10 @@ public:
bool GetEnabled();
void SetEnabled(bool enabled);
bool AllowsEnabledInBackground() { return false; }
bool GetEnabledInBackground() { return false; }
void SetEnabledInBackground(bool enabled) {}
void SetDefaultConfig();
FString GetIdentifier();

View file

@ -124,6 +124,9 @@ int BlockMouseMove;
static bool EventHandlerResultForNativeMouse;
EXTERN_CVAR(Bool, i_pauseinbackground);
CVAR (Bool, k_allowfullscreentoggle, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
static void I_CheckGUICapture ()
@ -481,8 +484,8 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
break;
case WM_ACTIVATEAPP:
AppActive = wParam == TRUE;
if (wParam)
AppActive = (wParam == TRUE);
if (wParam || !i_pauseinbackground)
{
SetPriorityClass (GetCurrentProcess (), INGAME_PRIORITY_CLASS);
}

View file

@ -158,7 +158,7 @@ int DoMain (HINSTANCE hInstance)
Args->AppendArg(FString(wargv[i]));
}
if (Args->CheckParm("-stdout"))
if (Args->CheckParm("-stdout") || Args->CheckParm("-norun"))
{
// As a GUI application, we don't normally get a console when we start.
// If we were run from the shell and are on XP+, we can attach to its

View file

@ -267,7 +267,7 @@ void I_CheckNativeMouse(bool preferNative, bool eventhandlerresult)
}
else
{
if ((GetForegroundWindow() != mainwindow.GetHandle()) || preferNative || !use_mouse)
if (preferNative || !use_mouse)
{
want_native = true;
}
@ -286,6 +286,10 @@ void I_CheckNativeMouse(bool preferNative, bool eventhandlerresult)
if (!want_native && eventhandlerresult)
want_native = true;
// The application should *never* grab the mouse cursor if its window doesn't have the focus.
if (GetForegroundWindow() != mainwindow.GetHandle())
want_native = true;
//Printf ("%d %d %d\n", wantNative, preferNative, NativeMouse);
if (want_native != NativeMouse)

View file

@ -117,6 +117,10 @@ public:
bool GetEnabled();
void SetEnabled(bool enabled);
bool AllowsEnabledInBackground() { return false; }
bool GetEnabledInBackground() { return false; }
void SetEnabledInBackground(bool enabled) {}
void SetDefaultConfig();
FString GetIdentifier();

View file

@ -353,7 +353,7 @@ static void SetQueryIWad(HWND dialog)
//
//==========================================================================
int I_PickIWad(WadStuff *wads, int numwads, bool showwin, int defaultiwad, int& autoloadflags)
int I_PickIWad(WadStuff *wads, int numwads, bool showwin, int defaultiwad, int& autoloadflags, FString &extraArgs)
{
int vkey;
if (stricmp(queryiwad_key, "shift") == 0)
@ -370,7 +370,7 @@ int I_PickIWad(WadStuff *wads, int numwads, bool showwin, int defaultiwad, int&
}
if (showwin || (vkey != 0 && GetAsyncKeyState(vkey)))
{
return LauncherWindow::ExecModal(wads, numwads, defaultiwad, &autoloadflags);
return LauncherWindow::ExecModal(wads, numwads, defaultiwad, &autoloadflags, extraArgs);
}
return defaultiwad;
}

View file

@ -38,7 +38,7 @@ void I_PrintStr (const char *cp);
void I_SetIWADInfo ();
// Pick from multiple IWADs to use
int I_PickIWad(WadStuff* wads, int numwads, bool queryiwad, int defaultiwad, int& autoloadflags);
int I_PickIWad(WadStuff* wads, int numwads, bool queryiwad, int defaultiwad, int& autoloadflags, FString &extraArgs);
// The ini could not be saved at exit
bool I_WriteIniFailed (const char* filename);

View file

@ -65,6 +65,8 @@
#endif
#endif
extern bool AppActive;
// TYPES -------------------------------------------------------------------
typedef DWORD (WINAPI *XInputGetStateType)(DWORD index, XINPUT_STATE *state);
@ -105,6 +107,10 @@ public:
bool GetEnabled();
void SetEnabled(bool enabled);
bool AllowsEnabledInBackground() { return true; }
bool GetEnabledInBackground() { return EnabledInBackground; }
void SetEnabledInBackground(bool enabled) { EnabledInBackground = enabled; }
void SetDefaultConfig();
FString GetIdentifier();
@ -142,6 +148,7 @@ protected:
int LastButtons;
bool Connected;
bool Enabled;
bool EnabledInBackground;
void Attached();
void Detached();
@ -743,10 +750,13 @@ bool FXInputManager::GetDevice()
void FXInputManager::ProcessInput()
{
for (int i = 0; i < XUSER_MAX_COUNT; ++i)
{
if(AppActive || Devices[i]->GetEnabledInBackground())
{
Devices[i]->ProcessInput();
}
}
}
//===========================================================================
//

View file

@ -76,7 +76,7 @@ static void CheckOpenGL(void)
{
if (opengl32dll == 0)
{
opengl32dll = LoadLibrary(L"OpenGL32.DLL");
opengl32dll = LoadLibraryA("OpenGL32.DLL");
if (opengl32dll != 0)
{
createcontext = (HGLRC(WINAPI*)(HDC)) GetProcAddress(opengl32dll, "wglCreateContext");

View file

@ -54,3 +54,6 @@ EXTERN_CVAR(Int, gl_shadowmap_filter)
EXTERN_CVAR(Bool, gl_brightfog)
EXTERN_CVAR(Bool, gl_lightadditivesurfaces)
EXTERN_CVAR(Bool, gl_notexturefill)
EXTERN_CVAR(Bool, r_radarclipper)
EXTERN_CVAR(Bool, r_dithertransparency)

View file

@ -25,7 +25,7 @@ enum ERenderEffect
EFF_SPHEREMAP,
EFF_BURN,
EFF_STENCIL,
EFF_DITHERTRANS,
MAX_EFFECTS
};

View file

@ -299,6 +299,7 @@ const FEffectShader effectshaders[] =
{ "spheremap", "shaders/glsl/main.vp", "shaders/glsl/main.fp", "shaders/glsl/func_normal.fp", "shaders/glsl/material_normal.fp", "#define SPHEREMAP\n#define NO_ALPHATEST\n" },
{ "burn", "shaders/glsl/main.vp", "shaders/glsl/burn.fp", nullptr, nullptr, "#define SIMPLE\n#define NO_ALPHATEST\n" },
{ "stencil", "shaders/glsl/main.vp", "shaders/glsl/stencil.fp", nullptr, nullptr, "#define SIMPLE\n#define NO_ALPHATEST\n" },
{ "dithertrans", "shaders/glsl/main.vp", "shaders/glsl/main.fp", "shaders/glsl/func_normal.fp", "shaders/glsl/material_normal.fp", "#define NO_ALPHATEST\n#define DITHERTRANS\n" },
};
int DFrameBuffer::GetShaderCount()

View file

@ -146,11 +146,27 @@ float VREyeInfo::getShift() const
return vr_swap_eyes ? -res : res;
}
VSMatrix VREyeInfo::GetProjection(float fov, float aspectRatio, float fovRatio) const
VSMatrix VREyeInfo::GetProjection(float fov, float aspectRatio, float fovRatio, bool iso_ortho) const
{
VSMatrix result;
if (mShiftFactor == 0)
if (iso_ortho) // Orthographic projection for isometric viewpoint
{
double zNear = -3.0/fovRatio; // screen->GetZNear();
double zFar = screen->GetZFar();
double fH = tan(DEG2RAD(fov) / 2) / fovRatio;
double fW = fH * aspectRatio * mScaleFactor;
double left = -fW;
double right = fW;
double bottom = -fH;
double top = fH;
VSMatrix fmat(1);
fmat.ortho((float)left, (float)right, (float)bottom, (float)top, (float)zNear, (float)zFar);
return fmat;
}
else if (mShiftFactor == 0)
{
float fovy = (float)(2 * RAD2DEG(atan(tan(DEG2RAD(fov) / 2) / fovRatio)));
result.perspective(fovy, aspectRatio, screen->GetZNear(), screen->GetZFar());

View file

@ -27,7 +27,7 @@ struct VREyeInfo
float mShiftFactor;
float mScaleFactor;
VSMatrix GetProjection(float fov, float aspectRatio, float fovRatio) const;
VSMatrix GetProjection(float fov, float aspectRatio, float fovRatio, bool iso_ortho) const;
DVector3 GetViewShift(float yaw) const;
private:
float getShift() const;

View file

@ -2828,10 +2828,17 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx)
// Special case: Assignment to a bitfield.
IsBitWrite = Base->GetBitValue();
if (IsBitWrite >= 0x10000)
{
// internal flags - need more here
IsBitWrite &= 0xffff;
}
return this;
}
ExpEmit FxAssign::Emit(VMFunctionBuilder *build)
{
if (IsBitWrite < 64)
{
static const uint8_t loadops[] = { OP_LK, OP_LKF, OP_LKS, OP_LKP };
assert(Base->ValueType->GetRegType() == Right->ValueType->GetRegType());
@ -2887,7 +2894,6 @@ ExpEmit FxAssign::Emit(VMFunctionBuilder *build)
{
build->Emit(OP_SBIT, pointer.RegNum, result.RegNum, 1 << IsBitWrite);
}
}
if (AddressRequested)
@ -2907,6 +2913,21 @@ ExpEmit FxAssign::Emit(VMFunctionBuilder *build)
return result;
}
}
else
{
VMFunction* callfunc;
auto sym = FindBuiltinFunction(NAME_HandleDeprecatedFlags);
assert(sym);
callfunc = sym->Variants[0].Implementation;
FunctionCallEmitter emitters(callfunc);
emitters.AddParameter(build, Base);
emitters.AddParameter(build, Right);
emitters.AddParameterIntConst(IsBitWrite - 64);
return emitters.EmitCall(build);
}
}
//==========================================================================
//
@ -2933,18 +2954,20 @@ FxExpression *FxAssignSelf::Resolve(FCompileContext &ctx)
}
ExpEmit FxAssignSelf::Emit(VMFunctionBuilder *build)
{
if (Assignment->IsBitWrite < 64)
{
ExpEmit pointer = Assignment->Address; // FxAssign should have already emitted it
if (!pointer.Target)
{
ExpEmit out(build, ValueType->GetRegType(), ValueType->GetRegCount());
if (Assignment->IsBitWrite != -1)
if (Assignment->IsBitWrite == -1)
{
build->Emit(OP_LBIT, out.RegNum, pointer.RegNum, 1 << Assignment->IsBitWrite);
build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, build->GetConstantInt(0));
}
else
{
build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, build->GetConstantInt(0));
build->Emit(OP_LBIT, out.RegNum, pointer.RegNum, 1 << Assignment->IsBitWrite);
}
return out;
}
@ -2953,6 +2976,21 @@ ExpEmit FxAssignSelf::Emit(VMFunctionBuilder *build)
return pointer;
}
}
else
{
VMFunction* callfunc;
auto sym = FindBuiltinFunction(NAME_CheckDeprecatedFlags);
assert(sym);
callfunc = sym->Variants[0].Implementation;
FunctionCallEmitter emitters(callfunc);
emitters.AddParameter(build, Assignment->Base);
emitters.AddParameterIntConst(Assignment->IsBitWrite - 64);
emitters.AddReturn(REGT_INT);
return emitters.EmitCall(build);
}
}
//==========================================================================
@ -7727,6 +7765,8 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx)
}
ExpEmit FxStructMember::Emit(VMFunctionBuilder *build)
{
if (membervar->BitValue < 64 || AddressRequested)
{
ExpEmit obj = classx->Emit(build);
assert(obj.RegType == REGT_POINTER);
@ -7779,6 +7819,21 @@ ExpEmit FxStructMember::Emit(VMFunctionBuilder *build)
obj.Free(build);
return loc;
}
else
{
VMFunction* callfunc;
auto sym = FindBuiltinFunction(NAME_CheckDeprecatedFlags);
assert(sym);
callfunc = sym->Variants[0].Implementation;
FunctionCallEmitter emitters(callfunc);
emitters.AddParameter(build, classx);
emitters.AddParameterIntConst(membervar->BitValue - 64);
emitters.AddReturn(REGT_INT);
return emitters.EmitCall(build);
}
}
//==========================================================================
@ -9544,7 +9599,9 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
if(FnPtrCall) static_cast<VMScriptFunction*>(ctx.Function->Variants[0].Implementation)->blockJit = true;
int implicit = Function->GetImplicitArgs();
unsigned implicit = Function->GetImplicitArgs();
bool relaxed_named_arugments = (ctx.Version >= MakeVersion(4, 13));
if (!CheckAccessibility(ctx.Version))
{
@ -9576,22 +9633,129 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
CallingFunction = ctx.Function;
if (ArgList.Size() > 0)
{
if (argtypes.Size() == 0)
if ((argtypes.Size() == 0) || (argtypes.Last() != nullptr && ArgList.Size() + implicit > argtypes.Size()))
{
ScriptPosition.Message(MSG_ERROR, "Too many arguments in call to %s", Function->SymbolName.GetChars());
delete this;
return nullptr;
}
bool foundvarargs = false;
PType * type = nullptr;
int flag = 0;
if (argtypes.Size() > 0 && argtypes.Last() != nullptr && ArgList.Size() + implicit > argtypes.Size())
bool isvararg = (argtypes.Last() == nullptr);
{
TDeletingArray<FxExpression*> OrderedArgs;
const unsigned count = (argtypes.Size() - implicit) - isvararg;
OrderedArgs.Resize(count);
memset(OrderedArgs.Data(), 0, sizeof(FxExpression*) * count);
unsigned index = 0;
unsigned n = ArgList.Size();
for(unsigned i = 0; i < n; i++)
{
if(ArgList[i]->ExprType == EFX_NamedNode)
{
if(FnPtrCall)
{
ScriptPosition.Message(MSG_ERROR, "Named arguments not supported in function pointer calls");
delete this;
return nullptr;
}
else if((index >= count) && isvararg)
{
ScriptPosition.Message(MSG_ERROR, "Cannot use a named argument in the varargs part of the parameter list.");
delete this;
return nullptr;
}
else
{
FName name = static_cast<FxNamedNode *>(ArgList[i])->name;
if(argnames[index + implicit] != name)
{
unsigned j;
for (j = 0; j < count; j++)
{
if (argnames[j + implicit] == name)
{
if(!relaxed_named_arugments && !(argflags[j + implicit] & VARF_Optional))
{
ScriptPosition.Message(MSG_ERROR, "Cannot use a named argument here - not all required arguments have been passed.");
}
else if(!relaxed_named_arugments && j < index)
{
ScriptPosition.Message(MSG_ERROR, "Named argument %s comes before current position in argument list.", name.GetChars());
}
// i don't think this needs any further optimization?
// O(N^2) complexity technically but N isn't likely to be large,
// and the check itself is just an int comparison, so it should be fine
index = j;
break;
}
}
if(j == count)
{
ScriptPosition.Message(MSG_ERROR, "Named argument %s not found.", name.GetChars());
delete this;
return nullptr;
}
}
else if(!relaxed_named_arugments && !(argflags[index + implicit] & VARF_Optional))
{
ScriptPosition.Message(MSG_ERROR, "Cannot use a named argument here - not all required arguments have been passed.");
}
}
}
if(index >= count)
{
if(isvararg)
{
OrderedArgs.Push(ArgList[i]);
ArgList[i] = nullptr;
index++;
}
else
{
ScriptPosition.Message(MSG_ERROR, "Too many arguments in call to %s", Function->SymbolName.GetChars());
delete this;
return nullptr;
}
}
else
{
if(ArgList[i]->ExprType == EFX_NamedNode)
{
auto * node = static_cast<FxNamedNode *>(ArgList[i]);
OrderedArgs[index] = node->value;
node->value = nullptr;
}
else
{
OrderedArgs[index] = ArgList[i];
}
ArgList[i] = nullptr;
index++;
}
}
ArgList = std::move(OrderedArgs);
}
bool foundvarargs = false;
PType * type = nullptr;
int flag = 0;
int defaults_index = 0;
for(unsigned i = 0; i < implicit; i++)
{
defaults_index += argtypes[i]->GetRegCount();
}
for (unsigned i = 0; i < ArgList.Size(); i++)
{
@ -9608,65 +9772,27 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
}
assert(type != nullptr);
if (ArgList[i]->ExprType == EFX_NamedNode)
if(!foundvarargs)
{
if(FnPtrCall)
if(ArgList[i] == nullptr)
{
ScriptPosition.Message(MSG_ERROR, "Named arguments not supported in function pointer calls");
delete this;
return nullptr;
}
if(!(flag & VARF_Optional))
{
ScriptPosition.Message(MSG_ERROR, "Cannot use a named argument here - not all required arguments have been passed.");
ScriptPosition.Message(MSG_ERROR, "Required argument %s has not been passed in call to %s", argnames[i + implicit].GetChars(), Function->SymbolName.GetChars());
delete this;
return nullptr;
}
if (foundvarargs)
{
ScriptPosition.Message(MSG_ERROR, "Cannot use a named argument in the varargs part of the parameter list.");
delete this;
return nullptr;
}
unsigned j;
bool done = false;
FName name = static_cast<FxNamedNode *>(ArgList[i])->name;
for (j = 0; j < argnames.Size() - implicit; j++)
{
if (argnames[j + implicit] == name)
{
if (j < i)
{
ScriptPosition.Message(MSG_ERROR, "Named argument %s comes before current position in argument list.", name.GetChars());
delete this;
return nullptr;
}
// copy the original argument into the list
auto old = static_cast<FxNamedNode *>(ArgList[i]);
ArgList[i] = old->value;
old->value = nullptr;
delete old;
// now fill the gap with constants created from the default list so that we got a full list of arguments.
int insert = j - i;
int skipdefs = 0;
// Defaults contain multiple entries for pointers so we need to calculate how much additional defaults we need to skip
for (unsigned k = 0; k < i + implicit; k++)
{
skipdefs += argtypes[k]->GetRegCount() - 1;
}
for (int k = 0; k < insert; k++)
{
auto ntype = argtypes[i + k + implicit];
auto ntype = argtypes[i + implicit];
// If this is a reference argument, the pointer type must be undone because the code below expects the pointed type as value type.
if (argflags[i + k + implicit] & VARF_Ref)
if (argflags[i + implicit] & VARF_Ref)
{
assert(ntype->isPointer());
ntype = TypeNullPtr; // the default of a reference type can only be a null pointer
}
if (ntype->GetRegCount() == 1)
{
auto x = new FxConstant(ntype, (*defaults)[i + k + skipdefs + implicit], ScriptPosition);
ArgList.Insert(i + k, x);
ArgList[i] = new FxConstant(ntype, (*defaults)[defaults_index], ScriptPosition);
}
else
{
@ -9674,28 +9800,17 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
FxConstant *cs[4] = { nullptr };
for (int l = 0; l < ntype->GetRegCount(); l++)
{
cs[l] = new FxConstant(TypeFloat64, (*defaults)[l + i + k + skipdefs + implicit], ScriptPosition);
cs[l] = new FxConstant(TypeFloat64, (*defaults)[l + defaults_index], ScriptPosition);
}
FxExpression *x = new FxVectorValue(cs[0], cs[1], cs[2], cs[3], ScriptPosition);
ArgList.Insert(i + k, x);
skipdefs += ntype->GetRegCount() - 1;
ArgList[i] = new FxVectorValue(cs[0], cs[1], cs[2], cs[3], ScriptPosition);
}
}
done = true;
break;
}
}
if (!done)
{
ScriptPosition.Message(MSG_ERROR, "Named argument %s not found.", name.GetChars());
delete this;
return nullptr;
}
// re-get the proper info for the inserted node.
type = argtypes[i + implicit];
flag = argflags[i + implicit];
defaults_index += argtypes[i + implicit]->GetRegCount();
}
assert(ArgList[i]);
FxExpression *x = nullptr;
if (foundvarargs && (Function->Variants[0].Flags & VARF_VarArg))
{

View file

@ -331,6 +331,7 @@ void PType::StaticInit()
TypeVoidPtr = NewPointer(TypeVoid, false);
TypeRawFunction = new PPointer;
TypeRawFunction->mDescriptiveName = "Raw Function Pointer";
TypeTable.AddType(TypeRawFunction, NAME_None);
TypeVMFunction = NewPointer(NewStruct("VMFunction", nullptr, true));
TypeColorStruct = NewStruct("@ColorStruct", nullptr); //This name is intentionally obfuscated so that it cannot be used explicitly. The point of this type is to gain access to the single channels of a color value.
TypeStringStruct = NewStruct("Stringstruct", nullptr, true);

View file

@ -282,9 +282,9 @@ DEFINE_ACTION_FUNCTION(FStringStruct, DeleteLastCharacter)
static void LocalizeString(const FString &label, bool prefixed, FString *result)
{
if (!prefixed) *result = GStrings(label);
if (!prefixed) *result = GStrings.GetString(label);
else if (label[0] != '$') *result = label;
else *result = GStrings(&label[1]);
else *result = GStrings.GetString(&label[1]);
}
DEFINE_ACTION_FUNCTION_NATIVE(FStringTable, Localize, LocalizeString)

View file

@ -670,7 +670,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetBottomAlignOffset, GetBottomAlignOffset)
static int StringWidth(FFont *font, const FString &str, int localize)
{
const char *txt = (localize && str[0] == '$') ? GStrings(&str[1]) : str.GetChars();
const char *txt = (localize && str[0] == '$') ? GStrings.GetString(&str[1]) : str.GetChars();
return font->StringWidth(txt);
}
@ -684,7 +684,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(FFont, StringWidth, StringWidth)
static int GetMaxAscender(FFont* font, const FString& str, int localize)
{
const char* txt = (localize && str[0] == '$') ? GStrings(&str[1]) : str.GetChars();
const char* txt = (localize && str[0] == '$') ? GStrings.GetString(&str[1]) : str.GetChars();
return font->GetMaxAscender(txt);
}
@ -698,7 +698,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetMaxAscender, GetMaxAscender)
static int CanPrint(FFont *font, const FString &str, int localize)
{
const char *txt = (localize && str[0] == '$') ? GStrings(&str[1]) : str.GetChars();
const char *txt = (localize && str[0] == '$') ? GStrings.GetString(&str[1]) : str.GetChars();
return font->CanPrint(txt);
}
@ -770,6 +770,26 @@ DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetDisplayTopOffset, GetDisplayTopOffset)
ACTION_RETURN_FLOAT(GetDisplayTopOffset(self, code));
}
static int GetChar(FFont* font, int c)
{
int texc = 0;
auto getch = font->GetChar(c, CR_UNDEFINED, nullptr);
if (getch)
texc = getch->GetID().GetIndex();
return texc;
}
DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetChar, ::GetChar)
{
PARAM_SELF_STRUCT_PROLOGUE(FFont);
PARAM_INT(mchar);
if (numret > 0) ret[0].SetInt(::GetChar(self, mchar));
if (numret > 1) ret[1].SetInt(self->GetCharWidth(mchar));
return min(2, numret);
}
//==========================================================================
//
// file system
@ -1142,6 +1162,17 @@ DEFINE_ACTION_FUNCTION(_Console, PrintfEx)
return 0;
}
DEFINE_ACTION_FUNCTION(_Console, DebugPrintf)
{
PARAM_PROLOGUE;
PARAM_INT(debugLevel);
PARAM_VA_POINTER(va_reginfo);
FString s = FStringFormat(VM_ARGS_NAMES, 1);
DPrintf(debugLevel, "%s\n", s.GetChars());
return 0;
}
static void StopAllSounds()
{
soundEngine->StopAllChannels();

View file

@ -111,7 +111,7 @@ FEndoomScreen::FEndoomScreen(int loading_lump)
StartupBitmap.Create(80 * 8, 26 * 16); // line 26 is for our own 'press any key to quit' message.
DrawTextScreen(StartupBitmap, endoom_screen);
ClearBlock(StartupBitmap, {0, 0, 0, 255}, 0, 25*16, 640, 16);
DrawString(StartupBitmap, 0, 25, GStrings("TXT_QUITENDOOM"), { 128, 128, 128 ,255}, { 0, 0, 0, 255});
DrawString(StartupBitmap, 0, 25, GStrings.GetString("TXT_QUITENDOOM"), { 128, 128, 128 ,255}, { 0, 0, 0, 255});
lastUpdateTime = I_msTime();
// Does this screen need blinking?

View file

@ -372,6 +372,13 @@ FStartScreen* GetGameStartScreen(int max_progress)
return nullptr;
}
FStartScreen::~FStartScreen()
{
if (StartupTexture) delete StartupTexture;
if (HeaderTexture) delete HeaderTexture;
if (NetTexture) delete NetTexture;
}
//==========================================================================
//
// ST_Util_ClearBlock
@ -607,7 +614,7 @@ bool FStartScreen::NetInit(const char* message, int numplayers)
{
NetMaxPos = numplayers;
NetCurPos = 0;
NetMessageString.Format("%s %s", message, GStrings("TXT_NET_PRESSESC"));
NetMessageString.Format("%s %s", message, GStrings.GetString("TXT_NET_PRESSESC"));
NetProgress(1); // You always know about yourself
return true;
}

View file

@ -70,7 +70,7 @@ protected:
FGameTexture* NetTexture = nullptr;
public:
FStartScreen(int maxp) { MaxPos = maxp; }
virtual ~FStartScreen() = default;
virtual ~FStartScreen();
void Render(bool force = false);
bool Progress(int);
void NetProgress(int count);

View file

@ -0,0 +1,139 @@
/*
** firetexture.cpp
** PSX/N64-style fire texture implementation
**
**---------------------------------------------------------------------------
** Copyright Cacodemon345 2024
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
/* Algorithm based on https://github.com/fabiensanglard/DoomFirePSX */
#include "bitmap.h"
#include "firetexture.h"
#include "m_random.h"
#include "imagehelpers.h"
#include "engineerrors.h"
static constexpr int32_t FIRESKY_W = 64;
static constexpr int32_t FIRESKY_H = 128;
FireTexture::FireTexture()
{
SetSize(FIRESKY_W, FIRESKY_H);
Image.Clear();
Image.AppendFill(0, Width * Height);
}
void FireTexture::SetPalette(TArray<PalEntry>& colors)
{
Palette.Clear();
Palette.Append(colors);
/* This shouldn't happen in any circumstances. */
if (Palette.Size() > 256)
{
I_FatalError("Fire palette too big!");
}
for (unsigned int i = 0; i < Width; i++) {
Image[(Height - 1) * Width + i] = (uint8_t)(Palette.Size() - 1);
}
}
void FireTexture::Update()
{
for (unsigned int y = 1; y < Height; y++)
{
for (unsigned int x = 0; x < Width; x++)
{
uint8_t srcPixel = Image[y * Width + x];
if (srcPixel == 0)
{
Image[(y - 1) * Width + x] = 0;
}
else
{
int XRand = M_Random() & 3;
int destRand = M_Random() & 1;
Image[(y - 1) * Width + ((x + 1 - XRand) % Width)] = srcPixel - destRand;
}
}
}
}
FBitmap FireTexture::GetBgraBitmap(const PalEntry* remap, int* trans)
{
FBitmap bitmap;
bitmap.Create(Width, Height);
uint32_t* pixels = (uint32_t*)bitmap.GetPixels();
for (unsigned int y = 0; y < Height; y++)
{
for (unsigned int x = 0; x < Width; x++)
{
pixels[y * Width + x] = Palette[Image[y * Width + x]];
}
}
return bitmap;
}
TArray<uint8_t> FireTexture::Get8BitPixels(bool alphatex)
{
FBitmap bitmap = GetBgraBitmap(nullptr, nullptr);
const uint8_t* data = bitmap.GetPixels();
uint8_t* dest_p;
int dest_adv = Height;
int dest_rew = Width * Height - 1;
TArray<uint8_t> Pixels(Width * Height);
dest_p = Pixels.Data();
bool doalpha = alphatex;
// Convert the source image from row-major to column-major format and remap it
for (int y = Height; y != 0; --y)
{
for (int x = Width; x != 0; --x)
{
int b = *data++;
int g = *data++;
int r = *data++;
int a = *data++;
if (a < 128) *dest_p = 0;
else *dest_p = ImageHelpers::RGBToPalette(doalpha, r, g, b);
dest_p += dest_adv;
}
dest_p -= dest_rew;
}
return Pixels;
}

View file

@ -0,0 +1,17 @@
#pragma once
#include "textures.h"
class FireTexture : public FTexture
{
TArray<uint8_t> Image;
TArray<PalEntry> Palette;
public:
FireTexture();
void SetPalette(TArray<PalEntry>& colors);
void Update();
virtual FBitmap GetBgraBitmap(const PalEntry* remap, int* trans) override;
virtual TArray<uint8_t> Get8BitPixels(bool alphatex) override;
};

View file

@ -306,6 +306,7 @@ void FImageSource::EndPrecaching()
void FImageSource::RegisterForPrecache(FImageSource *img, bool requiretruecolor)
{
if (img)
img->CollectForPrecache(precacheInfo, requiretruecolor);
}

View file

@ -378,7 +378,7 @@ FGameTexture *FTextureManager::FindGameTexture(const char *texname, ETextureType
bool FTextureManager::OkForLocalization(FTextureID texnum, const char *substitute, int locmode)
{
uint32_t langtable = 0;
if (*substitute == '$') substitute = GStrings.GetString(substitute+1, &langtable);
if (*substitute == '$') substitute = GStrings.CheckString(substitute+1, &langtable);
else return true; // String literals from the source data should never override graphics from the same definition.
if (substitute == nullptr) return true; // The text does not exist.

View file

@ -593,6 +593,26 @@ void CreatePath(const char *fn)
}
#endif
void RemoveFile(const char* file)
{
#ifndef _WIN32
remove(file);
#else
auto wpath = WideString(file);
_wremove(wpath.c_str());
#endif
}
int RemoveDir(const char* file)
{
#ifndef _WIN32
return rmdir(file);
#else
auto wpath = WideString(file);
return _wrmdir(wpath.c_str());
#endif
}
//==========================================================================
//
// strbin -- In-place version

View file

@ -71,6 +71,8 @@ int strbin (char *str);
FString strbin1 (const char *start);
void CreatePath(const char * fn);
void RemoveFile(const char* file);
int RemoveDir(const char* file);
FString ExpandEnvVars(const char *searchpathstring);
FString NicePath(const char *path);

View file

@ -189,7 +189,7 @@ int FArgs::CheckParmList(const char *check, FString **strings, int start) const
}
for (i = ++parmat; i < Argv.Size(); ++i)
{
if (Argv[i][0] == '-' || Argv[i][1] == '+')
if (Argv[i][0] == '-' || Argv[i][0] == '+')
{
break;
}
@ -345,6 +345,114 @@ void FArgs::AppendArgs(int argc, const FString *argv)
}
}
//===========================================================================
//
// FArgs :: AppendArgsString
//
// Adds extra args as a space-separated string, supporting simple quoting, and inserting -file args into the right place
//
//===========================================================================
void FArgs::AppendArgsString(FString argv)
{
auto file_index = Argv.Find("-file");
auto files_end = file_index + 1;
for (; files_end < Argv.Size() && Argv[files_end][0] != '-' && Argv[files_end][0] != '+'; ++files_end);
if(file_index == Argv.Size())
{
Argv.Push("-file");
}
bool inserting_file = true;
argv.StripLeftRight();
size_t i = 0;
size_t lastSection = 0;
size_t lastStart = 0;
char lastQuoteType = 0;
FString tmp;
bool has_tmp = false;
for(i = 0; i < argv.Len(); i++)
{
if(argv[i] == ' ')
{
FString arg = tmp + argv.Mid(lastSection, i - lastSection);
if(arg[0] == '-' || arg[0] == '+') inserting_file = false;
if(inserting_file)
{
Argv.Insert(files_end++, arg);
}
else if(arg.Compare("-file") == 0)
{
inserting_file = true;
}
else
{
files_end++;
Argv.Insert(file_index++, arg);
}
lastSection = i + 1;
tmp = "";
has_tmp = false;
for(;(i + 1) < argv.Len() && argv[i + 1] == ' '; i++, lastSection++);
lastStart = i + 1;
}
else if(argv[i] == '\'' || argv[i] == '"')
{
lastQuoteType = argv[i];
tmp += argv.Mid(lastSection, i - lastSection);
has_tmp = true;
bool wasSlash = false;
for(i++; (argv[i] != lastQuoteType || wasSlash) && i < argv.Len(); i++)
{
if(i == '\\' && !wasSlash)
{
wasSlash = true;
}
else
{
tmp += argv[i];
wasSlash = false;
}
}
lastSection = i + 1;
}
}
if(lastSection != i)
{ // ended on an unquoted section
FString arg = tmp + argv.Mid(lastSection);
if(inserting_file)
{
Argv.Insert(files_end, arg);
}
else if(arg.Compare("-file") != 0)
{
Argv.Insert(file_index, arg);
}
}
else if(has_tmp)
{ // ended on a quote
if(inserting_file)
{
Argv.Insert(files_end, tmp);
}
else if(tmp.Compare("-file") != 0)
{
Argv.Insert(file_index, tmp);
}
}
}
//===========================================================================
//
// FArgs :: RemoveArg

View file

@ -85,6 +85,7 @@ public:
void AppendArg(FString arg);
void AppendArgs(int argc, const FString *argv);
void AppendArgsString(FString argv);
void RemoveArg(int argindex);
void RemoveArgs(const char *check);
void SetArgs(int argc, char **argv);

View file

@ -72,6 +72,13 @@ public:
m_Box[BOXTOP] = pos.Y;
}
bool CheckOverlap(const FBoundingBox &box2)
{
bool hori = (Left() > box2.Right()) || (Right() < box2.Left());
bool vert = (Bottom() > box2.Top()) || (Top() < box2.Bottom());
return !(hori || vert); // [DVR] For alternative space partition
}
inline double Top () const { return m_Box[BOXTOP]; }
inline double Bottom () const { return m_Box[BOXBOTTOM]; }
inline double Left () const { return m_Box[BOXLEFT]; }

View file

@ -919,6 +919,7 @@ public:
TDeletingArray(TDeletingArray<T,TT> &&other) : TArray<T,TT>(std::move(other)) {}
TDeletingArray<T,TT> &operator=(TDeletingArray<T,TT> &&other)
{
DeleteAndClear();
TArray<T,TT>::operator=(std::move(other));
return *this;
}

View file

@ -1019,6 +1019,45 @@ struct TVector4
}
};
inline void ZeroSubnormalsF(double& num)
{
if (fabs(num) < FLT_MIN) num = 0;
}
inline void ZeroSubnormals(double& num)
{
if (fabs(num) < DBL_MIN) num = 0;
}
inline void ZeroSubnormals(float& num)
{
if (fabsf(num) < FLT_MIN) num = 0;
}
template<typename T>
inline void ZeroSubnormals(TVector2<T>& vec)
{
ZeroSubnormals(vec.X);
ZeroSubnormals(vec.Y);
}
template<typename T>
inline void ZeroSubnormals(TVector3<T>& vec)
{
ZeroSubnormals(vec.X);
ZeroSubnormals(vec.Y);
ZeroSubnormals(vec.Z);
}
template<typename T>
inline void ZeroSubnormals(TVector4<T>& vec)
{
ZeroSubnormals(vec.X);
ZeroSubnormals(vec.Y);
ZeroSubnormals(vec.Z);
ZeroSubnormals(vec.W);
}
template<class vec_t>
struct TMatrix3x3
{

View file

@ -40,6 +40,7 @@
#include "m_swap.h"
#include "w_zip.h"
#include "fs_decompress.h"
#include "cmdlib.h"
using FileSys::FCompressedBuffer;
@ -201,7 +202,7 @@ bool WriteZip(const char* filename, const FCompressedBuffer* content, size_t con
if (pos == -1)
{
delete f;
remove(filename);
RemoveFile(filename);
return false;
}
positions.Push(pos);
@ -213,7 +214,7 @@ bool WriteZip(const char* filename, const FCompressedBuffer* content, size_t con
if (AppendCentralDirectory(f, content[i], dostime, positions[i]) < 0)
{
delete f;
remove(filename);
RemoveFile(filename);
return false;
}
}
@ -230,7 +231,7 @@ bool WriteZip(const char* filename, const FCompressedBuffer* content, size_t con
if (f->Write(&dirend, sizeof(dirend)) != sizeof(dirend))
{
delete f;
remove(filename);
RemoveFile(filename);
return false;
}
delete f;

View file

@ -1089,6 +1089,12 @@ octdigits = [0-7];
("0" octdigits+ | "0" [xX] hexdigits+ | (digits \ '0') digits*) { return true; }
[\000-\377] { return false; }*/
//FIX for "0" returning false, doesn't fix 0 with whitespace, but that isn't necessary for savegame loading, so it'll need to be fixed later
if(Len() == 1 && Chars[0] == '0') return true;
const char *YYCURSOR = Chars;
char yych;

View file

@ -128,6 +128,7 @@ public:
FString (FString &&other) noexcept : Chars(other.Chars) { other.ResetToNull(); }
FString (const char *copyStr);
FString (const char *copyStr, size_t copyLen);
FString (const std::string &s) : FString(s.c_str(), s.length()) {}
FString (char oneChar);
FString(const TArray<char> & source) : FString(source.Data(), source.Size()) {}
FString(const TArray<uint8_t> & source) : FString((char*)source.Data(), source.Size()) {}

View file

@ -21,6 +21,7 @@ void InitWidgetResources(const char* filename)
void CloseWidgetResources()
{
if (WidgetResources) delete WidgetResources;
WidgetResources = nullptr;
}
static std::vector<uint8_t> LoadFile(const char* name)

View file

@ -87,7 +87,7 @@ CCMD(allmap)
if (!CheckCheatmode(true, false))
{
gFullMap = !gFullMap;
Printf("%s\n", GStrings(gFullMap ? "SHOW MAP: ON" : "SHOW MAP: OFF"));
Printf("%s\n", GStrings.GetString(gFullMap ? "SHOW MAP: ON" : "SHOW MAP: OFF"));
}
}
@ -105,7 +105,7 @@ CCMD(togglefollow)
{
am_followplayer = !am_followplayer;
auto msg = quoteMgr.GetQuote(am_followplayer ? 84 : 83);
if (!msg || !*msg) msg = am_followplayer ? GStrings("FOLLOW MODE ON") : GStrings("FOLLOW MODE Off");
if (!msg || !*msg) msg = am_followplayer ? GStrings.GetString("FOLLOW MODE ON") : GStrings.GetString("FOLLOW MODE Off");
Printf(PRINT_NOTIFY, "%s\n", msg);
if (am_followplayer) follow.X = INT_MAX;
}
@ -113,7 +113,7 @@ CCMD(togglefollow)
CCMD(togglerotate)
{
am_rotate = !am_rotate;
auto msg = am_rotate ? GStrings("TXT_ROTATE_ON") : GStrings("TXT_ROTATE_OFF");
auto msg = am_rotate ? GStrings.GetString("TXT_ROTATE_ON") : GStrings.GetString("TXT_ROTATE_OFF");
Printf(PRINT_NOTIFY, "%s\n", msg);
}

View file

@ -103,7 +103,7 @@ void genericCheat(int player, uint8_t** stream, bool skip)
Printf(PRINT_NOTIFY, "%s\n", msg);
else
{
FString message = GStrings("TXT_X_CHEATS");
FString message = GStrings.GetString("TXT_X_CHEATS");
//message.Substitute("%s", player->userinfo.GetName()); // fixme - make globally accessible
Printf(PRINT_NOTIFY, "%s: %s\n", message.GetChars(), msg);
}

View file

@ -175,7 +175,7 @@ static bool printNative()
// Blood originally uses its tiny font for the notify display which does not play along well with localization because it is too small, so for non-English switch to the text font.
if (con_notify_advanced) return false;
if (!isBlood()) return true;
auto p = GStrings["REQUIRED_CHARACTERS"];
auto p = GStrings.CheckString("REQUIRED_CHARACTERS");
if (p && *p) return false;
return true;
}

View file

@ -226,7 +226,7 @@ void CT_Drawer (void)
if (chatmodeon)
{
FStringf prompt("%s ", GStrings("TXT_SAY"));
FStringf prompt("%s ", GStrings.GetString("TXT_SAY"));
int x, scalex, y, promptwidth;
@ -356,7 +356,7 @@ static void ShoveChatStr (const char *str, uint8_t who)
Net_WriteString(MakeUTF8(substBuff));
}
#else
Printf("%s %s\n", GStrings("TXT_SAY"), str);
Printf("%s %s\n", GStrings.GetString("TXT_SAY"), str);
#endif
}
}

View file

@ -194,11 +194,6 @@ CUSTOM_CVAR(Int, cl_gender, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
if (self < 0 || self > 3) self = 0;
}
int StrTable_GetGender()
{
return cl_gender;
}
bool validFilter(const char* str);
extern int chatmodeon;
@ -600,7 +595,6 @@ int GameMain()
nullptr,
System_DispatchEvent,
validFilter,
StrTable_GetGender,
System_MenuClosed,
nullptr,
nullptr,
@ -829,7 +823,8 @@ static TArray<GrpEntry> SetupGame()
if (autoloadbrightmaps) flags |= 4;
if (autoloadwidescreen) flags |= 8;
pick = I_PickIWad(&wads[0], (int)wads.Size(), queryiwad, pick, flags);
FString extraArgs;
pick = I_PickIWad(&wads[0], (int)wads.Size(), queryiwad, pick, flags, extraArgs);
if (pick >= 0)
{
disableautoload = !!(flags & 1);
@ -1620,7 +1615,7 @@ void TITLE_InformName(const char* newname)
{
LevelName = newname;
if (newname[0] == '$')
LevelName = GStrings(newname + 1);
LevelName = GStrings.GetString(newname + 1);
I_UpdateWindowTitle();
}

View file

@ -235,7 +235,7 @@ CCMD(togglemouseaim)
in_mousemode = !in_mousemode;
if (!silentmouseaimtoggle)
{
Printf(PRINT_MEDIUM|PRINT_NOTIFY, "%s\n", in_mousemode? GStrings("TXT_MOUSEAIMON") : GStrings("TXT_MOUSEAIMOFF"));
Printf(PRINT_MEDIUM|PRINT_NOTIFY, "%s\n", in_mousemode? GStrings.GetString("TXT_MOUSEAIMON") : GStrings.GetString("TXT_MOUSEAIMOFF"));
}
}

View file

@ -157,7 +157,7 @@ struct MapRecord
const char* LabelName() const
{
if (flags & MI_USERMAP) return GStrings("MNU_USERMAP");
if (flags & MI_USERMAP) return GStrings.GetString("MNU_USERMAP");
return labelName.GetChars();
}
const char *DisplayName() const
@ -181,7 +181,7 @@ struct MapRecord
const char* GetMessage(int num)
{
if (num < 0 || num>= MAX_MESSAGES) return "";
return GStrings(messages[num]);
return GStrings.GetString(messages[num]);
}
void AddMessage(int num, const FString &msg)

View file

@ -98,7 +98,7 @@ static bool DoStartGame(FNewGameStartup& gs)
if (isShareware() && (vol->flags & VF_SHAREWARELOCK))
{
M_StartMessage(GStrings("SHAREWARELOCK"), 1, NAME_None);
M_StartMessage(GStrings.GetString("SHAREWARELOCK"), 1, NAME_None);
return false;
}
@ -164,7 +164,7 @@ bool M_SetSpecialMenu(FName& menu, int param)
if (!gi->CanSave())
{
// cannot save outside the game.
M_StartMessage(GStrings("SAVEDEAD"), 1, NAME_None);
M_StartMessage(GStrings.GetString("SAVEDEAD"), 1, NAME_None);
return true;
}
break;
@ -234,7 +234,7 @@ CCMD(menu_quit)
M_StartControlPanel(true);
FString EndString;
EndString << GStrings("CONFIRM_QUITMSG") << "\n\n" << GStrings("PRESSYN");
EndString << GStrings.GetString("CONFIRM_QUITMSG") << "\n\n" << GStrings.GetString("PRESSYN");
DMenu* newmenu = CreateMessageBoxMenu(CurrentMenu, EndString.GetChars(), 0, false, NAME_None, []()
{
@ -260,7 +260,7 @@ CCMD(menu_endgame)
M_StartControlPanel(true);
FString tempstring;
tempstring << GStrings("ENDGAME") << "\n\n" << GStrings("PRESSYN");
tempstring << GStrings.GetString("ENDGAME") << "\n\n" << GStrings.GetString("PRESSYN");
DMenu* newmenu = CreateMessageBoxMenu(CurrentMenu, tempstring.GetChars(), 0, false, NAME_None, []()
{
STAT_Cancel();
@ -305,7 +305,7 @@ CCMD(quicksave)
return;
}
FString tempstring = GStrings("QSPROMPT");
FString tempstring = GStrings.GetString("QSPROMPT");
tempstring.Substitute("%s", slot->SaveTitle.GetChars());
M_StartControlPanel(true);
@ -329,7 +329,7 @@ CCMD(quickload)
if (netgame)
{
M_StartControlPanel(true);
M_StartMessage(GStrings("QLOADNET"), 1);
M_StartMessage(GStrings.GetString("QLOADNET"), 1);
return;
}
@ -348,7 +348,7 @@ CCMD(quickload)
G_LoadGame(savegameManager.quickSaveSlot->Filename.GetChars());
return;
}
FString tempstring = GStrings("QLPROMPT");
FString tempstring = GStrings.GetString("QLPROMPT");
tempstring.Substitute("%s", savegameManager.quickSaveSlot->SaveTitle.GetChars());
M_StartControlPanel(true);

View file

@ -44,7 +44,7 @@
void Quotes::MakeStringLabel(FString &quote)
{
// Only prepend a quote if the string is localizable.
if (quote.Len() > 0 && quote[0] != '$' && GStrings[quote.GetChars()]) quote.Insert(0, "$");
if (quote.Len() > 0 && quote[0] != '$' && GStrings.CheckString(quote.GetChars())) quote.Insert(0, "$");
}
void Quotes::InitializeQuote(int num, const char *text, bool fromscript)

View file

@ -189,8 +189,8 @@ FFont* PickBigFont(const char* txt)
{
if (generic_ui) return NewSmallFont; // Note: Support is incomplete. Translations do not exist anyway for most content.
if (!OriginalBigFont || OriginalBigFont == BigFont) return BigFont;
if (txt && *txt == '$') txt = GStrings[txt + 1];
if (!txt || !*txt) txt = GStrings["REQUIRED_CHARACTERS"];
if (txt && *txt == '$') txt = GStrings.CheckString(txt + 1);
if (!txt || !*txt) txt = GStrings.CheckString("REQUIRED_CHARACTERS");
if (!txt || !*txt || BigFont->CanPrint(txt)) return BigFont;
return OriginalBigFont;
}
@ -212,8 +212,8 @@ FFont* PickSmallFont(const char* txt)
{
if (generic_ui) return NewSmallFont; // Note: Support is incomplete. Translations do not exist anyway for most content.
if (!OriginalSmallFont || OriginalSmallFont == SmallFont) return SmallFont;
if (txt && *txt == '$') txt = GStrings[txt + 1];
if (!txt || !*txt) txt = GStrings["REQUIRED_CHARACTERS"];
if (txt && *txt == '$') txt = GStrings.CheckString(txt + 1);
if (!txt || !*txt) txt = GStrings.CheckString("REQUIRED_CHARACTERS");
if (!txt || !*txt || SmallFont->CanPrint(txt)) return SmallFont;
return OriginalSmallFont;
}

View file

@ -153,7 +153,7 @@ void RenderViewpoint(FRenderViewpoint& mainvp, IntRect* bounds, float fov, float
di->Viewpoint.FieldOfView = FAngle::fromDeg(fov); // Set the real FOV for the current scene (it's not necessarily the same as the global setting in r_viewpoint)
// Stereo mode specific perspective projection
di->VPUniforms.mProjectionMatrix = eye.GetProjection(fov, ratio, fovratio);
di->VPUniforms.mProjectionMatrix = eye.GetProjection(fov, ratio, fovratio, false);
// Stereo mode specific viewpoint adjustment
if (eye.mShiftFactor != 0)

View file

@ -291,7 +291,7 @@ static bool CheckSingleFile (const char *name, bool &printRequires, bool printwa
{
if (!printRequires)
{
Printf ("%s:\n%s", GStrings("TXT_SAVEGAMENEEDS"), name);
Printf ("%s:\n%s", GStrings.GetString("TXT_SAVEGAMENEEDS"), name);
}
else
{
@ -790,15 +790,15 @@ void G_SaveGame(const char* filename, const char* description)
{
if (sendsave || gameaction == ga_savegame)
{
Printf("%s\n", GStrings("TXT_SAVEPENDING"));
Printf("%s\n", GStrings.GetString("TXT_SAVEPENDING"));
}
else if (gamestate != GS_LEVEL)
{
Printf("%s\n", GStrings("TXT_NOTINLEVEL"));
Printf("%s\n", GStrings.GetString("TXT_NOTINLEVEL"));
}
else if (!gi->CanSave())
{
Printf("%s\n", GStrings("TXT_SPPLAYERDEAD"));
Printf("%s\n", GStrings.GetString("TXT_SPPLAYERDEAD"));
}
else
{
@ -844,7 +844,7 @@ void G_DoSaveGame(bool ok4q, bool forceq, const char* fn, const char* desc)
if (WriteSavegame(fn, desc))
{
savegameManager.NotifyNewSave(fn, desc, ok4q, forceq);
Printf(PRINT_NOTIFY, "%s\n", GStrings("GGSAVED"));
Printf(PRINT_NOTIFY, "%s\n", GStrings.GetString("GGSAVED"));
BackupSaveGame = fn;
}
}

View file

@ -91,7 +91,7 @@ CCMD(secret)
{
FString levelname;
auto cc = currentLevel->name.GetChars();
if (*cc == '$') cc = GStrings[cc + 1];
if (*cc == '$') cc = GStrings.CheckString(cc + 1);
if (thislevel) levelname.Format("%s - %s", mapname, cc);
else levelname = mapname;
Printf(TEXTCOLOR_YELLOW "%s\n", levelname.GetChars());

View file

@ -60,6 +60,7 @@ const char *GetVersionString();
#define GAMENAME "Raze"
#define WGAMENAME L"Raze"
#define GAMENAMELOWERCASE "raze"
#define QUERYIWADDEFAULT true
#define FORUM_URL "http://forum.zdoom.org/"
#define BUGS_FORUM_URL "http://forum.zdoom.org/viewforum.php?f=340"
#define ENGINERES_FILE GAMENAMELOWERCASE ".pk3"

View file

@ -5,18 +5,3 @@ bool ShouldAllowGameSpecificVirtual(FName name, unsigned index, PType* arg, PTyp
{
return false;
}
void DObject::EnableNetworking(const bool enable)
{
return;
}
void DObject::RemoveFromNetwork(void)
{
return;
}
void DObject::ClearNetworkID()
{
return;
}

View file

@ -257,7 +257,7 @@ void evSend(EventObject& eob, int rxId, COMMAND_ID command, DBloodActor* initiat
if (gGameOptions.nGameType == 0)
{
viewSetMessage(GStrings(FStringf("TXTB_SECRET%d", Random(2))), nullptr, MESSAGE_PRIORITY_SECRET);
viewSetMessage(GStrings.GetString(FStringf("TXTB_SECRET%d", Random(2))), nullptr, MESSAGE_PRIORITY_SECRET);
}
}
}

View file

@ -50,14 +50,14 @@ const char* SetGodMode(DBloodPlayer* pPlayer, bool god)
{
playerSetGodMode(pPlayer, god);
bPlayerCheated = true;
return pPlayer->godMode ? GStrings("TXTB_GODMODE") : GStrings("TXTB_NOTGODMODE");
return pPlayer->godMode ? GStrings.GetString("TXTB_GODMODE") : GStrings.GetString("TXTB_NOTGODMODE");
}
const char* SetClipMode(bool noclip)
{
gNoClip = noclip;
bPlayerCheated = true;
return gNoClip ? GStrings("TXTB_NOCLIP") : GStrings("TXTB_NOCLIPOFF");
return gNoClip ? GStrings.GetString("TXTB_NOCLIP") : GStrings.GetString("TXTB_NOCLIPOFF");
}
void packStuff(DBloodPlayer* pPlayer)
@ -82,13 +82,13 @@ void SetAmmo(DBloodPlayer* pPlayer, bool stat)
{
for (int i = 0; i < 12; i++)
pPlayer->ammoCount[i] = gAmmoInfo[i].max;
viewSetMessage(GStrings("TXTB_FULLAMMO"));
viewSetMessage(GStrings.GetString("TXTB_FULLAMMO"));
}
else
{
for (int i = 0; i < 12; i++)
pPlayer->ammoCount[i] = 0;
viewSetMessage(GStrings("TXTB_NOAMMO"));
viewSetMessage(GStrings.GetString("TXTB_NOAMMO"));
}
}
@ -100,7 +100,7 @@ void SetWeapons(DBloodPlayer* pPlayer, bool stat)
}
SetAmmo(pPlayer, stat);
if (stat)
viewSetMessage(GStrings("TXTB_ALLWEAP"));
viewSetMessage(GStrings.GetString("TXTB_ALLWEAP"));
else
{
if (!VanillaMode())
@ -110,7 +110,7 @@ void SetWeapons(DBloodPlayer* pPlayer, bool stat)
pPlayer->curWeapon = kWeapNone;
pPlayer->nextWeapon = kWeapPitchFork;
}
viewSetMessage(GStrings("TXTB_NOWEAP"));
viewSetMessage(GStrings.GetString("TXTB_NOWEAP"));
}
}
@ -119,12 +119,12 @@ void SetToys(DBloodPlayer* pPlayer, bool stat)
if (stat)
{
packStuff(pPlayer);
viewSetMessage(GStrings("TXTB_FULLINV"));
viewSetMessage(GStrings.GetString("TXTB_FULLINV"));
}
else
{
packClear(pPlayer);
viewSetMessage(GStrings("TXTB_NOINV"));
viewSetMessage(GStrings.GetString("TXTB_NOINV"));
}
}
@ -133,12 +133,12 @@ void SetArmor(DBloodPlayer* pPlayer, bool stat)
int nAmount;
if (stat)
{
viewSetMessage(GStrings("TXTB_FULLARM"));
viewSetMessage(GStrings.GetString("TXTB_FULLARM"));
nAmount = 3200;
}
else
{
viewSetMessage(GStrings("TXTB_NOARM"));
viewSetMessage(GStrings.GetString("TXTB_NOARM"));
nAmount = 0;
}
for (int i = 0; i < 3; i++)
@ -150,27 +150,27 @@ void SetKeys(DBloodPlayer* pPlayer, bool stat)
for (int i = 1; i <= 7; i++)
pPlayer->hasKey[i] = stat;
if (stat)
viewSetMessage(GStrings("TXTB_ALLKEYS"));
viewSetMessage(GStrings.GetString("TXTB_ALLKEYS"));
else
viewSetMessage(GStrings("TXTB_NOKEYS"));
viewSetMessage(GStrings.GetString("TXTB_NOKEYS"));
}
void SetInfiniteAmmo(bool stat)
{
gInfiniteAmmo = stat;
if (gInfiniteAmmo)
viewSetMessage(GStrings("TXTB_INFAMMO"));
viewSetMessage(GStrings.GetString("TXTB_INFAMMO"));
else
viewSetMessage(GStrings("TXTB_LIMAMMO"));
viewSetMessage(GStrings.GetString("TXTB_LIMAMMO"));
}
void SetMap(bool stat)
{
gFullMap = stat;
if (gFullMap)
viewSetMessage(GStrings("TXTB_ALLMAP"));
viewSetMessage(GStrings.GetString("TXTB_ALLMAP"));
else
viewSetMessage(GStrings("TXTB_NOALLMAP"));
viewSetMessage(GStrings.GetString("TXTB_NOALLMAP"));
}
void SetWooMode(DBloodPlayer* pPlayer, bool stat)
@ -200,7 +200,7 @@ void ToggleBoots(DBloodPlayer* pPlayer)
{
if (powerupCheck(pPlayer, kPwUpJumpBoots))
{
viewSetMessage(GStrings("TXTB_NOJBOOTS"));
viewSetMessage(GStrings.GetString("TXTB_NOJBOOTS"));
if (!VanillaMode())
{
pPlayer->pwUpTime[kPwUpJumpBoots] = 0;
@ -210,7 +210,7 @@ void ToggleBoots(DBloodPlayer* pPlayer)
}
else
{
viewSetMessage(GStrings("TXTB_JBOOTS"));
viewSetMessage(GStrings.GetString("TXTB_JBOOTS"));
if (!VanillaMode())
pPlayer->pwUpTime[kPwUpJumpBoots] = gPowerUpInfo[kPwUpJumpBoots].bonusTime;
powerupActivate(pPlayer, kPwUpJumpBoots);
@ -221,14 +221,14 @@ void ToggleInvisibility(DBloodPlayer* pPlayer)
{
if (powerupCheck(pPlayer, kPwUpShadowCloak))
{
viewSetMessage(GStrings("TXTB_VISIBLE"));
viewSetMessage(GStrings.GetString("TXTB_VISIBLE"));
if (!VanillaMode())
pPlayer->pwUpTime[kPwUpShadowCloak] = 0;
powerupDeactivate(pPlayer, kPwUpShadowCloak);
}
else
{
viewSetMessage(GStrings("TXTB_INVISIBLE"));
viewSetMessage(GStrings.GetString("TXTB_INVISIBLE"));
powerupActivate(pPlayer, kPwUpShadowCloak);
}
}
@ -237,14 +237,14 @@ void ToggleInvulnerability(DBloodPlayer* pPlayer)
{
if (powerupCheck(pPlayer, kPwUpDeathMask))
{
viewSetMessage(GStrings("TXTB_VULN"));
viewSetMessage(GStrings.GetString("TXTB_VULN"));
if (!VanillaMode())
pPlayer->pwUpTime[kPwUpDeathMask] = 0;
powerupDeactivate(pPlayer, kPwUpDeathMask);
}
else
{
viewSetMessage(GStrings("TXTB_INVULN"));
viewSetMessage(GStrings.GetString("TXTB_INVULN"));
powerupActivate(pPlayer, kPwUpDeathMask);
}
}
@ -253,14 +253,14 @@ void ToggleDelirium(DBloodPlayer* pPlayer)
{
if (powerupCheck(pPlayer, kPwUpDeliriumShroom))
{
viewSetMessage(GStrings("TXTB_NODELIR"));
viewSetMessage(GStrings.GetString("TXTB_NODELIR"));
if (!VanillaMode())
pPlayer->pwUpTime[kPwUpDeliriumShroom] = 0;
powerupDeactivate(pPlayer, kPwUpDeliriumShroom);
}
else
{
viewSetMessage(GStrings("TXTB_DELIR"));
viewSetMessage(GStrings.GetString("TXTB_DELIR"));
powerupActivate(pPlayer, kPwUpDeliriumShroom);
}
}
@ -323,18 +323,18 @@ const char* GameInterface::GenericCheat(int player, int cheat)
break;
case kCheatKevorkian:
actDamageSprite(pPlayer->GetActor(), pPlayer->GetActor(), kDamageBullet, 8000);
return GStrings("TXTB_KEVORKIAN");
return GStrings.GetString("TXTB_KEVORKIAN");
case kCheatMcGee:
{
if (!pPlayer->GetActor()->xspr.burnTime)
evPostActor(pPlayer->GetActor(), 0, kCallbackFXFlameLick);
actBurnSprite(pPlayer->GetActor(), pPlayer->GetActor(), 2400);
return GStrings("TXTB_FIRED");
return GStrings.GetString("TXTB_FIRED");
}
case kCheatEdmark:
actDamageSprite(pPlayer->GetActor(), pPlayer->GetActor(), kDamageExplode, 8000);
return GStrings("TXTB_THEDAYS");
return GStrings.GetString("TXTB_THEDAYS");
case kCheatKrueger:
{
@ -343,7 +343,7 @@ const char* GameInterface::GenericCheat(int player, int cheat)
if (!pPlayer->GetActor()->xspr.burnTime)
evPostActor(pPlayer->GetActor(), 0, kCallbackFXFlameLick);
actBurnSprite(pPlayer->GetActor(), pPlayer->GetActor(), 2400);
return GStrings("TXTB_RETARD");
return GStrings.GetString("TXTB_RETARD");
}
case kCheatSterno:
pPlayer->blindEffect = 250;
@ -357,7 +357,7 @@ const char* GameInterface::GenericCheat(int player, int cheat)
case kCheatClarice:
for (int i = 0; i < 3; i++)
pPlayer->armor[i] = 1600;
return GStrings("TXTB_HALFARMOR");
return GStrings.GetString("TXTB_HALFARMOR");
case kCheatFrankenstein:
pPlayer->packSlots[0].curAmount = 100;
break;

View file

@ -1339,17 +1339,17 @@ void PickUp(DBloodPlayer* pPlayer, DBloodActor* actor)
if (nType >= kItemBase && nType <= kItemMax) {
pickedUp = PickupItem(pPlayer, actor);
if (pickedUp && customMsg == -1) msg = GStrings(FStringf("TXTB_ITEM%02d", int(nType - kItemBase + 1)));
if (pickedUp && customMsg == -1) msg = GStrings.GetString(FStringf("TXTB_ITEM%02d", int(nType - kItemBase + 1)));
}
else if (nType >= kItemAmmoBase && nType < kItemAmmoMax) {
pickedUp = PickupAmmo(pPlayer, actor);
if (pickedUp && customMsg == -1) msg = GStrings(FStringf("TXTB_AMMO%02d", int(nType - kItemAmmoBase + 1)));
if (pickedUp && customMsg == -1) msg = GStrings.GetString(FStringf("TXTB_AMMO%02d", int(nType - kItemAmmoBase + 1)));
}
else if (nType >= kItemWeaponBase && nType < kItemWeaponMax) {
pickedUp = PickupWeapon(pPlayer, actor);
if (pickedUp && customMsg == -1) msg = GStrings(FStringf("TXTB_WPN%02d", int(nType - kItemWeaponBase + 1)));
if (pickedUp && customMsg == -1) msg = GStrings.GetString(FStringf("TXTB_WPN%02d", int(nType - kItemWeaponBase + 1)));
}
if (!pickedUp) return;
@ -1618,7 +1618,7 @@ void ProcessInput(DBloodPlayer* pPlayer)
int key = pXSector->Key;
if (pXSector->locked && pPlayer->pnum == myconnectindex)
{
viewSetMessage(GStrings("TXTB_LOCKED"));
viewSetMessage(GStrings.GetString("TXTB_LOCKED"));
auto snd = 3062;
if (sndCheckPlaying(snd))
sndStopSample(snd);
@ -1628,7 +1628,7 @@ void ProcessInput(DBloodPlayer* pPlayer)
trTriggerSector(pSector, kCmdSpritePush);
else if (pPlayer->pnum == myconnectindex)
{
viewSetMessage(GStrings("TXTB_KEY"));
viewSetMessage(GStrings.GetString("TXTB_KEY"));
auto snd = 3063;
if (sndCheckPlaying(snd))
sndStopSample(snd);
@ -1643,7 +1643,7 @@ void ProcessInput(DBloodPlayer* pPlayer)
int key = pXWall->key;
if (pXWall->locked && pPlayer->pnum == myconnectindex)
{
viewSetMessage(GStrings("TXTB_LOCKED"));
viewSetMessage(GStrings.GetString("TXTB_LOCKED"));
auto snd = 3062;
if (sndCheckPlaying(snd))
sndStopSample(snd);
@ -1653,7 +1653,7 @@ void ProcessInput(DBloodPlayer* pPlayer)
trTriggerWall(pWall, kCmdWallPush);
else if (pPlayer->pnum == myconnectindex)
{
viewSetMessage(GStrings("TXTB_KEY"));
viewSetMessage(GStrings.GetString("TXTB_KEY"));
auto snd = 3063;
if (sndCheckPlaying(snd))
sndStopSample(snd);
@ -1671,7 +1671,7 @@ void ProcessInput(DBloodPlayer* pPlayer)
trTriggerSprite(act, kCmdSpritePush);
else if (pPlayer->pnum == myconnectindex)
{
viewSetMessage(GStrings("TXTB_KEY"));
viewSetMessage(GStrings.GetString("TXTB_KEY"));
sndStartSample(3063, 255, 2, 0);
}
break;
@ -1918,7 +1918,7 @@ void playerFrag(DBloodPlayer* pKiller, DBloodPlayer* pVictim)
int nSound = gSuicide[nMessage].Kills;
if (pVictim->pnum == myconnectindex && pVictim->handTime <= 0)
{
strcpy(buffer, GStrings("TXTB_KILLSELF"));
strcpy(buffer, GStrings.GetString("TXTB_KILLSELF"));
if (gGameOptions.nGameType > 0 && nSound >= 0)
sndStartSample(nSound, 255, 2, 0);
}
@ -2310,7 +2310,7 @@ void PlayerSurvive(int, DBloodActor* actor)
{
DBloodPlayer* pPlayer = getPlayer(actor->spr.type - kDudePlayer1);
if (pPlayer->pnum == myconnectindex)
viewSetMessage(GStrings("TXT_LIVEAGAIM"));
viewSetMessage(GStrings.GetString("TXT_LIVEAGAIM"));
else
{
snprintf(buffer, sizeof(buffer), "%s lives again!", PlayerName(pPlayer->pnum));

View file

@ -737,7 +737,7 @@ void viewDrawScreen(bool sceneonly)
viewDrawAimedPlayerName(pPlayer);
if (paused)
{
auto text = GStrings("TXTB_PAUSED");
auto text = GStrings.GetString("TXTB_PAUSED");
viewDrawText(PickBigFont(text), text, 160, 10, 0, 0, 1, 0);
}
else if (pPlayer->pnum != myconnectindex)

View file

@ -133,7 +133,7 @@ static const char * cheatMonsters()
static char textbuf[64];
if (++actor_tog == 3) actor_tog = 0;
static const char* s[] = { "OPTVAL_ON", "OPTVAL_OFF", "TXT_ON2" };
mysnprintf(textbuf, 64, "%s: %s", GStrings("NETMNU_MONSTERS"), GStrings(s[actor_tog]));
mysnprintf(textbuf, 64, "%s: %s", GStrings.GetString("NETMNU_MONSTERS"), GStrings.GetString(s[actor_tog]));
return textbuf;
}

View file

@ -282,7 +282,7 @@ void drawoverlays(double interpfrac)
{
double x = 160, y = 100;
double scale = isRR() ? 0.4 : 1.;
const char* text = GStrings("Game Paused");
const char* text = GStrings.GetString("Game Paused");
auto myfont = PickBigFont(text);
x -= myfont->StringWidth(text) * 0.5 * scale;
DrawText(twod, myfont, CR_UNTRANSLATED, x, y - 12, text, DTA_FullscreenScale, FSMode_Fit320x200, DTA_ScaleX, scale, DTA_ScaleY, scale, TAG_DONE);

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