From 3590de2f2ac17c625415af35ed252b05c36acf43 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 20 Jan 2025 14:47:21 +0100 Subject: [PATCH] backend update from GZDoom. --- source/common/2d/wipe.cpp | 160 +++++++++++++++--- source/common/audio/sound/s_sound.cpp | 2 +- source/common/console/c_commandline.cpp | 2 +- source/common/console/c_commandline.h | 2 +- source/common/console/c_cvars.cpp | 10 ++ source/common/console/c_cvars.h | 7 +- source/common/engine/i_net.cpp | 55 ++++-- source/common/engine/i_net.h | 1 + source/common/engine/m_random.cpp | 63 +++++-- source/common/engine/m_random.h | 26 ++- source/common/engine/namedef.h | 12 ++ source/common/engine/serializer.h | 2 +- source/common/engine/st_start.h | 2 + .../common/filesystem/include/fs_filesystem.h | 4 +- .../common/filesystem/source/filesystem.cpp | 47 +---- source/common/menu/savegamemanager.cpp | 24 ++- source/common/menu/savegamemanager.h | 1 + .../common/platform/posix/cocoa/st_console.h | 1 + .../common/platform/posix/cocoa/st_console.mm | 5 + .../common/platform/posix/cocoa/st_start.mm | 5 + source/common/platform/posix/i_system.h | 11 -- source/common/platform/posix/sdl/i_system.cpp | 2 +- source/common/platform/posix/sdl/st_start.cpp | 6 + source/common/platform/win32/i_main.cpp | 55 +++++- source/common/platform/win32/i_mainwindow.cpp | 5 + source/common/platform/win32/i_mainwindow.h | 1 + source/common/platform/win32/i_system.cpp | 4 +- source/common/platform/win32/st_start.cpp | 5 + .../common/rendering/hwrenderer/hw_draw2d.cpp | 5 +- .../postprocessing/hw_postprocess.cpp | 8 + .../postprocessing/hw_postprocessshader.cpp | 25 +++ .../postprocessing/hw_postprocessshader.h | 3 +- source/common/rendering/r_videoscale.cpp | 48 ++++-- source/common/scripting/backend/codegen.cpp | 136 ++++++++++++++- source/common/scripting/backend/vmbuilder.cpp | 17 +- .../common/scripting/frontend/zcc_compile.cpp | 5 + .../common/scripting/interface/vmnatives.cpp | 4 +- source/common/textures/gametexture.h | 4 + source/common/textures/m_png.cpp | 23 ++- source/common/utility/tarray.h | 2 +- source/common/widgets/netstartwindow.cpp | 6 + source/common/widgets/netstartwindow.h | 1 + source/launcher/launcherwindow.cpp | 4 +- source/launcher/launcherwindow.h | 2 +- 44 files changed, 645 insertions(+), 168 deletions(-) diff --git a/source/common/2d/wipe.cpp b/source/common/2d/wipe.cpp index cc57ca29f31..c829f7a8d10 100755 --- a/source/common/2d/wipe.cpp +++ b/source/common/2d/wipe.cpp @@ -43,6 +43,8 @@ #include "s_soundinternal.h" #include "i_time.h" +EXTERN_CVAR(Bool, cl_capfps) + class FBurnTexture : public FTexture { TArray WorkBuffer; @@ -163,6 +165,8 @@ class Wiper public: virtual ~Wiper(); virtual bool Run(int ticks) = 0; + virtual bool RunInterpolated(double ticks) { return true; }; + virtual bool Interpolatable() { return false; } virtual void SetTextures(FGameTexture* startscreen, FGameTexture* endscreen) { startScreen = startscreen; @@ -177,9 +181,11 @@ class Wiper_Crossfade : public Wiper { public: bool Run(int ticks) override; + bool RunInterpolated(double ticks) override; + bool Interpolatable() override { return true; } private: - int Clock = 0; + float Clock = 0; }; class Wiper_Melt : public Wiper @@ -187,10 +193,12 @@ class Wiper_Melt : public Wiper public: Wiper_Melt(); bool Run(int ticks) override; + bool RunInterpolated(double ticks) override; + bool Interpolatable() override { return true; } private: enum { WIDTH = 320, HEIGHT = 200 }; - int y[WIDTH]; + double y[WIDTH]; }; class Wiper_Burn : public Wiper @@ -268,7 +276,23 @@ bool Wiper_Crossfade::Run(int ticks) Clock += ticks; DrawTexture(twod, startScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, TAG_DONE); DrawTexture(twod, endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, DTA_Alpha, clamp(Clock / 32.f, 0.f, 1.f), TAG_DONE); - return Clock >= 32; + return Clock >= 32.; +} + +//========================================================================== +// +// OpenGLFrameBuffer :: Wiper_Crossfade :: Run +// +// Fades the old screen into the new one over 32 ticks. +// +//========================================================================== + +bool Wiper_Crossfade::RunInterpolated(double ticks) +{ + Clock += ticks; + DrawTexture(twod, startScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, TAG_DONE); + DrawTexture(twod, endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, DTA_Alpha, clamp(Clock / 32.f, 0.f, 1.f), TAG_DONE); + return Clock >= 32.; } //========================================================================== @@ -282,7 +306,7 @@ Wiper_Melt::Wiper_Melt() y[0] = -(M_Random() & 15); for (int i = 1; i < WIDTH; ++i) { - y[i] = clamp(y[i-1] + (M_Random() % 3) - 1, -15, 0); + y[i] = clamp(y[i-1] + (double)(M_Random() % 3) - 1., -15., 0.); } } @@ -307,25 +331,25 @@ bool Wiper_Melt::Run(int ticks) { if (y[i] < HEIGHT) { - if (y[i] < 0) - y[i]++; - else if (y[i] < 16) - y[i] += y[i] + 1; + if (y[i] < 0.) + y[i] = y[i] + 1.; + else if (y[i] < 16.) + y[i] += y[i] + 1.; else - y[i] = min(y[i] + 8, HEIGHT); + y[i] = min(y[i] + 8., HEIGHT); done = false; } if (ticks == 0) { struct { int32_t x; - int32_t y; + double y; } dpt; struct { int32_t left; - int32_t top; + double top; int32_t right; - int32_t bottom; + double bottom; } rect; // Only draw for the final tick. @@ -333,7 +357,7 @@ bool Wiper_Melt::Run(int ticks) int w = startScreen->GetTexelWidth(); int h = startScreen->GetTexelHeight(); dpt.x = i * w / WIDTH; - dpt.y = max(0, y[i] * h / HEIGHT); + dpt.y = max(0., y[i] * (double)h / (double)HEIGHT); rect.left = dpt.x; rect.top = 0; rect.right = (i + 1) * w / WIDTH; @@ -348,6 +372,77 @@ bool Wiper_Melt::Run(int ticks) return done; } +//========================================================================== +// +// Wiper_Melt :: RunInterpolated +// +// Melts the old screen into the new one over 32 ticks (interpolated). +// +//========================================================================== + +bool Wiper_Melt::RunInterpolated(double ticks) +{ + bool done = false; + DrawTexture(twod, endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, TAG_DONE); + + // Copy the old screen in vertical strips on top of the new one. + while (ticks > 0.) + { + done = true; + for (int i = 0; i < WIDTH; i++) + { + if (y[i] < (double)HEIGHT) + { + if (ticks > 0. && ticks < 1.) + { + if (y[i] < 0) + y[i] += ticks; + else if (y[i] < 16) + y[i] += (y[i] + 1) * ticks; + else + y[i] = min(y[i] + (8 * ticks), (double)HEIGHT); + } + else if (y[i] < 0.) + y[i] = y[i] + 1.; + else if (y[i] < 16.) + y[i] += y[i] + 1.; + else + y[i] = min(y[i] + 8., HEIGHT); + done = false; + } + } + ticks -= 1.; + } + for (int i = 0; i < WIDTH; i++) + { + struct { + int32_t x; + double y; + } dpt; + struct { + int32_t left; + double top; + int32_t right; + double bottom; + } rect; + + // Only draw for the final tick. + int w = startScreen->GetTexelWidth(); + double h = startScreen->GetTexelHeight(); + dpt.x = i * w / WIDTH; + dpt.y = max(0., y[i] * (double)h / (double)HEIGHT); + rect.left = dpt.x; + rect.top = 0; + rect.right = (i + 1) * w / WIDTH; + rect.bottom = h - dpt.y; + if (rect.bottom > rect.top) + { + DrawTexture(twod, startScreen, 0, dpt.y, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_ClipLeft, rect.left, DTA_ClipRight, rect.right, DTA_Masked, false, TAG_DONE); + } + } + return done; +} + //========================================================================== // // OpenGLFrameBuffer :: Wiper_Burn Constructor @@ -423,6 +518,7 @@ void PerformWipe(FTexture* startimg, FTexture* endimg, int wipe_type, bool stops { // wipe update uint64_t wipestart, nowtime, diff; + double diff_frac; bool done; GSnd->SetSfxPaused(true, 1); @@ -438,20 +534,34 @@ void PerformWipe(FTexture* startimg, FTexture* endimg, int wipe_type, bool stops do { - do + if (wiper->Interpolatable() && !cl_capfps) { - I_WaitVBL(2); nowtime = I_msTime(); - diff = (nowtime - wipestart) * 40 / 1000; // Using 35 here feels too slow. - } while (diff < 1); - wipestart = nowtime; - twod->Begin(screen->GetWidth(), screen->GetHeight()); - done = wiper->Run(1); - if (overlaydrawer) overlaydrawer(); - twod->End(); - screen->Update(); - twod->OnFrameDone(); - + diff_frac = (nowtime - wipestart) * 40. / 1000.; // Using 35 here feels too slow. + wipestart = nowtime; + twod->Begin(screen->GetWidth(), screen->GetHeight()); + done = wiper->RunInterpolated(diff_frac); + if (overlaydrawer) overlaydrawer(); + twod->End(); + screen->Update(); + twod->OnFrameDone(); + } + else + { + do + { + I_WaitVBL(2); + nowtime = I_msTime(); + diff = (nowtime - wipestart) * 40 / 1000; // Using 35 here feels too slow. + } while (diff < 1); + wipestart = nowtime; + twod->Begin(screen->GetWidth(), screen->GetHeight()); + done = wiper->Run(1); + if (overlaydrawer) overlaydrawer(); + twod->End(); + screen->Update(); + twod->OnFrameDone(); + } } while (!done); delete wiper; I_FreezeTime(false); diff --git a/source/common/audio/sound/s_sound.cpp b/source/common/audio/sound/s_sound.cpp index 852d389f5ac..d8ae7fe0017 100644 --- a/source/common/audio/sound/s_sound.cpp +++ b/source/common/audio/sound/s_sound.cpp @@ -61,7 +61,7 @@ enum { DEFAULT_PITCH = 128, }; -static FRandom pr_soundpitch ("SoundPitch"); +static FCRandom pr_soundpitch ("SoundPitch"); SoundEngine* soundEngine; //========================================================================== diff --git a/source/common/console/c_commandline.cpp b/source/common/console/c_commandline.cpp index 4f500ffe668..7fa9d1ff276 100644 --- a/source/common/console/c_commandline.cpp +++ b/source/common/console/c_commandline.cpp @@ -193,7 +193,7 @@ int FCommandLine::argc () return _argc; } -char *FCommandLine::operator[] (int i) +const char *FCommandLine::operator[] (int i) { if (_argv == NULL) { diff --git a/source/common/console/c_commandline.h b/source/common/console/c_commandline.h index dc5466df1cb..4886aa9c717 100644 --- a/source/common/console/c_commandline.h +++ b/source/common/console/c_commandline.h @@ -44,7 +44,7 @@ class FCommandLine FCommandLine (const char *commandline, bool no_escapes = false); ~FCommandLine (); int argc (); - char *operator[] (int i); + const char *operator[] (int i); const char *args () { return cmd; } void Shift(); diff --git a/source/common/console/c_cvars.cpp b/source/common/console/c_cvars.cpp index 1cbe6772d07..fc8c715b3b7 100644 --- a/source/common/console/c_cvars.cpp +++ b/source/common/console/c_cvars.cpp @@ -240,6 +240,16 @@ void* FBaseCVar::GetExtraDataPointer() return m_ExtraDataPointer; } +void FBaseCVar::SetExtraDataPointer2(void *pointer) +{ + m_ExtraDataPointer2 = pointer; +} + +void* FBaseCVar::GetExtraDataPointer2() +{ + return m_ExtraDataPointer2; +} + const char *FBaseCVar::GetHumanString(int precision) const { return GetGenericRep(CVAR_String).String; diff --git a/source/common/console/c_cvars.h b/source/common/console/c_cvars.h index 47337523fea..c52af0aeb8a 100644 --- a/source/common/console/c_cvars.h +++ b/source/common/console/c_cvars.h @@ -222,8 +222,10 @@ class FBaseCVar void ClearCallback(); void SetExtraDataPointer(void *pointer); + void SetExtraDataPointer2(void *pointer); void* GetExtraDataPointer(); + void* GetExtraDataPointer2(); int pnum = -1; FName userinfoName; @@ -259,7 +261,8 @@ class FBaseCVar static inline bool m_UseCallback = false; static inline bool m_DoNoSet = false; - void *m_ExtraDataPointer; + void *m_ExtraDataPointer = nullptr; + void *m_ExtraDataPointer2 = nullptr; // These need to go away! friend FString C_GetMassCVarString (uint32_t filter, bool compact); @@ -275,6 +278,8 @@ class FBaseCVar friend void FilterCompactCVars (TArray &cvars, uint32_t filter); friend void C_DeinitConsole(); friend void C_ListCVarsWithoutDescription(); + + friend class GLDefsParser; }; // Returns a string with all cvars whose flags match filter. In compact mode, diff --git a/source/common/engine/i_net.cpp b/source/common/engine/i_net.cpp index 33b4c126711..0a67062a010 100644 --- a/source/common/engine/i_net.cpp +++ b/source/common/engine/i_net.cpp @@ -132,7 +132,8 @@ enum PRE_CONACK, // Sent from host to guest to acknowledge PRE_CONNECT receipt PRE_ALLFULL, // Sent from host to an unwanted guest PRE_ALLHEREACK, // Sent from guest to host to acknowledge PRE_ALLHEREACK receipt - PRE_GO // Sent from host to guest to continue game startup + PRE_GO, // Sent from host to guest to continue game startup + PRE_IN_PROGRESS, // Sent from host to guest if the game has already started }; // Set PreGamePacket.fake to this so that the game rejects any pregame packets @@ -269,6 +270,8 @@ void PacketSend (void) // I_Error ("SendPacket error: %s",strerror(errno)); } +void PreSend(const void* buffer, int bufferlen, const sockaddr_in* to); +void SendConAck(int num_connected, int num_needed); // // PacketGet @@ -303,7 +306,7 @@ void PacketGet (void) GetPlayerName(node).GetChars()); } - doomcom.data[0] = 0x80; // NCMD_EXIT + doomcom.data[0] = NCMD_EXIT; c = 1; } else if (err != WSAEWOULDBLOCK) @@ -341,10 +344,11 @@ void PacketGet (void) } else if (c > 0) { //The packet is not from any in-game node, so we might as well discard it. - // Don't show the message for disconnect notifications. - if (c != 2 || TransmitBuffer[0] != PRE_FAKE || TransmitBuffer[1] != PRE_DISCONNECT) + if (TransmitBuffer[0] == PRE_FAKE) { - DPrintf(DMSG_WARNING, "Dropped packet: Unknown host (%s:%d)\n", inet_ntoa(fromaddress.sin_addr), fromaddress.sin_port); + // If it's someone waiting in the lobby, let them know the game already started + uint8_t msg[] = { PRE_FAKE, PRE_IN_PROGRESS }; + PreSend(msg, 2, &fromaddress); } doomcom.remotenode = -1; return; @@ -369,7 +373,22 @@ sockaddr_in *PreGet (void *buffer, int bufferlen, bool noabort) int err = WSAGetLastError(); if (err == WSAEWOULDBLOCK || (noabort && err == WSAECONNRESET)) return NULL; // no packet - I_Error ("PreGet: %s", neterror ()); + + if (doomcom.consoleplayer == 0) + { + int node = FindNode(&fromaddress); + I_NetMessage("Got unexpected disconnect."); + doomcom.numnodes--; + for (; node < doomcom.numnodes; ++node) + sendaddress[node] = sendaddress[node + 1]; + + // Let remaining guests know that somebody left. + SendConAck(doomcom.numnodes, doomcom.numplayers); + } + else + { + I_NetError("The host disbanded the game unexpectedly"); + } } return &fromaddress; } @@ -499,7 +518,7 @@ void SendAbort (void) } } -static void SendConAck (int num_connected, int num_needed) +void SendConAck (int num_connected, int num_needed) { PreGamePacket packet; @@ -708,7 +727,7 @@ bool HostGame (int i) doomcom.numnodes = 1; - I_NetInit ("Waiting for players", numplayers); + I_NetInit ("Hosting game", numplayers); // Wait for numplayers-1 different connections if (!I_NetLoop (Host_CheckForConnects, (void *)(intptr_t)numplayers)) @@ -783,13 +802,15 @@ bool Guest_ContactHost (void *userdata) } else if (packet.Message == PRE_DISCONNECT) { - doomcom.numnodes = 0; - I_FatalError ("The host cancelled the game."); + I_NetError("The host cancelled the game."); } else if (packet.Message == PRE_ALLFULL) { - doomcom.numnodes = 0; - I_FatalError ("The game is full."); + I_NetError("The game is full."); + } + else if (packet.Message == PRE_IN_PROGRESS) + { + I_NetError("The game was already started."); } } } @@ -850,7 +871,7 @@ bool Guest_WaitForOthers (void *userdata) return true; case PRE_DISCONNECT: - I_FatalError ("The host cancelled the game."); + I_NetError("The host cancelled the game."); break; } } @@ -875,6 +896,7 @@ bool JoinGame (int i) BuildAddress (&sendaddress[1], Args->GetArg(i+1)); sendplayer[1] = 0; doomcom.numnodes = 2; + doomcom.consoleplayer = -1; // Let host know we are here @@ -1046,6 +1068,13 @@ void I_NetMessage(const char* text, ...) #endif } +void I_NetError(const char* error) +{ + doomcom.numnodes = 0; + StartWindow->NetClose(); + I_FatalError("%s", error); +} + // todo: later these must be dispatched by the main menu, not the start screen. void I_NetProgress(int val) { diff --git a/source/common/engine/i_net.h b/source/common/engine/i_net.h index c52072c863d..15720374d0b 100644 --- a/source/common/engine/i_net.h +++ b/source/common/engine/i_net.h @@ -7,6 +7,7 @@ int I_InitNetwork (void); void I_NetCmd (void); void I_NetMessage(const char*, ...); +void I_NetError(const char* error); void I_NetProgress(int val); void I_NetInit(const char* msg, int num); bool I_NetLoop(bool (*timer_callback)(void*), void* userdata); diff --git a/source/common/engine/m_random.cpp b/source/common/engine/m_random.cpp index 3af14526bb8..11c4350b762 100644 --- a/source/common/engine/m_random.cpp +++ b/source/common/engine/m_random.cpp @@ -83,7 +83,7 @@ FRandom pr_exrandom("EX_Random"); // PUBLIC DATA DEFINITIONS ------------------------------------------------- -FRandom M_Random; +FCRandom M_Random; // Global seed. This is modified predictably to initialize every RNG. uint32_t rngseed; @@ -126,8 +126,8 @@ CCMD(rngseed) // PRIVATE DATA DEFINITIONS ------------------------------------------------ -FRandom *FRandom::RNGList; -static TDeletingArray NewRNGs; +FRandom *FRandom::RNGList, *FRandom::CRNGList; +static TDeletingArray NewRNGs, NewCRNGs; // CODE -------------------------------------------------------------------- @@ -139,14 +139,22 @@ static TDeletingArray NewRNGs; // //========================================================================== -FRandom::FRandom () -: NameCRC (0) +FRandom::FRandom (bool client) +: NameCRC (0), bClient(client) { #ifndef NDEBUG Name = NULL; #endif - Next = RNGList; - RNGList = this; + if (bClient) + { + Next = CRNGList; + CRNGList = this; + } + else + { + Next = RNGList; + RNGList = this; + } Init(0); } @@ -158,7 +166,7 @@ FRandom::FRandom () // //========================================================================== -FRandom::FRandom (const char *name) +FRandom::FRandom (const char *name, bool client) : bClient(client) { NameCRC = CalcCRC32 ((const uint8_t *)name, (unsigned int)strlen (name)); #ifndef NDEBUG @@ -170,7 +178,7 @@ FRandom::FRandom (const char *name) #endif // Insert the RNG in the list, sorted by CRC - FRandom **prev = &RNGList, *probe = RNGList; + FRandom **prev = (bClient ? &CRNGList : &RNGList), * probe = (bClient ? CRNGList : RNGList); while (probe != NULL && probe->NameCRC < NameCRC) { @@ -205,8 +213,8 @@ FRandom::~FRandom () FRandom *last = NULL; - prev = &RNGList; - rng = RNGList; + prev = bClient ? &CRNGList : &RNGList; + rng = bClient ? CRNGList : RNGList; while (rng != NULL && rng != this) { @@ -237,6 +245,11 @@ void FRandom::StaticClearRandom () { rng->Init(rngseed); } + + for (FRandom* rng = FRandom::CRNGList; rng != NULL; rng = rng->Next) + { + rng->Init(rngseed); + } } //========================================================================== @@ -345,15 +358,15 @@ void FRandom::StaticReadRNGState(FSerializer &arc) // //========================================================================== -FRandom *FRandom::StaticFindRNG (const char *name) +FRandom *FRandom::StaticFindRNG (const char *name, bool client) { uint32_t NameCRC = CalcCRC32 ((const uint8_t *)name, (unsigned int)strlen (name)); // Use the default RNG if this one happens to have a CRC of 0. - if (NameCRC == 0) return &pr_exrandom; + if (NameCRC == 0) return client ? &M_Random : &pr_exrandom; // Find the RNG in the list, sorted by CRC - FRandom **prev = &RNGList, *probe = RNGList; + FRandom **prev = (client ? &CRNGList : &RNGList), *probe = (client ? CRNGList : RNGList); while (probe != NULL && probe->NameCRC < NameCRC) { @@ -364,14 +377,32 @@ FRandom *FRandom::StaticFindRNG (const char *name) if (probe == NULL || probe->NameCRC != NameCRC) { // A matching RNG doesn't exist yet so create it. - probe = new FRandom(name); + probe = new FRandom(name, client); // Store the new RNG for destruction when ZDoom quits. - NewRNGs.Push(probe); + if (client) + NewCRNGs.Push(probe); + else + NewRNGs.Push(probe); } return probe; } +void FRandom::SaveRNGState(TArray& backups) +{ + for (auto cur = RNGList; cur != nullptr; cur = cur->Next) + backups.Push(*cur); +} + +void FRandom::RestoreRNGState(TArray& backups) +{ + unsigned int i = 0u; + for (auto cur = RNGList; cur != nullptr; cur = cur->Next) + *cur = backups[i++]; + + backups.Clear(); +} + //========================================================================== // // FRandom :: StaticPrintSeeds diff --git a/source/common/engine/m_random.h b/source/common/engine/m_random.h index d9eec6c44c0..ba0bcaf626c 100644 --- a/source/common/engine/m_random.h +++ b/source/common/engine/m_random.h @@ -44,9 +44,9 @@ class FSerializer; class FRandom : public SFMTObj { public: - FRandom (); - FRandom (const char *name); - ~FRandom (); + FRandom() : FRandom(false) {} + FRandom(const char* name) : FRandom(name, false) {} + ~FRandom(); int Seed() const { @@ -170,20 +170,34 @@ class FRandom : public SFMTObj static void StaticClearRandom (); static void StaticReadRNGState (FSerializer &arc); static void StaticWriteRNGState (FSerializer &file); - static FRandom *StaticFindRNG(const char *name); + static FRandom *StaticFindRNG(const char *name, bool client); + static void SaveRNGState(TArray& backups); + static void RestoreRNGState(TArray& backups); #ifndef NDEBUG static void StaticPrintSeeds (); #endif +protected: + FRandom(bool client); + FRandom(const char* name, bool client); + private: #ifndef NDEBUG const char *Name; #endif FRandom *Next; uint32_t NameCRC; + bool bClient; + + static FRandom *RNGList, *CRNGList; +}; - static FRandom *RNGList; +class FCRandom : public FRandom +{ +public: + FCRandom() : FRandom(true) {} + FCRandom(const char* name) : FRandom(name, true) {} }; extern uint32_t rngseed; // The starting seed (not part of state) @@ -193,6 +207,6 @@ extern bool use_staticrng; // M_Random can be used for numbers that do not affect gameplay -extern FRandom M_Random; +extern FCRandom M_Random; #endif diff --git a/source/common/engine/namedef.h b/source/common/engine/namedef.h index 13827382c0c..df4c574ecc9 100644 --- a/source/common/engine/namedef.h +++ b/source/common/engine/namedef.h @@ -41,6 +41,12 @@ xx(Random2) xx(RandomPick) xx(FRandomPick) xx(SetRandomSeed) +xx(CRandom) +xx(CFRandom) +xx(CRandom2) +xx(CRandomPick) +xx(CFRandomPick) +xx(CSetRandomSeed) xx(BuiltinRandomSeed) xx(BuiltinNew) xx(GetClass) @@ -190,9 +196,15 @@ xx(TranslationID) xx(Overlay) xx(IsValid) xx(IsNull) +xx(IsEmpty) +xx(IsFixed) +xx(IsKeep) xx(Exists) xx(SetInvalid) xx(SetNull) +xx(SetEmpty) +xx(SetFixed) +xx(SetKeep) xx(Key) xx(Index) xx(Find) diff --git a/source/common/engine/serializer.h b/source/common/engine/serializer.h index 40b6ab7062a..fb906aee888 100644 --- a/source/common/engine/serializer.h +++ b/source/common/engine/serializer.h @@ -252,7 +252,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, struct ModelOverride & FSerializer &Serialize(FSerializer &arc, const char *key, struct AnimModelOverride &mo, struct AnimModelOverride *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); +FSerializer &Serialize(FSerializer& arc, const char* key, FTranslationID& value, FTranslationID* defval); void SerializeFunctionPointer(FSerializer &arc, const char *key, FunctionPointerValue *&p); diff --git a/source/common/engine/st_start.h b/source/common/engine/st_start.h index a8b78aaa838..b09991d04f5 100644 --- a/source/common/engine/st_start.h +++ b/source/common/engine/st_start.h @@ -55,6 +55,7 @@ class FStartupScreen virtual void NetInit(const char *message, int num_players) {} virtual void NetProgress(int count) {} virtual void NetDone() {} + virtual void NetClose() {} virtual bool NetLoop(bool (*timer_callback)(void *), void *userdata) { return false; } virtual void AppendStatusLine(const char* status) {} virtual void LoadingStatus(const char* message, int colors) {} @@ -74,6 +75,7 @@ class FBasicStartupScreen : public FStartupScreen void NetProgress(int count); void NetMessage(const char* format, ...); // cover for printf void NetDone(); + void NetClose(); bool NetLoop(bool (*timer_callback)(void*), void* userdata); protected: int NetMaxPos, NetCurPos; diff --git a/source/common/filesystem/include/fs_filesystem.h b/source/common/filesystem/include/fs_filesystem.h index 858b7483745..e817bc12d77 100644 --- a/source/common/filesystem/include/fs_filesystem.h +++ b/source/common/filesystem/include/fs_filesystem.h @@ -42,8 +42,8 @@ class FileSystem void SetMaxIwadNum(int x) { MaxIwadIndex = x; } bool InitSingleFile(const char *filename, FileSystemMessageFunc Printf = nullptr); - bool InitMultipleFiles (std::vector& filenames, LumpFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, bool allowduplicates = false, FILE* hashfile = nullptr); - void AddFile (const char *filename, FileReader *wadinfo, LumpFilterInfo* filter, FileSystemMessageFunc Printf, FILE* hashfile); + bool InitMultipleFiles (std::vector& filenames, LumpFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, bool allowduplicates = false); + void AddFile (const char *filename, FileReader *wadinfo, LumpFilterInfo* filter, FileSystemMessageFunc Printf); int CheckIfResourceFileLoaded (const char *name) noexcept; void AddAdditionalFile(const char* filename, FileReader* wadinfo = NULL) {} diff --git a/source/common/filesystem/source/filesystem.cpp b/source/common/filesystem/source/filesystem.cpp index fee5f101143..0bc0dd5fe94 100644 --- a/source/common/filesystem/source/filesystem.cpp +++ b/source/common/filesystem/source/filesystem.cpp @@ -238,7 +238,7 @@ bool FileSystem::InitSingleFile(const char* filename, FileSystemMessageFunc Prin return InitMultipleFiles(filenames, nullptr, Printf); } -bool FileSystem::InitMultipleFiles (std::vector& filenames, LumpFilterInfo* filter, FileSystemMessageFunc Printf, bool allowduplicates, FILE* hashfile) +bool FileSystem::InitMultipleFiles (std::vector& filenames, LumpFilterInfo* filter, FileSystemMessageFunc Printf, bool allowduplicates) { int numfiles; @@ -269,7 +269,7 @@ bool FileSystem::InitMultipleFiles (std::vector& filenames, LumpFil for(size_t i=0;igetName(i); auto embedded = resfile->GetEntryReader(i, READER_CACHED); - AddFile(path.c_str(), &embedded, filter, Printf, hashfile); + AddFile(path.c_str(), &embedded, filter, Printf); } } - if (hashfile) - { - uint8_t cksum[16]; - char cksumout[33]; - memset(cksumout, 0, sizeof(cksumout)); - - if (filereader.isOpen()) - { - filereader.Seek(0, FileReader::SeekSet); - md5Hash(filereader, cksum); - - for (size_t j = 0; j < sizeof(cksum); ++j) - { - snprintf(cksumout + (j * 2), 3, "%02X", cksum[j]); - } - - fprintf(hashfile, "file: %s, hash: %s, size: %td\n", filename, cksumout, filereader.GetLength()); - } - - else - fprintf(hashfile, "file: %s, Directory structure\n", filename); - - for (int i = 0; i < resfile->EntryCount(); i++) - { - int flags = resfile->GetEntryFlags(i); - if (!(flags & RESFF_EMBEDDED)) - { - auto reader = resfile->GetEntryReader(i, READER_SHARED, 0); - md5Hash(filereader, cksum); - - for (size_t j = 0; j < sizeof(cksum); ++j) - { - snprintf(cksumout + (j * 2), 3, "%02X", cksum[j]); - } - - fprintf(hashfile, "file: %s, lump: %s, hash: %s, size: %zu\n", filename, resfile->getName(i), cksumout, (uint64_t)resfile->Length(i)); - } - } - } return; } } diff --git a/source/common/menu/savegamemanager.cpp b/source/common/menu/savegamemanager.cpp index 1350930210c..929d631d130 100644 --- a/source/common/menu/savegamemanager.cpp +++ b/source/common/menu/savegamemanager.cpp @@ -51,6 +51,7 @@ CVAR(String, save_dir, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG); FString SavegameFolder; +CVAR(Int, save_sort_order, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) //============================================================================= // @@ -136,7 +137,19 @@ int FSavegameManagerBase::InsertSaveNode(FSaveGameNode *node) //if (SaveGames[0] == &NewSaveNode) i++; // To not insert above the "new savegame" dummy entry. for (; i < SaveGames.Size(); i++) { - if (SaveGames[i]->bOldVersion || node->SaveTitle.CompareNoCase(SaveGames[i]->SaveTitle) <= 0) + bool sortcmp = false; + switch(save_sort_order) + { + case 1: + sortcmp = node->CreationTime.CompareNoCase(SaveGames[i]->CreationTime) > 0; + break; + default: + case 0: + sortcmp = node->SaveTitle.CompareNoCase(SaveGames[i]->SaveTitle) <= 0; + break; + } + + if (SaveGames[i]->bOldVersion || sortcmp) { break; } @@ -170,12 +183,18 @@ void FSavegameManagerBase::NotifyNewSave(const FString &file, const FString &tit #endif { node->SaveTitle = title; + node->CreationTime = myasctime(); node->bOldVersion = false; node->bMissingWads = false; + + // refresh my game's position on the list (needed if time/name changed) + SaveGames.Delete(i); + int index = InsertSaveNode(node); + if (okForQuicksave) { if (quickSaveSlot == nullptr || quickSaveSlot == (FSaveGameNode*)1 || forceQuicksave) quickSaveSlot = node; - LastAccessed = LastSaved = i; + LastAccessed = LastSaved = index; } return; } @@ -183,6 +202,7 @@ void FSavegameManagerBase::NotifyNewSave(const FString &file, const FString &tit auto node = new FSaveGameNode; node->SaveTitle = title; + node->CreationTime = myasctime(); node->Filename = file; node->bOldVersion = false; node->bMissingWads = false; diff --git a/source/common/menu/savegamemanager.h b/source/common/menu/savegamemanager.h index 20b466b53d7..4dd2eb69d49 100644 --- a/source/common/menu/savegamemanager.h +++ b/source/common/menu/savegamemanager.h @@ -11,6 +11,7 @@ struct FSaveGameNode { FString SaveTitle; FString Filename; + FString CreationTime; bool bOldVersion = false; bool bMissingWads = false; bool bNoDelete = false; diff --git a/source/common/platform/posix/cocoa/st_console.h b/source/common/platform/posix/cocoa/st_console.h index b2af7bade35..91f77d12438 100644 --- a/source/common/platform/posix/cocoa/st_console.h +++ b/source/common/platform/posix/cocoa/st_console.h @@ -66,6 +66,7 @@ class FConsoleWindow void NetInit(const char* message, int playerCount); void NetProgress(int count); void NetDone(); + void NetClose(); private: NSWindow* m_window; diff --git a/source/common/platform/posix/cocoa/st_console.mm b/source/common/platform/posix/cocoa/st_console.mm index 1c45776e6cf..95d0ee11eb5 100644 --- a/source/common/platform/posix/cocoa/st_console.mm +++ b/source/common/platform/posix/cocoa/st_console.mm @@ -531,3 +531,8 @@ static void UpdateTimed(const Function& function) m_netAbortButton = nil; } } + +void FConsoleWindow::NetClose() +{ + // TODO: Implement this +} diff --git a/source/common/platform/posix/cocoa/st_start.mm b/source/common/platform/posix/cocoa/st_start.mm index ee6ea262784..2cd73104d30 100644 --- a/source/common/platform/posix/cocoa/st_start.mm +++ b/source/common/platform/posix/cocoa/st_start.mm @@ -110,6 +110,11 @@ FConsoleWindow::GetInstance().NetDone(); } +void FBasicStartupScreen::NetClose() +{ + FConsoleWindow::GetInstance().NetClose(); +} + bool FBasicStartupScreen::NetLoop(bool (*timerCallback)(void*), void* const userData) { while (true) diff --git a/source/common/platform/posix/i_system.h b/source/common/platform/posix/i_system.h index 4d800d53b3b..5573e26d327 100644 --- a/source/common/platform/posix/i_system.h +++ b/source/common/platform/posix/i_system.h @@ -54,17 +54,6 @@ bool I_WriteIniFailed (const char* filename); class FGameTexture; bool I_SetCursor(FGameTexture *); -static inline char *strlwr(char *str) -{ - char *ptr = str; - while(*ptr) - { - *ptr = tolower(*ptr); - ++ptr; - } - return str; -} - inline int I_GetNumaNodeCount() { return 1; } inline int I_GetNumaNodeThreadCount(int numaNode) { return std::max(std::thread::hardware_concurrency(), 1); } inline void I_SetThreadNumaNode(std::thread &thread, int numaNode) { } diff --git a/source/common/platform/posix/sdl/i_system.cpp b/source/common/platform/posix/sdl/i_system.cpp index 31976ba3cf6..2c28368b005 100644 --- a/source/common/platform/posix/sdl/i_system.cpp +++ b/source/common/platform/posix/sdl/i_system.cpp @@ -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, extraArgs); + return LauncherWindow::ExecModal(wads, numwads, defaultiwad, &autoloadflags, &extraArgs); #endif } diff --git a/source/common/platform/posix/sdl/st_start.cpp b/source/common/platform/posix/sdl/st_start.cpp index 019a66122b6..5bd88684bba 100644 --- a/source/common/platform/posix/sdl/st_start.cpp +++ b/source/common/platform/posix/sdl/st_start.cpp @@ -57,6 +57,7 @@ class FTTYStartupScreen : public FStartupScreen void NetInit(const char *message, int num_players); void NetProgress(int count); void NetDone(); + void NetClose(); bool NetLoop(bool (*timer_callback)(void *), void *userdata); protected: bool DidNetInit; @@ -237,6 +238,11 @@ void FTTYStartupScreen::NetProgress(int count) } } +void FTTYStartupScreen::NetClose() +{ + // TODO: Implement this +} + //=========================================================================== // // FTTYStartupScreen :: NetLoop diff --git a/source/common/platform/win32/i_main.cpp b/source/common/platform/win32/i_main.cpp index acadc2dc823..c68b5a7aa1e 100644 --- a/source/common/platform/win32/i_main.cpp +++ b/source/common/platform/win32/i_main.cpp @@ -134,6 +134,39 @@ void I_SetIWADInfo() { } +//========================================================================== +// +// isConsoleApp() +// +// runtime detection to detect if this is a console subsystem app. +// +// the reason for doing this is because it is possible to edit a binary directly and change its subsystem +// type via hexedit so in order to gain flexibility it makes no sense to just compile out the unused code. +// +// we may plan to publish tools to allow users to do this manually on their own. +// +//========================================================================== + +bool isConsoleApp() +{ + static bool alreadychecked = false; + static bool returnvalue; + + if (!alreadychecked) + { + DWORD pids[2]; + DWORD num_pids = GetConsoleProcessList(pids, 2); + bool win32con_is_exclusive = (num_pids <= 1); + + returnvalue = ((GetConsoleWindow() != NULL && !win32con_is_exclusive) || (GetStdHandle(STD_OUTPUT_HANDLE) != NULL)); + alreadychecked = true; + } + + //printf("isConsoleApp is %i\n", returnvalue); + + return returnvalue; +} + //========================================================================== // // DoMain @@ -158,7 +191,22 @@ int DoMain (HINSTANCE hInstance) Args->AppendArg(FString(wargv[i])); } - if (Args->CheckParm("-stdout") || Args->CheckParm("-norun")) + if (isConsoleApp()) + { + StdOut = GetStdHandle(STD_OUTPUT_HANDLE); + + SetConsoleCP(CP_UTF8); + SetConsoleOutputCP(CP_UTF8); + + DWORD mode; + + if (GetConsoleMode(StdOut, &mode)) + { + if (SetConsoleMode(StdOut, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) + FancyStdOut = IsWindows10OrGreater(); // Windows 8.1 and lower do not understand ANSI formatting. + } + } + else 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 @@ -475,6 +523,11 @@ CUSTOM_CVAR(Bool, disablecrashlog, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // //========================================================================== +int wmain() +{ + return wWinMain(GetModuleHandle(0), 0, GetCommandLineW(), SW_SHOW); +} + int WINAPI wWinMain (HINSTANCE hInstance, HINSTANCE nothing, LPWSTR cmdline, int nCmdShow) { g_hInst = hInstance; diff --git a/source/common/platform/win32/i_mainwindow.cpp b/source/common/platform/win32/i_mainwindow.cpp index 95dda5031f3..5bdd3569c26 100644 --- a/source/common/platform/win32/i_mainwindow.cpp +++ b/source/common/platform/win32/i_mainwindow.cpp @@ -128,6 +128,11 @@ void MainWindow::HideNetStartPane() NetStartWindow::HideNetStartPane(); } +void MainWindow::CloseNetStartPane() +{ + NetStartWindow::NetClose(); +} + void MainWindow::SetNetStartProgress(int pos) { NetStartWindow::SetNetStartProgress(pos); diff --git a/source/common/platform/win32/i_mainwindow.h b/source/common/platform/win32/i_mainwindow.h index 3c0c7e55df4..83567135cf5 100644 --- a/source/common/platform/win32/i_mainwindow.h +++ b/source/common/platform/win32/i_mainwindow.h @@ -29,6 +29,7 @@ class MainWindow void SetNetStartProgress(int pos); bool RunMessageLoop(bool (*timer_callback)(void*), void* userdata); void HideNetStartPane(); + void CloseNetStartPane(); void SetWindowTitle(const char* caption); diff --git a/source/common/platform/win32/i_system.cpp b/source/common/platform/win32/i_system.cpp index 2c7eed495f8..caed820b0c9 100644 --- a/source/common/platform/win32/i_system.cpp +++ b/source/common/platform/win32/i_system.cpp @@ -102,6 +102,7 @@ // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- void DestroyCustomCursor(); +bool isConsoleApp(); // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- @@ -306,6 +307,7 @@ static void PrintToStdOut(const char *cpt, HANDLE StdOut) else break; } } + DWORD bytes_written; WriteFile(StdOut, printData.GetChars(), (DWORD)printData.Len(), &bytes_written, NULL); if (terminal) @@ -370,7 +372,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, extraArgs); + return LauncherWindow::ExecModal(wads, numwads, defaultiwad, &autoloadflags, &extraArgs); } return defaultiwad; } diff --git a/source/common/platform/win32/st_start.cpp b/source/common/platform/win32/st_start.cpp index 8bc48d26e5a..fceeb3cede3 100644 --- a/source/common/platform/win32/st_start.cpp +++ b/source/common/platform/win32/st_start.cpp @@ -201,3 +201,8 @@ bool FBasicStartupScreen::NetLoop(bool (*timer_callback)(void *), void *userdata { return mainwindow.RunMessageLoop(timer_callback, userdata); } + +void FBasicStartupScreen::NetClose() +{ + mainwindow.CloseNetStartPane(); +} diff --git a/source/common/rendering/hwrenderer/hw_draw2d.cpp b/source/common/rendering/hwrenderer/hw_draw2d.cpp index 5c7100b34fa..a5ed7b1eeb6 100644 --- a/source/common/rendering/hwrenderer/hw_draw2d.cpp +++ b/source/common/rendering/hwrenderer/hw_draw2d.cpp @@ -50,6 +50,7 @@ //=========================================================================== CVAR(Bool, gl_aalines, false, CVAR_ARCHIVE) +CVAR(Bool, hw_2dmip, true, CVAR_ARCHIVE) void Draw2D(F2DDrawer* drawer, FRenderState& state) { @@ -71,6 +72,8 @@ void Draw2D(F2DDrawer* drawer, FRenderState& state, int x, int y, int width, int state.EnableMultisampling(false); state.EnableLineSmooth(gl_aalines); + bool cache_hw_2dmip = hw_2dmip; // cache cvar lookup so it's not done in a loop + auto &vertices = drawer->mVertices; auto &indices = drawer->mIndices; auto &commands = drawer->mData; @@ -180,7 +183,7 @@ void Draw2D(F2DDrawer* drawer, FRenderState& state, int x, int y, int width, int auto flags = cmd.mTexture->GetUseType() >= ETextureType::Special? UF_None : cmd.mTexture->GetUseType() == ETextureType::FontChar? UF_Font : UF_Texture; auto scaleflags = cmd.mFlags & F2DDrawer::DTF_Indexed ? CTF_Indexed : 0; - state.SetMaterial(cmd.mTexture, flags, scaleflags, cmd.mFlags & F2DDrawer::DTF_Wrap ? CLAMP_NONE : CLAMP_XY_NOMIP, cmd.mTranslationId, -1); + state.SetMaterial(cmd.mTexture, flags, scaleflags, cmd.mFlags & F2DDrawer::DTF_Wrap ? CLAMP_NONE : (cache_hw_2dmip ? CLAMP_XY : CLAMP_XY_NOMIP), cmd.mTranslationId, -1); state.EnableTexture(true); // Canvas textures are stored upside down diff --git a/source/common/rendering/hwrenderer/postprocessing/hw_postprocess.cpp b/source/common/rendering/hwrenderer/postprocessing/hw_postprocess.cpp index e339f926782..2a685aa3d32 100644 --- a/source/common/rendering/hwrenderer/postprocessing/hw_postprocess.cpp +++ b/source/common/rendering/hwrenderer/postprocessing/hw_postprocess.cpp @@ -947,6 +947,7 @@ PPCustomShaderInstance::PPCustomShaderInstance(PostProcessShader *desc) : Desc(d case PostProcessUniformType::Int: AddUniformField(offset, name, UniformType::Int, sizeof(int)); break; case PostProcessUniformType::Vec2: AddUniformField(offset, name, UniformType::Vec2, sizeof(float) * 2); break; case PostProcessUniformType::Vec3: AddUniformField(offset, name, UniformType::Vec3, sizeof(float) * 3, sizeof(float) * 4); break; + case PostProcessUniformType::Vec4: AddUniformField(offset, name, UniformType::Vec4, sizeof(float) * 4); break; default: break; } } @@ -1085,6 +1086,13 @@ void PPCustomShaderInstance::SetUniforms(PPRenderState *renderstate) fValues[2] = (float)pair->Value.Values[2]; memcpy(dst, fValues, sizeof(float) * 3); break; + case PostProcessUniformType::Vec4: + fValues[0] = (float)pair->Value.Values[0]; + fValues[1] = (float)pair->Value.Values[1]; + fValues[2] = (float)pair->Value.Values[2]; + fValues[3] = (float)pair->Value.Values[3]; + memcpy(dst, fValues, sizeof(float) * 4); + break; default: break; } diff --git a/source/common/rendering/hwrenderer/postprocessing/hw_postprocessshader.cpp b/source/common/rendering/hwrenderer/postprocessing/hw_postprocessshader.cpp index f23d4497f16..f48d3f7d140 100644 --- a/source/common/rendering/hwrenderer/postprocessing/hw_postprocessshader.cpp +++ b/source/common/rendering/hwrenderer/postprocessing/hw_postprocessshader.cpp @@ -116,6 +116,31 @@ DEFINE_ACTION_FUNCTION(_PPShader, SetUniform3f) return 0; } +DEFINE_ACTION_FUNCTION(_PPShader, SetUniform4f) +{ + PARAM_PROLOGUE; + PARAM_STRING(shaderName); + PARAM_STRING(uniformName); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_FLOAT(w); + + for (unsigned int i = 0; i < PostProcessShaders.Size(); i++) + { + PostProcessShader &shader = PostProcessShaders[i]; + if (shader.Name == shaderName) + { + double *vec4 = shader.Uniforms[uniformName].Values; + vec4[0] = x; + vec4[1] = y; + vec4[2] = z; + vec4[3] = w; + } + } + return 0; +} + DEFINE_ACTION_FUNCTION(_PPShader, SetUniform1i) { PARAM_PROLOGUE; diff --git a/source/common/rendering/hwrenderer/postprocessing/hw_postprocessshader.h b/source/common/rendering/hwrenderer/postprocessing/hw_postprocessshader.h index 7ecbd4f84cf..fcb32c5e1b1 100644 --- a/source/common/rendering/hwrenderer/postprocessing/hw_postprocessshader.h +++ b/source/common/rendering/hwrenderer/postprocessing/hw_postprocessshader.h @@ -9,7 +9,8 @@ enum class PostProcessUniformType Int, Float, Vec2, - Vec3 + Vec3, + Vec4 }; struct PostProcessUniformValue diff --git a/source/common/rendering/r_videoscale.cpp b/source/common/rendering/r_videoscale.cpp index 705fe905f40..8921d89805e 100644 --- a/source/common/rendering/r_videoscale.cpp +++ b/source/common/rendering/r_videoscale.cpp @@ -1,7 +1,7 @@ /*--------------------------------------------------------------------------- ** ** Copyright(C) 2017 Magnus Norddahl -** Copyright(C) 2017-2020 Rachael Alexanderson +** Copyright(C) 2017-2024 Rachael Alexanderson ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -98,6 +98,33 @@ namespace { return (uint32_t)((float)inheight * v_MinimumToFill(inwidth, inheight)); } + + float v_MinimumToFill2(uint32_t inwidth, uint32_t inheight) + { + // sx = screen x dimension, sy = same for y + float sx = (float)inwidth * 1.2f, sy = (float)inheight; + static float lastsx = 0., lastsy = 0., result = 0.; + if (lastsx != sx || lastsy != sy) + { + if (sx <= 0. || sy <= 0.) + return 1.; // prevent x/0 error + // set absolute minimum scale to fill the entire screen but get as close to 640x400 as possible + float ssx = (float)(VID_MIN_UI_WIDTH) / 1.2f / sx, ssy = (float)(VID_MIN_UI_HEIGHT) / sy; + result = (ssx < ssy) ? ssy : ssx; + lastsx = sx; + lastsy = sy; + } + return result; + } + inline uint32_t v_mfillX2(uint32_t inwidth, uint32_t inheight) + { + return (uint32_t)((float)inwidth * v_MinimumToFill2(inwidth, inheight) * 1.2); + } + inline uint32_t v_mfillY2(uint32_t inwidth, uint32_t inheight) + { + return (uint32_t)((float)inheight * v_MinimumToFill2(inwidth, inheight)); + } + inline void refresh_minimums() { // specialUI is tracking a state where high-res console fonts are actually required, and @@ -128,16 +155,17 @@ namespace // the odd formatting of this struct definition is meant to resemble a table header. set your tab stops to 4 when editing this file. struct v_ScaleTable - { bool isValid; uint32_t(*GetScaledWidth)(uint32_t Width, uint32_t Height); uint32_t(*GetScaledHeight)(uint32_t Width, uint32_t Height); float pixelAspect; bool isCustom; }; + { bool isValid; uint32_t(*GetScaledWidth)(uint32_t Width, uint32_t Height); uint32_t(*GetScaledHeight)(uint32_t Width, uint32_t Height); float pixelAspect; bool isCustom; }; v_ScaleTable vScaleTable[] = { - { true, [](uint32_t Width, uint32_t Height)->uint32_t { return Width; }, [](uint32_t Width, uint32_t Height)->uint32_t { return Height; }, 1.0f, false }, // 0 - Native - { true, [](uint32_t Width, uint32_t Height)->uint32_t { return v_mfillX(Width, Height); }, [](uint32_t Width, uint32_t Height)->uint32_t { return v_mfillY(Width, Height); }, 1.0f, false }, // 6 - Minimum Scale to Fill Entire Screen - { true, [](uint32_t Width, uint32_t Height)->uint32_t { return 640; }, [](uint32_t Width, uint32_t Height)->uint32_t { return 400; }, 1.2f, false }, // 2 - 640x400 (formerly 320x200) - { true, [](uint32_t Width, uint32_t Height)->uint32_t { return 960; }, [](uint32_t Width, uint32_t Height)->uint32_t { return 600; }, 1.2f, false }, // 3 - 960x600 (formerly 640x400) - { true, [](uint32_t Width, uint32_t Height)->uint32_t { return 1280; }, [](uint32_t Width, uint32_t Height)->uint32_t { return 800; }, 1.2f, false }, // 4 - 1280x800 - { true, [](uint32_t Width, uint32_t Height)->uint32_t { return vid_scale_customwidth; }, [](uint32_t Width, uint32_t Height)->uint32_t { return vid_scale_customheight; }, 1.0f, true }, // 5 - Custom - { true, [](uint32_t Width, uint32_t Height)->uint32_t { return 320; }, [](uint32_t Width, uint32_t Height)->uint32_t { return 200; }, 1.2f, false }, // 7 - 320x200 + { true, [](uint32_t Width, uint32_t Height)->uint32_t { return Width; }, [](uint32_t Width, uint32_t Height)->uint32_t { return Height; }, 1.0f, false }, // 0 - Native + { true, [](uint32_t Width, uint32_t Height)->uint32_t { return v_mfillX(Width, Height); }, [](uint32_t Width, uint32_t Height)->uint32_t { return v_mfillY(Width, Height); }, 1.0f, false }, // 1 - Minimum Scale to Fill Entire Screen + { true, [](uint32_t Width, uint32_t Height)->uint32_t { return 640; }, [](uint32_t Width, uint32_t Height)->uint32_t { return 400; }, 1.2f, false }, // 2 - 640x400 (formerly 320x200) + { true, [](uint32_t Width, uint32_t Height)->uint32_t { return 960; }, [](uint32_t Width, uint32_t Height)->uint32_t { return 600; }, 1.2f, false }, // 3 - 960x600 (formerly 640x400) + { true, [](uint32_t Width, uint32_t Height)->uint32_t { return 1280; }, [](uint32_t Width, uint32_t Height)->uint32_t { return 800; }, 1.2f, false }, // 4 - 1280x800 + { true, [](uint32_t Width, uint32_t Height)->uint32_t { return vid_scale_customwidth; }, [](uint32_t Width, uint32_t Height)->uint32_t { return vid_scale_customheight; }, 1.0f, true }, // 5 - Custom + { true, [](uint32_t Width, uint32_t Height)->uint32_t { return 320; }, [](uint32_t Width, uint32_t Height)->uint32_t { return 200; }, 1.2f, false }, // 6 - 320x200 + { true, [](uint32_t Width, uint32_t Height)->uint32_t { return v_mfillX2(Width, Height) * 1.2f; }, [](uint32_t Width, uint32_t Height)->uint32_t { return v_mfillY2(Width, Height); }, 1.2f, false }, // 7 - Minimum Scale to Fill Entire Screen (1.2) }; bool isOutOfBounds(int x) { @@ -248,7 +276,7 @@ CCMD (vid_scaletoheight) } } -inline bool atob(char* I) +inline bool atob(const char* I) { if (stricmp (I, "true") == 0 || stricmp (I, "1") == 0) return true; diff --git a/source/common/scripting/backend/codegen.cpp b/source/common/scripting/backend/codegen.cpp index b14fb267cd6..07ced853ed6 100644 --- a/source/common/scripting/backend/codegen.cpp +++ b/source/common/scripting/backend/codegen.cpp @@ -1842,6 +1842,12 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx) { goto basereturn; } + else if (ctx.Version >= MakeVersion(4, 15, 0) && basex->ValueType == TypeNullPtr && (ValueType == TypeSpriteID || ValueType == TypeTextureID || ValueType == TypeTranslationID)) + { + delete basex; + basex = new FxConstant(0, ScriptPosition); + goto basereturn; + } else if (IsFloat()) { FxExpression *x = new FxFloatCast(basex); @@ -8268,8 +8274,12 @@ static bool CheckFunctionCompatiblity(FScriptPosition &ScriptPosition, PFunction FxFunctionCall::FxFunctionCall(FName methodname, FName rngname, FArgumentList &&args, const FScriptPosition &pos) : FxExpression(EFX_FunctionCall, pos) { + const bool isClient = methodname == NAME_CRandom || methodname == NAME_CFRandom + || methodname == NAME_CRandomPick || methodname == NAME_CFRandomPick + || methodname == NAME_CRandom2 || methodname == NAME_CSetRandomSeed; + MethodName = methodname; - RNG = &pr_exrandom; + RNG = isClient ? &M_Random : &pr_exrandom; ArgList = std::move(args); if (rngname != NAME_None) { @@ -8281,7 +8291,16 @@ FxFunctionCall::FxFunctionCall(FName methodname, FName rngname, FArgumentList && case NAME_FRandomPick: case NAME_Random2: case NAME_SetRandomSeed: - RNG = FRandom::StaticFindRNG(rngname.GetChars()); + RNG = FRandom::StaticFindRNG(rngname.GetChars(), false); + break; + + case NAME_CRandom: + case NAME_CFRandom: + case NAME_CRandomPick: + case NAME_CFRandomPick: + case NAME_CRandom2: + case NAME_CSetRandomSeed: + RNG = FRandom::StaticFindRNG(rngname.GetChars(), true); break; default: @@ -8498,6 +8517,7 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) case NAME_State: case NAME_SpriteID: case NAME_TextureID: + case NAME_TranslationID: if (CheckArgSize(MethodName, ArgList, 1, 1, ScriptPosition)) { PType *type = @@ -8547,13 +8567,22 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) } break; + case NAME_CSetRandomSeed: + if (CheckArgSize(NAME_CRandom, ArgList, 1, 1, ScriptPosition)) + { + func = new FxRandomSeed(RNG, ArgList[0], ScriptPosition, ctx.FromDecorate); + ArgList[0] = nullptr; + } + break; + case NAME_Random: + case NAME_CRandom: // allow calling Random without arguments to default to (0, 255) if (ArgList.Size() == 0) { func = new FxRandom(RNG, new FxConstant(0, ScriptPosition), new FxConstant(255, ScriptPosition), ScriptPosition, ctx.FromDecorate); } - else if (CheckArgSize(NAME_Random, ArgList, 2, 2, ScriptPosition)) + else if (CheckArgSize(MethodName, ArgList, 2, 2, ScriptPosition)) { func = new FxRandom(RNG, ArgList[0], ArgList[1], ScriptPosition, ctx.FromDecorate); ArgList[0] = ArgList[1] = nullptr; @@ -8561,7 +8590,8 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) break; case NAME_FRandom: - if (CheckArgSize(NAME_FRandom, ArgList, 2, 2, ScriptPosition)) + case NAME_CFRandom: + if (CheckArgSize(MethodName, ArgList, 2, 2, ScriptPosition)) { func = new FxFRandom(RNG, ArgList[0], ArgList[1], ScriptPosition); ArgList[0] = ArgList[1] = nullptr; @@ -8570,14 +8600,17 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) case NAME_RandomPick: case NAME_FRandomPick: + case NAME_CRandomPick: + case NAME_CFRandomPick: if (CheckArgSize(MethodName, ArgList, 1, -1, ScriptPosition)) { - func = new FxRandomPick(RNG, ArgList, MethodName == NAME_FRandomPick, ScriptPosition, ctx.FromDecorate); + func = new FxRandomPick(RNG, ArgList, MethodName == NAME_FRandomPick || MethodName == NAME_CFRandomPick, ScriptPosition, ctx.FromDecorate); } break; case NAME_Random2: - if (CheckArgSize(NAME_Random2, ArgList, 0, 1, ScriptPosition)) + case NAME_CRandom2: + if (CheckArgSize(MethodName, ArgList, 0, 1, ScriptPosition)) { func = new FxRandom2(RNG, ArgList.Size() == 0? nullptr : ArgList[0], ScriptPosition, ctx.FromDecorate); if (ArgList.Size() > 0) ArgList[0] = nullptr; @@ -8850,7 +8883,24 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) return Self; } } - else if (Self->ValueType == TypeTextureID) + else if (ctx.Version >= MakeVersion(4, 15, 0) && Self->ValueType == TypeSound && MethodName == NAME_IsValid) + { + if (ArgList.Size() > 0) + { + ScriptPosition.Message(MSG_ERROR, "Too many parameters in call to %s", MethodName.GetChars()); + delete this; + return nullptr; + } + + Self->ValueType = TypeSInt32; // treat as integer + FxExpression *x = new FxCompareRel('>', Self, new FxConstant(0, ScriptPosition)); + Self = nullptr; + SAFE_RESOLVE(x, ctx); + + delete this; + return x; + } + else if (Self->ValueType == TypeTextureID || (ctx.Version >= MakeVersion(4, 15, 0) && (Self->ValueType == TypeTranslationID))) { if (MethodName == NAME_IsValid || MethodName == NAME_IsNull || MethodName == NAME_Exists || MethodName == NAME_SetInvalid || MethodName == NAME_SetNull) { @@ -8893,6 +8943,67 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) } } + else if (ctx.Version >= MakeVersion(4, 15, 0) && Self->ValueType == TypeSpriteID) + { + if (MethodName == NAME_IsValid || MethodName == NAME_IsEmpty || MethodName == NAME_IsFixed || MethodName == NAME_IsKeep + || MethodName == NAME_Exists + || MethodName == NAME_SetInvalid || MethodName == NAME_SetEmpty || MethodName == NAME_SetFixed || MethodName == NAME_SetKeep) + { + if (ArgList.Size() > 0) + { + ScriptPosition.Message(MSG_ERROR, "Too many parameters in call to %s", MethodName.GetChars()); + delete this; + return nullptr; + } + // No need to create a dedicated node here, all builtins map directly to trivial operations. + Self->ValueType = TypeSInt32; // all builtins treat the texture index as integer. + FxExpression *x = nullptr; + switch (MethodName.GetIndex()) + { + case NAME_IsValid: + x = new FxCompareRel(TK_Geq, Self, new FxConstant(0, ScriptPosition)); + break; + + case NAME_IsEmpty: // TNT1 + x = new FxCompareEq(TK_Eq, Self, new FxConstant(0, ScriptPosition)); + break; + + case NAME_IsFixed: // "----" + x = new FxCompareEq(TK_Eq, Self, new FxConstant(1, ScriptPosition)); + break; + + case NAME_IsKeep: // "####" + x = new FxCompareEq(TK_Eq, Self, new FxConstant(2, ScriptPosition)); + break; + + case NAME_Exists: + x = new FxCompareRel(TK_Geq, Self, new FxConstant(3, ScriptPosition)); + break; + + case NAME_SetInvalid: + x = new FxAssign(Self, new FxConstant(-1, ScriptPosition)); + break; + + case NAME_SetEmpty: // TNT1 + x = new FxAssign(Self, new FxConstant(0, ScriptPosition)); + break; + + case NAME_SetFixed: // "----" + x = new FxAssign(Self, new FxConstant(1, ScriptPosition)); + break; + + case NAME_SetKeep: // "####" + x = new FxAssign(Self, new FxConstant(2, ScriptPosition)); + break; + } + Self = nullptr; + SAFE_RESOLVE(x, ctx); + if (MethodName == NAME_SetInvalid || MethodName == NAME_SetEmpty || MethodName == NAME_SetFixed || MethodName == NAME_SetKeep) x->ValueType = TypeVoid; // override the default type of the assignment operator. + delete this; + return x; + } + } + else if (Self->IsVector()) { // handle builtins: Vectors got 5. @@ -8967,7 +9078,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) } else { - if (PFunction **Override; ctx.Version >= MakeVersion(4, 11, 0) && (Override = static_cast(Self->ValueType)->FnOverrides.CheckKey(MethodName))) + if (PFunction **Override; (Override = static_cast(Self->ValueType)->FnOverrides.CheckKey(MethodName))) { afd_override = *Override; } @@ -12640,6 +12751,15 @@ FxExpression *FxLocalVariableDeclaration::Resolve(FCompileContext &ctx) if (ValueType->RegType == REGT_NIL && ValueType != TypeAuto) { auto sfunc = static_cast(ctx.Function->Variants[0].Implementation); + + const unsigned MAX_STACK_ALLOC = 512 * 1024; // Windows stack is 1 MB, but we cannot go up there without problems + if (uint64_t(ValueType->Size) + uint64_t(sfunc->ExtraSpace) > MAX_STACK_ALLOC) + { + ScriptPosition.Message(MSG_ERROR, "%s exceeds max. allowed size of 512kb for local variables at variable %s", sfunc->Name.GetChars(), Name.GetChars()); + delete this; + return nullptr; + } + StackOffset = sfunc->AllocExtraStack(ValueType); if (Init != nullptr) diff --git a/source/common/scripting/backend/vmbuilder.cpp b/source/common/scripting/backend/vmbuilder.cpp index 71a766d9a79..c9bfc63af86 100644 --- a/source/common/scripting/backend/vmbuilder.cpp +++ b/source/common/scripting/backend/vmbuilder.cpp @@ -40,6 +40,7 @@ #include "filesystem.h" CVAR(Bool, strictdecorate, false, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) +CVAR(Bool, warningstoerrors, false, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) EXTERN_CVAR(Bool, vm_jit) EXTERN_CVAR(Bool, vm_jit_aot) @@ -879,10 +880,18 @@ void FFunctionBuildList::Build() { if (!item.Code->CheckReturn()) { - auto newcmpd = new FxCompoundStatement(item.Code->ScriptPosition); - newcmpd->Add(item.Code); - newcmpd->Add(new FxReturnStatement(nullptr, item.Code->ScriptPosition)); - item.Code = newcmpd->Resolve(ctx); + if (ctx.ReturnProto == nullptr || !ctx.ReturnProto->ReturnTypes.Size()) + { + auto newcmpd = new FxCompoundStatement(item.Code->ScriptPosition); + newcmpd->Add(item.Code); + newcmpd->Add(new FxReturnStatement(nullptr, item.Code->ScriptPosition)); + item.Code = newcmpd->Resolve(ctx); + } + else + { + item.Code->ScriptPosition.Message(MSG_ERROR, "Missing return statement in %s", item.PrintableName.GetChars()); + continue; + } } item.Proto = ctx.ReturnProto; diff --git a/source/common/scripting/frontend/zcc_compile.cpp b/source/common/scripting/frontend/zcc_compile.cpp index d109717a32f..faef50959c8 100644 --- a/source/common/scripting/frontend/zcc_compile.cpp +++ b/source/common/scripting/frontend/zcc_compile.cpp @@ -2286,6 +2286,11 @@ PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, Error(arraysize, "Array size must be positive"); return TypeError; } + if (uint64_t(size) * baseType->Size > 0x7fffffff) + { + Error(arraysize, "Array size overflow. Total size must be less than 2GB"); + return TypeError; + } baseType = NewArray(baseType, size); } diff --git a/source/common/scripting/interface/vmnatives.cpp b/source/common/scripting/interface/vmnatives.cpp index 2b57ceb25a3..a798f1310ed 100644 --- a/source/common/scripting/interface/vmnatives.cpp +++ b/source/common/scripting/interface/vmnatives.cpp @@ -1706,7 +1706,7 @@ DEFINE_ACTION_FUNCTION(DScriptScanner, ScriptError) { PARAM_SELF_PROLOGUE(DScriptScanner); - FString s = FStringFormat(VM_ARGS_NAMES); + FString s = FStringFormat(VM_ARGS_NAMES, 1); self->wrapped.ScriptError("%s", s.GetChars()); return 0; } @@ -1715,7 +1715,7 @@ DEFINE_ACTION_FUNCTION(DScriptScanner, ScriptMessage) { PARAM_SELF_PROLOGUE(DScriptScanner); - FString s = FStringFormat(VM_ARGS_NAMES); + FString s = FStringFormat(VM_ARGS_NAMES, 1); self->wrapped.ScriptMessage("%s", s.GetChars()); return 0; } diff --git a/source/common/textures/gametexture.h b/source/common/textures/gametexture.h index 3eb3740a952..a55616e66eb 100644 --- a/source/common/textures/gametexture.h +++ b/source/common/textures/gametexture.h @@ -62,6 +62,7 @@ enum EGameTexFlags GTexf_OffsetsNotForFont = 512, // The offsets must be ignored when using this texture in a font. GTexf_NoTrim = 1024, // Don't perform trimming on this texture. GTexf_Seen = 2048, // Set to true when the texture is being used for rendering. Must be cleared manually if the check is needed. + GTexf_NoMipmap = 4096, // Disable mipmapping for this texture }; struct FMaterialLayers @@ -265,6 +266,9 @@ class FGameTexture void SetGlowing(PalEntry color) { flags = (flags & ~GTexf_AutoGlowing) | GTexf_Glowing; GlowColor = color; } void SetDisableBrightmap() { flags |= GTexf_BrightmapChecked; Brightmap = nullptr; } + bool isNoMipmap() const { return !!(flags & GTexf_NoMipmap); } + void SetNoMipmap(bool set) { if (set) flags |= GTexf_NoMipmap; else flags &= ~GTexf_NoMipmap; } + bool isUserContent() const; int CheckRealHeight() { return xs_RoundToInt(Base->CheckRealHeight() / ScaleY); } void SetSize(int x, int y) diff --git a/source/common/textures/m_png.cpp b/source/common/textures/m_png.cpp index 331b35e200e..83714a6ac2c 100644 --- a/source/common/textures/m_png.cpp +++ b/source/common/textures/m_png.cpp @@ -54,7 +54,7 @@ // MACROS ------------------------------------------------------------------ // The maximum size of an IDAT chunk ZDoom will write. This is also the -// size of the compression buffer it allocates on the stack. +// size of the compression buffer it allocates on the heap. #define PNG_WRITE_SIZE 32768 // Set this to 1 to use a simple heuristic to select the filter to apply @@ -926,8 +926,7 @@ bool M_SaveBitmap(const uint8_t *from, ESSType color_type, int width, int height temprow[i] = &temprow_storage[temprow_size * i]; } - TArray array(PNG_WRITE_SIZE, true); - auto buffer = array.data(); + TArray buffer(PNG_WRITE_SIZE, true); z_stream stream; int err; int y; @@ -944,8 +943,8 @@ bool M_SaveBitmap(const uint8_t *from, ESSType color_type, int width, int height } y = height; - stream.next_out = buffer; - stream.avail_out = sizeof(buffer); + stream.next_out = buffer.data(); + stream.avail_out = buffer.size(); temprow[0][0] = 0; #if USE_FILTER_HEURISTIC @@ -1007,12 +1006,12 @@ bool M_SaveBitmap(const uint8_t *from, ESSType color_type, int width, int height } while (stream.avail_out == 0) { - if (!WriteIDAT (file, buffer, sizeof(buffer))) + if (!WriteIDAT (file, buffer.data(), buffer.size())) { return false; } - stream.next_out = buffer; - stream.avail_out = sizeof(buffer); + stream.next_out = buffer.data(); + stream.avail_out = buffer.size(); if (stream.avail_in != 0) { err = deflate (&stream, (y == 0) ? Z_FINISH : 0); @@ -1033,12 +1032,12 @@ bool M_SaveBitmap(const uint8_t *from, ESSType color_type, int width, int height } if (stream.avail_out == 0) { - if (!WriteIDAT (file, buffer, sizeof(buffer))) + if (!WriteIDAT (file, buffer.data(), buffer.size())) { return false; } - stream.next_out = buffer; - stream.avail_out = sizeof(buffer); + stream.next_out = buffer.data(); + stream.avail_out = buffer.size(); } } @@ -1048,7 +1047,7 @@ bool M_SaveBitmap(const uint8_t *from, ESSType color_type, int width, int height { return false; } - return WriteIDAT (file, buffer, sizeof(buffer)-stream.avail_out); + return WriteIDAT (file, buffer.data(), buffer.size() - stream.avail_out); } //========================================================================== diff --git a/source/common/utility/tarray.h b/source/common/utility/tarray.h index 3445bd48409..25d6e0e7f5c 100644 --- a/source/common/utility/tarray.h +++ b/source/common/utility/tarray.h @@ -924,7 +924,7 @@ class TDeletingArray : public TArray return *this; } - ~TDeletingArray () + ~TDeletingArray() { for (unsigned int i = 0; i < TArray::Size(); ++i) { diff --git a/source/common/widgets/netstartwindow.cpp b/source/common/widgets/netstartwindow.cpp index 69c83e56542..887f9cc3163 100644 --- a/source/common/widgets/netstartwindow.cpp +++ b/source/common/widgets/netstartwindow.cpp @@ -64,6 +64,12 @@ bool NetStartWindow::RunMessageLoop(bool (*newtimer_callback)(void*), void* newu return Instance->exitreason; } +void NetStartWindow::NetClose() +{ + if (Instance != nullptr) + Instance->OnClose(); +} + NetStartWindow::NetStartWindow() : Widget(nullptr, WidgetType::Window) { SetWindowBackground(Colorf::fromRgba8(51, 51, 51)); diff --git a/source/common/widgets/netstartwindow.h b/source/common/widgets/netstartwindow.h index 5d27b8ebfc7..dcc9d688eac 100644 --- a/source/common/widgets/netstartwindow.h +++ b/source/common/widgets/netstartwindow.h @@ -14,6 +14,7 @@ class NetStartWindow : public Widget static void HideNetStartPane(); static void SetNetStartProgress(int pos); static bool RunMessageLoop(bool (*timer_callback)(void*), void* userdata); + static void NetClose(); private: NetStartWindow(); diff --git a/source/launcher/launcherwindow.cpp b/source/launcher/launcherwindow.cpp index 1cf8335eadd..87a400df385 100644 --- a/source/launcher/launcherwindow.cpp +++ b/source/launcher/launcherwindow.cpp @@ -11,13 +11,13 @@ #include #include -int LauncherWindow::ExecModal(WadStuff* wads, int numwads, int defaultiwad, int* autoloadflags, FString& extraArgs) +int LauncherWindow::ExecModal(WadStuff* wads, int numwads, int defaultiwad, int* autoloadflags, FString* extraArgs) { Size screenSize = GetScreenSize(); double windowWidth = 615.0; double windowHeight = 700.0; - auto launcher = std::make_unique(wads, numwads, defaultiwad, autoloadflags, extraArgs); + auto launcher = std::make_unique(wads, numwads, defaultiwad, autoloadflags, *extraArgs); launcher->SetFrameGeometry((screenSize.width - windowWidth) * 0.5, (screenSize.height - windowHeight) * 0.5, windowWidth, windowHeight); launcher->Show(); diff --git a/source/launcher/launcherwindow.h b/source/launcher/launcherwindow.h index c64676a467e..58c5ae3a250 100644 --- a/source/launcher/launcherwindow.h +++ b/source/launcher/launcherwindow.h @@ -14,7 +14,7 @@ struct WadStuff; class LauncherWindow : public Widget { public: - static int ExecModal(WadStuff* wads, int numwads, int defaultiwad, int* autoloadflags, FString& extraArgs); + static int ExecModal(WadStuff* wads, int numwads, int defaultiwad, int* autoloadflags, FString* extraArgs); LauncherWindow(WadStuff* wads, int numwads, int defaultiwad, int* autoloadflags, FString& extraArgs); void UpdateLanguage();