From 762ce6f14c9f465c6245b1b79fb6064aca719983 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 10 Jan 2024 06:06:28 +0100 Subject: [PATCH 01/16] Add a tab widget --- libraries/ZWidget/CMakeLists.txt | 4 + .../ZWidget/include/zwidget/core/widget.h | 2 +- .../zwidget/widgets/tabwidget/tabwidget.h | 116 +++++++ .../zwidget/widgets/textlabel/textlabel.h | 1 + libraries/ZWidget/src/core/widget.cpp | 4 +- .../src/widgets/tabwidget/tabwidget.cpp | 308 ++++++++++++++++++ .../src/widgets/textlabel/textlabel.cpp | 6 + 7 files changed, 438 insertions(+), 3 deletions(-) create mode 100644 libraries/ZWidget/include/zwidget/widgets/tabwidget/tabwidget.h create mode 100644 libraries/ZWidget/src/widgets/tabwidget/tabwidget.cpp diff --git a/libraries/ZWidget/CMakeLists.txt b/libraries/ZWidget/CMakeLists.txt index 42fea2e59..dd836cd6d 100644 --- a/libraries/ZWidget/CMakeLists.txt +++ b/libraries/ZWidget/CMakeLists.txt @@ -30,6 +30,7 @@ set(ZWIDGET_SOURCES src/widgets/pushbutton/pushbutton.cpp src/widgets/checkboxlabel/checkboxlabel.cpp src/widgets/listview/listview.cpp + src/widgets/tabwidget/tabwidget.cpp src/window/window.cpp ) @@ -58,6 +59,7 @@ set(ZWIDGET_INCLUDES include/zwidget/widgets/pushbutton/pushbutton.h include/zwidget/widgets/checkboxlabel/checkboxlabel.h include/zwidget/widgets/listview/listview.h + include/zwidget/widgets/tabwidget/tabwidget.h include/zwidget/window/window.h ) @@ -91,6 +93,7 @@ source_group("src\\widgets\\textlabel" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURC source_group("src\\widgets\\pushbutton" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/widgets/pushbutton/.+") source_group("src\\widgets\\checkboxlabel" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/widgets/checkboxlabel/.+") source_group("src\\widgets\\listview" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/widgets/listview/.+") +source_group("src\\widgets\\tabwidget" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/widgets/tabwidget/.+") source_group("src\\window" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/window/.+") source_group("include" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/.+") source_group("include\\core" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/core/.+") @@ -107,6 +110,7 @@ source_group("include\\widgets\\textlabel" REGULAR_EXPRESSION "${CMAKE_CURRENT_S source_group("include\\widgets\\pushbutton" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/widgets/pushbutton/.+") source_group("include\\widgets\\checkboxlabel" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/widgets/checkboxlabel/.+") source_group("include\\widgets\\listview" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/widgets/listview/.+") +source_group("include\\widgets\\tabwidget" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/widgets/tabwidget/.+") source_group("include\\window" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/window/.+") source_group("include\\window\\win32" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/window/win32/.+") source_group("include\\window\\sdl2" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/window/sdl2/.+") diff --git a/libraries/ZWidget/include/zwidget/core/widget.h b/libraries/ZWidget/include/zwidget/core/widget.h index 69862fdb4..932a6b5dd 100644 --- a/libraries/ZWidget/include/zwidget/core/widget.h +++ b/libraries/ZWidget/include/zwidget/core/widget.h @@ -86,7 +86,7 @@ public: void SetClipboardText(const std::string& text); Widget* Window(); - Canvas* GetCanvas(); + Canvas* GetCanvas() const; Widget* ChildAt(double x, double y) { return ChildAt(Point(x, y)); } Widget* ChildAt(const Point& pos); diff --git a/libraries/ZWidget/include/zwidget/widgets/tabwidget/tabwidget.h b/libraries/ZWidget/include/zwidget/widgets/tabwidget/tabwidget.h new file mode 100644 index 000000000..56bb345a8 --- /dev/null +++ b/libraries/ZWidget/include/zwidget/widgets/tabwidget/tabwidget.h @@ -0,0 +1,116 @@ + +#pragma once + +#include "../../core/widget.h" +#include +#include + +class TabBar; +class TabBarTab; +class TabWidgetStack; +class TextLabel; +class ImageBox; +class Image; + +class TabWidget : public Widget +{ +public: + TabWidget(Widget* parent); + + int AddTab(Widget* page, const std::string& label); + int AddTab(Widget* page, const std::shared_ptr& icon, const std::string& label); + + int GetCurrentIndex() const; + Widget* GetCurrentWidget() const; + + int GetPageIndex(Widget* pageWidget) const; + + void SetCurrentIndex(int pageIndex); + void SetCurrentWidget(Widget* pageWidget); + + std::function OnCurrentChanged; + +protected: + void OnPaintFrame(Canvas* canvas) override; + void OnGeometryChanged() override; + +private: + void OnBarCurrentChanged(); + + TabBar* Bar = nullptr; + TabWidgetStack* PageStack = nullptr; + std::vector Pages; +}; + +class TabBar : public Widget +{ +public: + TabBar(Widget* parent); + + int AddTab(const std::string& label); + int AddTab(const std::shared_ptr& icon, const std::string& label); + + int GetCurrentIndex() const; + void SetCurrentIndex(int pageIndex); + + double GetPreferredHeight() const { return 30.0; } + + std::function OnCurrentChanged; + +protected: + void OnPaintFrame(Canvas* canvas) override; + void OnGeometryChanged() override; + +private: + void OnTabClicked(TabBarTab* tab); + int GetTabIndex(TabBarTab* tab); + + int CurrentIndex = -1; + std::vector Tabs; +}; + +class TabBarTab : public Widget +{ +public: + TabBarTab(Widget* parent); + + void SetText(const std::string& text); + void SetIcon(const std::shared_ptr& icon); + void SetCurrent(bool value); + + double GetPreferredWidth() const; + + std::function OnClick; + +protected: + void OnPaintFrame(Canvas* canvas) override; + void OnGeometryChanged() override; + void OnMouseMove(const Point& pos) override; + void OnMouseDown(const Point& pos, int key) override; + void OnMouseUp(const Point& pos, int key) override; + void OnMouseLeave() override; + +private: + bool IsCurrent = false; + + ImageBox* Icon = nullptr; + TextLabel* Label = nullptr; + bool mouseDown = false; + bool hot = false; +}; + +class TabWidgetStack : public Widget +{ +public: + TabWidgetStack(Widget* parent); + + void SetCurrentWidget(Widget* widget); + Widget* GetCurrentWidget() const { return CurrentWidget; } + +protected: + void OnPaintFrame(Canvas* canvas) override; + void OnGeometryChanged() override; + +private: + Widget* CurrentWidget = nullptr; +}; diff --git a/libraries/ZWidget/include/zwidget/widgets/textlabel/textlabel.h b/libraries/ZWidget/include/zwidget/widgets/textlabel/textlabel.h index 32f250c6c..45515dfcb 100644 --- a/libraries/ZWidget/include/zwidget/widgets/textlabel/textlabel.h +++ b/libraries/ZWidget/include/zwidget/widgets/textlabel/textlabel.h @@ -21,6 +21,7 @@ public: void SetTextAlignment(TextLabelAlignment alignment); TextLabelAlignment GetTextAlignment() const; + double GetPreferredWidth() const; double GetPreferredHeight() const; protected: diff --git a/libraries/ZWidget/src/core/widget.cpp b/libraries/ZWidget/src/core/widget.cpp index 9c6dc6319..f32385583 100644 --- a/libraries/ZWidget/src/core/widget.cpp +++ b/libraries/ZWidget/src/core/widget.cpp @@ -427,9 +427,9 @@ Widget* Widget::Window() return nullptr; } -Canvas* Widget::GetCanvas() +Canvas* Widget::GetCanvas() const { - for (Widget* w = this; w != nullptr; w = w->Parent()) + for (const Widget* w = this; w != nullptr; w = w->Parent()) { if (w->DispCanvas) return w->DispCanvas.get(); diff --git a/libraries/ZWidget/src/widgets/tabwidget/tabwidget.cpp b/libraries/ZWidget/src/widgets/tabwidget/tabwidget.cpp new file mode 100644 index 000000000..adb2e2917 --- /dev/null +++ b/libraries/ZWidget/src/widgets/tabwidget/tabwidget.cpp @@ -0,0 +1,308 @@ + +#include "widgets/tabwidget/tabwidget.h" +#include "widgets/textlabel/textlabel.h" +#include "widgets/imagebox/imagebox.h" +#include + +TabWidget::TabWidget(Widget* parent) : Widget(parent) +{ + Bar = new TabBar(this); + PageStack = new TabWidgetStack(this); + + Bar->OnCurrentChanged = [=]() { OnBarCurrentChanged(); }; +} + +int TabWidget::AddTab(Widget* page, const std::string& label) +{ + return AddTab(page, nullptr, label); +} + +int TabWidget::AddTab(Widget* page, const std::shared_ptr& icon, const std::string& label) +{ + int pageIndex = Bar->AddTab(label); + page->SetParent(PageStack); + page->SetVisible(false); + Pages.push_back(page); + if (Pages.size() == 1) + { + PageStack->SetCurrentWidget(page); + } + return pageIndex; +} + +int TabWidget::GetCurrentIndex() const +{ + return Bar->GetCurrentIndex(); +} + +Widget* TabWidget::GetCurrentWidget() const +{ + return Pages[Bar->GetCurrentIndex()]; +} + +void TabWidget::SetCurrentIndex(int pageIndex) +{ + if (Bar->GetCurrentIndex() != pageIndex) + { + Bar->SetCurrentIndex(pageIndex); + PageStack->SetCurrentWidget(Pages[pageIndex]); + } +} + +void TabWidget::SetCurrentWidget(Widget* pageWidget) +{ + int pageIndex = GetPageIndex(pageWidget); + if (pageIndex != -1) + SetCurrentIndex(pageIndex); +} + +int TabWidget::GetPageIndex(Widget* pageWidget) const +{ + for (size_t i = 0; i < Pages.size(); i++) + { + if (Pages[i] == pageWidget) + return i; + } + return -1; +} + +void TabWidget::OnBarCurrentChanged() +{ + int pageIndex = Bar->GetCurrentIndex(); + PageStack->SetCurrentWidget(Pages[pageIndex]); + if (OnCurrentChanged) + OnCurrentChanged(); +} + +void TabWidget::OnPaintFrame(Canvas* canvas) +{ +} + +void TabWidget::OnGeometryChanged() +{ + double w = GetWidth(); + double h = GetHeight(); + double barHeight = Bar->GetPreferredHeight(); + Bar->SetFrameGeometry(Rect::xywh(0.0, 0.0, w, barHeight)); + PageStack->SetFrameGeometry(Rect::xywh(0.0, barHeight, w, std::max(h - barHeight, 0.0))); +} + +///////////////////////////////////////////////////////////////////////////// + +TabBar::TabBar(Widget* parent) : Widget(parent) +{ +} + +int TabBar::AddTab(const std::string& label) +{ + return AddTab(nullptr, label); +} + +int TabBar::AddTab(const std::shared_ptr& icon, const std::string& label) +{ + TabBarTab* tab = new TabBarTab(this); + tab->SetIcon(icon); + tab->SetText(label); + int pageIndex = Tabs.size(); + Tabs.push_back(tab); + if (CurrentIndex == -1) + SetCurrentIndex(pageIndex); + OnGeometryChanged(); + return pageIndex; +} + +int TabBar::GetCurrentIndex() const +{ + return CurrentIndex; +} + +void TabBar::SetCurrentIndex(int pageIndex) +{ + if (CurrentIndex != pageIndex) + { + if (CurrentIndex != -1) + Tabs[CurrentIndex]->SetCurrent(false); + CurrentIndex = pageIndex; + if (CurrentIndex != -1) + Tabs[CurrentIndex]->SetCurrent(true); + } +} + +void TabBar::OnTabClicked(TabBarTab* tab) +{ + int pageIndex = GetTabIndex(tab); + if (CurrentIndex != pageIndex) + { + SetCurrentIndex(pageIndex); + if (OnCurrentChanged) + OnCurrentChanged(); + } +} + +int TabBar::GetTabIndex(TabBarTab* tab) +{ + for (size_t i = 0; i < Tabs.size(); i++) + { + if (Tabs[i] == tab) + return i; + } + return -1; +} + +void TabBar::OnPaintFrame(Canvas* canvas) +{ +} + +void TabBar::OnGeometryChanged() +{ + double w = GetWidth(); + double h = GetHeight(); + double x = 0.0; + for (TabBarTab* tab : Tabs) + { + double tabWidth = tab->GetPreferredWidth(); + tab->SetFrameGeometry(Rect::xywh(x, 0.0, tabWidth, h)); + x += tabWidth; + } +} + +///////////////////////////////////////////////////////////////////////////// + +TabBarTab::TabBarTab(Widget* parent) : Widget(parent) +{ +} + +void TabBarTab::SetText(const std::string& text) +{ + if (!text.empty()) + { + if (!Label) + { + Label = new TextLabel(this); + OnGeometryChanged(); + } + Label->SetText(text); + } + else + { + delete Label; + Label = nullptr; + OnGeometryChanged(); + } +} + +void TabBarTab::SetIcon(const std::shared_ptr& image) +{ + if (image) + { + if (!Icon) + { + Icon = new ImageBox(this); + OnGeometryChanged(); + } + Icon->SetImage(image); + } + else + { + delete Icon; + Icon = nullptr; + OnGeometryChanged(); + } +} + +void TabBarTab::SetCurrent(bool value) +{ + if (IsCurrent != value) + { + IsCurrent = value; + Update(); + } +} + +double TabBarTab::GetPreferredWidth() const +{ + double x = Icon ? 32.0 + 5.0 : 0.0; + if (Label) x += Label->GetPreferredWidth(); + return x; +} + +void TabBarTab::OnPaintFrame(Canvas* canvas) +{ +} + +void TabBarTab::OnGeometryChanged() +{ + double x = 0.0; + double w = GetWidth(); + double h = GetHeight(); + if (Icon) + { + Icon->SetFrameGeometry(Rect::xywh(x, (h - 32.0) * 0.5, 32.0, 32.0)); + x = 32.0 + 5.0; + } + if (Label) + { + Label->SetFrameGeometry(Rect::xywh(x, 0.0, std::max(w - x, 0.0), h)); + } +} + +void TabBarTab::OnMouseMove(const Point& pos) +{ + if (!hot) + { + hot = true; + Update(); + } +} + +void TabBarTab::OnMouseDown(const Point& pos, int key) +{ + mouseDown = true; + Update(); +} + +void TabBarTab::OnMouseUp(const Point& pos, int key) +{ + if (mouseDown) + { + mouseDown = false; + Repaint(); + if (OnClick) + OnClick(); + } +} + +void TabBarTab::OnMouseLeave() +{ + hot = false; + mouseDown = false; + Update(); +} + +///////////////////////////////////////////////////////////////////////////// + +TabWidgetStack::TabWidgetStack(Widget* parent) : Widget(parent) +{ +} + +void TabWidgetStack::SetCurrentWidget(Widget* widget) +{ + if (widget != CurrentWidget) + { + if (CurrentWidget) + CurrentWidget->SetVisible(false); + CurrentWidget = widget; + if (CurrentWidget) + CurrentWidget->SetVisible(true); + } +} + +void TabWidgetStack::OnPaintFrame(Canvas* canvas) +{ +} + +void TabWidgetStack::OnGeometryChanged() +{ + if (CurrentWidget) + CurrentWidget->SetFrameGeometry(Rect::xywh(0.0, 0.0, GetWidth(), GetHeight())); +} diff --git a/libraries/ZWidget/src/widgets/textlabel/textlabel.cpp b/libraries/ZWidget/src/widgets/textlabel/textlabel.cpp index 3c034ddb2..55518f0a4 100644 --- a/libraries/ZWidget/src/widgets/textlabel/textlabel.cpp +++ b/libraries/ZWidget/src/widgets/textlabel/textlabel.cpp @@ -33,6 +33,12 @@ TextLabelAlignment TextLabel::GetTextAlignment() const return textAlignment; } +double TextLabel::GetPreferredWidth() const +{ + Canvas* canvas = GetCanvas(); + return canvas->measureText(text).width; +} + double TextLabel::GetPreferredHeight() const { return 20.0; From a0f52411d3e1a1396957455b4837799d4b32fbe0 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 10 Jan 2024 13:52:48 +0100 Subject: [PATCH 02/16] Add tabs to the launcher window --- .../ZWidget/include/zwidget/core/widget.h | 4 + .../src/widgets/tabwidget/tabwidget.cpp | 20 +- src/CMakeLists.txt | 4 + src/launcher/launcherbanner.cpp | 34 ++ src/launcher/launcherbanner.h | 21 ++ src/launcher/launcherbuttonbar.cpp | 46 +++ src/launcher/launcherbuttonbar.h | 25 ++ src/launcher/launcherwindow.cpp | 321 ++---------------- src/launcher/launcherwindow.h | 63 +--- src/launcher/playgamepage.cpp | 100 ++++++ src/launcher/playgamepage.h | 32 ++ src/launcher/settingspage.cpp | 206 +++++++++++ src/launcher/settingspage.h | 47 +++ 13 files changed, 592 insertions(+), 331 deletions(-) create mode 100644 src/launcher/launcherbanner.cpp create mode 100644 src/launcher/launcherbanner.h create mode 100644 src/launcher/launcherbuttonbar.cpp create mode 100644 src/launcher/launcherbuttonbar.h create mode 100644 src/launcher/playgamepage.cpp create mode 100644 src/launcher/playgamepage.h create mode 100644 src/launcher/settingspage.cpp create mode 100644 src/launcher/settingspage.h diff --git a/libraries/ZWidget/include/zwidget/core/widget.h b/libraries/ZWidget/include/zwidget/core/widget.h index 932a6b5dd..639bfe09c 100644 --- a/libraries/ZWidget/include/zwidget/core/widget.h +++ b/libraries/ZWidget/include/zwidget/core/widget.h @@ -39,6 +39,10 @@ public: // Widget noncontent area void SetNoncontentSizes(double left, double top, double right, double bottom); + double GetNoncontentLeft() const { return Noncontent.Left; } + double GetNoncontentTop() const { return Noncontent.Top; } + double GetNoncontentRight() const { return Noncontent.Right; } + double GetNoncontentBottom() const { return Noncontent.Bottom; } // Widget frame box Rect GetFrameGeometry() const; diff --git a/libraries/ZWidget/src/widgets/tabwidget/tabwidget.cpp b/libraries/ZWidget/src/widgets/tabwidget/tabwidget.cpp index adb2e2917..2d8b26ba8 100644 --- a/libraries/ZWidget/src/widgets/tabwidget/tabwidget.cpp +++ b/libraries/ZWidget/src/widgets/tabwidget/tabwidget.cpp @@ -91,6 +91,7 @@ void TabWidget::OnGeometryChanged() TabBar::TabBar(Widget* parent) : Widget(parent) { + SetNoncontentSizes(20.0, 0.0, 20.0, 0.0); } int TabBar::AddTab(const std::string& label) @@ -151,6 +152,9 @@ int TabBar::GetTabIndex(TabBarTab* tab) void TabBar::OnPaintFrame(Canvas* canvas) { + double w = GetFrameGeometry().width; + double h = GetFrameGeometry().height; + canvas->fillRect(Rect::xywh(0.0, 0.0, w, h), Colorf::fromRgba8(38, 38, 38)); } void TabBar::OnGeometryChanged() @@ -160,7 +164,7 @@ void TabBar::OnGeometryChanged() double x = 0.0; for (TabBarTab* tab : Tabs) { - double tabWidth = tab->GetPreferredWidth(); + double tabWidth = tab->GetNoncontentLeft() + tab->GetPreferredWidth() + tab->GetNoncontentRight(); tab->SetFrameGeometry(Rect::xywh(x, 0.0, tabWidth, h)); x += tabWidth; } @@ -170,6 +174,7 @@ void TabBar::OnGeometryChanged() TabBarTab::TabBarTab(Widget* parent) : Widget(parent) { + SetNoncontentSizes(15.0, 0.0, 15.0, 0.0); } void TabBarTab::SetText(const std::string& text) @@ -228,6 +233,16 @@ double TabBarTab::GetPreferredWidth() const void TabBarTab::OnPaintFrame(Canvas* canvas) { + double w = GetFrameGeometry().width; + double h = GetFrameGeometry().height; + if (IsCurrent) + { + canvas->fillRect(Rect::xywh(0.0, 0.0, w, h), Colorf::fromRgba8(51, 51, 51)); + } + else if (hot) + { + canvas->fillRect(Rect::xywh(0.0, 0.0, w, h), Colorf::fromRgba8(45, 45, 45)); + } } void TabBarTab::OnGeometryChanged() @@ -242,7 +257,7 @@ void TabBarTab::OnGeometryChanged() } if (Label) { - Label->SetFrameGeometry(Rect::xywh(x, 0.0, std::max(w - x, 0.0), h)); + Label->SetFrameGeometry(Rect::xywh(x, (h - Label->GetPreferredHeight()) * 0.5, std::max(w - x, 0.0), Label->GetPreferredHeight())); } } @@ -283,6 +298,7 @@ void TabBarTab::OnMouseLeave() TabWidgetStack::TabWidgetStack(Widget* parent) : Widget(parent) { + SetNoncontentSizes(20.0, 5.0, 20.0, 5.0); } void TabWidgetStack::SetCurrentWidget(Widget* widget) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index afc3686b8..58dbefd6f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -978,6 +978,10 @@ set (PCH_SOURCES rendering/swrenderer/textures/swcanvastexture.cpp events.cpp launcher/launcherwindow.cpp + launcher/launcherbanner.cpp + launcher/launcherbuttonbar.cpp + launcher/playgamepage.cpp + launcher/settingspage.cpp common/audio/sound/i_sound.cpp common/audio/sound/oalsound.cpp diff --git a/src/launcher/launcherbanner.cpp b/src/launcher/launcherbanner.cpp new file mode 100644 index 000000000..69f7e7ee1 --- /dev/null +++ b/src/launcher/launcherbanner.cpp @@ -0,0 +1,34 @@ + +#include "launcherbanner.h" +#include "gstrings.h" +#include "version.h" +#include +#include +#include + +LauncherBanner::LauncherBanner(Widget* parent) : Widget(parent) +{ + Logo = new ImageBox(this); + VersionLabel = new TextLabel(this); + VersionLabel->SetTextAlignment(TextLabelAlignment::Right); + + Logo->SetImage(Image::LoadResource("widgets/banner.png")); +} + +void LauncherBanner::UpdateLanguage() +{ + FString versionText = GStrings("PICKER_VERSION"); + versionText.Substitute("%s", GetVersionString()); + VersionLabel->SetText(versionText.GetChars()); +} + +double LauncherBanner::GetPreferredHeight() const +{ + return Logo->GetPreferredHeight(); +} + +void LauncherBanner::OnGeometryChanged() +{ + Logo->SetFrameGeometry(0.0, 0.0, GetWidth(), Logo->GetPreferredHeight()); + VersionLabel->SetFrameGeometry(20.0, GetHeight() - 10.0 - VersionLabel->GetPreferredHeight(), GetWidth() - 40.0, VersionLabel->GetPreferredHeight()); +} diff --git a/src/launcher/launcherbanner.h b/src/launcher/launcherbanner.h new file mode 100644 index 000000000..9a27a5694 --- /dev/null +++ b/src/launcher/launcherbanner.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +class ImageBox; +class TextLabel; + +class LauncherBanner : public Widget +{ +public: + LauncherBanner(Widget* parent); + void UpdateLanguage(); + + double GetPreferredHeight() const; + +private: + void OnGeometryChanged() override; + + ImageBox* Logo = nullptr; + TextLabel* VersionLabel = nullptr; +}; diff --git a/src/launcher/launcherbuttonbar.cpp b/src/launcher/launcherbuttonbar.cpp new file mode 100644 index 000000000..d542ea51e --- /dev/null +++ b/src/launcher/launcherbuttonbar.cpp @@ -0,0 +1,46 @@ + +#include "launcherbuttonbar.h" +#include "launcherwindow.h" +#include "gstrings.h" +#include + +LauncherButtonbar::LauncherButtonbar(LauncherWindow* parent) : Widget(parent) +{ + PlayButton = new PushButton(this); + ExitButton = new PushButton(this); + + PlayButton->OnClick = [=]() { OnPlayButtonClicked(); }; + ExitButton->OnClick = [=]() { OnExitButtonClicked(); }; +} + +void LauncherButtonbar::UpdateLanguage() +{ + PlayButton->SetText(GStrings("PICKER_PLAY")); + ExitButton->SetText(GStrings("PICKER_EXIT")); +} + +double LauncherButtonbar::GetPreferredHeight() const +{ + return 20.0 + std::max(PlayButton->GetPreferredHeight(), ExitButton->GetPreferredHeight()); +} + +void LauncherButtonbar::OnGeometryChanged() +{ + PlayButton->SetFrameGeometry(20.0, 10.0, 120.0, PlayButton->GetPreferredHeight()); + ExitButton->SetFrameGeometry(GetWidth() - 20.0 - 120.0, 10.0, 120.0, PlayButton->GetPreferredHeight()); +} + +void LauncherButtonbar::OnPlayButtonClicked() +{ + GetLauncher()->Start(); +} + +void LauncherButtonbar::OnExitButtonClicked() +{ + GetLauncher()->Exit(); +} + +LauncherWindow* LauncherButtonbar::GetLauncher() const +{ + return static_cast(Parent()); +} diff --git a/src/launcher/launcherbuttonbar.h b/src/launcher/launcherbuttonbar.h new file mode 100644 index 000000000..4872cb612 --- /dev/null +++ b/src/launcher/launcherbuttonbar.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +class LauncherWindow; +class PushButton; + +class LauncherButtonbar : public Widget +{ +public: + LauncherButtonbar(LauncherWindow* parent); + void UpdateLanguage(); + + double GetPreferredHeight() const; + +private: + void OnGeometryChanged() override; + void OnPlayButtonClicked(); + void OnExitButtonClicked(); + + LauncherWindow* GetLauncher() const; + + PushButton* PlayButton = nullptr; + PushButton* ExitButton = nullptr; +}; diff --git a/src/launcher/launcherwindow.cpp b/src/launcher/launcherwindow.cpp index 48d1e5b7d..ae0551ad9 100644 --- a/src/launcher/launcherwindow.cpp +++ b/src/launcher/launcherwindow.cpp @@ -1,25 +1,15 @@ #include "launcherwindow.h" +#include "launcherbanner.h" +#include "launcherbuttonbar.h" +#include "playgamepage.h" +#include "settingspage.h" #include "v_video.h" #include "version.h" #include "i_interface.h" #include "gstrings.h" #include -#include #include -#include -#include -#include -#include -#include -#include -#include - -#ifdef RENDER_BACKENDS -EXTERN_CVAR(Int, vid_preferbackend); -#endif - -EXTERN_CVAR(String, language) -EXTERN_CVAR(Bool, queryiwad); +#include int LauncherWindow::ExecModal(WadStuff* wads, int numwads, int defaultiwad, int* autoloadflags) { @@ -36,39 +26,7 @@ int LauncherWindow::ExecModal(WadStuff* wads, int numwads, int defaultiwad, int* return launcher->ExecResult; } -void LauncherWindow::UpdateLanguage() -{ - LangLabel->SetText(GStrings("OPTMNU_LANGUAGE")); - SelectLabel->SetText(GStrings("PICKER_SELECT")); - PlayButton->SetText(GStrings("PICKER_PLAY")); - ExitButton->SetText(GStrings("PICKER_EXIT")); - - GeneralLabel->SetText(GStrings("PICKER_GENERAL")); - ExtrasLabel->SetText(GStrings("PICKER_EXTRA")); - FullscreenCheckbox->SetText(GStrings("PICKER_FULLSCREEN")); - DisableAutoloadCheckbox->SetText(GStrings("PICKER_NOAUTOLOAD")); - DontAskAgainCheckbox->SetText(GStrings("PICKER_DONTASK")); - LightsCheckbox->SetText(GStrings("PICKER_LIGHTS")); - BrightmapsCheckbox->SetText(GStrings("PICKER_BRIGHTMAPS")); - WidescreenCheckbox->SetText(GStrings("PICKER_WIDESCREEN")); - ParametersLabel->SetText(GStrings("PICKER_ADDPARM")); - -#ifdef RENDER_BACKENDS - BackendLabel->SetText(GStrings("PICKER_PREFERBACKEND")); - VulkanCheckbox->SetText(GStrings("OPTVAL_VULKAN")); - OpenGLCheckbox->SetText(GStrings("OPTVAL_OPENGL")); - GLESCheckbox->SetText(GStrings("OPTVAL_OPENGLES")); -#endif - - FString welcomeText = GStrings("PICKER_WELCOME"); - welcomeText.Substitute("%s", GAMENAME); - FString versionText = GStrings("PICKER_VERSION"); - versionText.Substitute("%s", GetVersionString()); - WelcomeLabel->SetText(welcomeText.GetChars()); - VersionLabel->SetText(versionText.GetChars()); -} - -LauncherWindow::LauncherWindow(WadStuff* wads, int numwads, int defaultiwad, int* autoloadflags) : Widget(nullptr, WidgetType::Window), AutoloadFlags(autoloadflags) +LauncherWindow::LauncherWindow(WadStuff* wads, int numwads, int defaultiwad, int* autoloadflags) : Widget(nullptr, WidgetType::Window) { SetWindowBackground(Colorf::fromRgba8(51, 51, 51)); SetWindowBorderColor(Colorf::fromRgba8(51, 51, 51)); @@ -76,270 +34,65 @@ LauncherWindow::LauncherWindow(WadStuff* wads, int numwads, int defaultiwad, int SetWindowCaptionTextColor(Colorf::fromRgba8(226, 223, 219)); SetWindowTitle(GAMENAME); - Logo = new ImageBox(this); - WelcomeLabel = new TextLabel(this); - VersionLabel = new TextLabel(this); - LangLabel = new TextLabel(this); - SelectLabel = new TextLabel(this); - GeneralLabel = new TextLabel(this); - ExtrasLabel = new TextLabel(this); - ParametersLabel = new TextLabel(this); - FullscreenCheckbox = new CheckboxLabel(this); - DisableAutoloadCheckbox = new CheckboxLabel(this); - DontAskAgainCheckbox = new CheckboxLabel(this); - LightsCheckbox = new CheckboxLabel(this); - BrightmapsCheckbox = new CheckboxLabel(this); - WidescreenCheckbox = new CheckboxLabel(this); - PlayButton = new PushButton(this); - ExitButton = new PushButton(this); - LangList = new ListView(this); - GamesList = new ListView(this); - ParametersEdit = new LineEdit(this); + Banner = new LauncherBanner(this); + Pages = new TabWidget(this); + Buttonbar = new LauncherButtonbar(this); -#ifdef RENDER_BACKENDS - BackendLabel = new TextLabel(this); - VulkanCheckbox = new CheckboxLabel(this); - OpenGLCheckbox = new CheckboxLabel(this); - GLESCheckbox = new CheckboxLabel(this); -#endif + PlayGame = new PlayGamePage(this, wads, numwads, defaultiwad); + Settings = new SettingsPage(this, autoloadflags); - PlayButton->OnClick = [=]() { OnPlayButtonClicked(); }; - ExitButton->OnClick = [=]() { OnExitButtonClicked(); }; - GamesList->OnActivated = [=]() { OnGamesListActivated(); }; + Pages->AddTab(PlayGame, "Play"); + Pages->AddTab(Settings, "Settings"); UpdateLanguage(); - FullscreenCheckbox->SetChecked(vid_fullscreen); - DontAskAgainCheckbox->SetChecked(!queryiwad); - - int flags = *autoloadflags; - DisableAutoloadCheckbox->SetChecked(flags & 1); - LightsCheckbox->SetChecked(flags & 2); - BrightmapsCheckbox->SetChecked(flags & 4); - WidescreenCheckbox->SetChecked(flags & 8); - -#ifdef RENDER_BACKENDS - OpenGLCheckbox->SetRadioStyle(true); - VulkanCheckbox->SetRadioStyle(true); - GLESCheckbox->SetRadioStyle(true); - OpenGLCheckbox->FuncChanged = [this](bool on) { if (on) { VulkanCheckbox->SetChecked(false); GLESCheckbox->SetChecked(false); }}; - VulkanCheckbox->FuncChanged = [this](bool on) { if (on) { OpenGLCheckbox->SetChecked(false); GLESCheckbox->SetChecked(false); }}; - GLESCheckbox->FuncChanged = [this](bool on) { if (on) { VulkanCheckbox->SetChecked(false); OpenGLCheckbox->SetChecked(false); }}; - switch (vid_preferbackend) - { - case 0: - OpenGLCheckbox->SetChecked(true); - break; - case 1: - VulkanCheckbox->SetChecked(true); - break; - case 2: - GLESCheckbox->SetChecked(true); - break; - } -#endif - - - try - { - auto data = LoadWidgetData("menudef.txt"); - FScanner sc; - sc.OpenMem("menudef.txt", data); - while (sc.GetString()) - { - if (sc.Compare("OptionString")) - { - sc.MustGetString(); - if (sc.Compare("LanguageOptions")) - { - sc.MustGetStringName("{"); - while (!sc.CheckString("}")) - { - sc.MustGetString(); - FString iso = sc.String; - sc.MustGetStringName(","); - sc.MustGetString(); - if(iso.CompareNoCase("auto")) - languages.push_back(std::make_pair(iso, FString(sc.String))); - } - } - } - } - } - catch (const std::exception& ex) - { - hideLanguage = true; - } - int i = 0; - for (auto& l : languages) - { - LangList->AddItem(l.second.GetChars()); - if (!l.first.CompareNoCase(::language)) - LangList->SetSelectedItem(i); - i++; - } - for (int i = 0; i < numwads; i++) - { - const char* filepart = strrchr(wads[i].Path.GetChars(), '/'); - if (filepart == NULL) - filepart = wads[i].Path.GetChars(); - else - filepart++; - - FString work; - if (*filepart) work.Format("%s (%s)", wads[i].Name.GetChars(), filepart); - else work = wads[i].Name.GetChars(); - - GamesList->AddItem(work.GetChars()); - } - - if (defaultiwad >= 0 && defaultiwad < numwads) - { - GamesList->SetSelectedItem(defaultiwad); - GamesList->ScrollToItem(defaultiwad); - } - - Logo->SetImage(Image::LoadResource("widgets/banner.png")); - - GamesList->SetFocus(); - - LangList->OnChanged = [this](int i) - { - ::language = languages[i].first.GetChars(); - GStrings.UpdateLanguage(::language); // CVAR callbacks are not active yet. - UpdateLanguage(); - Update(); - }; + Pages->SetCurrentWidget(PlayGame); + PlayGame->SetFocus(); } -void LauncherWindow::OnClose() +void LauncherWindow::Start() { - OnExitButtonClicked(); -} + Settings->Save(); -void LauncherWindow::OnPlayButtonClicked() -{ - vid_fullscreen = FullscreenCheckbox->GetChecked(); - queryiwad = !DontAskAgainCheckbox->GetChecked(); - - int flags = 0; - if (DisableAutoloadCheckbox->GetChecked()) flags |= 1; - if (LightsCheckbox->GetChecked()) flags |= 2; - if (BrightmapsCheckbox->GetChecked()) flags |= 4; - if (WidescreenCheckbox->GetChecked()) flags |= 8; - *AutoloadFlags = flags; - -#ifdef RENDER_BACKENDS - int v = 1; - if (OpenGLCheckbox->GetChecked()) v = 0; - else if (VulkanCheckbox->GetChecked()) v = 1; - else if (GLESCheckbox->GetChecked()) v = 2; - if (v != vid_preferbackend) vid_preferbackend = v; -#endif - - std::string extraargs = ParametersEdit->GetText(); + std::string extraargs = PlayGame->GetExtraArgs(); if (!extraargs.empty()) { // To do: restart the process like the cocoa backend is doing? } - ExecResult = GamesList->GetSelectedItem(); + ExecResult = PlayGame->GetSelectedGame(); DisplayWindow::ExitLoop(); } -void LauncherWindow::OnExitButtonClicked() +void LauncherWindow::Exit() { ExecResult = -1; DisplayWindow::ExitLoop(); } -void LauncherWindow::OnGamesListActivated() +void LauncherWindow::UpdateLanguage() { - OnPlayButtonClicked(); + Banner->UpdateLanguage(); + PlayGame->UpdateLanguage(); + Settings->UpdateLanguage(); + Buttonbar->UpdateLanguage(); +} + +void LauncherWindow::OnClose() +{ + Exit(); } void LauncherWindow::OnGeometryChanged() { - double y = 0.0; + double top = 0.0; + double bottom = GetHeight(); - Logo->SetFrameGeometry(0.0, y, GetWidth(), Logo->GetPreferredHeight()); - y += Logo->GetPreferredHeight(); + Banner->SetFrameGeometry(0.0, top, GetWidth(), Banner->GetPreferredHeight()); + top += Banner->GetPreferredHeight(); - y += 10.0; + bottom -= Buttonbar->GetPreferredHeight(); + Buttonbar->SetFrameGeometry(0.0, bottom, GetWidth(), Buttonbar->GetPreferredHeight()); - WelcomeLabel->SetFrameGeometry(20.0, y, GetWidth() - 40.0, WelcomeLabel->GetPreferredHeight()); - y += WelcomeLabel->GetPreferredHeight(); - - VersionLabel->SetFrameGeometry(20.0, y, GetWidth() - 40.0, VersionLabel->GetPreferredHeight()); - y += VersionLabel->GetPreferredHeight(); - - y += 10.0; - - if (!hideLanguage) - { - LangLabel->SetFrameGeometry(20.0, y, GetWidth() - 40.0, SelectLabel->GetPreferredHeight()); - y += LangLabel->GetPreferredHeight(); - LangList->SetFrameGeometry(20.0, y, GetWidth() - 40.0, 61); - y += 64.0; - } - - - SelectLabel->SetFrameGeometry(20.0, y, GetWidth() - 40.0, SelectLabel->GetPreferredHeight()); - y += SelectLabel->GetPreferredHeight(); - - double listViewTop = y; - - y = GetHeight() - 15.0 - PlayButton->GetPreferredHeight(); - PlayButton->SetFrameGeometry(20.0, y, 120.0, PlayButton->GetPreferredHeight()); - ExitButton->SetFrameGeometry(GetWidth() - 20.0 - 120.0, y, 120.0, PlayButton->GetPreferredHeight()); - - y -= 20.0; - - double editHeight = 24.0; - y -= editHeight; - ParametersEdit->SetFrameGeometry(20.0, y, GetWidth() - 40.0, editHeight); - y -= 5.0; - - double labelHeight = ParametersLabel->GetPreferredHeight(); - y -= labelHeight; - ParametersLabel->SetFrameGeometry(20.0, y, GetWidth() - 40.0, labelHeight); - y -= 10.0; - - double panelWidth = 150.0; - -#ifdef RENDER_BACKENDS - auto yy = y; - y -= GLESCheckbox->GetPreferredHeight(); - double x = GetWidth() / 2 - panelWidth / 2; - GLESCheckbox->SetFrameGeometry(x, y, 190.0, GLESCheckbox->GetPreferredHeight()); - - y -= OpenGLCheckbox->GetPreferredHeight(); - OpenGLCheckbox->SetFrameGeometry(x, y, 190.0, OpenGLCheckbox->GetPreferredHeight()); - - y -= VulkanCheckbox->GetPreferredHeight(); - VulkanCheckbox->SetFrameGeometry(x, y, 190.0, VulkanCheckbox->GetPreferredHeight()); - - y -= BackendLabel->GetPreferredHeight(); - BackendLabel->SetFrameGeometry(x, y, 190.0, BackendLabel->GetPreferredHeight()); - - y = yy; -#endif - y -= DontAskAgainCheckbox->GetPreferredHeight(); - DontAskAgainCheckbox->SetFrameGeometry(20.0, y, 190.0, DontAskAgainCheckbox->GetPreferredHeight()); - WidescreenCheckbox->SetFrameGeometry(GetWidth() - 20.0 - panelWidth, y, panelWidth, WidescreenCheckbox->GetPreferredHeight()); - - y -= DisableAutoloadCheckbox->GetPreferredHeight(); - DisableAutoloadCheckbox->SetFrameGeometry(20.0, y, 190.0, DisableAutoloadCheckbox->GetPreferredHeight()); - BrightmapsCheckbox->SetFrameGeometry(GetWidth() - 20.0 - panelWidth, y, panelWidth, BrightmapsCheckbox->GetPreferredHeight()); - - y -= FullscreenCheckbox->GetPreferredHeight(); - FullscreenCheckbox->SetFrameGeometry(20.0, y, 190.0, FullscreenCheckbox->GetPreferredHeight()); - LightsCheckbox->SetFrameGeometry(GetWidth() - 20.0 - panelWidth, y, panelWidth, LightsCheckbox->GetPreferredHeight()); - - y -= GeneralLabel->GetPreferredHeight(); - GeneralLabel->SetFrameGeometry(20.0, y, 190.0, GeneralLabel->GetPreferredHeight()); - ExtrasLabel->SetFrameGeometry(GetWidth() - 20.0 - panelWidth, y, panelWidth, ExtrasLabel->GetPreferredHeight()); - - double listViewBottom = y - 10.0; - GamesList->SetFrameGeometry(20.0, listViewTop, GetWidth() - 40.0, std::max(listViewBottom - listViewTop, 0.0)); + Pages->SetFrameGeometry(0.0, top, GetWidth(), std::max(bottom - top, 0.0)); } diff --git a/src/launcher/launcherwindow.h b/src/launcher/launcherwindow.h index d54f77464..8cdbc6ce7 100644 --- a/src/launcher/launcherwindow.h +++ b/src/launcher/launcherwindow.h @@ -4,15 +4,11 @@ #include "tarray.h" #include "zstring.h" - -#define RENDER_BACKENDS - -class ImageBox; -class TextLabel; -class CheckboxLabel; -class PushButton; -class ListView; -class LineEdit; +class TabWidget; +class LauncherBanner; +class LauncherButtonbar; +class PlayGamePage; +class SettingsPage; struct WadStuff; class LauncherWindow : public Widget @@ -21,44 +17,21 @@ public: static int ExecModal(WadStuff* wads, int numwads, int defaultiwad, int* autoloadflags); LauncherWindow(WadStuff* wads, int numwads, int defaultiwad, int* autoloadflags); - -private: - void OnPlayButtonClicked(); - void OnExitButtonClicked(); - void OnGamesListActivated(); - - void OnClose() override; - void OnGeometryChanged() override; void UpdateLanguage(); - ImageBox* Logo = nullptr; - TextLabel* WelcomeLabel = nullptr; - TextLabel* VersionLabel = nullptr; - TextLabel* LangLabel = nullptr; - TextLabel* SelectLabel = nullptr; - TextLabel* GeneralLabel = nullptr; - TextLabel* ExtrasLabel = nullptr; - TextLabel* ParametersLabel = nullptr; - CheckboxLabel* FullscreenCheckbox = nullptr; - CheckboxLabel* DisableAutoloadCheckbox = nullptr; - CheckboxLabel* DontAskAgainCheckbox = nullptr; - CheckboxLabel* LightsCheckbox = nullptr; - CheckboxLabel* BrightmapsCheckbox = nullptr; - CheckboxLabel* WidescreenCheckbox = nullptr; -#ifdef RENDER_BACKENDS - TextLabel* BackendLabel = nullptr; - CheckboxLabel* VulkanCheckbox = nullptr; - CheckboxLabel* OpenGLCheckbox = nullptr; - CheckboxLabel* GLESCheckbox = nullptr; -#endif - PushButton* PlayButton = nullptr; - PushButton* ExitButton = nullptr; - ListView* GamesList = nullptr; - ListView* LangList = nullptr; - LineEdit* ParametersEdit = nullptr; + void Start(); + void Exit(); + +private: + void OnClose() override; + void OnGeometryChanged() override; + + LauncherBanner* Banner = nullptr; + TabWidget* Pages = nullptr; + LauncherButtonbar* Buttonbar = nullptr; + + PlayGamePage* PlayGame = nullptr; + SettingsPage* Settings = nullptr; - int* AutoloadFlags = nullptr; int ExecResult = -1; - bool hideLanguage = false; - TArray> languages; }; diff --git a/src/launcher/playgamepage.cpp b/src/launcher/playgamepage.cpp new file mode 100644 index 000000000..5c585c9e5 --- /dev/null +++ b/src/launcher/playgamepage.cpp @@ -0,0 +1,100 @@ + +#include "playgamepage.h" +#include "launcherwindow.h" +#include "i_interface.h" +#include "gstrings.h" +#include "version.h" +#include +#include +#include + +PlayGamePage::PlayGamePage(LauncherWindow* launcher, WadStuff* wads, int numwads, int defaultiwad) : Widget(nullptr), Launcher(launcher) +{ + WelcomeLabel = new TextLabel(this); + SelectLabel = new TextLabel(this); + ParametersLabel = new TextLabel(this); + GamesList = new ListView(this); + ParametersEdit = new LineEdit(this); + + for (int i = 0; i < numwads; i++) + { + const char* filepart = strrchr(wads[i].Path.GetChars(), '/'); + if (filepart == NULL) + filepart = wads[i].Path.GetChars(); + else + filepart++; + + FString work; + if (*filepart) work.Format("%s (%s)", wads[i].Name.GetChars(), filepart); + else work = wads[i].Name.GetChars(); + + GamesList->AddItem(work.GetChars()); + } + + if (defaultiwad >= 0 && defaultiwad < numwads) + { + GamesList->SetSelectedItem(defaultiwad); + GamesList->ScrollToItem(defaultiwad); + } + + GamesList->OnActivated = [=]() { OnGamesListActivated(); }; +} + +std::string PlayGamePage::GetExtraArgs() +{ + return ParametersEdit->GetText(); +} + +int PlayGamePage::GetSelectedGame() +{ + return GamesList->GetSelectedItem(); +} + +void PlayGamePage::UpdateLanguage() +{ + SelectLabel->SetText(GStrings("PICKER_SELECT")); + ParametersLabel->SetText(GStrings("PICKER_ADDPARM")); + FString welcomeText = GStrings("PICKER_WELCOME"); + welcomeText.Substitute("%s", GAMENAME); + WelcomeLabel->SetText(welcomeText.GetChars()); +} + +void PlayGamePage::OnGamesListActivated() +{ + Launcher->Start(); +} + +void PlayGamePage::OnSetFocus() +{ + GamesList->SetFocus(); +} + +void PlayGamePage::OnGeometryChanged() +{ + double y = 10.0; + + WelcomeLabel->SetFrameGeometry(0.0, y, GetWidth(), WelcomeLabel->GetPreferredHeight()); + y += WelcomeLabel->GetPreferredHeight(); + + y += 10.0; + + SelectLabel->SetFrameGeometry(0.0, y, GetWidth(), SelectLabel->GetPreferredHeight()); + y += SelectLabel->GetPreferredHeight(); + + double listViewTop = y; + + y = GetHeight() - 10.0; + + double editHeight = 24.0; + y -= editHeight; + ParametersEdit->SetFrameGeometry(0.0, y, GetWidth(), editHeight); + y -= 5.0; + + double labelHeight = ParametersLabel->GetPreferredHeight(); + y -= labelHeight; + ParametersLabel->SetFrameGeometry(0.0, y, GetWidth(), labelHeight); + y -= 10.0; + + double listViewBottom = y - 10.0; + GamesList->SetFrameGeometry(0.0, listViewTop, GetWidth(), std::max(listViewBottom - listViewTop, 0.0)); +} diff --git a/src/launcher/playgamepage.h b/src/launcher/playgamepage.h new file mode 100644 index 000000000..af0e95bc3 --- /dev/null +++ b/src/launcher/playgamepage.h @@ -0,0 +1,32 @@ +#pragma once + +#include + +class LauncherWindow; +class TextLabel; +class ListView; +class LineEdit; +struct WadStuff; + +class PlayGamePage : public Widget +{ +public: + PlayGamePage(LauncherWindow* launcher, WadStuff* wads, int numwads, int defaultiwad); + void UpdateLanguage(); + + std::string GetExtraArgs(); + int GetSelectedGame(); + +private: + void OnGeometryChanged() override; + void OnSetFocus() override; + void OnGamesListActivated(); + + LauncherWindow* Launcher = nullptr; + + TextLabel* WelcomeLabel = nullptr; + TextLabel* SelectLabel = nullptr; + TextLabel* ParametersLabel = nullptr; + ListView* GamesList = nullptr; + LineEdit* ParametersEdit = nullptr; +}; diff --git a/src/launcher/settingspage.cpp b/src/launcher/settingspage.cpp new file mode 100644 index 000000000..731c29a15 --- /dev/null +++ b/src/launcher/settingspage.cpp @@ -0,0 +1,206 @@ + +#include "settingspage.h" +#include "launcherwindow.h" +#include "gstrings.h" +#include "i_interface.h" +#include "v_video.h" +#include +#include +#include +#include + +#ifdef RENDER_BACKENDS +EXTERN_CVAR(Int, vid_preferbackend); +#endif + +EXTERN_CVAR(String, language) +EXTERN_CVAR(Bool, queryiwad); + +SettingsPage::SettingsPage(LauncherWindow* launcher, int* autoloadflags) : Widget(nullptr), Launcher(launcher), AutoloadFlags(autoloadflags) +{ + LangLabel = new TextLabel(this); + GeneralLabel = new TextLabel(this); + ExtrasLabel = new TextLabel(this); + FullscreenCheckbox = new CheckboxLabel(this); + DisableAutoloadCheckbox = new CheckboxLabel(this); + DontAskAgainCheckbox = new CheckboxLabel(this); + LightsCheckbox = new CheckboxLabel(this); + BrightmapsCheckbox = new CheckboxLabel(this); + WidescreenCheckbox = new CheckboxLabel(this); + +#ifdef RENDER_BACKENDS + BackendLabel = new TextLabel(this); + VulkanCheckbox = new CheckboxLabel(this); + OpenGLCheckbox = new CheckboxLabel(this); + GLESCheckbox = new CheckboxLabel(this); +#endif + + FullscreenCheckbox->SetChecked(vid_fullscreen); + DontAskAgainCheckbox->SetChecked(!queryiwad); + + int flags = *autoloadflags; + DisableAutoloadCheckbox->SetChecked(flags & 1); + LightsCheckbox->SetChecked(flags & 2); + BrightmapsCheckbox->SetChecked(flags & 4); + WidescreenCheckbox->SetChecked(flags & 8); + +#ifdef RENDER_BACKENDS + OpenGLCheckbox->SetRadioStyle(true); + VulkanCheckbox->SetRadioStyle(true); + GLESCheckbox->SetRadioStyle(true); + OpenGLCheckbox->FuncChanged = [this](bool on) { if (on) { VulkanCheckbox->SetChecked(false); GLESCheckbox->SetChecked(false); }}; + VulkanCheckbox->FuncChanged = [this](bool on) { if (on) { OpenGLCheckbox->SetChecked(false); GLESCheckbox->SetChecked(false); }}; + GLESCheckbox->FuncChanged = [this](bool on) { if (on) { VulkanCheckbox->SetChecked(false); OpenGLCheckbox->SetChecked(false); }}; + switch (vid_preferbackend) + { + case 0: + OpenGLCheckbox->SetChecked(true); + break; + case 1: + VulkanCheckbox->SetChecked(true); + break; + case 2: + GLESCheckbox->SetChecked(true); + break; + } +#endif + + LangList = new ListView(this); + + try + { + auto data = LoadWidgetData("menudef.txt"); + FScanner sc; + sc.OpenMem("menudef.txt", data); + while (sc.GetString()) + { + if (sc.Compare("OptionString")) + { + sc.MustGetString(); + if (sc.Compare("LanguageOptions")) + { + sc.MustGetStringName("{"); + while (!sc.CheckString("}")) + { + sc.MustGetString(); + FString iso = sc.String; + sc.MustGetStringName(","); + sc.MustGetString(); + if(iso.CompareNoCase("auto")) + languages.push_back(std::make_pair(iso, FString(sc.String))); + } + } + } + } + } + catch (const std::exception& ex) + { + hideLanguage = true; + } + int i = 0; + for (auto& l : languages) + { + LangList->AddItem(l.second.GetChars()); + if (!l.first.CompareNoCase(::language)) + LangList->SetSelectedItem(i); + i++; + } + + LangList->OnChanged = [=](int i) { OnLanguageChanged(i); }; +} + +void SettingsPage::Save() +{ + vid_fullscreen = FullscreenCheckbox->GetChecked(); + queryiwad = !DontAskAgainCheckbox->GetChecked(); + + int flags = 0; + if (DisableAutoloadCheckbox->GetChecked()) flags |= 1; + if (LightsCheckbox->GetChecked()) flags |= 2; + if (BrightmapsCheckbox->GetChecked()) flags |= 4; + if (WidescreenCheckbox->GetChecked()) flags |= 8; + *AutoloadFlags = flags; + +#ifdef RENDER_BACKENDS + int v = 1; + if (OpenGLCheckbox->GetChecked()) v = 0; + else if (VulkanCheckbox->GetChecked()) v = 1; + else if (GLESCheckbox->GetChecked()) v = 2; + if (v != vid_preferbackend) vid_preferbackend = v; +#endif +} + +void SettingsPage::UpdateLanguage() +{ + LangLabel->SetText(GStrings("OPTMNU_LANGUAGE")); + GeneralLabel->SetText(GStrings("PICKER_GENERAL")); + ExtrasLabel->SetText(GStrings("PICKER_EXTRA")); + FullscreenCheckbox->SetText(GStrings("PICKER_FULLSCREEN")); + DisableAutoloadCheckbox->SetText(GStrings("PICKER_NOAUTOLOAD")); + DontAskAgainCheckbox->SetText(GStrings("PICKER_DONTASK")); + LightsCheckbox->SetText(GStrings("PICKER_LIGHTS")); + BrightmapsCheckbox->SetText(GStrings("PICKER_BRIGHTMAPS")); + WidescreenCheckbox->SetText(GStrings("PICKER_WIDESCREEN")); + +#ifdef RENDER_BACKENDS + BackendLabel->SetText(GStrings("PICKER_PREFERBACKEND")); + VulkanCheckbox->SetText(GStrings("OPTVAL_VULKAN")); + OpenGLCheckbox->SetText(GStrings("OPTVAL_OPENGL")); + GLESCheckbox->SetText(GStrings("OPTVAL_OPENGLES")); +#endif +} + +void SettingsPage::OnLanguageChanged(int i) +{ + ::language = languages[i].first.GetChars(); + GStrings.UpdateLanguage(::language); // CVAR callbacks are not active yet. + UpdateLanguage(); + Update(); + Launcher->UpdateLanguage(); +} + +void SettingsPage::OnGeometryChanged() +{ + double panelWidth = 200.0; + double y = 0.0; + double w = GetWidth(); + double h = GetHeight(); + + GeneralLabel->SetFrameGeometry(0.0, y, 190.0, GeneralLabel->GetPreferredHeight()); + ExtrasLabel->SetFrameGeometry(w - panelWidth, y, panelWidth, ExtrasLabel->GetPreferredHeight()); + y += GeneralLabel->GetPreferredHeight(); + + FullscreenCheckbox->SetFrameGeometry(0.0, y, 190.0, FullscreenCheckbox->GetPreferredHeight()); + LightsCheckbox->SetFrameGeometry(w - panelWidth, y, panelWidth, LightsCheckbox->GetPreferredHeight()); + y += FullscreenCheckbox->GetPreferredHeight(); + + DisableAutoloadCheckbox->SetFrameGeometry(0.0, y, 190.0, DisableAutoloadCheckbox->GetPreferredHeight()); + BrightmapsCheckbox->SetFrameGeometry(w - panelWidth, y, panelWidth, BrightmapsCheckbox->GetPreferredHeight()); + y += DisableAutoloadCheckbox->GetPreferredHeight(); + + DontAskAgainCheckbox->SetFrameGeometry(0.0, y, 190.0, DontAskAgainCheckbox->GetPreferredHeight()); + WidescreenCheckbox->SetFrameGeometry(w - panelWidth, y, panelWidth, WidescreenCheckbox->GetPreferredHeight()); + y += DontAskAgainCheckbox->GetPreferredHeight(); + +#ifdef RENDER_BACKENDS + BackendLabel->SetFrameGeometry(x, y, 190.0, BackendLabel->GetPreferredHeight()); + y += BackendLabel->GetPreferredHeight(); + + VulkanCheckbox->SetFrameGeometry(x, y, 190.0, VulkanCheckbox->GetPreferredHeight()); + y += VulkanCheckbox->GetPreferredHeight(); + + OpenGLCheckbox->SetFrameGeometry(x, y, 190.0, OpenGLCheckbox->GetPreferredHeight()); + y += OpenGLCheckbox->GetPreferredHeight(); + + double x = w / 2 - panelWidth / 2; + GLESCheckbox->SetFrameGeometry(x, y, 190.0, GLESCheckbox->GetPreferredHeight()); + y += GLESCheckbox->GetPreferredHeight(); +#endif + + if (!hideLanguage) + { + LangLabel->SetFrameGeometry(0.0, y, w, LangLabel->GetPreferredHeight()); + y += LangLabel->GetPreferredHeight(); + LangList->SetFrameGeometry(0.0, y, w, std::max(h - y, 0.0)); + } +} diff --git a/src/launcher/settingspage.h b/src/launcher/settingspage.h new file mode 100644 index 000000000..246fe31c5 --- /dev/null +++ b/src/launcher/settingspage.h @@ -0,0 +1,47 @@ +#pragma once + +#include + +// #define RENDER_BACKENDS + +class LauncherWindow; +class TextLabel; +class CheckboxLabel; +class ListView; + +class SettingsPage : public Widget +{ +public: + SettingsPage(LauncherWindow* launcher, int* autoloadflags); + void UpdateLanguage(); + + void Save(); + +private: + void OnLanguageChanged(int i); + void OnGeometryChanged() override; + + LauncherWindow* Launcher = nullptr; + + TextLabel* LangLabel = nullptr; + TextLabel* GeneralLabel = nullptr; + TextLabel* ExtrasLabel = nullptr; + CheckboxLabel* FullscreenCheckbox = nullptr; + CheckboxLabel* DisableAutoloadCheckbox = nullptr; + CheckboxLabel* DontAskAgainCheckbox = nullptr; + CheckboxLabel* LightsCheckbox = nullptr; + CheckboxLabel* BrightmapsCheckbox = nullptr; + CheckboxLabel* WidescreenCheckbox = nullptr; +#ifdef RENDER_BACKENDS + TextLabel* BackendLabel = nullptr; + CheckboxLabel* VulkanCheckbox = nullptr; + CheckboxLabel* OpenGLCheckbox = nullptr; + CheckboxLabel* GLESCheckbox = nullptr; +#endif + ListView* LangList = nullptr; + + int* AutoloadFlags = nullptr; + + TArray> languages; + bool hideLanguage = false; +}; From 8cc531e283fbf08b0280b0a11c2e6498296f98a9 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 10 Jan 2024 23:06:05 +0100 Subject: [PATCH 03/16] Implement mouse event propagation --- .../ZWidget/include/zwidget/core/widget.h | 10 ++- .../widgets/checkboxlabel/checkboxlabel.h | 4 +- .../zwidget/widgets/lineedit/lineedit.h | 6 +- .../zwidget/widgets/listview/listview.h | 6 +- .../zwidget/widgets/pushbutton/pushbutton.h | 4 +- .../zwidget/widgets/scrollbar/scrollbar.h | 4 +- .../zwidget/widgets/tabwidget/tabwidget.h | 5 +- .../zwidget/widgets/textedit/textedit.h | 6 +- libraries/ZWidget/src/core/widget.cpp | 78 ++++++++++++++++--- .../widgets/checkboxlabel/checkboxlabel.cpp | 6 +- .../ZWidget/src/widgets/lineedit/lineedit.cpp | 9 ++- .../ZWidget/src/widgets/listview/listview.cpp | 9 ++- .../src/widgets/pushbutton/pushbutton.cpp | 6 +- .../src/widgets/scrollbar/scrollbar.cpp | 6 +- .../src/widgets/tabwidget/tabwidget.cpp | 22 +++--- .../ZWidget/src/widgets/textedit/textedit.cpp | 9 ++- src/common/widgets/errorwindow.cpp | 3 +- src/common/widgets/errorwindow.h | 2 +- 18 files changed, 135 insertions(+), 60 deletions(-) diff --git a/libraries/ZWidget/include/zwidget/core/widget.h b/libraries/ZWidget/include/zwidget/core/widget.h index 639bfe09c..34faa14e9 100644 --- a/libraries/ZWidget/include/zwidget/core/widget.h +++ b/libraries/ZWidget/include/zwidget/core/widget.h @@ -72,6 +72,7 @@ public: bool HasFocus(); bool IsEnabled(); bool IsVisible(); + bool IsHidden(); void SetFocus(); void SetEnabled(bool value); @@ -113,11 +114,11 @@ public: protected: virtual void OnPaintFrame(Canvas* canvas) { } virtual void OnPaint(Canvas* canvas) { } + virtual bool OnMouseDown(const Point& pos, int key) { return false; } + virtual bool OnMouseDoubleclick(const Point& pos, int key) { return false; } + virtual bool OnMouseUp(const Point& pos, int key) { return false; } + virtual bool OnMouseWheel(const Point& pos, EInputKey key) { return false; } virtual void OnMouseMove(const Point& pos) { } - virtual void OnMouseDown(const Point& pos, int key) { } - virtual void OnMouseDoubleclick(const Point& pos, int key) { } - virtual void OnMouseUp(const Point& pos, int key) { } - virtual void OnMouseWheel(const Point& pos, EInputKey key) { } virtual void OnMouseLeave() { } virtual void OnRawMouseMove(int dx, int dy) { } virtual void OnKeyChar(std::string chars) { } @@ -180,6 +181,7 @@ private: Widget* FocusWidget = nullptr; Widget* CaptureWidget = nullptr; Widget* HoverWidget = nullptr; + bool HiddenFlag = false; StandardCursor CurrentCursor = StandardCursor::arrow; diff --git a/libraries/ZWidget/include/zwidget/widgets/checkboxlabel/checkboxlabel.h b/libraries/ZWidget/include/zwidget/widgets/checkboxlabel/checkboxlabel.h index 03d9089eb..c3f3fb465 100644 --- a/libraries/ZWidget/include/zwidget/widgets/checkboxlabel/checkboxlabel.h +++ b/libraries/ZWidget/include/zwidget/widgets/checkboxlabel/checkboxlabel.h @@ -21,8 +21,8 @@ public: protected: void OnPaint(Canvas* canvas) override; - void OnMouseDown(const Point& pos, int key) override; - void OnMouseUp(const Point& pos, int key) override; + bool OnMouseDown(const Point& pos, int key) override; + bool OnMouseUp(const Point& pos, int key) override; void OnMouseLeave() override; void OnKeyUp(EInputKey key) override; diff --git a/libraries/ZWidget/include/zwidget/widgets/lineedit/lineedit.h b/libraries/ZWidget/include/zwidget/widgets/lineedit/lineedit.h index c34ab1190..526d9eee9 100644 --- a/libraries/ZWidget/include/zwidget/widgets/lineedit/lineedit.h +++ b/libraries/ZWidget/include/zwidget/widgets/lineedit/lineedit.h @@ -72,9 +72,9 @@ protected: void OnPaintFrame(Canvas* canvas) override; void OnPaint(Canvas* canvas) override; void OnMouseMove(const Point& pos) override; - void OnMouseDown(const Point& pos, int key) override; - void OnMouseDoubleclick(const Point& pos, int key) override; - void OnMouseUp(const Point& pos, int key) override; + bool OnMouseDown(const Point& pos, int key) override; + bool OnMouseDoubleclick(const Point& pos, int key) override; + bool OnMouseUp(const Point& pos, int key) override; void OnKeyChar(std::string chars) override; void OnKeyDown(EInputKey key) override; void OnKeyUp(EInputKey key) override; diff --git a/libraries/ZWidget/include/zwidget/widgets/listview/listview.h b/libraries/ZWidget/include/zwidget/widgets/listview/listview.h index 879bda114..2b150abc0 100644 --- a/libraries/ZWidget/include/zwidget/widgets/listview/listview.h +++ b/libraries/ZWidget/include/zwidget/widgets/listview/listview.h @@ -25,9 +25,9 @@ public: protected: void OnPaint(Canvas* canvas) override; void OnPaintFrame(Canvas* canvas) override; - void OnMouseDown(const Point& pos, int key) override; - void OnMouseDoubleclick(const Point& pos, int key) override; - void OnMouseWheel(const Point& pos, EInputKey key) override; + bool OnMouseDown(const Point& pos, int key) override; + bool OnMouseDoubleclick(const Point& pos, int key) override; + bool OnMouseWheel(const Point& pos, EInputKey key) override; void OnKeyDown(EInputKey key) override; void OnGeometryChanged() override; void OnScrollbarScroll(); diff --git a/libraries/ZWidget/include/zwidget/widgets/pushbutton/pushbutton.h b/libraries/ZWidget/include/zwidget/widgets/pushbutton/pushbutton.h index 80d827d39..b9b6c9654 100644 --- a/libraries/ZWidget/include/zwidget/widgets/pushbutton/pushbutton.h +++ b/libraries/ZWidget/include/zwidget/widgets/pushbutton/pushbutton.h @@ -21,9 +21,9 @@ public: protected: void OnPaintFrame(Canvas* canvas) override; void OnPaint(Canvas* canvas) override; + bool OnMouseDown(const Point& pos, int key) override; + bool OnMouseUp(const Point& pos, int key) override; void OnMouseMove(const Point& pos) override; - void OnMouseDown(const Point& pos, int key) override; - void OnMouseUp(const Point& pos, int key) override; void OnMouseLeave() override; void OnKeyDown(EInputKey key) override; void OnKeyUp(EInputKey key) override; diff --git a/libraries/ZWidget/include/zwidget/widgets/scrollbar/scrollbar.h b/libraries/ZWidget/include/zwidget/widgets/scrollbar/scrollbar.h index 38afda383..5ec95c841 100644 --- a/libraries/ZWidget/include/zwidget/widgets/scrollbar/scrollbar.h +++ b/libraries/ZWidget/include/zwidget/widgets/scrollbar/scrollbar.h @@ -47,9 +47,9 @@ public: std::function FuncScrollEnd; protected: + bool OnMouseDown(const Point& pos, int key) override; + bool OnMouseUp(const Point& pos, int key) override; void OnMouseMove(const Point& pos) override; - void OnMouseDown(const Point& pos, int key) override; - void OnMouseUp(const Point& pos, int key) override; void OnMouseLeave() override; void OnPaint(Canvas* canvas) override; void OnEnableChanged() override; diff --git a/libraries/ZWidget/include/zwidget/widgets/tabwidget/tabwidget.h b/libraries/ZWidget/include/zwidget/widgets/tabwidget/tabwidget.h index 56bb345a8..357ef8f3b 100644 --- a/libraries/ZWidget/include/zwidget/widgets/tabwidget/tabwidget.h +++ b/libraries/ZWidget/include/zwidget/widgets/tabwidget/tabwidget.h @@ -85,9 +85,9 @@ public: protected: void OnPaintFrame(Canvas* canvas) override; void OnGeometryChanged() override; + bool OnMouseDown(const Point& pos, int key) override; + bool OnMouseUp(const Point& pos, int key) override; void OnMouseMove(const Point& pos) override; - void OnMouseDown(const Point& pos, int key) override; - void OnMouseUp(const Point& pos, int key) override; void OnMouseLeave() override; private: @@ -95,7 +95,6 @@ private: ImageBox* Icon = nullptr; TextLabel* Label = nullptr; - bool mouseDown = false; bool hot = false; }; diff --git a/libraries/ZWidget/include/zwidget/widgets/textedit/textedit.h b/libraries/ZWidget/include/zwidget/widgets/textedit/textedit.h index e2c6c760c..ed80eec36 100644 --- a/libraries/ZWidget/include/zwidget/widgets/textedit/textedit.h +++ b/libraries/ZWidget/include/zwidget/widgets/textedit/textedit.h @@ -56,9 +56,9 @@ protected: void OnPaintFrame(Canvas* canvas) override; void OnPaint(Canvas* canvas) override; void OnMouseMove(const Point& pos) override; - void OnMouseDown(const Point& pos, int key) override; - void OnMouseDoubleclick(const Point& pos, int key) override; - void OnMouseUp(const Point& pos, int key) override; + bool OnMouseDown(const Point& pos, int key) override; + bool OnMouseDoubleclick(const Point& pos, int key) override; + bool OnMouseUp(const Point& pos, int key) override; void OnKeyChar(std::string chars) override; void OnKeyDown(EInputKey key) override; void OnKeyUp(EInputKey key) override; diff --git a/libraries/ZWidget/src/core/widget.cpp b/libraries/ZWidget/src/core/widget.cpp index f32385583..7ddc1ca59 100644 --- a/libraries/ZWidget/src/core/widget.cpp +++ b/libraries/ZWidget/src/core/widget.cpp @@ -172,6 +172,11 @@ void Widget::Show() { DispWindow->Show(); } + else if (HiddenFlag) + { + HiddenFlag = false; + Update(); + } } void Widget::ShowFullscreen() @@ -213,6 +218,11 @@ void Widget::Hide() if (DispWindow) DispWindow->Hide(); } + else if (!HiddenFlag) + { + HiddenFlag = true; + Update(); + } } void Widget::ActivateWindow() @@ -299,7 +309,7 @@ void Widget::Paint(Canvas* canvas) OnPaint(canvas); for (Widget* w = FirstChild(); w != nullptr; w = w->NextSibling()) { - if (w->Type == WidgetType::Child) + if (w->Type == WidgetType::Child && !w->HiddenFlag) w->Paint(canvas); } canvas->setOrigin(oldOrigin); @@ -323,9 +333,21 @@ bool Widget::IsEnabled() return true; } +bool Widget::IsHidden() +{ + return !IsVisible(); +} + bool Widget::IsVisible() { - return true; + if (Type != WidgetType::Child) + { + return true; // DispWindow->IsVisible(); + } + else + { + return !HiddenFlag; + } } void Widget::SetFocus() @@ -441,7 +463,7 @@ Widget* Widget::ChildAt(const Point& pos) { for (Widget* cur = LastChild(); cur != nullptr; cur = cur->PrevSibling()) { - if (cur->FrameGeometry.contains(pos)) + if (!cur->HiddenFlag && cur->FrameGeometry.contains(pos)) { Widget* cur2 = cur->ChildAt(pos - cur->ContentGeometry.topLeft()); return cur2 ? cur2 : cur; @@ -523,12 +545,26 @@ void Widget::OnWindowMouseMove(const Point& pos) if (HoverWidget != widget) { if (HoverWidget) - HoverWidget->OnMouseLeave(); + { + for (Widget* w = HoverWidget; w != widget && w != this; w = w->Parent()) + { + Widget* p = w->Parent(); + if (!w->FrameGeometry.contains(p->MapFrom(this, pos))) + { + w->OnMouseLeave(); + } + } + } HoverWidget = widget; } DispWindow->SetCursor(widget->CurrentCursor); - widget->OnMouseMove(widget->MapFrom(this, pos)); + + do + { + widget->OnMouseMove(widget->MapFrom(this, pos)); + widget = widget->Parent(); + } while (widget != this); } } @@ -543,7 +579,13 @@ void Widget::OnWindowMouseDown(const Point& pos, EInputKey key) Widget* widget = ChildAt(pos); if (!widget) widget = this; - widget->OnMouseDown(widget->MapFrom(this, pos), key); + while (widget) + { + bool stopPropagation = widget->OnMouseDown(widget->MapFrom(this, pos), key); + if (stopPropagation || widget == this) + break; + widget = widget->Parent(); + } } } @@ -558,7 +600,13 @@ void Widget::OnWindowMouseDoubleclick(const Point& pos, EInputKey key) Widget* widget = ChildAt(pos); if (!widget) widget = this; - widget->OnMouseDoubleclick(widget->MapFrom(this, pos), key); + while (widget) + { + bool stopPropagation = widget->OnMouseDoubleclick(widget->MapFrom(this, pos), key); + if (stopPropagation || widget == this) + break; + widget = widget->Parent(); + } } } @@ -573,7 +621,13 @@ void Widget::OnWindowMouseUp(const Point& pos, EInputKey key) Widget* widget = ChildAt(pos); if (!widget) widget = this; - widget->OnMouseUp(widget->MapFrom(this, pos), key); + while (widget) + { + bool stopPropagation = widget->OnMouseUp(widget->MapFrom(this, pos), key); + if (stopPropagation || widget == this) + break; + widget = widget->Parent(); + } } } @@ -588,7 +642,13 @@ void Widget::OnWindowMouseWheel(const Point& pos, EInputKey key) Widget* widget = ChildAt(pos); if (!widget) widget = this; - widget->OnMouseWheel(widget->MapFrom(this, pos), key); + while (widget) + { + bool stopPropagation = widget->OnMouseWheel(widget->MapFrom(this, pos), key); + if (stopPropagation || widget == this) + break; + widget = widget->Parent(); + } } } diff --git a/libraries/ZWidget/src/widgets/checkboxlabel/checkboxlabel.cpp b/libraries/ZWidget/src/widgets/checkboxlabel/checkboxlabel.cpp index deed9d507..6cf90badf 100644 --- a/libraries/ZWidget/src/widgets/checkboxlabel/checkboxlabel.cpp +++ b/libraries/ZWidget/src/widgets/checkboxlabel/checkboxlabel.cpp @@ -56,19 +56,21 @@ void CheckboxLabel::OnPaint(Canvas* canvas) canvas->drawText(Point(14.0, GetHeight() - 5.0), Colorf::fromRgba8(255, 255, 255), text); } -void CheckboxLabel::OnMouseDown(const Point& pos, int key) +bool CheckboxLabel::OnMouseDown(const Point& pos, int key) { mouseDownActive = true; SetFocus(); + return true; } -void CheckboxLabel::OnMouseUp(const Point& pos, int key) +bool CheckboxLabel::OnMouseUp(const Point& pos, int key) { if (mouseDownActive) { Toggle(); } mouseDownActive = false; + return true; } void CheckboxLabel::OnMouseLeave() diff --git a/libraries/ZWidget/src/widgets/lineedit/lineedit.cpp b/libraries/ZWidget/src/widgets/lineedit/lineedit.cpp index 8a7af4ec4..34391fd19 100644 --- a/libraries/ZWidget/src/widgets/lineedit/lineedit.cpp +++ b/libraries/ZWidget/src/widgets/lineedit/lineedit.cpp @@ -301,7 +301,7 @@ void LineEdit::OnMouseMove(const Point& pos) } } -void LineEdit::OnMouseDown(const Point& pos, int key) +bool LineEdit::OnMouseDown(const Point& pos, int key) { if (key == IK_LeftMouse) { @@ -318,13 +318,15 @@ void LineEdit::OnMouseDown(const Point& pos, int key) } Update(); } + return true; } -void LineEdit::OnMouseDoubleclick(const Point& pos, int key) +bool LineEdit::OnMouseDoubleclick(const Point& pos, int key) { + return true; } -void LineEdit::OnMouseUp(const Point& pos, int key) +bool LineEdit::OnMouseUp(const Point& pos, int key) { if (mouse_selecting && key == IK_LeftMouse) { @@ -346,6 +348,7 @@ void LineEdit::OnMouseUp(const Point& pos, int key) Update(); } } + return true; } void LineEdit::OnKeyChar(std::string chars) diff --git a/libraries/ZWidget/src/widgets/listview/listview.cpp b/libraries/ZWidget/src/widgets/listview/listview.cpp index 680b41d14..717f95827 100644 --- a/libraries/ZWidget/src/widgets/listview/listview.cpp +++ b/libraries/ZWidget/src/widgets/listview/listview.cpp @@ -96,7 +96,7 @@ void ListView::OnPaintFrame(Canvas* canvas) canvas->fillRect(Rect::xywh(w - 1.0, 0.0, 1.0, h - 0.0), bordercolor); } -void ListView::OnMouseDown(const Point& pos, int key) +bool ListView::OnMouseDown(const Point& pos, int key) { SetFocus(); @@ -109,17 +109,19 @@ void ListView::OnMouseDown(const Point& pos, int key) ScrollToItem(selectedItem); } } + return true; } -void ListView::OnMouseDoubleclick(const Point& pos, int key) +bool ListView::OnMouseDoubleclick(const Point& pos, int key) { if (key == IK_LeftMouse) { Activate(); } + return true; } -void ListView::OnMouseWheel(const Point& pos, EInputKey key) +bool ListView::OnMouseWheel(const Point& pos, EInputKey key) { if (key == IK_MouseWheelUp) { @@ -129,6 +131,7 @@ void ListView::OnMouseWheel(const Point& pos, EInputKey key) { scrollbar->SetPosition(std::min(scrollbar->GetPosition() + 20.0, scrollbar->GetMax())); } + return true; } void ListView::OnKeyDown(EInputKey key) diff --git a/libraries/ZWidget/src/widgets/pushbutton/pushbutton.cpp b/libraries/ZWidget/src/widgets/pushbutton/pushbutton.cpp index 2e2e348cb..d838fe424 100644 --- a/libraries/ZWidget/src/widgets/pushbutton/pushbutton.cpp +++ b/libraries/ZWidget/src/widgets/pushbutton/pushbutton.cpp @@ -57,14 +57,15 @@ void PushButton::OnMouseMove(const Point& pos) } } -void PushButton::OnMouseDown(const Point& pos, int key) +bool PushButton::OnMouseDown(const Point& pos, int key) { SetFocus(); buttonDown = true; Update(); + return true; } -void PushButton::OnMouseUp(const Point& pos, int key) +bool PushButton::OnMouseUp(const Point& pos, int key) { if (buttonDown) { @@ -73,6 +74,7 @@ void PushButton::OnMouseUp(const Point& pos, int key) Repaint(); Click(); } + return true; } void PushButton::OnMouseLeave() diff --git a/libraries/ZWidget/src/widgets/scrollbar/scrollbar.cpp b/libraries/ZWidget/src/widgets/scrollbar/scrollbar.cpp index 146298163..489a66343 100644 --- a/libraries/ZWidget/src/widgets/scrollbar/scrollbar.cpp +++ b/libraries/ZWidget/src/widgets/scrollbar/scrollbar.cpp @@ -169,7 +169,7 @@ void Scrollbar::OnMouseMove(const Point& pos) Update(); } -void Scrollbar::OnMouseDown(const Point& pos, int key) +bool Scrollbar::OnMouseDown(const Point& pos, int key) { mouse_drag_start_pos = pos; @@ -254,9 +254,10 @@ void Scrollbar::OnMouseDown(const Point& pos, int key) Update(); CaptureMouse(); + return true; } -void Scrollbar::OnMouseUp(const Point& pos, int key) +bool Scrollbar::OnMouseUp(const Point& pos, int key) { if (mouse_down_mode == mouse_down_thumb_drag) { @@ -269,6 +270,7 @@ void Scrollbar::OnMouseUp(const Point& pos, int key) Update(); ReleaseMouseCapture(); + return true; } void Scrollbar::OnMouseLeave() diff --git a/libraries/ZWidget/src/widgets/tabwidget/tabwidget.cpp b/libraries/ZWidget/src/widgets/tabwidget/tabwidget.cpp index 2d8b26ba8..d22b7e2e6 100644 --- a/libraries/ZWidget/src/widgets/tabwidget/tabwidget.cpp +++ b/libraries/ZWidget/src/widgets/tabwidget/tabwidget.cpp @@ -104,6 +104,7 @@ int TabBar::AddTab(const std::shared_ptr& icon, const std::string& label) TabBarTab* tab = new TabBarTab(this); tab->SetIcon(icon); tab->SetText(label); + tab->OnClick = [=]() { OnTabClicked(tab); }; int pageIndex = Tabs.size(); Tabs.push_back(tab); if (CurrentIndex == -1) @@ -270,27 +271,21 @@ void TabBarTab::OnMouseMove(const Point& pos) } } -void TabBarTab::OnMouseDown(const Point& pos, int key) +bool TabBarTab::OnMouseDown(const Point& pos, int key) { - mouseDown = true; - Update(); + if (OnClick) + OnClick(); + return true; } -void TabBarTab::OnMouseUp(const Point& pos, int key) +bool TabBarTab::OnMouseUp(const Point& pos, int key) { - if (mouseDown) - { - mouseDown = false; - Repaint(); - if (OnClick) - OnClick(); - } + return true; } void TabBarTab::OnMouseLeave() { hot = false; - mouseDown = false; Update(); } @@ -309,7 +304,10 @@ void TabWidgetStack::SetCurrentWidget(Widget* widget) CurrentWidget->SetVisible(false); CurrentWidget = widget; if (CurrentWidget) + { CurrentWidget->SetVisible(true); + OnGeometryChanged(); + } } } diff --git a/libraries/ZWidget/src/widgets/textedit/textedit.cpp b/libraries/ZWidget/src/widgets/textedit/textedit.cpp index 9ddb5fba4..dca840a1b 100644 --- a/libraries/ZWidget/src/widgets/textedit/textedit.cpp +++ b/libraries/ZWidget/src/widgets/textedit/textedit.cpp @@ -286,7 +286,7 @@ void TextEdit::OnMouseMove(const Point& pos) } } -void TextEdit::OnMouseDown(const Point& pos, int key) +bool TextEdit::OnMouseDown(const Point& pos, int key) { if (key == IK_LeftMouse) { @@ -298,13 +298,15 @@ void TextEdit::OnMouseDown(const Point& pos, int key) Update(); } + return true; } -void TextEdit::OnMouseDoubleclick(const Point& pos, int key) +bool TextEdit::OnMouseDoubleclick(const Point& pos, int key) { + return true; } -void TextEdit::OnMouseUp(const Point& pos, int key) +bool TextEdit::OnMouseUp(const Point& pos, int key) { if (mouse_selecting && key == IK_LeftMouse) { @@ -326,6 +328,7 @@ void TextEdit::OnMouseUp(const Point& pos, int key) Update(); } } + return true; } void TextEdit::OnKeyChar(std::string chars) diff --git a/src/common/widgets/errorwindow.cpp b/src/common/widgets/errorwindow.cpp index 6b6b71035..e0af0730b 100644 --- a/src/common/widgets/errorwindow.cpp +++ b/src/common/widgets/errorwindow.cpp @@ -212,7 +212,7 @@ void LogViewer::OnPaint(Canvas* canvas) } } -void LogViewer::OnMouseWheel(const Point& pos, EInputKey key) +bool LogViewer::OnMouseWheel(const Point& pos, EInputKey key) { if (key == IK_MouseWheelUp) { @@ -222,6 +222,7 @@ void LogViewer::OnMouseWheel(const Point& pos, EInputKey key) { ScrollDown(4); } + return true; } void LogViewer::OnKeyDown(EInputKey key) diff --git a/src/common/widgets/errorwindow.h b/src/common/widgets/errorwindow.h index 63304b33f..f38eb676c 100644 --- a/src/common/widgets/errorwindow.h +++ b/src/common/widgets/errorwindow.h @@ -43,7 +43,7 @@ public: protected: void OnPaintFrame(Canvas* canvas) override; void OnPaint(Canvas* canvas) override; - void OnMouseWheel(const Point& pos, EInputKey key) override; + bool OnMouseWheel(const Point& pos, EInputKey key) override; void OnKeyDown(EInputKey key) override; void OnGeometryChanged() override; From 55d90a18dcbe47dc6edc50faf882ad8e8c91abb8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 10 Jan 2024 23:26:45 +0100 Subject: [PATCH 04/16] fix render API selection --- src/launcher/settingspage.cpp | 3 ++- src/launcher/settingspage.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/launcher/settingspage.cpp b/src/launcher/settingspage.cpp index 731c29a15..d1d21b45d 100644 --- a/src/launcher/settingspage.cpp +++ b/src/launcher/settingspage.cpp @@ -183,6 +183,8 @@ void SettingsPage::OnGeometryChanged() y += DontAskAgainCheckbox->GetPreferredHeight(); #ifdef RENDER_BACKENDS + double x = w / 2 - panelWidth / 2; + y = 0; BackendLabel->SetFrameGeometry(x, y, 190.0, BackendLabel->GetPreferredHeight()); y += BackendLabel->GetPreferredHeight(); @@ -192,7 +194,6 @@ void SettingsPage::OnGeometryChanged() OpenGLCheckbox->SetFrameGeometry(x, y, 190.0, OpenGLCheckbox->GetPreferredHeight()); y += OpenGLCheckbox->GetPreferredHeight(); - double x = w / 2 - panelWidth / 2; GLESCheckbox->SetFrameGeometry(x, y, 190.0, GLESCheckbox->GetPreferredHeight()); y += GLESCheckbox->GetPreferredHeight(); #endif diff --git a/src/launcher/settingspage.h b/src/launcher/settingspage.h index 246fe31c5..5c0753194 100644 --- a/src/launcher/settingspage.h +++ b/src/launcher/settingspage.h @@ -2,7 +2,7 @@ #include -// #define RENDER_BACKENDS +#define RENDER_BACKENDS class LauncherWindow; class TextLabel; From 64096658e54dc4c05c3d3e8788b1da86cbbf020d Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Thu, 11 Jan 2024 08:02:14 -0500 Subject: [PATCH 05/16] - reverse allowduplicates check since it is a misnomer to what it actually did --- src/common/filesystem/source/filesystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/filesystem/source/filesystem.cpp b/src/common/filesystem/source/filesystem.cpp index f011c4c57..a8418956f 100644 --- a/src/common/filesystem/source/filesystem.cpp +++ b/src/common/filesystem/source/filesystem.cpp @@ -252,7 +252,7 @@ bool FileSystem::InitMultipleFiles (std::vector& filenames, LumpFil stringpool->shared = true; // will be used by all owned resource files. // first, check for duplicates - if (allowduplicates) + if (!allowduplicates) { for (size_t i=0;i Date: Thu, 11 Jan 2024 07:02:23 +0300 Subject: [PATCH 06/16] Fix "unexpected end of TTF file" error Changed returnv vector size to 3 by default and set size 5 for WIN32 only. --- src/common/widgets/widgetresourcedata.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/common/widgets/widgetresourcedata.cpp b/src/common/widgets/widgetresourcedata.cpp index 73adb14e0..85ee3e249 100644 --- a/src/common/widgets/widgetresourcedata.cpp +++ b/src/common/widgets/widgetresourcedata.cpp @@ -54,7 +54,7 @@ std::vector LoadWidgetFontData(const std::string& name) std::vector returnv; if (!stricmp(name.c_str(), "notosans")) { - returnv.resize(5); + returnv.resize(3); returnv[0].fontdata = LoadFile("widgets/noto/notosans-regular.ttf"); returnv[1].fontdata = LoadFile("widgets/noto/notosansarmenian-regular.ttf"); returnv[2].fontdata = LoadFile("widgets/noto/notosansgeorgian-regular.ttf"); @@ -62,6 +62,7 @@ std::vector LoadWidgetFontData(const std::string& name) wchar_t wbuffer[256]; if (GetWindowsDirectoryW(wbuffer, 256)) { + returnv.resize(5); FString windir(wbuffer); returnv[3].fontdata = LoadDiskFile((windir + "/fonts/yugothm.ttc").GetChars()); returnv[3].language = "ja"; From 53c60027466e7d4ba073fa4830cfe863d4e63eb3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 11 Jan 2024 16:41:21 +0100 Subject: [PATCH 07/16] attempt to fix compilation on macOS --- libraries/ZWidget/include/zwidget/widgets/tabwidget/tabwidget.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/ZWidget/include/zwidget/widgets/tabwidget/tabwidget.h b/libraries/ZWidget/include/zwidget/widgets/tabwidget/tabwidget.h index 357ef8f3b..48a2d8ffa 100644 --- a/libraries/ZWidget/include/zwidget/widgets/tabwidget/tabwidget.h +++ b/libraries/ZWidget/include/zwidget/widgets/tabwidget/tabwidget.h @@ -2,6 +2,7 @@ #pragma once #include "../../core/widget.h" +#include #include #include From 63f1326e621495173cd80a6082cafb3028543ec1 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 10 Jan 2024 23:28:26 +0100 Subject: [PATCH 08/16] Add support for changing the tab labels --- .../zwidget/widgets/tabwidget/tabwidget.h | 8 +++++ .../src/widgets/tabwidget/tabwidget.cpp | 36 +++++++++++++++++++ src/launcher/launcherwindow.cpp | 2 ++ 3 files changed, 46 insertions(+) diff --git a/libraries/ZWidget/include/zwidget/widgets/tabwidget/tabwidget.h b/libraries/ZWidget/include/zwidget/widgets/tabwidget/tabwidget.h index 48a2d8ffa..242094024 100644 --- a/libraries/ZWidget/include/zwidget/widgets/tabwidget/tabwidget.h +++ b/libraries/ZWidget/include/zwidget/widgets/tabwidget/tabwidget.h @@ -21,6 +21,11 @@ public: int AddTab(Widget* page, const std::string& label); int AddTab(Widget* page, const std::shared_ptr& icon, const std::string& label); + void SetTabText(int index, const std::string& text); + void SetTabText(Widget* page, const std::string& text); + void SetTabIcon(int index, const std::shared_ptr& icon); + void SetTabIcon(Widget* page, const std::shared_ptr& icon); + int GetCurrentIndex() const; Widget* GetCurrentWidget() const; @@ -51,6 +56,9 @@ public: int AddTab(const std::string& label); int AddTab(const std::shared_ptr& icon, const std::string& label); + void SetTabText(int index, const std::string& text); + void SetTabIcon(int index, const std::shared_ptr& icon); + int GetCurrentIndex() const; void SetCurrentIndex(int pageIndex); diff --git a/libraries/ZWidget/src/widgets/tabwidget/tabwidget.cpp b/libraries/ZWidget/src/widgets/tabwidget/tabwidget.cpp index d22b7e2e6..cbac877aa 100644 --- a/libraries/ZWidget/src/widgets/tabwidget/tabwidget.cpp +++ b/libraries/ZWidget/src/widgets/tabwidget/tabwidget.cpp @@ -30,6 +30,30 @@ int TabWidget::AddTab(Widget* page, const std::shared_ptr& icon, const st return pageIndex; } +void TabWidget::SetTabText(int index, const std::string& text) +{ + Bar->SetTabText(index, text); +} + +void TabWidget::SetTabText(Widget* page, const std::string& text) +{ + int index = GetPageIndex(page); + if (index != -1) + SetTabText(index, text); +} + +void TabWidget::SetTabIcon(int index, const std::shared_ptr& icon) +{ + Bar->SetTabIcon(index, icon); +} + +void TabWidget::SetTabIcon(Widget* page, const std::shared_ptr& icon) +{ + int index = GetPageIndex(page); + if (index != -1) + SetTabIcon(index, icon); +} + int TabWidget::GetCurrentIndex() const { return Bar->GetCurrentIndex(); @@ -113,6 +137,18 @@ int TabBar::AddTab(const std::shared_ptr& icon, const std::string& label) return pageIndex; } +void TabBar::SetTabText(int index, const std::string& text) +{ + Tabs[index]->SetText(text); + OnGeometryChanged(); +} + +void TabBar::SetTabIcon(int index, const std::shared_ptr& icon) +{ + Tabs[index]->SetIcon(icon); + OnGeometryChanged(); +} + int TabBar::GetCurrentIndex() const { return CurrentIndex; diff --git a/src/launcher/launcherwindow.cpp b/src/launcher/launcherwindow.cpp index ae0551ad9..55158ccc5 100644 --- a/src/launcher/launcherwindow.cpp +++ b/src/launcher/launcherwindow.cpp @@ -72,6 +72,8 @@ void LauncherWindow::Exit() void LauncherWindow::UpdateLanguage() { + // Pages->SetTabText(PlayGame, GStrings("PICKER_TAB_PLAY")); + // Pages->SetTabText(Settings, GStrings("PICKER_TAB_SETTINGS")); Banner->UpdateLanguage(); PlayGame->UpdateLanguage(); Settings->UpdateLanguage(); From 04e6eba9e05162534761460b3bb1d3ebd186fe87 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 11 Jan 2024 17:50:26 +0100 Subject: [PATCH 09/16] activate localization of tabs and text update. --- src/launcher/launcherwindow.cpp | 4 +-- wadsrc/static/language.0 | 49 +++++++++++++++++---------------- wadsrc/static/language.csv | 16 ++++++----- 3 files changed, 36 insertions(+), 33 deletions(-) diff --git a/src/launcher/launcherwindow.cpp b/src/launcher/launcherwindow.cpp index 55158ccc5..96039ea08 100644 --- a/src/launcher/launcherwindow.cpp +++ b/src/launcher/launcherwindow.cpp @@ -72,8 +72,8 @@ void LauncherWindow::Exit() void LauncherWindow::UpdateLanguage() { - // Pages->SetTabText(PlayGame, GStrings("PICKER_TAB_PLAY")); - // Pages->SetTabText(Settings, GStrings("PICKER_TAB_SETTINGS")); + Pages->SetTabText(PlayGame, GStrings("PICKER_TAB_PLAY")); + Pages->SetTabText(Settings, GStrings("OPTMNU_TITLE")); Banner->UpdateLanguage(); PlayGame->UpdateLanguage(); Settings->UpdateLanguage(); diff --git a/wadsrc/static/language.0 b/wadsrc/static/language.0 index b43bba5a3..b669c46c1 100644 --- a/wadsrc/static/language.0 +++ b/wadsrc/static/language.0 @@ -843,7 +843,7 @@ Simple options menu,OPTMNU_SIMPLEON,,,,Zjednodušená nastavení,Enkel menu med Browse Game Config,OPTMNU_OPENCONFIG,,,,Procházet konfigurační soubory,Gennemse spilkonfiguration,Konfigurationsdatei anzeigen,,Foliumi agordojn de ludo,Abrir carpeta de configuración de juego,,Selaa pelin asetuksia,Parcourir configuration,Játék konfiguráció böngészése,Apri le Configurazioni di Gioco,ゲームコンフィグ参照,게임 환경설정 찾아보기,Door gameconfiguratie bladeren,Bla gjennom spillkonfigurasjon,Przeglądaj Ustawienia Gry,Abrir pasta de configuração de jogo,,Caută Configurația Jocului,Открыть файл настроек игры,,Bläddra i spelkonfigurationen,Oyun Yapılandırmasına Gözat,Перегляд налаштувань гри, Browse Screenshots,OPTMNU_OPENSCREENSHOTS,,,,Procházet snímky obrazovky,Gennemse skærmbilleder,Screenshots anzeigen,,Foliumi ekrankopiojn,Abrir carpeta de capturas de pantalla,,Selaa kuvakaappauksia,Parcourir les captures d'écran,Képernyőképek böngészése,Apri gli Screenshot,クリーンショット参照,스크린샷 찾아보기,Door schermafbeeldingen bladeren,Bla gjennom skjermbilder,Przeglądaj Zrzuty Ekranu,Abrir pasta de capturas de tela,,Caută Capturi de Ecran,Просмотр снимков экрана,,Bläddra bland skärmdumpar,Ekran Görüntülerine Gözat,Перегляд скріншотів, Browse Saved Games,OPTMNU_OPENSAVES,,,,Procházet uložené hry,Gennemse gemte spil,Spielstände anzeigen,,Foliumi konservitajn ludadojn,Abrir carpeta de partidas guardadas,,Selaa tallennettuja pelejä,Parcourir sauvegardes,Elmentett játékok böngészése,Apri i Giochi Salvati,セーブしたゲーム参照,저장된 게임 찾아보기,Door opgeslagen games bladeren,Bla gjennom lagrede spill,Przeglądaj Zapisy Gry,Abrir pasta de jogos salvos,,Caută Salvări,Просмотр сохранённых игр,,Bläddra bland sparade spel,Kaydedilen Oyunlara Gözat,Перегляд збережень ігр, -Swap mouse buttons,MOUSEMNU_SWAPBUTTONS,,,,Prohodit tlačítka myši,Udskift museknapper,Maustasten vertauschen,,Permuti musbutonojn,Alternar botones de ratón,,Vaihda hiiren painikkeita,Permuter les boutons de la souris,Egérgombok felcserélése,Inverti i comandi del mouse,マウスボタンを反転,마우스 버튼 바꾸기,Muisknoppen verwisselen,Bytt museknapper,Zamień Przyciski Myszki,Trocar botões do mouse,,Schimbă Butoanele Mouse-ului între Ele,Поменять местами кнопки мыши,,Byta musknappar,Fare düğmelerini değiştirme,Поміняти місцями кнопки миші, +Swap mouse buttons,MOUSEMNU_SWAPBUTTONS,,,,Prohodit tlačítka myši,Udskift museknapper,Maustasten vertauschen,,Permuti musbutonojn,Alternar botones de ratón,,Vaihda hiiren painikkeita,Permuter les boutons de la souris,Egérgombok felcserélése,Inverti i comandi del mouse,マウスボタンを反転,마우스 버튼 바꾸기,Muisknoppen verwisselen,Bytt museknapper,Zamień Przyciski Myszki,Trocar botões do mouse,,Schimbă Butoanele Mouse-ului între Ele,Поменять местами кнопки мыши,Замените дугмад миша,Byta musknappar,Fare düğmelerini değiştirme,Поміняти місцями кнопки миші, ,,,,,,,,,,,,,,,,,,,,,,,,,,,,, Only modified,OPTVAL_ONLYMODIFIED,,,,Pouze upravené,Kun ændret,Nur modfizierte,,Nur modifitaj,Solo modificados,,Vain muunneltu,Modifié seulement,Csak módosított,Solo modificato,モディファイのみ,수정된 것만,Alleen gewijzigd,Bare endret,Tylko zmodyfikowane,Somente modificado,,Numai modificat,Только изменённый,Само модификовано,Endast ändrat,Yalnızca değiştirilmiş,Тільки в модифікаціях, Unknown,TXT_UNKNOWN,,,,Neznámé,Ukendt,Unbekannt,Άχνωστο,Nekonata,Desconocido,,Tuntematon,Inconnue,Ismeretlen,Sconosciuto,不明,알 수 없음,Onbekend,Ukjent,Nieznane,Desconhecido,,Necunoscut,Неизвестно,Непознат,Okänd,Bilinmiyor,Невідомо, @@ -851,26 +851,27 @@ HUD,OPTVAL_HUD,,,,,,,,,,,,ATH,,,,,,,,,,,Отображение информац Automap,OPTVAL_AUTOMAP,,,,Automapa,,,,Aŭtomata mapo,Automapa,,,Carte,Auto-térkép,Automappa,オートマップ,오토맵,,,Automapa,Automapa,,Hartă Computerizată,Автокарта,Аутомап,,,Автокарта, HUD + Automap,OPTVAL_HUDANDMAP,,,,HUD + Automapa,,,,HUD + Aŭtomata mapo,HUD + Automapa,,,ATH + Carte,HUD + Auto-térkép,HUD + Automappa,HUD+オートマップ,HUD + 오토맵,,,HUD + Automapa,HUD + Automapa,,Interfață + Hartă Computerizată,Интерфейс + автокарта,HUD + Аутомап,,,Інтерфейс + Автокарта, This savegame needs these files,TXT_SAVEGAMENEEDS,,,,Uložená hra potřebuje tyto soubory,Dette savegame har brug for disse filer,Dieser Spielstand benötigt die folgenden Dateien,Το αρχείο αποθήκευσης χριάζετε αυτά τα αρχεία,Ĉi tiu konservita ludo bezonas ĉi tiujn dosierojn,Esta partida guardada necesita los siguientes archivos,,Tämä pelitallenne tarvitsee nämä tiedostot,Cette sauvegarde nécessite les fichiers suivants:,Ehhez a mentéshez a következő fájlok kellenek:,Questo salvataggio ha bisogno di questi file,このセーブデータには 必要なファイルがある,이 저장 된 게임은 해당 파일이 필요합니다.,Dit spel heeft de volgende bestanden nodig,Dette lagringsspillet trenger disse filene,Ten zapis gry potrzebuje tych plików,Este jogo salvo precisa destes arquivos,Este jogo guardado precisa destes arquivos,Acest joc salvat necesită următoarele fișiere,Данное сохранение требует следующие файлы,Овој сачуваној игри требају ови фајлови,Detta sparande behöver dessa filer,Bu kayıt oyunu şu dosyalara ihtiyaç duyar,Цій грі потрібні такі файли, -Multiplayer Options,OPTMNU_MULTIPLAYER,,,,Multiplayer,Multiplayer-indstillinger,Mehrspieleroptionen,,Agordoj de la plurludanta reĝimo,Opciones del multijugador,,,,,,マルチプレイ オプション,,Multiplayer Opties,Alternativer for flerspiller,Opcje Trybu Wielu Graczy,Opções de multijogador,,,Настройки сетевой игры,,Alternativ för flera spelare,Çok Oyunculu Seçenekler,Параметри багатокористувацької гри, -Input Options,OPTMNU_INPUT,,,,Vstupní zařízení,Input-indstillinger,Eingabeoptionen,,Enig-agordoj,Opciones de entrada (input),,,,,,入力オプション,,In1voeropties,Alternativer for inndata,Opcje Sterowania,Opções de entrada,,,Настройки ввода,,Inmatningsalternativ,Girdi Seçenekleri,Параметри введення, -System Options,OPTMNU_SYSTEM,,,,Systém,Systemindstillinger,Systemoptionen,,Agordoj de la sistemo,Opciones del sistema,,,,,,システムオプション,,Systeem Opties,Systemalternativer,Opcje Systemowe,Opções de sistema,,,Настройки системы,,Systemalternativ,Sistem Seçenekleri,Системні налаштування, -Light Options,OPTMNU_LIGHT,,,,Osvětlení,Lysindstillinger,Beleuchtungsoptionen,,Lum-agordoj,Opciones de iluminación,,,,,,光源オプション,,Licht Opties,Alternativer for lys,Opcje Oświetlenia,Opções de iluminação,,,Настройки освещения,,Alternativ för ljus,Işık Seçenekleri,Параметри освітлення, -Sprite Options,OPTMNU_SPRITE,,,,Sprity,Sprite-indstillinger,Spriteoptionen,,Agordoj de la mov-rastrumoj,Opciones de los «sprites»,,,,,,スプライトオプション,,Sprite-opties,Sprite-alternativer,Opcje Sprite'ów,Opções de sprite,,,Настройки спрайтов,,Alternativ för sprite,Sprite Seçenekleri,Параметри спрайтів, -Coronas,GLPREFMNU_CORONAS,,,,Záře,Coronas,,,Lum-ampoloj,Focos de luz,,,,,,光冠,,Corona's,Koronaer,Korony,,,,Короны,,Koronor,Koronalar,Корони, -Appearance,DSPLYMNU_APPEARANCE,,,,Vzhled,Udseende,Spieldarstellung,,Aspekto,Apariencia,,,,,,アピアランス,,Uiterlijk,Utseende,Wygląd,Aparência,,,Внешность,,Utseende,Görünüş,Зовнішній вигляд, -Advanced Display Options,DSPLYMNU_ADVANCED,,,,Grafika (pokročilé),Avancerede visningsindstillinger,Erweiterte Anzeigeoptionen,,Altnivelaj ekran-agordoj,Opciones avanzadas de visualización,,,,,,高度なディスプレイオプション,,Geavanceerde Weergave Opties,Avanserte visningsalternativer,Zaawansowane Opcje Wyświetlania,Opções de vídeo avançadas,,,Расширенные настройки экрана,,Avancerade visningsalternativ,Gelişmiş Görüntüleme Seçenekleri,Додаткові параметри відображення, -Select which game file to run.,PICKER_SELECT,,,,,,Bitte wähle ein Spiel aus.,,,,,,,,,,,,,,,,,Выбор файла игры для запуска.,,,,, -Play Game,PICKER_PLAY,,,,,,Spielen,,,,,,,,,,,,,,,,,Играть,,,,, -Exit,PICKER_EXIT,,,,,,Verlassen,,,,,,,,,,,,,,,,,Выход,,,,, -General,PICKER_GENERAL,,,,,,Allgemein,,,,,,,,,,,,,,,,,Общее,,,,, -Extra Graphics,PICKER_EXTRA,,,,,,Extragrafiken,,,,,,,,,,,,,,,,,Доп. графика,,,,, -Fullscreen,PICKER_FULLSCREEN,,,,,,Vollbild,,,,,,,,,,,,,,,,,Полный экран,,,,, -Disable autoload,PICKER_NOAUTOLOAD,,,,,,Autoload deaktivieren,,,,,,,,,,,,,,,,,Отключить автозагрузку,,,,, -Don't ask me again,PICKER_DONTASK,,,,,,Nicht nochmal fragen,,,,,,,,,,,,,,,,,Не спрашивать снова,,,,, -Lights,PICKER_LIGHTS,,,,,,Lichter,,,,,,,,,,,,,,,,,Освещение,,,,, -Brightmaps,PICKER_BRIGHTMAPS,,,,,,,,,,,,,,,,,,,,,,,Карты освещения,,,,, -Widescreen,PICKER_WIDESCREEN,,,,,,Breitbildunterstützung,,,,,,,,,,,,,,,,,Широкий экран,,,,, -Additional Parameters:,PICKER_ADDPARM,,,,,,Zusätzliche Parameter,,,,,,,,,,,,,,,,,Доп. параметры:,,,,, -Welcome to %s!,PICKER_WELCOME,,,,,,Willkommen bei %s!,,,,,,,,,,,,,,,,,Добро пожаловать в %s!,,,,, -Version %s,PICKER_VERSION,,,,,,,,,,,,,,,,,,,,,,,Версия %s,,,,, -Rendering API,PICKER_PREFERBACKEND,,,,API vykreslování,,Render API,,Preferita bildigado de API,API de renderizado,,Renderöinti API,API de rendu,Renderelő API,API di rendering,優先レンダリングAPI,기본적인 API 랜더링,,,API renderowania,API de renderização,,API Video Preferat,API для рендеринга,АПИ приказивања,API för rendering,,API для візуалізації, \ No newline at end of file +Multiplayer Options,OPTMNU_MULTIPLAYER,,,,Multiplayer,Multiplayer-indstillinger,Mehrspieleroptionen,,Agordoj de la plurludanta reĝimo,Opciones del multijugador,,,Options multijoueurs,,,マルチプレイ オプション,,Multiplayer Opties,Alternativer for flerspiller,Opcje Trybu Wielu Graczy,Opções de multijogador,,,Настройки сетевой игры,Опције за више играча,Alternativ för flera spelare,Çok Oyunculu Seçenekler,Параметри багатокористувацької гри, +Input Options,OPTMNU_INPUT,,,,Vstupní zařízení,Input-indstillinger,Eingabeoptionen,,Enig-agordoj,Opciones de entrada (input),,,Options d'entrée,,,入力オプション,,In1voeropties,Alternativer for inndata,Opcje Sterowania,Opções de entrada,,,Настройки ввода,Опције уноса,Inmatningsalternativ,Girdi Seçenekleri,Параметри введення, +System Options,OPTMNU_SYSTEM,,,,Systém,Systemindstillinger,Systemoptionen,,Agordoj de la sistemo,Opciones del sistema,,,Options du système,,,システムオプション,,Systeem Opties,Systemalternativer,Opcje Systemowe,Opções de sistema,,,Настройки системы,Системске опције,Systemalternativ,Sistem Seçenekleri,Системні налаштування, +Light Options,OPTMNU_LIGHT,,,,Osvětlení,Lysindstillinger,Beleuchtungsoptionen,,Lum-agordoj,Opciones de iluminación,,,Options de lumière,,,光源オプション,,Licht Opties,Alternativer for lys,Opcje Oświetlenia,Opções de iluminação,,,Настройки освещения,Опције осветљења,Alternativ för ljus,Işık Seçenekleri,Параметри освітлення, +Sprite Options,OPTMNU_SPRITE,,,,Sprity,Sprite-indstillinger,Spriteoptionen,,Agordoj de la mov-rastrumoj,Opciones de los «sprites»,,,Options des sprites,,,スプライトオプション,,Sprite-opties,Sprite-alternativer,Opcje Sprite'ów,Opções de sprite,,,Настройки спрайтов,Сприте опције,Alternativ för sprite,Sprite Seçenekleri,Параметри спрайтів, +Coronas,GLPREFMNU_CORONAS,,,,Záře,Coronas,,,Lum-ampoloj,Focos de luz,,,Corons,,,光冠,,Corona's,Koronaer,Korony,,,,Короны,Цоронас,Koronor,Koronalar,Корони, +Appearance,DSPLYMNU_APPEARANCE,,,,Vzhled,Udseende,Spieldarstellung,,Aspekto,Apariencia,,,Apparence,,,アピアランス,,Uiterlijk,Utseende,Wygląd,Aparência,,,Внешность,Изглед,Utseende,Görünüş,Зовнішній вигляд, +Advanced Display Options,DSPLYMNU_ADVANCED,,,,Grafika (pokročilé),Avancerede visningsindstillinger,Erweiterte Anzeigeoptionen,,Altnivelaj ekran-agordoj,Opciones avanzadas de visualización,,,Options d'affichage avancées,,,高度なディスプレイオプション,,Geavanceerde Weergave Opties,Avanserte visningsalternativer,Zaawansowane Opcje Wyświetlania,Opções de vídeo avançadas,,,Расширенные настройки экрана,Напредне опције приказа,Avancerade visningsalternativ,Gelişmiş Görüntüleme Seçenekleri,Додаткові параметри відображення, +Select which game file to run.,PICKER_SELECT,,,,,"Vælg, hvilket spil du vil spille",Bitte wähle ein Spiel aus.,,,,,,Sélectionner le jeu à jouer,,,,,Selecteer welk spel je wilt spelen,Velg hvilket spill du vil spille,,Selecione o arquivo de jogo para rodar.,,,Выбор файла игры для запуска.,Изаберите коју датотеку игре желите да покренете.,Välj vilket spel du vill spela,Hangi oyunu oynayacağınızı seçin,, +Play Game,PICKER_PLAY,,,,,Start spil,Spielen,,,,,,Démarrer le jeu,,,,,Spel starten,Start spill,,Jogar,,,Играть,Играј игру,Starta spel,Oyunu Başlat,, +Exit,PICKER_EXIT,,,,,Afslut,Verlassen,,,,,,Quitter,,,,,Verlaten,Avslutt,,Sair,,,Выход,Изађи,Avsluta,Çıkış,, +General,PICKER_GENERAL,,,,,Generelt,Allgemein,,,,,,Général,,,,,Algemeen,Generelt,,Geral,,,Общее,Генерал,Allmänt,Genel,, +Extra Graphics,PICKER_EXTRA,,,,,Ekstra grafik,Extragrafiken,,,,,,Graphiques supplémentaires,,,,,Extra afbeeldingen,Ekstra grafikk,,Gráficos extra,,,Доп. графика,Ектра Грапхицс,Extra grafik,Ekstra Grafikler,, +Fullscreen,PICKER_FULLSCREEN,,,,,Fuld skærm,Vollbild,,,,,,Plein écran,,,,,Volledig scherm,Fullskjerm,,Tela cheia,,,Полный экран,Цео екран,Fullskärm,Tam Ekran,, +Disable autoload,PICKER_NOAUTOLOAD,,,,,Deaktiver autoload,Autoload deaktivieren,,,,,,Désactiver le chargement automatique,,,,,Autoload uitschakelen,Deaktiver autolading,,Desativar autocarregamento,,,Отключить автозагрузку,Онемогући аутоматско учитавање,Inaktivera autoload,Otomatik yükleme yok,, +Don't ask me again,PICKER_DONTASK,,,,,Spørg mig ikke igen,Nicht nochmal fragen,,,,,,Ne me demandez plus rien,,,,,Vraag me niet opnieuw,Ikke spør meg igjen,,Não me pergunte de novo,,,Не спрашивать снова,Не питај ме поново,Fråga mig inte igen,Bir daha sorma.,, +Lights,PICKER_LIGHTS,,,,,Lys,Lichtdefinitionen,,,,,,Lumières,,,,,Verlichting,Lysdefinisjoner,,Luzes,,,Освещение,Светла,Definitioner av ljus,Işık tanımları,, +Brightmaps,PICKER_BRIGHTMAPS,,,,,,,,,,,,Cartes lumineuses,,,,,Heldermaps,Lyskart,,,,,Карты освещения,Бригхтмапс,Ljuskartor,Brightmaps,, +Widescreen,PICKER_WIDESCREEN,,,,,,Breitbildunterstützung,,,,,,Écran large,,,,,Breedbeeld,Bredskjerm,,,,,Широкий экран,Широки екран,Bredbildsskärm,Geniş Ekran,, +Additional Parameters:,PICKER_ADDPARM,,,,,Yderligere parametre:,Zusätzliche Parameter,,,,,,Paramètres supplémentaires :,,,,,Extra parameters:,Ytterligere parametere:,,Parâmetros adicionais:,,,Доп. параметры:,Додатни параметри:,Ytterligare parametrar:,Ek Parametreler:,, +Welcome to %s!,PICKER_WELCOME,,,,,Velkommen til %s!,Willkommen bei %s!,,,,,,Bienvenue à %s !,,,,,Welkom bij %s!,Velkommen til %s!,,Boas vindas ao %s!,,,Добро пожаловать в %s!,Добродошли у %s!,Välkommen till %s!,S'ye hoş geldiniz!,, +Version %s,PICKER_VERSION,,,,,,,,,,,,,,,,,Versie %s,Versjon %s,,Versão %s,,,Версия %s,Верзија %s,,Sürüm %s,, +Rendering API,PICKER_PREFERBACKEND,,,,API vykreslování,,Render API,,Preferita bildigado de API,API de renderizado,,Renderöinti API,API de rendu,Renderelő API,API di rendering,優先レンダリングAPI,기본적인 API 랜더링,,,API renderowania,API de renderização,,API Video Preferat,API для рендеринга,АПИ приказивања,API för rendering,,API для візуалізації, +Game,PICKER_TAB_PLAY,,,,Hra,Spil,Spiel,,Ludo,Juego,,Peli,Jeu,Játék,Gioco,ゲーム,게임,Spel,Spill,Gra,Jogo,,Joc,Игра,Игра,Spel,Oyun,Гра, \ No newline at end of file diff --git a/wadsrc/static/language.csv b/wadsrc/static/language.csv index d20f814c3..fcefad347 100644 --- a/wadsrc/static/language.csv +++ b/wadsrc/static/language.csv @@ -1856,7 +1856,7 @@ zorcher.",Получена батарея фазерного зорчера.,П Picked up a large zorcher recharge.,GOTLARGEZORCHERRECHARGE,,,,Sebrán náboj pro velký bzukr.,Afhentede en stor zorcher-opladning.,Du hast eine Zorcher-Ladung genommen.,,Prenis grandzorĉilo-reŝargon.,Recogiste una gran recarga de zorch.,,Poimit ison zorcherin latauksen,Vous avez pris une recharge pour zorcheur large.,Felvettél egy Nagy Zorker Újratöltőt,Raccolta una ricarica per zorcher grande.,ラージ ゾーチャーリチャージ をひろった。,대형 저치 카트리지 획득.,Je hebt een zorcherlading opgepakt.,Plukket opp en stor zorcher-opplading.,Zebrano ładunek do dużego zorchera.,Pegou recarga para zorcher grande.,Apanhaste recarga para o zorcher grande.,Ai ridicat o încărcătură mare pentru zorcher.,Получена зарядка большого зорчера.,Покупио си велики зорчер пуњач.,Plockade upp en stor zorcher-uppladdning.,Büyük bir zorcher şarjı aldım.,Взято заряд великого Зорчера. Picked up a large zorcher pack.,GOTLARGEZORCHERPACK,,,,Sebrán balík pro velký bzukr.,Afhentede en stor zorcher-pakke.,Du hast ein Zorcher-Ladepaket genommen.,,Prenis grandegzorĉilo-reŝargon.,Recogiste un gran paquete de zorch.,,Poimit ison zorcherin paketin.,Vous avez pris un pack de recharges pour zorcheur large.,Felvettél egy Nagy Zorker Csomagot,Raccolta una scatola per zorcher grande.,ラージ ゾーチャーパック をひろった。,저치 카트리지 묶음 획득.,Je hebt een pakket met zorcherladingen opgepakt.,Plukket opp en stor zorcherpakke.,Zebrano paczkę dużego zorchera.,Pegou um pacote de recargas para zorcher grande.,Apanhaste um pacote de recargas para o zocher grande.,Ai ridicat un pachet mare de încărcături pentru zorcher.,Получена батарея большого зорчера.,Покупио си велики зорчер пакет.,Plockade upp ett stort zorcherpaket.,Büyük bir zorcher paketi aldı.,Взято батарею великого Зорчера. Picked up a Zorchpak!,GOTZORCHPACK,,,,Sebrán Bzukrbatoh!,Afhentede en Zorchpak!,Du hast ein Zorchpaket genommen.,,Prenis Zorĉpakon!,¡Recogiste un Zorchpak!,,Poimit zorchpakin!,Vous avez pris un zorchpak!,Felvettél egy Zorkpakkot!,Raccolto uno ZorchZaino!,ゾーチパックをてにいれた!,저치 팩 획득!,Je hebt en zorchpak opgepakt.,Plukket opp en Zorchpak!,Zebrano Paczkę Zorch.,Pegou um Zorchpak!,Apanhaste um Zorchpak!,Ai ridicat un Ghiozdan Zorch!,Получен зорч-рюкзак!,Покупио си зорчпак.,Jag hämtade en Zorchpak!,Bir Zorchpak aldım!,Взято Зорч-сумку! -You got the LAZ Device! Woot!,GOTLAZDEVICE,,,,Získal@[ao_cs] jsi velkodosahový bzukr! Cooo?,Du fik LAZ-enheden! Woot!,Du hast den Flächenzorcher!,,Vi prenis la LAZ-aparaton! Hura!,¡Tienes el dispositivo LAZ! ¡Yuju!,,Sait SAZ-laitteen! Juhuu!,Vous avez pris l'Outil ZZL! Wahou!,Felvetted a LAZ Készüléket! Wáó!,Hai trovato il dispositivo LAZ! Cavolo!,LAZ デバイスをてにいれた! ワァオ!,LAZ 장치 습득! 완전 짱인걸!,Je hebt het LAZ-apparaat! Woot!,Du har LAZ-enheten! Woot!,Zdobył@[irreg_3_pl] urządzenie LAZ! Juhu!,Você achou o Dispositivo LAZ! Oba!,Apanhaste um Dispositivo LAZ! Fixe!,Ai ridicat un Dispozitiv LAZ! Uraa!,Получено устройство зорчирования большого радиуса! Ура!,Добио си ЛАЗ уређај. ВУТ!,Du fick LAZ-enheten! Woot!,LAZ cihazını aldın! Woot!, +You got the LAZ Device! Woot!,GOTLAZDEVICE,,,,Získal@[ao_cs] jsi velkodosahový bzukr! Cooo?,Du fik LAZ-enheden! Woot!,Du hast den Flächenzorcher!,,Vi prenis la LAZ-aparaton! Hura!,¡Tienes el dispositivo LAZ! ¡Yuju!,,Sait SAZ-laitteen! Juhuu!,Vous avez pris l'Outil ZZL! Wahou!,Felvetted a LAZ Készüléket! Wáó!,Hai trovato il dispositivo LAZ! Cavolo!,LAZ デバイスをてにいれた! ワァオ!,LAZ 장치 습득! 완전 짱인걸!,Je hebt het LAZ-apparaat! Woot!,Du har LAZ-enheten! Woot!,Zdobył@[irreg_3_pl] urządzenie LAZ! Juhu!,Você achou o Dispositivo LAZ! Oba!,Apanhaste um Dispositivo LAZ! Fixe!,Ai ridicat un Dispozitiv LAZ! Uraa!,Получено устройство зорчирования большого радиуса! Ура!,Добио си ЛАЗ уређај. ВУТ!,Du fick LAZ-enheten! Woot!,LAZ cihazını aldın! Woot!,Ти отримав пристрій LAZ! Супер! You got the Rapid Zorcher!,GOTRAPIDZORCHER,,,,Získal@[ao_cs] jsi rychlobzukr!,Du fik en Rapid Zorcher!,Du hast den schnellen Zorcher genommen!,,Vi prenis la Rapidzorĉilon!,¡Tienes el Zorcher Rápido!,,Sait pikazorcherin!,Vous avez pris le Zorcheur Rapide!,Felvetted a Gyors Zorkert!,Hai trovato il zorcher rapido!,ラピッドゾーチャー をてにいれた!,속사 자쳐 습득!,Je hebt de snelle Zorcher!,Du har Rapid Zorcher!,Zdobył@[irreg_3_pl] Szybkostrzelny Zorcher!,Você pegou o Zorcher Automático!,Apanhaste o Zorcher Automático!,Ai ridicat un Zorcher cu Foc Rapid!,Получен скорострельный зорчер!,Добио си рапидан зорчер!,Du fick den snabba Zorcher!,Hızlı Zorcher'ı aldın!, You got the Super Bootspork!,GOTSUPERBOOTSPORK,,,,Získal@[ao_cs] jsi super botovidličku!,Du fik Super Bootspork!,Du hast den Super-Gabelquirl genommen!,,Vi prenis la Superan Ŝargmanĝilaron!,¡Tienes el Súper Cuchador!,,Sait superluhan!,Vous avez pris la Super Fourchette!,Felvetted a Szuper Rotációs Villát!,Hai trovato il super bootspork!,スーパーさきわれスプーン をてにいれた!,부트스포크 습득!,Je hebt de Super Bootspork!,Du har Super Bootspork!,Zdobył@[irreg_3_pl] Super Łyżkowidelec!,Você pegou o Super Garfo!,Apanhaste o Super Garfo-Colher!,Ai ridicat o Super Lingură!,Получена суперложковилка!,Добио си супер чизмо-порк!,Du fick Super Bootspork!,Süper Bootspork'u aldın!, You got the Zorch Propulsor!,GOTZORCHPROPULSOR,,,,Získal@[ao_cs] jsi bzukový propulsor!,Du fik Zorch-propulsoren!,Du hast den Propellerzorcher genommen!,,Vi prenis la Zorĉpropulsilon!,¡Tienes el Propulsor de Zorch!,,Sait zorchtyöntimen!,Vous avez pris le Propulseur Zorch!,Felvetted a Zork Elhárítót!,Hai trovato il propulsore zorch!,ロケット ゾーチャー をてにいれた!,저치 추진기 습득!,Je hebt de Zorch Propulsor!,Du fikk Zorch Propulsor!,Zdobył@[irreg_3_pl] Pędnik Zorch!,Você pegou o Propulsor de Zorch!,Apanhaste o Propulsor de Zorch!,Ai ridicat un Accelerator Zorch!,Получен ускоритель хорча!,Добио си зорч погон!,Du fick Zorch Propulsor!,Zorch Propulsor'u aldın!, @@ -3344,9 +3344,11 @@ Show time widget,ALTHUDMNU_SHOWTIMESTAT,,,,Zobrazit widget s časem,Vis tid widg MBF21,OPTVAL_MBF21,,,,,,,,,,,,,,,,,,,,,,,,,,, Crushed monsters get resurrected as ghosts,CMPTMNU_VILEGHOSTS,,,,Oživovat rozdrcené příšery jako duchy,Knuste monstre genopstår som spøgelser,Zermalmte Monster werden als Geister wiedererweckt,Συνθλιμένα τέρατα αναστήνοντε ως φαντάσματα,Dispremitaj monstroj reviviĝas kiel fantomojn,Los monstruos aplastados son resucitados como fantasmas,,Murskatut hirviöt heräävät henkiin aaveina...,Les monstres écrasés ressuscitent en fantômes,Összenyomott szörnyek szellemként születnek újra,Mostri schiacciati vengono resuscitati come fantasmi,圧死した敵が蘇生でゴースト化,분쇄된 몬스터는 유령으로 부활합니다.,Verpletterde monsters worden herrezen als geesten,Knuste monstre gjenoppstår som spøkelser,Zmiażdżone potwory wskrzeszone jako duchy,Monstros esmagados ressucitam como fantasmas,,Monștrii striviți sunt readuși la viață ca fantome.,Раздавленные монстры воскресают в виде призраков,Сломљена чудовишта васкрсавају као духови,Krossade monster återuppstår som spöken.,Ezilmiş canavarlar hayalet olarak dirilir, View bobbing while flying,MISCMNU_FVIEWBOB,,,,Pohupování pohledu při létání,Vis bobbing mens du flyver,Waffenpendeln beim Fliegen,,Vidi kapo-balanciĝon dum flugado,La vista tambalea al volar,,,Chaloupage en vol,Nézet repüléskori billegése,,飛行中の視点揺れ,비행 중 흔들림 보기,Bekijk bob bedrag terwijl je vliegt,Se bobbing mens du flyr,Pokaż bujanie podczas lotu,Balanço na visão durante voo,,Mișcare cameră în timpul zborului,Покачивание камеры при полёте,Погледајте скакање током лета,Visa att det guppar när du flyger,Uçarken sallanmayı görüntüle, -%o was maimed by a Serpent.,OB_DEMON1HIT,,,,%o byl@[ao_cs] zmrzačen@[ao_cs] zlohadem.,%o blev lemlæstet af en slange.,%o wurde von einer Schlange zerfleischt.,,%o vundegiĝis de Serpento.,,,,%o a été mutilé@[e_fr] par un Serpent.,,,,,%o werd verminkt door een slang.,%o ble lemlestet av en slange.,Wąż skaleczył gracza %o,%o foi mutilad@[ao_ptb] por uma Serpente.,,,Игрок %o искалечен змеем.,,%o blev lemlästad av en orm.,"%o, bir yılan tarafından sakat bırakıldı.", -Antialias Lines,AUTOMAPMNU_LINEANTIALIASING,,,,Vyhlazovat čáry,,Linien glätten,,Glatigaj Linioj,,,,,,,,,,,Linie Antyaliasowe,Linhas com antiserrilhamento,,,Линии сглаживания,,,, -Move and shoot through other players,GMPLYMNU_NOPLAYERCLIP ,,,,,,Keine Kollisionen mit anderen Spielern,,,,,,,,,,,,,Brak kolizji z innymi graczami,Mover e atirar através de outros jogadores,,,Перемещение и стрельба через игроков,,,, -Share keys with all players,GMPLYMNU_SHAREKEYS,,,,,,Schlüssel mit allen Spielern teilen,,,,,,,,,,,,,Współdziel klucze z innymi graczami,Compartilhar chaves com todos os jogadores,,,Общие ключи игроков,,,, -Disallow override of camera facing mode,GLPREFMNU_SPRBILLFACECAMERAFORCE,,,,,,,,,,,,,,,,,,,Zabroń nadpisywania trybu widoku,Forçar modo de alinhamento do sprite à câmera,,,Запретить переопределение режима поворота камеры,,,, -Swap health and armor,ALTHUDMNU_SWAPHEALTHARMOR,,,,,,Anzeige für Gesundheit und Panzerung tauschen,,,,,,,,,,,,,Zamień zdrowie i pancerz,,,,Поменять отображение здоровья и брони местами,,,, \ No newline at end of file +%o was maimed by a Serpent.,OB_DEMON1HIT,,,,%o byl@[ao_cs] zmrzačen@[ao_cs] zlohadem.,%o blev lemlæstet af en slange.,%o wurde von einer Schlange zerfleischt.,,%o vundegiĝis de Serpento.,,,,%o a été mutilé@[e_fr] par un Serpent.,,%o è stato mutilato da un serpente.,,,%o werd verminkt door een slang.,%o ble lemlestet av en slange.,Wąż skaleczył gracza %o,%o foi mutilad@[ao_ptb] por uma Serpente.,,,Игрок %o искалечен змеем.,,%o blev lemlästad av en orm.,"%o, bir yılan tarafından sakat bırakıldı.", +Antialias Lines,AUTOMAPMNU_LINEANTIALIASING,,,,Vyhlazovat čáry,Antialias-linjer,Linien glätten,,Glatigaj Linioj,,,,Lignes Antialias,,,,,Antialijnen,Antialias-linjer,Linie Antyaliasowe,Linhas com antiserrilhamento,,,Линии сглаживания,,Antialias Linjer,Antialias Hatları, +Move and shoot through other players,GMPLYMNU_NOPLAYERCLIP ,,,,,Bevæg dig og skyd gennem andre spillere,Keine Kollisionen mit anderen Spielern,,,,,,Déplacez-vous et tirez à travers les autres joueurs,,Muoversi e sparare attraverso gli altri giocatori,,,Beweeg en schiet door andere spelers,Beveg deg og skyt gjennom andre spillere,Brak kolizji z innymi graczami,Mover e atirar através de outros jogadores,,,Перемещение и стрельба через игроков,,Förflytta dig och skjut genom andra spelare,Diğer oyuncuların arasından geçin ve ateş edin, +Share keys with all players,GMPLYMNU_SHAREKEYS,,,,,Del nøgler med alle spillere,Schlüssel mit allen Spielern teilen,,,,,,Partager les clés avec tous les joueurs,,Condividere i tasti con tutti i giocatori,,,Deel toetsen met alle spelers,Del nøkler med alle spillere,Współdziel klucze z innymi graczami,Compartilhar chaves com todos os jogadores,,,Общие ключи игроков,,Dela nycklar med alla spelare,Anahtarları tüm oyuncularla paylaşın, +Disallow override of camera facing mode,GLPREFMNU_SPRBILLFACECAMERAFORCE,,,,,Tillad ikke tilsidesættelse af kameravendt tilstand,Änderung des Kameramodus nicht erlauben,,,,,,Interdiction de modifier le mode d'orientation de la caméra,,Disconoscimento della modalità telecamera,,,Overschrijven van camerastand verbieden,Tillat ikke overstyring av kameramodus,Zabroń nadpisywania trybu widoku,Forçar modo de alinhamento do sprite à câmera,,,Запретить переопределение режима поворота камеры,,Tillåt inte åsidosättande av kamerans vändläge,Kameraya bakma modunun geçersiz kılınmasına izin verme, +Swap health and armor,ALTHUDMNU_SWAPHEALTHARMOR,,,,,Byt om på helbred og rustning,Anzeige für Gesundheit und Panzerung tauschen,,,,,,Échanger la santé et l'armure,,Scambio di salute e armatura,,,Verwissel gezondheid en pantser,Bytt helse og rustning,Zamień zdrowie i pancerz,Trocar saúde e armadura,,,Поменять отображение здоровья и брони местами,,Byt hälsa och rustning,Sağlık ve zırhı değiştir, +Use classic HUD scaling,SCALEMNU_HUD_OLDSCALE,hud_oldscale,,,,Brug klassisk HUD-skalering,Klassische HUD-Skalierung,,,,,,Utiliser l'échelle classique du HUD,,Utilizzare la scalatura classica dell'HUD,,,Gebruik klassieke HUD-schaling,Bruk klassisk HUD-skalering,,Usar escala clássica do HUD,,,Классическое масштабирование интерфейса,,Använd klassisk HUD-skalning,Klasik HUD ölçeklendirmesini kullanın, +HUD scale factor,SCALEMNU_HUD_SCALEFACTOR,hud_scalefactor,,,,HUD-skaleringsfaktor,HUD-Skalierungsfaktor,,,,,,Facteur d'échelle du HUD,,Fattore di scala dell'HUD,,,HUD-schaalfactor,HUD-skaleringsfaktor,,Fator de escala do HUD,,,Значение масштабирования интерфейса,,Skalningsfaktor för HUD,HUD ölçek faktörü, \ No newline at end of file From d789676b26da43d1a67acdaadb498c6e79e52241 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Fri, 12 Jan 2024 09:23:10 -0600 Subject: [PATCH 10/16] Fixed music unpausing when alt-tabbing back. --- src/common/audio/sound/s_sound.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/common/audio/sound/s_sound.cpp b/src/common/audio/sound/s_sound.cpp index 6f53e663e..f2195f890 100644 --- a/src/common/audio/sound/s_sound.cpp +++ b/src/common/audio/sound/s_sound.cpp @@ -1826,7 +1826,8 @@ void S_SetSoundPaused(int state) if ((state || i_soundinbackground) && !pauseext) { - S_ResumeSound(true); + if (!paused) + S_ResumeSound(true); if (GSnd != nullptr) { GSnd->SetInactive(SoundRenderer::INACTIVE_Active); From 98e6330eaac751b0cf648f13f18c7ee0383e335c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Lu=C3=ADs=20Vaz=20Silva?= Date: Fri, 5 Jan 2024 09:46:15 -0300 Subject: [PATCH 11/16] allow modeldef flags to be overriden --- src/common/models/model.h | 5 ++ src/common/models/modelrenderer.h | 8 +-- src/playsim/actor.h | 5 +- src/playsim/p_actionfunctions.cpp | 70 +++++++++++++++++-- src/r_data/models.cpp | 59 ++++++++++------ src/rendering/hwrenderer/hw_models.cpp | 16 ++--- src/rendering/hwrenderer/hw_models.h | 8 +-- .../hwrenderer/scene/hw_drawstructs.h | 1 + src/rendering/hwrenderer/scene/hw_sprites.cpp | 3 +- wadsrc/static/zscript/actors/actor.zs | 4 ++ wadsrc/static/zscript/constants.zs | 23 ++++++ 11 files changed, 156 insertions(+), 46 deletions(-) diff --git a/src/common/models/model.h b/src/common/models/model.h index 84adab556..f5bbf43db 100644 --- a/src/common/models/model.h +++ b/src/common/models/model.h @@ -41,7 +41,9 @@ struct FSpriteModelFrame float xrotate, yrotate, zrotate; float rotationCenterX, rotationCenterY, rotationCenterZ; float rotationSpeed; +private: unsigned int flags; +public: const void* type; // used for hashing, must point to something usable as identifier for the model's owner. short sprite; short frame; @@ -50,6 +52,9 @@ struct FSpriteModelFrame // added pithoffset, rolloffset. float pitchoffset, rolloffset; // I don't want to bother with type transformations, so I made this variables float. bool isVoxel; + unsigned int getFlags(class DActorModelData * defs) const; + friend void InitModels(); + friend void ParseModelDefLump(int Lump); }; diff --git a/src/common/models/modelrenderer.h b/src/common/models/modelrenderer.h index 3a8388e72..d2d774eab 100644 --- a/src/common/models/modelrenderer.h +++ b/src/common/models/modelrenderer.h @@ -10,15 +10,15 @@ public: virtual ModelRendererType GetType() const = 0; - virtual void BeginDrawModel(FRenderStyle style, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix, bool mirrored) = 0; - virtual void EndDrawModel(FRenderStyle style, FSpriteModelFrame *smf) = 0; + virtual void BeginDrawModel(FRenderStyle style, int smf_flags, const VSMatrix &objectToWorldMatrix, bool mirrored) = 0; + virtual void EndDrawModel(FRenderStyle style, int smf_flags) = 0; virtual IModelVertexBuffer *CreateVertexBuffer(bool needindex, bool singleframe) = 0; virtual VSMatrix GetViewToWorldMatrix() = 0; - virtual void BeginDrawHUDModel(FRenderStyle style, const VSMatrix &objectToWorldMatrix, bool mirrored, FSpriteModelFrame *smf) = 0; - virtual void EndDrawHUDModel(FRenderStyle style, FSpriteModelFrame *smf) = 0; + virtual void BeginDrawHUDModel(FRenderStyle style, const VSMatrix &objectToWorldMatrix, bool mirrored, int smf_flags) = 0; + virtual void EndDrawHUDModel(FRenderStyle style, int smf_flags) = 0; virtual void SetInterpolation(double interpolation) = 0; virtual void SetMaterial(FGameTexture *skin, bool clampNoFilter, FTranslationID translation) = 0; diff --git a/src/playsim/actor.h b/src/playsim/actor.h index 9c8ca7883..43e8b5b2e 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -719,18 +719,21 @@ struct ModelOverride enum EModelDataFlags { MODELDATA_HADMODEL = 1 << 0, + MODELDATA_OVERRIDE_FLAGS = 1 << 1, }; class DActorModelData : public DObject { DECLARE_CLASS(DActorModelData, DObject); public: - FName modelDef; + PClass * modelDef; TArray models; TArray skinIDs; TArray animationIDs; TArray modelFrameGenerators; int flags; + int overrideFlagsSet; + int overrideFlagsClear; AnimOverride curAnim; AnimOverride prevAnim; // used for interpolation when switching anims diff --git a/src/playsim/p_actionfunctions.cpp b/src/playsim/p_actionfunctions.cpp index 687543712..4c842d3bb 100644 --- a/src/playsim/p_actionfunctions.cpp +++ b/src/playsim/p_actionfunctions.cpp @@ -5096,7 +5096,7 @@ static void EnsureModelData(AActor * mobj) auto ptr = Create(); ptr->flags = (mobj->hasmodel ? MODELDATA_HADMODEL : 0); - ptr->modelDef = NAME_None; + ptr->modelDef = nullptr; mobj->modelData = ptr; mobj->hasmodel = true; @@ -5111,7 +5111,8 @@ static void CleanupModelData(AActor * mobj) && mobj->modelData->modelFrameGenerators.Size() == 0 && mobj->modelData->skinIDs.Size() == 0 && mobj->modelData->animationIDs.Size() == 0 - && mobj->modelData->modelDef == NAME_None) + && mobj->modelData->modelDef == nullptr + &&(mobj->modelData->flags & ~MODELDATA_HADMODEL) == 0 ) { mobj->hasmodel = mobj->modelData->flags & MODELDATA_HADMODEL; mobj->modelData->Destroy(); @@ -5123,6 +5124,8 @@ enum ESetAnimationFlags { SAF_INSTANT = 1 << 0, SAF_LOOP = 1 << 1, + SAF_USEACTORROLL = 1 << 2, + SAF_USEACTORPITCH = 1 << 3, }; void SetAnimationInternal(AActor * self, FName animName, double framerate, int startFrame, int loopFrame, int interpolateTics, int flags, double ticFrac) @@ -5265,6 +5268,32 @@ void SetAnimationFrameRateUINative(AActor * self, double framerate) SetAnimationFrameRateInternal(self, framerate, I_GetTimeFrac()); } +void SetModelFlag(AActor * self, int flag) +{ + EnsureModelData(self); + self->modelData->flags |= MODELDATA_OVERRIDE_FLAGS; + self->modelData->overrideFlagsSet |= flag; + self->modelData->overrideFlagsClear &= ~flag; +} + +void ClearModelFlag(AActor * self, int flag) +{ + EnsureModelData(self); + self->modelData->flags |= MODELDATA_OVERRIDE_FLAGS; + self->modelData->overrideFlagsClear |= flag; + self->modelData->overrideFlagsSet &= ~flag; +} + +void ResetModelFlags(AActor * self) +{ + if(self->modelData) + { + self->modelData->overrideFlagsClear = 0; + self->modelData->overrideFlagsSet = 0; + self->modelData->flags &= ~MODELDATA_OVERRIDE_FLAGS; + } +} + enum ChangeModelFlags { CMDL_WEAPONTOPLAYER = 1 << 0, @@ -5291,14 +5320,16 @@ void ChangeModelNative( ) { if(!self) ThrowAbortException(X_READ_NIL, "In function parameter self"); - FName modeldef { ENamedName(i_modeldef) }; + FName n_modeldef { ENamedName(i_modeldef) }; FName model { ENamedName(i_model) }; FName skin { ENamedName(i_skin) }; FName animation { ENamedName(i_animation) }; - if (modeldef != NAME_None && PClass::FindClass(modeldef.GetChars()) == nullptr) + PClass * modeldef = nullptr; + + if (n_modeldef != NAME_None && (modeldef = PClass::FindActor(n_modeldef.GetChars())) == nullptr) { - Printf("Attempt to pass invalid modeldef name %s in %s.", modeldef.GetChars(), self->GetCharacterName()); + Printf("Attempt to pass invalid modeldef name %s in %s.", n_modeldef.GetChars(), self->GetCharacterName()); return; } @@ -5533,6 +5564,35 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetAnimationFrameRateUI, SetAnimationFrame return 0; } +DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetModelFlag, SetModelFlag) +{ + PARAM_ACTION_PROLOGUE(AActor); + PARAM_INT(flag); + + SetModelFlag(self, flag); + + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, ClearModelFlag, ClearModelFlag) +{ + PARAM_ACTION_PROLOGUE(AActor); + PARAM_INT(flag); + + ClearModelFlag(self, flag); + + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, ResetModelFlags, ResetModelFlags) +{ + PARAM_ACTION_PROLOGUE(AActor); + + ResetModelFlags(self); + + return 0; +} + // This needs to account for the fact that internally renderstyles are stored as a series of operations, // but the script side only cares about symbolic constants. DEFINE_ACTION_FUNCTION(AActor, GetRenderStyle) diff --git a/src/r_data/models.cpp b/src/r_data/models.cpp index 0cfb14b0a..3cca0791c 100644 --- a/src/r_data/models.cpp +++ b/src/r_data/models.cpp @@ -63,8 +63,10 @@ void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteMod { // Setup transformation. + int smf_flags = smf->getFlags(actor->modelData); + FTranslationID translation = NO_TRANSLATION; - if (!(smf->flags & MDL_IGNORETRANSLATION)) + if (!(smf_flags & MDL_IGNORETRANSLATION)) translation = actor->Translation; // y scale for a sprite means height, i.e. z in the world! @@ -82,7 +84,7 @@ void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteMod float angle = angles.Yaw.Degrees(); // [BB] Workaround for the missing pitch information. - if ((smf->flags & MDL_PITCHFROMMOMENTUM)) + if ((smf_flags & MDL_PITCHFROMMOMENTUM)) { const double x = actor->Vel.X; const double y = actor->Vel.Y; @@ -102,7 +104,7 @@ void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteMod } } - if (smf->flags & MDL_ROTATING) + if (smf_flags & MDL_ROTATING) { if (smf->rotationSpeed > 0.0000000001 || smf->rotationSpeed < -0.0000000001) { @@ -118,13 +120,13 @@ void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteMod // Added MDL_USEACTORPITCH and MDL_USEACTORROLL flags processing. // If both flags MDL_USEACTORPITCH and MDL_PITCHFROMMOMENTUM are set, the pitch sums up the actor pitch and the velocity vector pitch. - if (smf->flags & MDL_USEACTORPITCH) + if (smf_flags & MDL_USEACTORPITCH) { double d = angles.Pitch.Degrees(); - if (smf->flags & MDL_BADROTATION) pitch += d; + if (smf_flags & MDL_BADROTATION) pitch += d; else pitch -= d; } - if (smf->flags & MDL_USEACTORROLL) roll += angles.Roll.Degrees(); + if (smf_flags & MDL_USEACTORROLL) roll += angles.Roll.Degrees(); VSMatrix objectToWorldMatrix; objectToWorldMatrix.loadIdentity(); @@ -140,7 +142,7 @@ void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteMod // [MK] distortions might happen depending on when the pixel stretch is compensated for // so we make the "undistorted" behavior opt-in - if (smf->flags & MDL_CORRECTPIXELSTRETCH) + if (smf_flags & MDL_CORRECTPIXELSTRETCH) { stretch = (smf->modelIDs[0] != -1 ? Models[smf->modelIDs[0]]->getAspectFactor(actor->Level->info->pixelstretch) : 1.f) / actor->Level->info->pixelstretch; objectToWorldMatrix.scale(1, stretch, 1); @@ -148,14 +150,14 @@ void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteMod // Applying model transformations: // 1) Applying actor angle, pitch and roll to the model - if (smf->flags & MDL_USEROTATIONCENTER) + if (smf_flags & MDL_USEROTATIONCENTER) { objectToWorldMatrix.translate(smf->rotationCenterX, smf->rotationCenterZ/stretch, smf->rotationCenterY); } objectToWorldMatrix.rotate(-angle, 0, 1, 0); objectToWorldMatrix.rotate(pitch, 0, 0, 1); objectToWorldMatrix.rotate(-roll, 1, 0, 0); - if (smf->flags & MDL_USEROTATIONCENTER) + if (smf_flags & MDL_USEROTATIONCENTER) { objectToWorldMatrix.translate(-smf->rotationCenterX, -smf->rotationCenterZ/stretch, -smf->rotationCenterY); } @@ -163,7 +165,7 @@ void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteMod // 2) Applying Doomsday like rotation of the weapon pickup models // The rotation angle is based on the elapsed time. - if (smf->flags & MDL_ROTATING) + if (smf_flags & MDL_ROTATING) { objectToWorldMatrix.translate(smf->rotationCenterX, smf->rotationCenterY/stretch, smf->rotationCenterZ); objectToWorldMatrix.rotate(rotateOffset, smf->xrotate, smf->yrotate, smf->zrotate); @@ -181,7 +183,7 @@ void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteMod objectToWorldMatrix.rotate(smf->pitchoffset, 0, 0, 1); objectToWorldMatrix.rotate(-smf->rolloffset, 1, 0, 0); - if (!(smf->flags & MDL_CORRECTPIXELSTRETCH)) + if (!(smf_flags & MDL_CORRECTPIXELSTRETCH)) { stretch = (smf->modelIDs[0] != -1 ? Models[smf->modelIDs[0]]->getAspectFactor(actor->Level->info->pixelstretch) : 1.f) / actor->Level->info->pixelstretch; objectToWorldMatrix.scale(1, stretch, 1); @@ -189,15 +191,17 @@ void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteMod float orientation = scaleFactorX * scaleFactorY * scaleFactorZ; - renderer->BeginDrawModel(actor->RenderStyle, smf, objectToWorldMatrix, orientation < 0); + renderer->BeginDrawModel(actor->RenderStyle, smf_flags, objectToWorldMatrix, orientation < 0); RenderFrameModels(renderer, actor->Level, smf, actor->state, actor->tics, translation, actor); - renderer->EndDrawModel(actor->RenderStyle, smf); + renderer->EndDrawModel(actor->RenderStyle, smf_flags); } void RenderHUDModel(FModelRenderer *renderer, DPSprite *psp, FVector3 translation, FVector3 rotation, FVector3 rotation_pivot, FSpriteModelFrame *smf) { AActor * playermo = players[consoleplayer].camera; + int smf_flags = smf->getFlags(psp->Caller->modelData); + // [BB] No model found for this sprite, so we can't render anything. if (smf == nullptr) return; @@ -208,7 +212,7 @@ void RenderHUDModel(FModelRenderer *renderer, DPSprite *psp, FVector3 translatio // [Nash] Optional scale weapon FOV float fovscale = 1.0f; - if (smf->flags & MDL_SCALEWEAPONFOV) + if (smf_flags & MDL_SCALEWEAPONFOV) { fovscale = tan(players[consoleplayer].DesiredFOV * (0.5f * M_PI / 180.f)); fovscale = 1.f + (fovscale - 1.f) * cl_scaleweaponfov; @@ -245,12 +249,12 @@ void RenderHUDModel(FModelRenderer *renderer, DPSprite *psp, FVector3 translatio float orientation = smf->xscale * smf->yscale * smf->zscale; - renderer->BeginDrawHUDModel(playermo->RenderStyle, objectToWorldMatrix, orientation < 0, smf); + renderer->BeginDrawHUDModel(playermo->RenderStyle, objectToWorldMatrix, orientation < 0, smf_flags); auto trans = psp->GetTranslation(); if ((psp->Flags & PSPF_PLAYERTRANSLATED)) trans = psp->Owner->mo->Translation; RenderFrameModels(renderer, playermo->Level, smf, psp->GetState(), psp->GetTics(), trans, psp->Caller); - renderer->EndDrawHUDModel(playermo->RenderStyle, smf); + renderer->EndDrawHUDModel(playermo->RenderStyle, smf_flags); } double getCurrentFrame(const AnimOverride &anim, double tic) @@ -295,6 +299,9 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr { // [BB] Frame interpolation: Find the FSpriteModelFrame smfNext which follows after smf in the animation // and the scalar value inter ( element of [0,1) ), both necessary to determine the interpolated frame. + + int smf_flags = smf->getFlags(actor->modelData); + const FSpriteModelFrame * smfNext = nullptr; double inter = 0.; double inter_main = -1.f; @@ -334,7 +341,7 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr } } } - else if (gl_interpolate_model_frames && !(smf->flags & MDL_NOINTERPOLATION)) + else if (gl_interpolate_model_frames && !(smf_flags & MDL_NOINTERPOLATION)) { FState *nextState = curState->GetNextState(); if (curState != nextState && nextState) @@ -356,7 +363,7 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr { // [BB] Workaround for actors that use the same frame twice in a row. // Most of the standard Doom monsters do this in their see state. - if ((smf->flags & MDL_INTERPOLATEDOUBLEDFRAMES)) + if ((smf_flags & MDL_INTERPOLATEDOUBLEDFRAMES)) { const FState *prevState = curState - 1; if ((curState->sprite == prevState->sprite) && (curState->Frame == prevState->Frame)) @@ -522,7 +529,7 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr } // [RL0] while per-model animations aren't done, DECOUPLEDANIMATIONS does the same as MODELSAREATTACHMENTS - if ((!(smf->flags & MDL_MODELSAREATTACHMENTS) && !is_decoupled) || !evaluatedSingle) + if ((!(smf_flags & MDL_MODELSAREATTACHMENTS) && !is_decoupled) || !evaluatedSingle) { if (animationid >= 0) { @@ -576,7 +583,7 @@ static TArray SpriteModelHash; // //=========================================================================== -static void ParseModelDefLump(int Lump); +void ParseModelDefLump(int Lump); void InitModels() { @@ -658,7 +665,7 @@ void InitModels() } } -static void ParseModelDefLump(int Lump) +void ParseModelDefLump(int Lump) { FScanner sc(Lump); while (sc.GetString()) @@ -1117,11 +1124,11 @@ FSpriteModelFrame * FindModelFrame(const AActor * thing, int sprite, int frame, if(thing->flags9 & MF9_DECOUPLEDANIMATIONS) { - return &BaseSpriteModelFrames[thing->GetClass()]; + return &BaseSpriteModelFrames[(thing->modelData != nullptr && thing->modelData->modelDef != nullptr) ? thing->modelData->modelDef : thing->GetClass()]; } else { - return FindModelFrameRaw((thing->modelData != nullptr && thing->modelData->modelDef != NAME_None) ? PClass::FindActor(thing->modelData->modelDef) : thing->GetClass(), sprite, frame, dropped); + return FindModelFrameRaw((thing->modelData != nullptr && thing->modelData->modelDef != nullptr) ? thing->modelData->modelDef : thing->GetClass(), sprite, frame, dropped); } } @@ -1143,3 +1150,9 @@ bool IsHUDModelForPlayerAvailable (player_t * player) } return false; } + + +unsigned int FSpriteModelFrame::getFlags(class DActorModelData * defs) const +{ + return (defs && defs->flags & MODELDATA_OVERRIDE_FLAGS)? (flags | defs->overrideFlagsSet) & ~(defs->overrideFlagsClear) : flags; +} \ No newline at end of file diff --git a/src/rendering/hwrenderer/hw_models.cpp b/src/rendering/hwrenderer/hw_models.cpp index d383f0777..06ce5942e 100644 --- a/src/rendering/hwrenderer/hw_models.cpp +++ b/src/rendering/hwrenderer/hw_models.cpp @@ -53,7 +53,7 @@ VSMatrix FHWModelRenderer::GetViewToWorldMatrix() return objectToWorldMatrix; } -void FHWModelRenderer::BeginDrawModel(FRenderStyle style, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix, bool mirrored) +void FHWModelRenderer::BeginDrawModel(FRenderStyle style, int smf_flags, const VSMatrix &objectToWorldMatrix, bool mirrored) { state.SetDepthFunc(DF_LEqual); state.EnableTexture(true); @@ -61,7 +61,7 @@ void FHWModelRenderer::BeginDrawModel(FRenderStyle style, FSpriteModelFrame *smf // This solves a few of the problems caused by the lack of depth sorting. // [Nash] Don't do back face culling if explicitly specified in MODELDEF // TO-DO: Implement proper depth sorting. - if ((smf->flags & MDL_FORCECULLBACKFACES) || (!(style == DefaultRenderStyle()) && !(smf->flags & MDL_DONTCULLBACKFACES))) + if ((smf_flags & MDL_FORCECULLBACKFACES) || (!(style == DefaultRenderStyle()) && !(smf_flags & MDL_DONTCULLBACKFACES))) { state.SetCulling((mirrored ^ portalState.isMirrored()) ? Cull_CCW : Cull_CW); } @@ -70,16 +70,16 @@ void FHWModelRenderer::BeginDrawModel(FRenderStyle style, FSpriteModelFrame *smf state.EnableModelMatrix(true); } -void FHWModelRenderer::EndDrawModel(FRenderStyle style, FSpriteModelFrame *smf) +void FHWModelRenderer::EndDrawModel(FRenderStyle style, int smf_flags) { state.SetBoneIndexBase(-1); state.EnableModelMatrix(false); state.SetDepthFunc(DF_Less); - if ((smf->flags & MDL_FORCECULLBACKFACES) || (!(style == DefaultRenderStyle()) && !(smf->flags & MDL_DONTCULLBACKFACES))) + if ((smf_flags & MDL_FORCECULLBACKFACES) || (!(style == DefaultRenderStyle()) && !(smf_flags & MDL_DONTCULLBACKFACES))) state.SetCulling(Cull_None); } -void FHWModelRenderer::BeginDrawHUDModel(FRenderStyle style, const VSMatrix &objectToWorldMatrix, bool mirrored, FSpriteModelFrame *smf) +void FHWModelRenderer::BeginDrawHUDModel(FRenderStyle style, const VSMatrix &objectToWorldMatrix, bool mirrored, int smf_flags) { state.SetDepthFunc(DF_LEqual); state.SetDepthClamp(true); @@ -87,7 +87,7 @@ void FHWModelRenderer::BeginDrawHUDModel(FRenderStyle style, const VSMatrix &obj // [BB] In case the model should be rendered translucent, do back face culling. // This solves a few of the problems caused by the lack of depth sorting. // TO-DO: Implement proper depth sorting. - if (!(style == DefaultRenderStyle()) || (smf->flags & MDL_FORCECULLBACKFACES)) + if (!(style == DefaultRenderStyle()) || (smf_flags & MDL_FORCECULLBACKFACES)) { state.SetCulling((mirrored ^ portalState.isMirrored()) ? Cull_CW : Cull_CCW); } @@ -96,13 +96,13 @@ void FHWModelRenderer::BeginDrawHUDModel(FRenderStyle style, const VSMatrix &obj state.EnableModelMatrix(true); } -void FHWModelRenderer::EndDrawHUDModel(FRenderStyle style, FSpriteModelFrame *smf) +void FHWModelRenderer::EndDrawHUDModel(FRenderStyle style, int smf_flags) { state.SetBoneIndexBase(-1); state.EnableModelMatrix(false); state.SetDepthFunc(DF_Less); - if (!(style == DefaultRenderStyle()) || (smf->flags & MDL_FORCECULLBACKFACES)) + if (!(style == DefaultRenderStyle()) || (smf_flags & MDL_FORCECULLBACKFACES)) state.SetCulling(Cull_None); } diff --git a/src/rendering/hwrenderer/hw_models.h b/src/rendering/hwrenderer/hw_models.h index c2c80bd75..c3e5125da 100644 --- a/src/rendering/hwrenderer/hw_models.h +++ b/src/rendering/hwrenderer/hw_models.h @@ -46,12 +46,12 @@ public: FHWModelRenderer(HWDrawInfo *d, FRenderState &st, int mli) : modellightindex(mli), di(d), state(st) {} ModelRendererType GetType() const override { return GLModelRendererType; } - void BeginDrawModel(FRenderStyle style, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix, bool mirrored) override; - void EndDrawModel(FRenderStyle style, FSpriteModelFrame *smf) override; + void BeginDrawModel(FRenderStyle style, int smf_flags, const VSMatrix &objectToWorldMatrix, bool mirrored) override; + void EndDrawModel(FRenderStyle style, int smf_flags) override; IModelVertexBuffer *CreateVertexBuffer(bool needindex, bool singleframe) override; VSMatrix GetViewToWorldMatrix() override; - void BeginDrawHUDModel(FRenderStyle style, const VSMatrix &objectToWorldMatrix, bool mirrored, FSpriteModelFrame *smf) override; - void EndDrawHUDModel(FRenderStyle style, FSpriteModelFrame *smf) override; + void BeginDrawHUDModel(FRenderStyle style, const VSMatrix &objectToWorldMatrix, bool mirrored, int smf_flags) override; + void EndDrawHUDModel(FRenderStyle style, int smf_flags) override; void SetInterpolation(double interpolation) override; void SetMaterial(FGameTexture *skin, bool clampNoFilter, FTranslationID translation) override; void DrawArrays(int start, int count) override; diff --git a/src/rendering/hwrenderer/scene/hw_drawstructs.h b/src/rendering/hwrenderer/scene/hw_drawstructs.h index 04179d250..a025c87c9 100644 --- a/src/rendering/hwrenderer/scene/hw_drawstructs.h +++ b/src/rendering/hwrenderer/scene/hw_drawstructs.h @@ -365,6 +365,7 @@ public: PalEntry ThingColor; // thing's own color FColormap Colormap; FSpriteModelFrame * modelframe; + int modelframeflags; FRenderStyle RenderStyle; int OverrideShader; diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index 472a4f607..8735c0f46 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -507,7 +507,7 @@ bool HWSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp) inline void HWSprite::PutSprite(HWDrawInfo *di, bool translucent) { // That's a lot of checks... - if (modelframe && !modelframe->isVoxel && !(modelframe->flags & MDL_NOPERPIXELLIGHTING) && RenderStyle.BlendOp != STYLEOP_Shadow && gl_light_sprites && di->Level->HasDynamicLights && !di->isFullbrightScene() && !fullbright) + if (modelframe && !modelframe->isVoxel && !(modelframeflags & MDL_NOPERPIXELLIGHTING) && RenderStyle.BlendOp != STYLEOP_Shadow && gl_light_sprites && di->Level->HasDynamicLights && !di->isFullbrightScene() && !fullbright) { hw_GetDynModelLight(actor, lightdata); dynlightindex = screen->mLights->UploadLights(lightdata); @@ -797,6 +797,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t } modelframe = isPicnumOverride ? nullptr : FindModelFrame(thing, spritenum, thing->frame, !!(thing->flags & MF_DROPPED)); + modelframeflags = modelframe ? modelframe->getFlags(thing->modelData) : 0; // Too close to the camera. This doesn't look good if it is a sprite. if (fabs(thingpos.X - vp.Pos.X) < 2 && fabs(thingpos.Y - vp.Pos.Y) < 2 diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index 585554302..a89072066 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -1300,6 +1300,10 @@ class Actor : Thinker native native version("4.12") void SetAnimationFrameRate(double framerate); native version("4.12") ui void SetAnimationFrameRateUI(double framerate); + native version("4.12") void SetModelFlag(int flag); + native version("4.12") void ClearModelFlag(int flag); + native version("4.12") void ResetModelFlags(); + int ACS_NamedExecute(name script, int mapnum=0, int arg1=0, int arg2=0, int arg3=0) { return ACS_Execute(-int(script), mapnum, arg1, arg2, arg3); diff --git a/wadsrc/static/zscript/constants.zs b/wadsrc/static/zscript/constants.zs index 85239ef04..71b0fb99d 100644 --- a/wadsrc/static/zscript/constants.zs +++ b/wadsrc/static/zscript/constants.zs @@ -1470,3 +1470,26 @@ const WATER_SINK_FACTOR = 0.125; const WATER_SINK_SMALL_FACTOR = 0.25; const WATER_SINK_SPEED = 0.5; const WATER_JUMP_SPEED = 3.5; + + +// for SetModelFlag/ClearModelFlag +enum EModelFlags +{ + // [BB] Color translations for the model skin are ignored. This is + // useful if the skin texture is not using the game palette. + MDL_IGNORETRANSLATION = 1<<0, + MDL_PITCHFROMMOMENTUM = 1<<1, + MDL_ROTATING = 1<<2, + MDL_INTERPOLATEDOUBLEDFRAMES = 1<<3, + MDL_NOINTERPOLATION = 1<<4, + MDL_USEACTORPITCH = 1<<5, + MDL_USEACTORROLL = 1<<6, + MDL_BADROTATION = 1<<7, + MDL_DONTCULLBACKFACES = 1<<8, + MDL_USEROTATIONCENTER = 1<<9, + MDL_NOPERPIXELLIGHTING = 1<<10, // forces a model to not use per-pixel lighting. useful for voxel-converted-to-model objects. + MDL_SCALEWEAPONFOV = 1<<11, // scale weapon view model with higher user FOVs + MDL_MODELSAREATTACHMENTS = 1<<12, // any model index after 0 is treated as an attachment, and therefore will use the bone results of index 0 + MDL_CORRECTPIXELSTRETCH = 1<<13, // ensure model does not distort with pixel stretch when pitch/roll is applied + MDL_FORCECULLBACKFACES = 1<<14, +}; \ No newline at end of file From b708e16193dceccd25a25fe4233edafa8f26e17e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Lu=C3=ADs=20Vaz=20Silva?= Date: Fri, 5 Jan 2024 14:34:43 -0300 Subject: [PATCH 12/16] fix serialization --- src/playsim/p_mobj.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index 87c58a071..d3a8eeb34 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -1361,6 +1361,8 @@ void DActorModelData::Serialize(FSerializer& arc) ("animationIDs", animationIDs) ("modelFrameGenerators", modelFrameGenerators) ("flags", flags) + ("overrideFlagsSet", overrideFlagsSet) + ("overrideFlagsClear", overrideFlagsClear) ("curAnim", curAnim) ("prevAnim", prevAnim); } From 79d9217340add28af0c9a7c6565b8bd1be92bff9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Lu=C3=ADs=20Vaz=20Silva?= Date: Fri, 5 Jan 2024 18:17:27 -0300 Subject: [PATCH 13/16] Add action versions of the animation/model methods --- wadsrc/static/zscript/actors/actor.zs | 30 +++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index a89072066..d3395e656 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -1303,6 +1303,36 @@ class Actor : Thinker native native version("4.12") void SetModelFlag(int flag); native version("4.12") void ClearModelFlag(int flag); native version("4.12") void ResetModelFlags(); + + + action version("4.12") void A_SetAnimation(Name animName, double framerate = -1, int startFrame = -1, int loopFrame= -1, int interpolateTics = -1, int flags = 0) + { + invoker.SetAnimation(animName, framerate, startFrame, loopFrame, interpolateTics, flags); + } + + action version("4.12") void A_SetAnimationFrameRate(double framerate) + { + invoker.SetAnimationFrameRate(framerate); + } + + action version("4.12") void A_SetModelFlag(int flag) + { + invoker.SetModelFlag(flag); + } + + action version("4.12") void A_ClearModelFlag(int flag) + { + invoker.ClearModelFlag(flag); + } + + action version("4.12") void A_ResetModelFlags() + { + invoker.ResetModelFlags(); + } + + + + int ACS_NamedExecute(name script, int mapnum=0, int arg1=0, int arg2=0, int arg3=0) { From cfb4e4f105671fb9139f2d8158719b75414bc72a Mon Sep 17 00:00:00 2001 From: Professor Hastig Date: Wed, 17 Jan 2024 12:17:36 +0100 Subject: [PATCH 14/16] fix file names in mounted directories. This used the normalized file name for access which only works on case insensitive file systems and only as long as no character gets mangled by Unicode normalization. --- src/common/filesystem/source/file_directory.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/common/filesystem/source/file_directory.cpp b/src/common/filesystem/source/file_directory.cpp index 2b891b9a6..c2ac8624f 100644 --- a/src/common/filesystem/source/file_directory.cpp +++ b/src/common/filesystem/source/file_directory.cpp @@ -128,9 +128,15 @@ int FDirectory::AddDirectory(const char *dirpath, LumpFilterInfo* filter, FileSy Printf(FSMessageLevel::Warning, "%s is larger than 2GB and will be ignored\n", entry.FilePath.c_str()); continue; } + // for accessing the file we need to retain the original unaltered path. + // On Linux this is important because its file system is case sensitive, + // but even on Windows the Unicode normalization is destructive + // for some characters and cannot be used for file names. + // Examples for this are the Turkish 'i's or the German . + SystemFilePath[count] = stringpool->Strdup(entry.FilePathRel.c_str()); // for internal access we use the normalized form of the relative path. + // this is fine because the paths that get compared against this will also be normalized. Entries[count].FileName = NormalizeFileName(entry.FilePathRel.c_str()); - SystemFilePath[count] = Entries[count].FileName; Entries[count].CompressedSize = Entries[count].Length = entry.Length; Entries[count].Flags = RESFF_FULLPATH; Entries[count].ResourceID = -1; From f9a88f10ed890ed05bfd118e40538a974004b00e Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Wed, 3 Jan 2024 10:16:42 -0500 Subject: [PATCH 15/16] - use correct isHostile checks for target considerations --- src/playsim/p_enemy.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/playsim/p_enemy.cpp b/src/playsim/p_enemy.cpp index 6111a6019..58adfb737 100644 --- a/src/playsim/p_enemy.cpp +++ b/src/playsim/p_enemy.cpp @@ -1823,7 +1823,7 @@ int P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params) if (!(player->mo->flags & MF_SHOOTABLE)) continue; // not shootable (observer or dead) - if (actor->IsFriend(player->mo)) + if (!actor->IsHostile(player->mo)) continue; // same +MF_FRIENDLY, ignore if (player->cheats & CF_NOTARGET) @@ -1917,7 +1917,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look) targ = NULL; } - if (targ && targ->player && ((targ->player->cheats & CF_NOTARGET) || !(targ->flags & MF_FRIENDLY))) + if (targ && targ->player && ((targ->player->cheats & CF_NOTARGET) || !self->IsHostile(targ))) { return 0; } @@ -1931,7 +1931,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look) if (targ && (targ->flags & MF_SHOOTABLE)) { - if (self->IsFriend (targ)) // be a little more precise! + if (!self->IsHostile (targ)) // be a little more precise! { // If we find a valid target here, the wandering logic should *not* // be activated! It would cause the seestate to be set twice. From 1c7f1953536b9e13eb1cd84d2190db9544a44e1c Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Thu, 4 Jan 2024 00:28:43 -0500 Subject: [PATCH 16/16] - reverse y offset for SpriteOffset to be consistent with software renderer and past versions --- src/rendering/hwrenderer/scene/hw_sprites.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index 8735c0f46..6156f1f63 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -427,7 +427,7 @@ bool HWSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp) FQuaternion quat = FQuaternion::FromAngles(FAngle::fromDeg(270) - di->Viewpoint.HWAngles.Yaw, di->Viewpoint.HWAngles.Pitch, FAngle::fromDeg(0)); FVector3 sideVec = quat * FVector3(0, 1, 0); FVector3 upVec = quat * FVector3(0, 0, 1); - FVector3 res = sideVec * -offx + upVec * offy; + FVector3 res = sideVec * -offx + upVec * -offy; mat.Translate(res.X, res.Z, res.Y); }