mirror of
https://github.com/ZDoom/Raze.git
synced 2024-11-27 22:42:22 +00:00
Backend update from GZDoom.
This commit is contained in:
parent
27dc590931
commit
b3a2523099
125 changed files with 1542 additions and 509 deletions
Binary file not shown.
|
@ -148,9 +148,10 @@ typedef enum EIntConfigKey_
|
|||
zmusic_mod_autochip_scan_threshold,
|
||||
|
||||
zmusic_snd_streambuffersize,
|
||||
|
||||
|
||||
zmusic_snd_mididevice,
|
||||
zmusic_snd_outputrate,
|
||||
zmusic_mod_preferredplayer,
|
||||
|
||||
NUM_ZMUSIC_INT_CONFIGS
|
||||
} EIntConfigKey;
|
||||
|
@ -226,7 +227,7 @@ typedef struct ZMusicCallbacks_
|
|||
{
|
||||
// Callbacks the client can install to capture messages from the backends
|
||||
// or to provide sound font data.
|
||||
|
||||
|
||||
void (*MessageFunc)(int severity, const char* msg);
|
||||
// The message callbacks are optional, without them the output goes to stdout.
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstdint>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -18,6 +18,8 @@ LineEdit::LineEdit(Widget* parent) : Widget(parent)
|
|||
|
||||
LineEdit::~LineEdit()
|
||||
{
|
||||
delete timer;
|
||||
delete scroll_timer;
|
||||
}
|
||||
|
||||
bool LineEdit::IsReadOnly() const
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#include "window/window.h"
|
||||
#include <stdexcept>
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32
|
||||
|
||||
#include "win32/win32window.h"
|
||||
|
||||
|
|
|
@ -13,4 +13,5 @@ add_library( bz2 STATIC
|
|||
decompress.c
|
||||
huffman.c
|
||||
randtable.c )
|
||||
link_libraries("-static")
|
||||
target_link_libraries( bz2 )
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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]));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -903,11 +903,11 @@ bool JoinGame (int i)
|
|||
static int PrivateNetOf(in_addr in)
|
||||
{
|
||||
int addr = ntohl(in.s_addr);
|
||||
if ((addr & 0xFFFF0000) == 0xC0A80000) // 192.168.0.0
|
||||
if ((addr & 0xFFFF0000) == 0xC0A80000) // 192.168.0.0
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -278,6 +278,8 @@ xx(BuiltinNameToClass)
|
|||
xx(BuiltinClassCast)
|
||||
xx(BuiltinFunctionPtrCast)
|
||||
xx(BuiltinFindTranslation)
|
||||
xx(HandleDeprecatedFlags)
|
||||
xx(CheckDeprecatedFlags)
|
||||
|
||||
xx(ScreenJobRunner)
|
||||
xx(Action)
|
||||
|
|
|
@ -197,7 +197,10 @@ void FSerializer::Close()
|
|||
}
|
||||
if (mErrors > 0)
|
||||
{
|
||||
I_Error("%d errors parsing JSON", mErrors);
|
||||
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())
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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]; }
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,9 +698,16 @@ const TArray<VSMatrix> IQMModel::CalculateBones(int frame1, int frame2, float in
|
|||
{
|
||||
TRS prev;
|
||||
|
||||
if(frame1 >= 0 && (frame1_prev >= 0 || inter1_prev < 0))
|
||||
if(precalculated)
|
||||
{
|
||||
prev = inter1_prev <= 0 ? animationFrames[offset1 + i] : InterpolateBone(animationFrames[offset1_1 + i], animationFrames[offset1 + i], inter1_prev, invt1);
|
||||
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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -167,6 +167,10 @@ public:
|
|||
Enabled = enabled;
|
||||
}
|
||||
|
||||
bool AllowsEnabledInBackground() { return false; }
|
||||
bool GetEnabledInBackground() { return false; }
|
||||
void SetEnabledInBackground(bool enabled) {}
|
||||
|
||||
FString GetIdentifier()
|
||||
{
|
||||
char id[16];
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
@ -744,7 +751,10 @@ void FXInputManager::ProcessInput()
|
|||
{
|
||||
for (int i = 0; i < XUSER_MAX_COUNT; ++i)
|
||||
{
|
||||
Devices[i]->ProcessInput();
|
||||
if(AppActive || Devices[i]->GetEnabledInBackground())
|
||||
{
|
||||
Devices[i]->ProcessInput();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -25,7 +25,7 @@ enum ERenderEffect
|
|||
EFF_SPHEREMAP,
|
||||
EFF_BURN,
|
||||
EFF_STENCIL,
|
||||
|
||||
EFF_DITHERTRANS,
|
||||
MAX_EFFECTS
|
||||
};
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -2828,83 +2828,104 @@ 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)
|
||||
{
|
||||
static const uint8_t loadops[] = { OP_LK, OP_LKF, OP_LKS, OP_LKP };
|
||||
assert(Base->ValueType->GetRegType() == Right->ValueType->GetRegType());
|
||||
|
||||
ExpEmit pointer = Base->Emit(build);
|
||||
Address = pointer;
|
||||
|
||||
ExpEmit result;
|
||||
bool intconst = false;
|
||||
int intconstval = 0;
|
||||
|
||||
if (Right->isConstant() && Right->ValueType->GetRegType() == REGT_INT)
|
||||
if (IsBitWrite < 64)
|
||||
{
|
||||
intconst = true;
|
||||
intconstval = static_cast<FxConstant*>(Right)->GetValue().GetInt();
|
||||
result.Konst = true;
|
||||
result.RegType = REGT_INT;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = Right->Emit(build);
|
||||
}
|
||||
assert(result.RegType <= REGT_TYPE);
|
||||
static const uint8_t loadops[] = { OP_LK, OP_LKF, OP_LKS, OP_LKP };
|
||||
assert(Base->ValueType->GetRegType() == Right->ValueType->GetRegType());
|
||||
|
||||
if (pointer.Target)
|
||||
{
|
||||
if (result.Konst)
|
||||
ExpEmit pointer = Base->Emit(build);
|
||||
Address = pointer;
|
||||
|
||||
ExpEmit result;
|
||||
bool intconst = false;
|
||||
int intconstval = 0;
|
||||
|
||||
if (Right->isConstant() && Right->ValueType->GetRegType() == REGT_INT)
|
||||
{
|
||||
if (intconst) build->EmitLoadInt(pointer.RegNum, intconstval);
|
||||
else build->Emit(loadops[result.RegType], pointer.RegNum, result.RegNum);
|
||||
intconst = true;
|
||||
intconstval = static_cast<FxConstant*>(Right)->GetValue().GetInt();
|
||||
result.Konst = true;
|
||||
result.RegType = REGT_INT;
|
||||
}
|
||||
else
|
||||
{
|
||||
build->Emit(Right->ValueType->GetMoveOp(), pointer.RegNum, result.RegNum);
|
||||
result = Right->Emit(build);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result.Konst)
|
||||
assert(result.RegType <= REGT_TYPE);
|
||||
|
||||
if (pointer.Target)
|
||||
{
|
||||
if (result.Konst)
|
||||
{
|
||||
if (intconst) build->EmitLoadInt(pointer.RegNum, intconstval);
|
||||
else build->Emit(loadops[result.RegType], pointer.RegNum, result.RegNum);
|
||||
}
|
||||
else
|
||||
{
|
||||
build->Emit(Right->ValueType->GetMoveOp(), pointer.RegNum, result.RegNum);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result.Konst)
|
||||
{
|
||||
ExpEmit temp(build, result.RegType);
|
||||
if (intconst) build->EmitLoadInt(temp.RegNum, intconstval);
|
||||
else build->Emit(loadops[result.RegType], temp.RegNum, result.RegNum);
|
||||
result.Free(build);
|
||||
result = temp;
|
||||
}
|
||||
|
||||
if (IsBitWrite == -1)
|
||||
{
|
||||
build->Emit(Base->ValueType->GetStoreOp(), pointer.RegNum, result.RegNum, build->GetConstantInt(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
build->Emit(OP_SBIT, pointer.RegNum, result.RegNum, 1 << IsBitWrite);
|
||||
}
|
||||
}
|
||||
|
||||
if (AddressRequested)
|
||||
{
|
||||
ExpEmit temp(build, result.RegType);
|
||||
if (intconst) build->EmitLoadInt(temp.RegNum, intconstval);
|
||||
else build->Emit(loadops[result.RegType], temp.RegNum, result.RegNum);
|
||||
result.Free(build);
|
||||
result = temp;
|
||||
return pointer;
|
||||
}
|
||||
|
||||
if (IsBitWrite == -1)
|
||||
{
|
||||
build->Emit(Base->ValueType->GetStoreOp(), pointer.RegNum, result.RegNum, build->GetConstantInt(0));
|
||||
pointer.Free(build);
|
||||
|
||||
if (intconst)
|
||||
{ //fix int constant return for assignment
|
||||
return Right->Emit(build);
|
||||
}
|
||||
else
|
||||
{
|
||||
build->Emit(OP_SBIT, pointer.RegNum, result.RegNum, 1 << IsBitWrite);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (AddressRequested)
|
||||
{
|
||||
result.Free(build);
|
||||
return pointer;
|
||||
}
|
||||
|
||||
pointer.Free(build);
|
||||
|
||||
if(intconst)
|
||||
{ //fix int constant return for assignment
|
||||
return Right->Emit(build);
|
||||
}
|
||||
else
|
||||
{
|
||||
return result;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2934,23 +2955,40 @@ FxExpression *FxAssignSelf::Resolve(FCompileContext &ctx)
|
|||
|
||||
ExpEmit FxAssignSelf::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
ExpEmit pointer = Assignment->Address; // FxAssign should have already emitted it
|
||||
if (!pointer.Target)
|
||||
if (Assignment->IsBitWrite < 64)
|
||||
{
|
||||
ExpEmit out(build, ValueType->GetRegType(), ValueType->GetRegCount());
|
||||
if (Assignment->IsBitWrite != -1)
|
||||
ExpEmit pointer = Assignment->Address; // FxAssign should have already emitted it
|
||||
if (!pointer.Target)
|
||||
{
|
||||
build->Emit(OP_LBIT, out.RegNum, pointer.RegNum, 1 << Assignment->IsBitWrite);
|
||||
ExpEmit out(build, ValueType->GetRegType(), ValueType->GetRegCount());
|
||||
if (Assignment->IsBitWrite == -1)
|
||||
{
|
||||
build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, build->GetConstantInt(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
build->Emit(OP_LBIT, out.RegNum, pointer.RegNum, 1 << Assignment->IsBitWrite);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
else
|
||||
{
|
||||
build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, build->GetConstantInt(0));
|
||||
return pointer;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
else
|
||||
{
|
||||
return pointer;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7728,56 +7766,73 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx)
|
|||
|
||||
ExpEmit FxStructMember::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
ExpEmit obj = classx->Emit(build);
|
||||
assert(obj.RegType == REGT_POINTER);
|
||||
|
||||
if (obj.Konst)
|
||||
if (membervar->BitValue < 64 || AddressRequested)
|
||||
{
|
||||
// If the situation where we are dereferencing a constant
|
||||
// pointer is common, then it would probably be worthwhile
|
||||
// to add new opcodes for those. But as of right now, I
|
||||
// don't expect it to be a particularly common case.
|
||||
ExpEmit newobj(build, REGT_POINTER);
|
||||
build->Emit(OP_LKP, newobj.RegNum, obj.RegNum);
|
||||
obj = newobj;
|
||||
}
|
||||
ExpEmit obj = classx->Emit(build);
|
||||
assert(obj.RegType == REGT_POINTER);
|
||||
|
||||
if (membervar->Flags & VARF_Meta)
|
||||
{
|
||||
obj.Free(build);
|
||||
ExpEmit meta(build, REGT_POINTER);
|
||||
build->Emit(OP_META, meta.RegNum, obj.RegNum);
|
||||
obj = meta;
|
||||
}
|
||||
|
||||
if (AddressRequested)
|
||||
{
|
||||
if (membervar->Offset == 0)
|
||||
if (obj.Konst)
|
||||
{
|
||||
return obj;
|
||||
// If the situation where we are dereferencing a constant
|
||||
// pointer is common, then it would probably be worthwhile
|
||||
// to add new opcodes for those. But as of right now, I
|
||||
// don't expect it to be a particularly common case.
|
||||
ExpEmit newobj(build, REGT_POINTER);
|
||||
build->Emit(OP_LKP, newobj.RegNum, obj.RegNum);
|
||||
obj = newobj;
|
||||
}
|
||||
|
||||
if (membervar->Flags & VARF_Meta)
|
||||
{
|
||||
obj.Free(build);
|
||||
ExpEmit meta(build, REGT_POINTER);
|
||||
build->Emit(OP_META, meta.RegNum, obj.RegNum);
|
||||
obj = meta;
|
||||
}
|
||||
|
||||
if (AddressRequested)
|
||||
{
|
||||
if (membervar->Offset == 0)
|
||||
{
|
||||
return obj;
|
||||
}
|
||||
obj.Free(build);
|
||||
ExpEmit out(build, REGT_POINTER);
|
||||
build->Emit(OP_ADDA_RK, out.RegNum, obj.RegNum, build->GetConstantInt((int)membervar->Offset));
|
||||
return out;
|
||||
}
|
||||
|
||||
int offsetreg = build->GetConstantInt((int)membervar->Offset);
|
||||
ExpEmit loc(build, membervar->Type->GetRegType(), membervar->Type->GetRegCount());
|
||||
|
||||
if (membervar->BitValue == -1)
|
||||
{
|
||||
build->Emit(membervar->Type->GetLoadOp(), loc.RegNum, obj.RegNum, offsetreg);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExpEmit out(build, REGT_POINTER);
|
||||
build->Emit(OP_ADDA_RK, out.RegNum, obj.RegNum, offsetreg);
|
||||
build->Emit(OP_LBIT, loc.RegNum, out.RegNum, 1 << membervar->BitValue);
|
||||
out.Free(build);
|
||||
}
|
||||
obj.Free(build);
|
||||
ExpEmit out(build, REGT_POINTER);
|
||||
build->Emit(OP_ADDA_RK, out.RegNum, obj.RegNum, build->GetConstantInt((int)membervar->Offset));
|
||||
return out;
|
||||
}
|
||||
|
||||
int offsetreg = build->GetConstantInt((int)membervar->Offset);
|
||||
ExpEmit loc(build, membervar->Type->GetRegType(), membervar->Type->GetRegCount());
|
||||
|
||||
if (membervar->BitValue == -1)
|
||||
{
|
||||
build->Emit(membervar->Type->GetLoadOp(), loc.RegNum, obj.RegNum, offsetreg);
|
||||
return loc;
|
||||
}
|
||||
else
|
||||
{
|
||||
ExpEmit out(build, REGT_POINTER);
|
||||
build->Emit(OP_ADDA_RK, out.RegNum, obj.RegNum, offsetreg);
|
||||
build->Emit(OP_LBIT, loc.RegNum, out.RegNum, 1 << membervar->BitValue);
|
||||
out.Free(build);
|
||||
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);
|
||||
}
|
||||
obj.Free(build);
|
||||
return loc;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,21 +9633,128 @@ 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 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;
|
||||
if (argtypes.Size() > 0 && argtypes.Last() != nullptr && ArgList.Size() + implicit > argtypes.Size())
|
||||
|
||||
int defaults_index = 0;
|
||||
|
||||
for(unsigned i = 0; i < implicit; i++)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Too many arguments in call to %s", Function->SymbolName.GetChars());
|
||||
delete this;
|
||||
return nullptr;
|
||||
defaults_index += argtypes[i]->GetRegCount();
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < ArgList.Size(); i++)
|
||||
|
@ -9608,94 +9772,45 @@ 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.");
|
||||
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(!(flag & VARF_Optional))
|
||||
{
|
||||
if (j < i)
|
||||
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;
|
||||
}
|
||||
|
||||
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 + implicit] & VARF_Ref)
|
||||
{
|
||||
assert(ntype->isPointer());
|
||||
ntype = TypeNullPtr; // the default of a reference type can only be a null pointer
|
||||
}
|
||||
if (ntype->GetRegCount() == 1)
|
||||
{
|
||||
ArgList[i] = new FxConstant(ntype, (*defaults)[defaults_index], ScriptPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Vectors need special treatment because they are not normal constants
|
||||
FxConstant *cs[4] = { nullptr };
|
||||
for (int l = 0; l < ntype->GetRegCount(); l++)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Named argument %s comes before current position in argument list.", name.GetChars());
|
||||
delete this;
|
||||
return nullptr;
|
||||
cs[l] = new FxConstant(TypeFloat64, (*defaults)[l + defaults_index], ScriptPosition);
|
||||
}
|
||||
// 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];
|
||||
// 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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Vectors need special treatment because they are not normal constants
|
||||
FxConstant *cs[4] = { nullptr };
|
||||
for (int l = 0; l < ntype->GetRegCount(); l++)
|
||||
{
|
||||
cs[l] = new FxConstant(TypeFloat64, (*defaults)[l + i + k + skipdefs + implicit], ScriptPosition);
|
||||
}
|
||||
FxExpression *x = new FxVectorValue(cs[0], cs[1], cs[2], cs[3], ScriptPosition);
|
||||
ArgList.Insert(i + k, x);
|
||||
skipdefs += ntype->GetRegCount() - 1;
|
||||
}
|
||||
}
|
||||
done = true;
|
||||
break;
|
||||
ArgList[i] = new FxVectorValue(cs[0], cs[1], cs[2], cs[3], ScriptPosition);
|
||||
}
|
||||
}
|
||||
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))
|
||||
{
|
||||
|
|
|
@ -330,7 +330,8 @@ void PType::StaticInit()
|
|||
|
||||
TypeVoidPtr = NewPointer(TypeVoid, false);
|
||||
TypeRawFunction = new PPointer;
|
||||
TypeRawFunction->mDescriptiveName = "Raw Function Pointer";
|
||||
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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
139
source/common/textures/firetexture.cpp
Normal file
139
source/common/textures/firetexture.cpp
Normal 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;
|
||||
}
|
17
source/common/textures/firetexture.h
Normal file
17
source/common/textures/firetexture.h
Normal 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;
|
||||
};
|
|
@ -306,7 +306,8 @@ void FImageSource::EndPrecaching()
|
|||
|
||||
void FImageSource::RegisterForPrecache(FImageSource *img, bool requiretruecolor)
|
||||
{
|
||||
img->CollectForPrecache(precacheInfo, requiretruecolor);
|
||||
if (img)
|
||||
img->CollectForPrecache(precacheInfo, requiretruecolor);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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]; }
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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()) {}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
void Quotes::MakeStringLabel(FString "e)
|
||||
{
|
||||
// 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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue