From 17938cdb7e475d83514cf91b9e20d99f20d3dd39 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Tue, 1 Apr 2025 01:25:08 +0300 Subject: [PATCH 001/330] Make the crosshair smaller --- files/data/mygui/openmw_hud.layout | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/files/data/mygui/openmw_hud.layout b/files/data/mygui/openmw_hud.layout index a189075f44..78b8ff1aed 100644 --- a/files/data/mygui/openmw_hud.layout +++ b/files/data/mygui/openmw_hud.layout @@ -108,8 +108,7 @@ - - + @@ -131,4 +130,4 @@ - \ No newline at end of file + From 0547f09bf09e6e4258b39bd56d189a8ab6458200 Mon Sep 17 00:00:00 2001 From: Kindi Date: Tue, 1 Apr 2025 13:03:11 +0800 Subject: [PATCH 002/330] update container window when item is added or removed --- apps/openmw/mwgui/container.cpp | 6 ++++++ apps/openmw/mwgui/container.hpp | 9 ++++++++- apps/openmw/mwgui/draganddrop.cpp | 2 ++ apps/openmw/mwgui/inventorywindow.cpp | 2 ++ apps/openmw/mwgui/inventorywindow.hpp | 6 +++++- 5 files changed, 23 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 6ab2c862d4..b0c3197519 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -160,6 +160,12 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton); setTitle(container.getClass().getName(container)); + mPtr.getClass().getContainerStore(mPtr).setContListener(this); + } + + void ContainerWindow::updateItemView() + { + mItemView->update(); } void ContainerWindow::resetReference() diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 555fa8e1ae..4898a0eb1c 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -6,6 +6,8 @@ #include "itemmodel.hpp" +#include "../mwworld/containerstore.hpp" + namespace MyGUI { class Gui; @@ -21,7 +23,7 @@ namespace MWGui namespace MWGui { - class ContainerWindow : public WindowBase, public ReferenceInterface + class ContainerWindow : public WindowBase, public ReferenceInterface, public MWWorld::ContainerStoreListener { public: ContainerWindow(DragAndDrop* dragAndDrop); @@ -38,6 +40,11 @@ namespace MWGui void treatNextOpenAsLoot() { mTreatNextOpenAsLoot = true; } + void updateItemView(); + + void itemAdded(const MWWorld::ConstPtr& item, int count) override { updateItemView(); } + void itemRemoved(const MWWorld::ConstPtr& item, int count) override { updateItemView(); } + std::string_view getWindowIdForLua() const override { return "Container"; } private: diff --git a/apps/openmw/mwgui/draganddrop.cpp b/apps/openmw/mwgui/draganddrop.cpp index 0fa2cc4e21..36cfe649d6 100644 --- a/apps/openmw/mwgui/draganddrop.cpp +++ b/apps/openmw/mwgui/draganddrop.cpp @@ -91,6 +91,8 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setDragDrop(true); mIsOnDragAndDrop = true; + + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView(); } void DragAndDrop::drop(ItemModel* targetModel, ItemView* targetView) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index a773b4635b..27dab07d34 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -145,6 +145,8 @@ namespace MWGui auto tradeModel = std::make_unique(std::make_unique(mPtr), MWWorld::Ptr()); mTradeModel = tradeModel.get(); + mPtr.getClass().getInventoryStore(mPtr).setContListener(this); + if (mSortModel) // reuse existing SortModel when possible to keep previous category/filter settings mSortModel->setSourceModel(std::move(tradeModel)); else diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 9fc77ceec5..1dd12aa550 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -5,6 +5,7 @@ #include "windowpinnablebase.hpp" #include "../mwrender/characterpreview.hpp" +#include "../mwworld/containerstore.hpp" #include "../mwworld/ptr.hpp" namespace osg @@ -30,7 +31,7 @@ namespace MWGui class DragAndDrop; class ItemModel; - class InventoryWindow : public WindowPinnableBase + class InventoryWindow : public WindowPinnableBase, public MWWorld::ContainerStoreListener { public: InventoryWindow(DragAndDrop* dragAndDrop, osg::Group* parent, Resource::ResourceSystem* resourceSystem); @@ -62,6 +63,9 @@ namespace MWGui void setGuiMode(GuiMode mode); + void itemAdded(const MWWorld::ConstPtr& item, int count) override { updateItemView(); } + void itemRemoved(const MWWorld::ConstPtr& item, int count) override { updateItemView(); } + /// Cycle to previous/next weapon void cycle(bool next); From 15ceee4b1a35842c80bb683fe7e714604dac3996 Mon Sep 17 00:00:00 2001 From: Kindi Date: Thu, 3 Apr 2025 11:26:56 +0800 Subject: [PATCH 003/330] also update companion window and tradewindow --- apps/openmw/mwgui/companionwindow.cpp | 7 +++++++ apps/openmw/mwgui/companionwindow.hpp | 9 ++++++++- apps/openmw/mwgui/container.cpp | 11 ++++++----- apps/openmw/mwgui/tradewindow.cpp | 8 ++++++++ apps/openmw/mwgui/tradewindow.hpp | 9 ++++++++- 5 files changed, 37 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 240198eddc..731403f3a3 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -134,6 +134,8 @@ namespace MWGui mItemView->resetScrollBars(); setTitle(actor.getClass().getName(actor)); + + mPtr.getClass().getContainerStore(mPtr).setContListener(this); } void CompanionWindow::onFrame(float dt) @@ -202,4 +204,9 @@ namespace MWGui mSortModel = nullptr; } + void CompanionWindow::updateItemView() + { + mItemView->update(); + } + } diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index 97f3a0072e..6f8452997f 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -4,6 +4,8 @@ #include "referenceinterface.hpp" #include "windowbase.hpp" +#include "../mwworld/containerstore.hpp" + namespace MWGui { namespace Widgets @@ -17,7 +19,7 @@ namespace MWGui class SortFilterItemModel; class CompanionItemModel; - class CompanionWindow : public WindowBase, public ReferenceInterface + class CompanionWindow : public WindowBase, public ReferenceInterface, public MWWorld::ContainerStoreListener { public: CompanionWindow(DragAndDrop* dragAndDrop, MessageBoxManager* manager); @@ -30,6 +32,11 @@ namespace MWGui void onFrame(float dt) override; void clear() override { resetReference(); } + void updateItemView(); + + void itemAdded(const MWWorld::ConstPtr& item, int count) override { updateItemView(); } + void itemRemoved(const MWWorld::ConstPtr& item, int count) override { updateItemView(); } + std::string_view getWindowIdForLua() const override { return "Companion"; } private: diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index b0c3197519..bb0f90ddc9 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -160,12 +160,8 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton); setTitle(container.getClass().getName(container)); - mPtr.getClass().getContainerStore(mPtr).setContListener(this); - } - void ContainerWindow::updateItemView() - { - mItemView->update(); + mPtr.getClass().getContainerStore(mPtr).setContListener(this); } void ContainerWindow::resetReference() @@ -326,4 +322,9 @@ namespace MWGui if (mModel && mModel->usesContainer(ptr)) MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); } + + void ContainerWindow::updateItemView() + { + mItemView->update(); + } } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index ba752303d2..ad5165c6ae 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -201,6 +201,9 @@ namespace MWGui onFilterChanged(mFilterAll); mFilterEdit->setCaption({}); + + for (const auto& source : itemSources) + source.getClass().getContainerStore(source).setContListener(this); } void TradeWindow::onFrame(float dt) @@ -643,4 +646,9 @@ namespace MWGui if (mTradeModel && mTradeModel->usesContainer(ptr)) MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); } + + void TradeWindow::updateItemView() + { + mItemView->update(); + } } diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 33c39cb269..8614655c47 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -4,6 +4,8 @@ #include "referenceinterface.hpp" #include "windowbase.hpp" +#include "../mwworld/containerstore.hpp" + namespace Gui { class NumericEditBox; @@ -20,7 +22,7 @@ namespace MWGui class SortFilterItemModel; class TradeItemModel; - class TradeWindow : public WindowBase, public ReferenceInterface + class TradeWindow : public WindowBase, public ReferenceInterface, public MWWorld::ContainerStoreListener { public: TradeWindow(); @@ -42,6 +44,11 @@ namespace MWGui void onDeleteCustomData(const MWWorld::Ptr& ptr) override; + void updateItemView(); + + void itemAdded(const MWWorld::ConstPtr& item, int count) override { updateItemView(); } + void itemRemoved(const MWWorld::ConstPtr& item, int count) override { updateItemView(); } + typedef MyGUI::delegates::MultiDelegate<> EventHandle_TradeDone; EventHandle_TradeDone eventTradeDone; From a9870bbcde803890dfd2e42062787c2ca2b0bfef Mon Sep 17 00:00:00 2001 From: Kindi Date: Tue, 1 Apr 2025 13:03:11 +0800 Subject: [PATCH 004/330] update container window when item is added or removed --- apps/openmw/mwgui/container.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index bb0f90ddc9..b0c3197519 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -160,10 +160,14 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton); setTitle(container.getClass().getName(container)); - mPtr.getClass().getContainerStore(mPtr).setContListener(this); } + void ContainerWindow::updateItemView() + { + mItemView->update(); + } + void ContainerWindow::resetReference() { ReferenceInterface::resetReference(); @@ -322,9 +326,4 @@ namespace MWGui if (mModel && mModel->usesContainer(ptr)) MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); } - - void ContainerWindow::updateItemView() - { - mItemView->update(); - } } From bdf025a5325f85cdfa97720b01a5798505c0f221 Mon Sep 17 00:00:00 2001 From: Kindi Date: Thu, 3 Apr 2025 11:26:56 +0800 Subject: [PATCH 005/330] also update companion window and tradewindow --- apps/openmw/mwgui/container.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index b0c3197519..bb0f90ddc9 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -160,12 +160,8 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton); setTitle(container.getClass().getName(container)); - mPtr.getClass().getContainerStore(mPtr).setContListener(this); - } - void ContainerWindow::updateItemView() - { - mItemView->update(); + mPtr.getClass().getContainerStore(mPtr).setContListener(this); } void ContainerWindow::resetReference() @@ -326,4 +322,9 @@ namespace MWGui if (mModel && mModel->usesContainer(ptr)) MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); } + + void ContainerWindow::updateItemView() + { + mItemView->update(); + } } From 4b94b6f678cd8c812ceaf78d59b02a708ba6d6dd Mon Sep 17 00:00:00 2001 From: Kindi Date: Wed, 23 Apr 2025 17:22:01 +0800 Subject: [PATCH 006/330] also update draganddrop and trade items --- apps/openmw/mwgui/draganddrop.cpp | 28 ++++++++++++++++++++------- apps/openmw/mwgui/draganddrop.hpp | 4 +++- apps/openmw/mwgui/inventorywindow.cpp | 15 ++++++++++++++ apps/openmw/mwgui/inventorywindow.hpp | 2 +- apps/openmw/mwgui/tradeitemmodel.cpp | 19 ++++++++++++++++++ apps/openmw/mwgui/tradeitemmodel.hpp | 3 +++ apps/openmw/mwgui/tradewindow.cpp | 9 +++++++++ apps/openmw/mwgui/tradewindow.hpp | 4 +++- 8 files changed, 74 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwgui/draganddrop.cpp b/apps/openmw/mwgui/draganddrop.cpp index 36cfe649d6..17ce5360c0 100644 --- a/apps/openmw/mwgui/draganddrop.cpp +++ b/apps/openmw/mwgui/draganddrop.cpp @@ -11,7 +11,6 @@ #include "controllers.hpp" #include "inventorywindow.hpp" #include "itemview.hpp" -#include "itemwidget.hpp" #include "sortfilteritemmodel.hpp" namespace MWGui @@ -72,19 +71,18 @@ namespace MWGui mSourceSortModel->addDragItem(mItem.mBase, count); } - ItemWidget* baseWidget = MyGUI::Gui::getInstance().createWidget( + mDraggedWidget = MyGUI::Gui::getInstance().createWidget( "MW_ItemIcon", 0, 0, 42, 42, MyGUI::Align::Default, "DragAndDrop"); Controllers::ControllerFollowMouse* controller = MyGUI::ControllerManager::getInstance() .createItem(Controllers::ControllerFollowMouse::getClassTypeName()) ->castType(); - MyGUI::ControllerManager::getInstance().addItem(baseWidget, controller); + MyGUI::ControllerManager::getInstance().addItem(mDraggedWidget, controller); - mDraggedWidget = baseWidget; - baseWidget->setItem(mItem.mBase); - baseWidget->setNeedMouseFocus(false); - baseWidget->setCount(count); + mDraggedWidget->setItem(mItem.mBase); + mDraggedWidget->setNeedMouseFocus(false); + mDraggedWidget->setCount(count); sourceView->update(); @@ -126,6 +124,22 @@ namespace MWGui mSourceView->update(); } + void DragAndDrop::update() + { + if (mIsOnDragAndDrop) + { + int count = mItem.mBase.getCellRef().getCount(); + if (count < mDraggedCount) + { + mItem.mCount = count; + mDraggedCount = count; + mDraggedWidget->setCount(mDraggedCount); + mSourceSortModel->clearDragItems(); + mSourceSortModel->addDragItem(mItem.mBase, mDraggedCount); + } + } + } + void DragAndDrop::onFrame() { if (mIsOnDragAndDrop && mItem.mBase.getCellRef().getCount() == 0) diff --git a/apps/openmw/mwgui/draganddrop.hpp b/apps/openmw/mwgui/draganddrop.hpp index fab7f30d75..94da6cce5f 100644 --- a/apps/openmw/mwgui/draganddrop.hpp +++ b/apps/openmw/mwgui/draganddrop.hpp @@ -2,6 +2,7 @@ #define OPENMW_MWGUI_DRAGANDDROP_H #include "itemmodel.hpp" +#include "itemwidget.hpp" namespace MyGUI { @@ -18,7 +19,7 @@ namespace MWGui { public: bool mIsOnDragAndDrop; - MyGUI::Widget* mDraggedWidget; + ItemWidget* mDraggedWidget; ItemModel* mSourceModel; ItemView* mSourceView; SortFilterItemModel* mSourceSortModel; @@ -30,6 +31,7 @@ namespace MWGui void startDrag( int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, int count); void drop(ItemModel* targetModel, ItemView* targetView); + void update(); void onFrame(); void finish(); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 27dab07d34..656f1a3db4 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -850,6 +850,21 @@ namespace MWGui mPreview->rebuild(); } + void InventoryWindow::itemRemoved(const MWWorld::ConstPtr& item, int count) + { + if (mDragAndDrop->mIsOnDragAndDrop && mDragAndDrop->mItem.mBase == item) + mDragAndDrop->update(); + + if (mTrading) + { + mTradeModel->updateBorrowed(); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->getTradeModel()->updateBorrowed(); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->updateItemView(); + } + + updateItemView(); + } + MyGUI::IntSize InventoryWindow::getPreviewViewportSize() const { const MyGUI::IntSize previewWindowSize = mAvatarImage->getSize(); diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 1dd12aa550..079e629673 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -64,7 +64,7 @@ namespace MWGui void setGuiMode(GuiMode mode); void itemAdded(const MWWorld::ConstPtr& item, int count) override { updateItemView(); } - void itemRemoved(const MWWorld::ConstPtr& item, int count) override { updateItemView(); } + void itemRemoved(const MWWorld::ConstPtr& item, int count) override; /// Cycle to previous/next weapon void cycle(bool next); diff --git a/apps/openmw/mwgui/tradeitemmodel.cpp b/apps/openmw/mwgui/tradeitemmodel.cpp index 50a55f5061..5df048d6db 100644 --- a/apps/openmw/mwgui/tradeitemmodel.cpp +++ b/apps/openmw/mwgui/tradeitemmodel.cpp @@ -113,6 +113,25 @@ namespace MWGui encumbrance = std::max(0.f, encumbrance); } + void TradeItemModel::updateBorrowed() + { + auto update = [](std::vector& list) { + for (auto it = list.begin(); it != list.end();) + { + int actualCount = it->mBase.getCellRef().getCount(); + if (actualCount < it->mCount) + it->mCount = actualCount; + if (it->mCount == 0) + it = list.erase(it); + else + ++it; + } + }; + + update(mBorrowedFromUs); + update(mBorrowedToUs); + } + void TradeItemModel::abort() { mBorrowedFromUs.clear(); diff --git a/apps/openmw/mwgui/tradeitemmodel.hpp b/apps/openmw/mwgui/tradeitemmodel.hpp index d395744d2a..856f33563d 100644 --- a/apps/openmw/mwgui/tradeitemmodel.hpp +++ b/apps/openmw/mwgui/tradeitemmodel.hpp @@ -31,6 +31,9 @@ namespace MWGui void returnItemBorrowedFromUs(ModelIndex itemIndex, ItemModel* source, size_t count); + /// Update borrowed items in this model + void updateBorrowed(); + /// Permanently transfers items that were borrowed to us from another model to this model void transferItems(); /// Aborts trade diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index ad5165c6ae..60ec6d589a 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -651,4 +651,13 @@ namespace MWGui { mItemView->update(); } + + void TradeWindow::itemRemoved(const MWWorld::ConstPtr& item, int count) + { + mTradeModel->updateBorrowed(); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getTradeModel()->updateBorrowed(); + + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView(); + updateItemView(); + } } diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 8614655c47..c4bde5fc11 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -44,10 +44,12 @@ namespace MWGui void onDeleteCustomData(const MWWorld::Ptr& ptr) override; + TradeItemModel* getTradeModel() { return mTradeModel; }; + void updateItemView(); void itemAdded(const MWWorld::ConstPtr& item, int count) override { updateItemView(); } - void itemRemoved(const MWWorld::ConstPtr& item, int count) override { updateItemView(); } + void itemRemoved(const MWWorld::ConstPtr& item, int count) override; typedef MyGUI::delegates::MultiDelegate<> EventHandle_TradeDone; EventHandle_TradeDone eventTradeDone; From 0247082e198ded78e06b13d6c039d102d7de43e0 Mon Sep 17 00:00:00 2001 From: Kindi Date: Thu, 24 Apr 2025 20:24:55 +0800 Subject: [PATCH 007/330] fix signedness, remove extra semicolon, update offer --- apps/openmw/mwgui/tradeitemmodel.cpp | 2 +- apps/openmw/mwgui/tradewindow.cpp | 2 ++ apps/openmw/mwgui/tradewindow.hpp | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/tradeitemmodel.cpp b/apps/openmw/mwgui/tradeitemmodel.cpp index 5df048d6db..660e940367 100644 --- a/apps/openmw/mwgui/tradeitemmodel.cpp +++ b/apps/openmw/mwgui/tradeitemmodel.cpp @@ -118,7 +118,7 @@ namespace MWGui auto update = [](std::vector& list) { for (auto it = list.begin(); it != list.end();) { - int actualCount = it->mBase.getCellRef().getCount(); + size_t actualCount = it->mBase.getCellRef().getCount(); if (actualCount < it->mCount) it->mCount = actualCount; if (it->mCount == 0) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 60ec6d589a..cf882d96cf 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -659,5 +659,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView(); updateItemView(); + + updateOffer(); } } diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index c4bde5fc11..748d7ce7d5 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -44,7 +44,7 @@ namespace MWGui void onDeleteCustomData(const MWWorld::Ptr& ptr) override; - TradeItemModel* getTradeModel() { return mTradeModel; }; + TradeItemModel* getTradeModel() { return mTradeModel; } void updateItemView(); From 71aa11404ccd2abca26e008b3b29ef6ed6e246a3 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Mon, 5 May 2025 22:47:55 -0700 Subject: [PATCH 008/330] Add checkbox to enable controller menus to openmw launcher. --- apps/launcher/settingspage.cpp | 2 ++ apps/launcher/ui/settingspage.ui | 10 ++++++++++ components/settings/categories/gui.hpp | 1 + files/settings-default.cfg | 3 +++ 4 files changed, 16 insertions(+) diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index dfddc45bc5..94a1a0b8a0 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -304,6 +304,7 @@ bool Launcher::SettingsPage::loadSettings() loadSettingBool(Settings::gui().mColorTopicEnable, *changeDialogTopicsCheckBox); showOwnedComboBox->setCurrentIndex(Settings::game().mShowOwned); loadSettingBool(Settings::gui().mStretchMenuBackground, *stretchBackgroundCheckBox); + loadSettingBool(Settings::gui().mControllerMenus, *controllerMenusCheckBox); loadSettingBool(Settings::map().mAllowZooming, *useZoomOnMapCheckBox); loadSettingBool(Settings::game().mGraphicHerbalism, *graphicHerbalismCheckBox); scalingSpinBox->setValue(Settings::gui().mScalingFactor); @@ -497,6 +498,7 @@ void Launcher::SettingsPage::saveSettings() saveSettingBool(*changeDialogTopicsCheckBox, Settings::gui().mColorTopicEnable); saveSettingInt(*showOwnedComboBox, Settings::game().mShowOwned); saveSettingBool(*stretchBackgroundCheckBox, Settings::gui().mStretchMenuBackground); + saveSettingBool(*controllerMenusCheckBox, Settings::gui().mControllerMenus); saveSettingBool(*useZoomOnMapCheckBox, Settings::map().mAllowZooming); saveSettingBool(*graphicHerbalismCheckBox, Settings::game().mGraphicHerbalism); Settings::gui().mScalingFactor.set(scalingSpinBox->value()); diff --git a/apps/launcher/ui/settingspage.ui b/apps/launcher/ui/settingspage.ui index e792ac2843..e501ed156f 100644 --- a/apps/launcher/ui/settingspage.ui +++ b/apps/launcher/ui/settingspage.ui @@ -1398,6 +1398,16 @@ + + + + <html><head/><body><p>Make it easier to use game menus with a controller.</p></body></html> + + + Enable Controller Menus + + + diff --git a/components/settings/categories/gui.hpp b/components/settings/categories/gui.hpp index a26364c5dd..139d55d9c8 100644 --- a/components/settings/categories/gui.hpp +++ b/components/settings/categories/gui.hpp @@ -25,6 +25,7 @@ namespace Settings SettingValue mMenuTransparency{ mIndex, "GUI", "menu transparency", makeClampSanitizerFloat(0, 1) }; SettingValue mTooltipDelay{ mIndex, "GUI", "tooltip delay", makeMaxSanitizerFloat(0) }; SettingValue mStretchMenuBackground{ mIndex, "GUI", "stretch menu background" }; + SettingValue mControllerMenus{ mIndex, "GUI", "controller menus" }; SettingValue mSubtitles{ mIndex, "GUI", "subtitles" }; SettingValue mHitFader{ mIndex, "GUI", "hit fader" }; SettingValue mWerewolfOverlay{ mIndex, "GUI", "werewolf overlay" }; diff --git a/files/settings-default.cfg b/files/settings-default.cfg index e5654794cc..6a0701803b 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -201,6 +201,9 @@ tooltip delay = 0.0 # Stretch menus, load screens, etc. to the window aspect ratio. stretch menu background = false +# Make menus easier to navigate with a controller. +controller menus = false + # Subtitles for NPC spoken dialog and some sound effects. subtitles = false From a8824b46a8f2f871c280fc32897a767361dd24bf Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Fri, 9 May 2025 22:56:04 -0700 Subject: [PATCH 009/330] Add first batch of controller-enabled windows --- apps/openmw/mwbase/windowmanager.hpp | 3 ++ apps/openmw/mwgui/confirmationdialog.cpp | 17 ++++++++++++ apps/openmw/mwgui/confirmationdialog.hpp | 2 ++ apps/openmw/mwgui/mainmenu.cpp | 31 +++++++++++++++++++-- apps/openmw/mwgui/mainmenu.hpp | 1 + apps/openmw/mwgui/waitdialog.cpp | 25 +++++++++++++++++ apps/openmw/mwgui/waitdialog.hpp | 1 + apps/openmw/mwgui/windowbase.cpp | 25 +++++++++++++++++ apps/openmw/mwgui/windowbase.hpp | 15 ++++++++++ apps/openmw/mwgui/windowmanagerimp.cpp | 34 +++++++++++++++++++++++ apps/openmw/mwgui/windowmanagerimp.hpp | 2 ++ apps/openmw/mwinput/controllermanager.cpp | 12 ++++++++ 12 files changed, 166 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 8164501b4b..d2f1fc6514 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -12,6 +12,7 @@ #include #include "../mwgui/mode.hpp" +#include "../mwgui/windowbase.hpp" #include @@ -381,6 +382,8 @@ namespace MWBase /// Same as viewer->getCamera()->getCullMask(), provided for consistency. virtual uint32_t getCullMask() = 0; + virtual MWGui::WindowBase* getTopWindow() = 0; + // Used in Lua bindings virtual const std::vector& getGuiModeStack() const = 0; virtual void setDisabledByLua(std::string_view windowId, bool disabled) = 0; diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index 48b209f17e..903fb4f898 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -17,6 +17,8 @@ namespace MWGui mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ConfirmationDialog::onCancelButtonClicked); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ConfirmationDialog::onOkButtonClicked); + + trackFocusEvents(mCancelButton); } void ConfirmationDialog::askForConfirmation(const std::string& message) @@ -56,4 +58,19 @@ namespace MWGui eventOkClicked(); } + + bool ConfirmationDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + if (mMouseFocus != nullptr) + return false; + + onOkButtonClicked(mOkButton); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + onCancelButtonClicked(mCancelButton); + + return true; + } } diff --git a/apps/openmw/mwgui/confirmationdialog.hpp b/apps/openmw/mwgui/confirmationdialog.hpp index 1344f2a501..2a1886398b 100644 --- a/apps/openmw/mwgui/confirmationdialog.hpp +++ b/apps/openmw/mwgui/confirmationdialog.hpp @@ -27,6 +27,8 @@ namespace MWGui void onCancelButtonClicked(MyGUI::Widget* _sender); void onOkButtonClicked(MyGUI::Widget* _sender); + + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; }; } diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 1b3619bd9f..ae5b5f9be2 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -1,6 +1,7 @@ #include "mainmenu.hpp" #include +#include #include #include @@ -163,9 +164,7 @@ namespace MWGui const std::string& name = *sender->getUserData(); winMgr->playSound(ESM::RefId::stringRefId("Menu Click")); if (name == "return") - { winMgr->removeGuiMode(GM_MainMenu); - } else if (name == "credits") winMgr->playVideo("mw_credits.bik", true); else if (name == "exitgame") @@ -208,6 +207,34 @@ namespace MWGui } } + bool MainMenu::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + // REMOVEME + Log(Debug::Verbose) << "MainMenu::onControllerButtonEvent " << arg.button; + + MyGUI::KeyCode key = MyGUI::KeyCode::None; + switch (arg.button) + { + case SDL_CONTROLLER_BUTTON_DPAD_UP: + MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::LeftShift); + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Tab, 0, false); + MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::LeftShift); + return true; + case SDL_CONTROLLER_BUTTON_DPAD_DOWN: + key = MyGUI::KeyCode::Tab; + break; + case SDL_CONTROLLER_BUTTON_A: + key = MyGUI::KeyCode::Space; + break; + case SDL_CONTROLLER_BUTTON_B: + case SDL_CONTROLLER_BUTTON_START: + onButtonClicked(mButtons["return"]); + return true; + } + MWBase::Environment::get().getWindowManager()->injectKeyPress(key, 0, false); + return true; + } + void MainMenu::showBackground(bool show) { if (mVideo && !show) diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index 06a8c945c1..453a16b5e4 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -49,6 +49,7 @@ namespace MWGui MainMenu(int w, int h, const VFS::Manager* vfs, const std::string& versionDescription); void onResChange(int w, int h) override; + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; void setVisible(bool visible) override; diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 568f05abc3..3c39590dee 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -80,6 +80,10 @@ namespace MWGui mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &WaitDialog::onWaitingProgressChanged); mTimeAdvancer.eventInterrupted += MyGUI::newDelegate(this, &WaitDialog::onWaitingInterrupted); mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &WaitDialog::onWaitingFinished); + + trackFocusEvents(mUntilHealedButton); + trackFocusEvents(mWaitButton); + trackFocusEvents(mCancelButton); } void WaitDialog::setPtr(const MWWorld::Ptr& ptr) @@ -326,6 +330,27 @@ namespace MWGui } } + bool WaitDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + if (mMouseFocus != nullptr) + return false; + + onWaitButtonClicked(mWaitButton); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + onCancelButtonClicked(mCancelButton); + else if (arg.button == SDL_CONTROLLER_BUTTON_X && mUntilHealedButton->getVisible()) + onUntilHealedButtonClicked(mUntilHealedButton); + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::ArrowUp, 0, false); + + return true; + } + void WaitDialog::stopWaiting() { MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.2f); diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 3d66584f54..8a38dd0976 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -36,6 +36,7 @@ namespace MWGui void clear() override; void onFrame(float dt) override; + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; bool getSleeping() { return mTimeAdvancer.isRunning() && mSleeping; } void wakeUp(); diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index f5d90590f8..d01822f704 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -7,6 +7,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include #include #include "draganddrop.hpp" @@ -105,6 +106,30 @@ void WindowBase::clampWindowCoordinates(MyGUI::Window* window) window->setPosition(left, top); } +void WindowBase::focusGain(MyGUI::Widget* _new, MyGUI::Widget* _old) +{ + // REMOVEME + Log(Debug::Verbose) << "WindowBase::focusGain new=" << _new << ", old=" << _old; + mMouseFocus = _new; +} + +void WindowBase::focusLoss(MyGUI::Widget* _old, MyGUI::Widget* _new) +{ + // REMOVEME + Log(Debug::Verbose) << "WindowBase::focusLoss old=" << _old << ", new=" << _new; + if (mMouseFocus == _old) + mMouseFocus = nullptr; +} + +void WindowBase::trackFocusEvents(MyGUI::Widget* widget) +{ + if (!Settings::gui().mControllerMenus) + return; + + widget->eventMouseSetFocus += MyGUI::newDelegate(this, &WindowBase::focusGain); + widget->eventMouseLostFocus += MyGUI::newDelegate(this, &WindowBase::focusLoss); +} + WindowModal::WindowModal(const std::string& parLayout) : WindowBase(parLayout) { diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index 466060c6ad..3db4399d85 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -1,6 +1,8 @@ #ifndef MWGUI_WINDOW_BASE_H #define MWGUI_WINDOW_BASE_H +#include + #include "layout.hpp" namespace MWWorld @@ -54,13 +56,26 @@ namespace MWGui static void clampWindowCoordinates(MyGUI::Window* window); + /// Called by controllermanager to handle controller events + virtual bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { return true; }; + virtual bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) { return true; }; + // REMOVEME + // virtual bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) = 0; + // virtual bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) = 0; + protected: virtual void onTitleDoubleClicked(); + MyGUI::Widget* mMouseFocus = nullptr; + void trackFocusEvents(MyGUI::Widget* widget); + private: void onDoubleClick(MyGUI::Widget* _sender); bool mDisabledByLua = false; + + void focusGain(MyGUI::Widget* _new, MyGUI::Widget* _old); + void focusLoss(MyGUI::Widget* _old, MyGUI::Widget* _new); }; /* diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 565fb43127..b328176014 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -859,6 +859,40 @@ namespace MWGui mHud->setPlayerPos(x, y, u, v); } + WindowBase* WindowManager::getTopWindow() + { + if (!mCurrentModals.empty()) + return mCurrentModals.back(); + + if (isSettingsWindowVisible()) + return mSettingsWindow; + + if (!mGuiModes.empty()) + { + GuiModeState& state = mGuiModeStates[mGuiModes.back()]; + // REMOVEME + Log(Debug::Error) << "getTopWindow: " << state.mWindows.size() << " windows in state " << mGuiModes.back(); + // find the topmost window + for (WindowBase* window : state.mWindows) + if (window->isVisible()) + return window; + else + Log(Debug::Error) << "-- Skipping hidden window " << window; + } + else + { + // return pinned windows if visible + // REMOVEME + Log(Debug::Error) << "getTopWindow: " << mGuiModeStates[GM_Inventory].mWindows.size() << " pinned windows"; + for (WindowBase* window : mGuiModeStates[GM_Inventory].mWindows) + if (window->isVisible()) + return window; + else + Log(Debug::Error) << "-- Skipping hidden window " << window; + } + return nullptr; + } + void WindowManager::update(float frameDuration) { handleScheduledMessageBoxes(); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 03902e21c4..fd035ed12e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -387,6 +387,8 @@ namespace MWGui void asyncPrepareSaveMap() override; + WindowBase* getTopWindow() override; + // Used in Lua bindings const std::vector& getGuiModeStack() const override { return mGuiModes; } void setDisabledByLua(std::string_view windowId, bool disabled) override; diff --git a/apps/openmw/mwinput/controllermanager.cpp b/apps/openmw/mwinput/controllermanager.cpp index 1a8490d8b7..404b156c24 100644 --- a/apps/openmw/mwinput/controllermanager.cpp +++ b/apps/openmw/mwinput/controllermanager.cpp @@ -241,6 +241,12 @@ namespace MWInput bool ControllerManager::gamepadToGuiControl(const SDL_ControllerButtonEvent& arg) { + if (Settings::gui().mControllerMenus) + { + MWGui::WindowBase* topWin = MWBase::Environment::get().getWindowManager()->getTopWindow(); + return topWin && topWin->onControllerButtonEvent(arg); + } + // Presumption of GUI mode will be removed in the future. // MyGUI KeyCodes *may* change. MyGUI::KeyCode key = MyGUI::KeyCode::None; @@ -302,6 +308,12 @@ namespace MWInput bool ControllerManager::gamepadToGuiControl(const SDL_ControllerAxisEvent& arg) { + if (Settings::gui().mControllerMenus) + { + MWGui::WindowBase* topWin = MWBase::Environment::get().getWindowManager()->getTopWindow(); + return topWin && topWin->onControllerThumbstickEvent(arg); + } + switch (arg.axis) { case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: From fc86878922f72d673e2d160be8084d7e023a9644 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Fri, 9 May 2025 23:43:29 -0700 Subject: [PATCH 010/330] Allow exiting credits by pressing B --- apps/openmw/mwgui/mainmenu.cpp | 10 ++++++++-- apps/openmw/mwinput/controllermanager.cpp | 6 ++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index ae5b5f9be2..5d0e2dc585 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -228,8 +228,14 @@ namespace MWGui break; case SDL_CONTROLLER_BUTTON_B: case SDL_CONTROLLER_BUTTON_START: - onButtonClicked(mButtons["return"]); - return true; + if (mButtons["return"]->getVisible()) + { + onButtonClicked(mButtons["return"]); + return true; + } + else + key = MyGUI::KeyCode::Escape; + break; } MWBase::Environment::get().getWindowManager()->injectKeyPress(key, 0, false); return true; diff --git a/apps/openmw/mwinput/controllermanager.cpp b/apps/openmw/mwinput/controllermanager.cpp index 404b156c24..7aff8172ce 100644 --- a/apps/openmw/mwinput/controllermanager.cpp +++ b/apps/openmw/mwinput/controllermanager.cpp @@ -244,7 +244,8 @@ namespace MWInput if (Settings::gui().mControllerMenus) { MWGui::WindowBase* topWin = MWBase::Environment::get().getWindowManager()->getTopWindow(); - return topWin && topWin->onControllerButtonEvent(arg); + if (topWin && topWin->onControllerButtonEvent(arg)) + return true; } // Presumption of GUI mode will be removed in the future. @@ -311,7 +312,8 @@ namespace MWInput if (Settings::gui().mControllerMenus) { MWGui::WindowBase* topWin = MWBase::Environment::get().getWindowManager()->getTopWindow(); - return topWin && topWin->onControllerThumbstickEvent(arg); + if (topWin && topWin->onControllerThumbstickEvent(arg)) + return true; } switch (arg.axis) From 2970913d553aed9881489acdfd6b71ae474e23e8 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Fri, 9 May 2025 23:44:06 -0700 Subject: [PATCH 011/330] Minimal controller bindings for settings window --- apps/openmw/mwgui/settingswindow.cpp | 34 ++++++++++++++++++++++++++++ apps/openmw/mwgui/settingswindow.hpp | 2 ++ 2 files changed, 36 insertions(+) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 02353c5d41..7f8d98ee05 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -1128,4 +1128,38 @@ namespace MWGui mResolutionList->setScrollPosition(0); mControlsBox->setViewOffset(MyGUI::IntPoint(0, 0)); } + + bool SettingsWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_B) + { + onOkButtonClicked(mOkButton); + return true; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) + { + uint32_t index = mSettingsTab->getIndexSelected(); + if (index <= 0) + index = mSettingsTab->getItemCount() - 1; + else + index--; + mSettingsTab->setIndexSelected(index); + + return true; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) + { + uint32_t index = mSettingsTab->getIndexSelected(); + if (index >= mSettingsTab->getItemCount() - 1) + index = 0; + else + index++; + mSettingsTab->setIndexSelected(index); + + return true; + } + + return false; + } + } diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index dc4e09f8ac..555468d806 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -26,6 +26,8 @@ namespace MWGui void onResChange(int, int) override; + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + protected: MyGUI::TabControl* mSettingsTab; MyGUI::Button* mOkButton; From 58c4e0ddf735747105c5fc4c2db7a0aa912888a3 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sat, 10 May 2025 01:41:53 -0700 Subject: [PATCH 012/330] Minimal controller bindings for save/load window --- apps/openmw/mwgui/savegamedialog.cpp | 58 ++++++++++++++++++++++++++++ apps/openmw/mwgui/savegamedialog.hpp | 2 + 2 files changed, 60 insertions(+) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 94f25e118b..fc6171b8dc 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -63,6 +63,9 @@ namespace MWGui // To avoid accidental deletions mDeleteButton->setNeedKeyFocus(false); + + trackFocusEvents(mCancelButton); + trackFocusEvents(mDeleteButton); } void SaveGameDialog::onSlotActivated(MyGUI::ListBox* sender, size_t pos) @@ -487,4 +490,59 @@ namespace MWGui mScreenshotTexture = std::make_unique(texture); mScreenshot->setRenderItemTexture(mScreenshotTexture.get()); } + + bool SaveGameDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + if (mMouseFocus != nullptr) + return false; + + onOkButtonClicked(mOkButton); + return true; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + { + onCancelButtonClicked(mCancelButton); + return true; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) + { + MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); + winMgr->setKeyFocusWidget(mSaveList); + winMgr->injectKeyPress(MyGUI::KeyCode::ArrowUp, 0, false); + return true; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + { + MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); + winMgr->setKeyFocusWidget(mSaveList); + winMgr->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); + return true; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) + { + uint32_t index = mCharacterSelection->getIndexSelected(); + if (index <= 0) + index = mCharacterSelection->getItemCount() - 1; + else + index--; + mCharacterSelection->setIndexSelected(index); + + return true; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) + { + uint32_t index = mCharacterSelection->getIndexSelected(); + if (index >= mCharacterSelection->getItemCount() - 1) + index = 0; + else + index++; + mCharacterSelection->setIndexSelected(index); + + return true; + } + + return false; + } } diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index 35e65fbed0..caabff2431 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -24,6 +24,8 @@ namespace MWGui void setLoadOrSave(bool load); + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + private: void confirmDeleteSave(); From bb88becc2bb1a0fe22a9b98aa3161e11ab7095a5 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sat, 10 May 2025 22:50:16 -0700 Subject: [PATCH 013/330] Basic controller support for the journal --- apps/openmw/mwgui/journalwindow.cpp | 61 +++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 574c425d3e..7fd6e3d995 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -639,6 +639,67 @@ namespace } } } + + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + // Fall through to mouse click + return false; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + { + if (mOptionsMode) + notifyCancel(getWidget(CancelBTN)); + else if (mStates.size() > 1) + notifyJournal(getWidget(JournalBTN)); + else + notifyClose(getWidget(CloseBTN)); + return true; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_X) + { + if (mQuestMode) + { + if (!mOptionsMode) + notifyOptions(getWidget(OptionsBTN)); + notifyTopics(getWidget(TopicsBTN)); + } + return true; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_Y) + { + if (!mQuestMode) + { + if (!mOptionsMode) + notifyOptions(getWidget(OptionsBTN)); + notifyQuests(getWidget(QuestsBTN)); + } + return true; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) + { + return true; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + { + return true; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER || + arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) + { + notifyPrevPage(getWidget(PrevPageBTN)); + return true; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER || + arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + { + notifyNextPage(getWidget(NextPageBTN)); + return true; + } + + return false; + } }; } From be298f78cb3d8172e0fa18608475ac3803e9e79e Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sat, 10 May 2025 23:17:23 -0700 Subject: [PATCH 014/330] Basic controller support for the books --- apps/openmw/mwgui/bookwindow.cpp | 42 ++++++++++++++++++++++++++++++++ apps/openmw/mwgui/bookwindow.hpp | 1 + 2 files changed, 43 insertions(+) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index ef875a18b9..91b1af615e 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -27,15 +27,19 @@ namespace MWGui { getWidget(mCloseButton, "CloseButton"); mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onCloseButtonClicked); + trackFocusEvents(mCloseButton); getWidget(mTakeButton, "TakeButton"); mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onTakeButtonClicked); + trackFocusEvents(mTakeButton); getWidget(mNextPageButton, "NextPageBTN"); mNextPageButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onNextPageButtonClicked); + trackFocusEvents(mNextPageButton); getWidget(mPrevPageButton, "PrevPageBTN"); mPrevPageButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onPrevPageButtonClicked); + trackFocusEvents(mPrevPageButton); getWidget(mLeftPageNumber, "LeftPageNumber"); getWidget(mRightPageNumber, "RightPageNumber"); @@ -218,4 +222,42 @@ namespace MWGui } } + bool BookWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + if (mMouseFocus != nullptr) + return false; + + if (mTakeButton->getVisible()) + onTakeButtonClicked(mTakeButton); + else + onCloseButtonClicked(mCloseButton); + return true; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + { + onCloseButtonClicked(mCloseButton); + return true; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP || + arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + { + return true; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER || + arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) + { + prevPage(); + return true; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER || + arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + { + nextPage(); + return true; + } + + return false; + } } diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index 5a3dfdf584..062c6e9dbd 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -18,6 +18,7 @@ namespace MWGui void setInventoryAllowed(bool allowed); void onResChange(int, int) override { center(); } + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; std::string_view getWindowIdForLua() const override { return "Book"; } From 80166cddd06e7d49639762a73578ed1901089cd3 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 11 May 2025 00:19:01 -0700 Subject: [PATCH 015/330] Make main menu honor controller mouse clicks --- apps/openmw/mwgui/mainmenu.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 5d0e2dc585..cfcb63e4d5 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -224,6 +224,8 @@ namespace MWGui key = MyGUI::KeyCode::Tab; break; case SDL_CONTROLLER_BUTTON_A: + if (mMouseFocus != nullptr) + return false; key = MyGUI::KeyCode::Space; break; case SDL_CONTROLLER_BUTTON_B: @@ -341,6 +343,7 @@ namespace MWGui button->setProperty("ImagePushed", "textures\\menu_" + buttonId + "_pressed.dds"); button->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::onButtonClicked); button->setUserData(buttonId); + trackFocusEvents(button); } } From 3b42d02cfc602230c2d92f2369235269e2cecb8a Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 11 May 2025 00:20:31 -0700 Subject: [PATCH 016/330] Add controller support to message boxes --- apps/openmw/mwgui/messagebox.cpp | 50 ++++++++++++++++++++++++++++++++ apps/openmw/mwgui/messagebox.hpp | 3 ++ 2 files changed, 53 insertions(+) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 1d6e1511c4..7bc6d70931 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -8,6 +8,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/inputmanager.hpp" @@ -259,6 +260,7 @@ namespace MWGui button->setCaptionWithReplacing(buttonId); button->eventMouseButtonClick += MyGUI::newDelegate(this, &InteractiveMessageBox::mousePressed); + trackFocusEvents(button); mButtons.push_back(button); @@ -280,6 +282,12 @@ namespace MWGui } } + if (Settings::gui().mControllerMenus && mButtons.size() > 1) + { + // If we have more than one button, we need to set the focus to the first one. + mButtons[0]->setStateSelected(true); + } + MyGUI::IntSize mainWidgetSize; if (buttonsWidth < textSize.width) { @@ -431,4 +439,46 @@ namespace MWGui return mButtonPressed; } + bool InteractiveMessageBox::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + if (mMouseFocus != nullptr) + return false; + + buttonActivated(mButtons[mControllerFocus]); + return true; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + { + if (mButtons.size() == 1) + buttonActivated(mButtons[0]); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) + { + if (mButtons.size() > 1) + { + mButtons[mControllerFocus]->setStateSelected(false); + if (mControllerFocus == 0) + mControllerFocus = mButtons.size() - 1; + else + mControllerFocus--; + mButtons[mControllerFocus]->setStateSelected(true); + } + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + { + if (mButtons.size() > 1) + { + mButtons[mControllerFocus]->setStateSelected(false); + if (mControllerFocus == mButtons.size() - 1) + mControllerFocus = 0; + else + mControllerFocus++; + mButtons[mControllerFocus]->setStateSelected(true); + } + } + + return true; + } } diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index feb717e0ad..e6128ee0d1 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -103,6 +103,8 @@ namespace MWGui bool mMarkedToDelete; + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + private: void buttonActivated(MyGUI::Widget* _widget); @@ -114,6 +116,7 @@ namespace MWGui int mButtonPressed; int mDefaultFocus; bool mImmediate; + int mControllerFocus = 0; }; } From 4c5db612f05f12cce0cf1fb4f44c5d06a54bc494 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 11 May 2025 00:32:29 -0700 Subject: [PATCH 017/330] Improve controller support for confirmation dialogs by highlighting selected choice --- apps/openmw/mwgui/confirmationdialog.cpp | 23 +++++++++++++++++++++-- apps/openmw/mwgui/confirmationdialog.hpp | 1 + 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index 903fb4f898..67da1f94a7 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -3,6 +3,8 @@ #include #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" @@ -18,7 +20,12 @@ namespace MWGui mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ConfirmationDialog::onCancelButtonClicked); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ConfirmationDialog::onOkButtonClicked); - trackFocusEvents(mCancelButton); + if (Settings::gui().mControllerMenus) + { + mOkButton->setStateSelected(true); + trackFocusEvents(mOkButton); + trackFocusEvents(mCancelButton); + } } void ConfirmationDialog::askForConfirmation(const std::string& message) @@ -66,10 +73,22 @@ namespace MWGui if (mMouseFocus != nullptr) return false; - onOkButtonClicked(mOkButton); + if (mOkButtonFocus) + onOkButtonClicked(mOkButton); + else + onCancelButtonClicked(mCancelButton); } else if (arg.button == SDL_CONTROLLER_BUTTON_B) + { onCancelButtonClicked(mCancelButton); + } + else if ((arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && !mOkButtonFocus) || + (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && mOkButtonFocus)) + { + mOkButtonFocus = !mOkButtonFocus; + mOkButton->setStateSelected(mOkButtonFocus); + mCancelButton->setStateSelected(!mOkButtonFocus); + } return true; } diff --git a/apps/openmw/mwgui/confirmationdialog.hpp b/apps/openmw/mwgui/confirmationdialog.hpp index 2a1886398b..93d7f360c5 100644 --- a/apps/openmw/mwgui/confirmationdialog.hpp +++ b/apps/openmw/mwgui/confirmationdialog.hpp @@ -29,6 +29,7 @@ namespace MWGui void onOkButtonClicked(MyGUI::Widget* _sender); bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + int mOkButtonFocus = true; }; } From c9ce93a22f68a23812795167c5c79729e0c33a79 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 11 May 2025 13:48:50 -0700 Subject: [PATCH 018/330] Controller menus: don't wrap focus when only two buttons --- apps/openmw/mwgui/messagebox.cpp | 40 ++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 7bc6d70931..be0f284b04 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -456,27 +456,31 @@ namespace MWGui } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) { - if (mButtons.size() > 1) - { - mButtons[mControllerFocus]->setStateSelected(false); - if (mControllerFocus == 0) - mControllerFocus = mButtons.size() - 1; - else - mControllerFocus--; - mButtons[mControllerFocus]->setStateSelected(true); - } + if (mButtons.size() <= 1) + return true; + if (mButtons.size() == 2 && mControllerFocus == 0) + return true; + + mButtons[mControllerFocus]->setStateSelected(false); + if (mControllerFocus == 0) + mControllerFocus = mButtons.size() - 1; + else + mControllerFocus--; + mButtons[mControllerFocus]->setStateSelected(true); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) { - if (mButtons.size() > 1) - { - mButtons[mControllerFocus]->setStateSelected(false); - if (mControllerFocus == mButtons.size() - 1) - mControllerFocus = 0; - else - mControllerFocus++; - mButtons[mControllerFocus]->setStateSelected(true); - } + if (mButtons.size() <= 1) + return true; + if (mButtons.size() == 2 && mControllerFocus == mButtons.size() - 1) + return true; + + mButtons[mControllerFocus]->setStateSelected(false); + if (mControllerFocus == mButtons.size() - 1) + mControllerFocus = 0; + else + mControllerFocus++; + mButtons[mControllerFocus]->setStateSelected(true); } return true; From 1e200ed0485362982dbff799c0c114da78f08b6b Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 11 May 2025 14:48:42 -0700 Subject: [PATCH 019/330] Add controller support to race menu --- apps/openmw/mwgui/race.cpp | 55 ++++++++++++++++++++++++++++++++++++++ apps/openmw/mwgui/race.hpp | 3 +++ 2 files changed, 58 insertions(+) diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 7b445d419f..6d7ec19f88 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -462,6 +462,61 @@ namespace MWGui } } + bool RaceDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + // Have A button do nothing so mouse controller still works. + return false; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_START) + { + onOkClicked(nullptr); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + { + onBackClicked(nullptr); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_X) + { + onSelectNextGender(nullptr); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) + { + onSelectNextHair(nullptr); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) + { + onSelectNextFace(nullptr); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) + { + MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); + winMgr->setKeyFocusWidget(mRaceList); + winMgr->injectKeyPress(MyGUI::KeyCode::ArrowUp, 0, false); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + { + MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); + winMgr->setKeyFocusWidget(mRaceList); + winMgr->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); + } + + return true; + } + + bool RaceDialog::onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) + { + if (arg.axis == SDL_CONTROLLER_AXIS_RIGHTX) + { + if (arg.value < -1000 || arg.value > 1000) + onPreviewScroll(nullptr, arg.value < 0 ? 1 : -1); + return true; + } + + return false; + } + const ESM::NPC& RaceDialog::getResult() const { return mPreview->getPrototype(); diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index a6ac0e2813..5452753747 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -118,6 +118,9 @@ namespace MWGui std::unique_ptr mPreviewTexture; bool mPreviewDirty; + + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) override; }; } #endif From 5e7761bef1c1a47aff52285535eba31dd667d4db Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 11 May 2025 14:56:58 -0700 Subject: [PATCH 020/330] Add controller support to text input menu --- apps/openmw/mwgui/textinput.cpp | 10 ++++++++++ apps/openmw/mwgui/textinput.hpp | 1 + 2 files changed, 11 insertions(+) diff --git a/apps/openmw/mwgui/textinput.cpp b/apps/openmw/mwgui/textinput.cpp index 5f47b96f03..44e0defef6 100644 --- a/apps/openmw/mwgui/textinput.cpp +++ b/apps/openmw/mwgui/textinput.cpp @@ -83,4 +83,14 @@ namespace MWGui mTextEdit->setCaption(text); } + bool TextInputDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + onOkClicked(nullptr); + return true; + } + + return false; + } } diff --git a/apps/openmw/mwgui/textinput.hpp b/apps/openmw/mwgui/textinput.hpp index c11d40f1a9..ad7896ff27 100644 --- a/apps/openmw/mwgui/textinput.hpp +++ b/apps/openmw/mwgui/textinput.hpp @@ -27,6 +27,7 @@ namespace MWGui protected: void onOkClicked(MyGUI::Widget* _sender); void onTextAccepted(MyGUI::EditBox* _sender); + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; private: MyGUI::EditBox* mTextEdit; From b2620c861a43ef5655c11d68a7515a856b36f3cc Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 11 May 2025 22:24:05 -0700 Subject: [PATCH 021/330] Add scrollbar override to capture mouse hover events --- apps/openmw/mwgui/waitdialog.cpp | 2 ++ apps/openmw/mwgui/waitdialog.hpp | 3 ++- components/CMakeLists.txt | 2 +- components/widgets/scrollbar.cpp | 17 +++++++++++++++++ components/widgets/scrollbar.hpp | 18 ++++++++++++++++++ components/widgets/widgets.cpp | 2 ++ 6 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 components/widgets/scrollbar.cpp create mode 100644 components/widgets/scrollbar.hpp diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 3c39590dee..5b92699982 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -84,6 +84,8 @@ namespace MWGui trackFocusEvents(mUntilHealedButton); trackFocusEvents(mWaitButton); trackFocusEvents(mCancelButton); + for (MyGUI::Widget* widget : mHourSlider->getAllWidgets()) + trackFocusEvents(widget); } void WaitDialog::setPtr(const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 8a38dd0976..0d6d2a82d2 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -4,6 +4,7 @@ #include "timeadvancer.hpp" #include "windowbase.hpp" #include +#include namespace MWGui { @@ -53,7 +54,7 @@ namespace MWGui MyGUI::Button* mUntilHealedButton; MyGUI::Button* mWaitButton; MyGUI::Button* mCancelButton; - MyGUI::ScrollBar* mHourSlider; + Gui::ScrollBar* mHourSlider; TimeAdvancer mTimeAdvancer; bool mSleeping; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 7659de0ffd..6e6d3ee984 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -353,7 +353,7 @@ add_component_dir (myguiplatform ) add_component_dir (widgets - box fontwrapper imagebutton tags list numericeditbox sharedstatebutton windowcaption widgets + box fontwrapper imagebutton tags list numericeditbox scrollbar sharedstatebutton windowcaption widgets ) add_component_dir (fontloader diff --git a/components/widgets/scrollbar.cpp b/components/widgets/scrollbar.cpp new file mode 100644 index 0000000000..0384003e65 --- /dev/null +++ b/components/widgets/scrollbar.cpp @@ -0,0 +1,17 @@ +#include "scrollbar.hpp" + +#include + +namespace Gui +{ + std::vector ScrollBar::getAllWidgets() + { + std::vector widgets; + widgets.push_back(mWidgetStart); + widgets.push_back(mWidgetEnd); + widgets.push_back(mWidgetTrack); + widgets.push_back(mWidgetFirstPart); + widgets.push_back(mWidgetSecondPart); + return widgets; + } +} diff --git a/components/widgets/scrollbar.hpp b/components/widgets/scrollbar.hpp new file mode 100644 index 0000000000..fa4cee01f0 --- /dev/null +++ b/components/widgets/scrollbar.hpp @@ -0,0 +1,18 @@ +#ifndef OPENMW_COMPONENTS_WIDGETS_SCROLLBAR_H +#define OPENMW_COMPONENTS_WIDGETS_SCROLLBAR_H + +#include + +namespace Gui +{ + /// @brief A scrollbar that can return all its widgets for binding hover listeners. + class ScrollBar : public MyGUI::ScrollBar + { + MYGUI_RTTI_DERIVED(ScrollBar) + + public: + std::vector getAllWidgets(); + }; +} + +#endif diff --git a/components/widgets/widgets.cpp b/components/widgets/widgets.cpp index d27d7e5fc9..58b5736b30 100644 --- a/components/widgets/widgets.cpp +++ b/components/widgets/widgets.cpp @@ -6,6 +6,7 @@ #include "imagebutton.hpp" #include "list.hpp" #include "numericeditbox.hpp" +#include "scrollbar.hpp" #include "sharedstatebutton.hpp" #include "windowcaption.hpp" @@ -26,6 +27,7 @@ namespace Gui MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); } From 8f415ceab640ea62d97a81d23662d9dca2d75140 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 11 May 2025 22:30:58 -0700 Subject: [PATCH 022/330] Convert UI widgets to local scrollbar implementation --- apps/openmw/mwgui/countdialog.hpp | 4 +++- apps/openmw/mwgui/spellcreationdialog.hpp | 9 +++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/countdialog.hpp b/apps/openmw/mwgui/countdialog.hpp index 9cdf231549..95d4a9a8d4 100644 --- a/apps/openmw/mwgui/countdialog.hpp +++ b/apps/openmw/mwgui/countdialog.hpp @@ -3,6 +3,8 @@ #include "windowbase.hpp" +#include + namespace Gui { class NumericEditBox; @@ -24,7 +26,7 @@ namespace MWGui EventHandle_WidgetInt eventOkClicked; private: - MyGUI::ScrollBar* mSlider; + Gui::ScrollBar* mSlider; Gui::NumericEditBox* mItemEdit; MyGUI::TextBox* mItemText; MyGUI::TextBox* mLabelText; diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index 6dfe61fc57..b2bd71d9c4 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -5,6 +5,7 @@ #include #include +#include #include "referenceinterface.hpp" #include "windowbase.hpp" @@ -57,10 +58,10 @@ namespace MWGui MyGUI::TextBox* mDurationValue; MyGUI::TextBox* mAreaValue; - MyGUI::ScrollBar* mMagnitudeMinSlider; - MyGUI::ScrollBar* mMagnitudeMaxSlider; - MyGUI::ScrollBar* mDurationSlider; - MyGUI::ScrollBar* mAreaSlider; + Gui::ScrollBar* mMagnitudeMinSlider; + Gui::ScrollBar* mMagnitudeMaxSlider; + Gui::ScrollBar* mDurationSlider; + Gui::ScrollBar* mAreaSlider; MyGUI::TextBox* mAreaText; From c4a87cfe4d15558db843927dcd8f469377540390 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 11 May 2025 22:59:11 -0700 Subject: [PATCH 023/330] Fix selecting saves with mouse controller --- apps/openmw/mwgui/savegamedialog.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index fc6171b8dc..51fa4c6717 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -362,6 +362,12 @@ namespace MWGui } else onSlotSelected(mSaveList, MyGUI::ITEM_NONE); + + if (Settings::gui().mControllerMenus) + { + for (int i = 0; i < mSaveList->getItemCount(); i++) + trackFocusEvents(mSaveList->getWidgetByIndex(i)); + } } std::string formatTimeplayed(const double timeInSeconds) From 83162477ec50199a06c11336fa378736c0efe043 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Mon, 12 May 2025 01:34:28 -0700 Subject: [PATCH 024/330] Basic controller support for all character creation windows --- apps/openmw/mwgui/birth.cpp | 31 ++++ apps/openmw/mwgui/birth.hpp | 2 + apps/openmw/mwgui/class.cpp | 192 ++++++++++++++++++++++- apps/openmw/mwgui/class.hpp | 13 ++ apps/openmw/mwgui/confirmationdialog.hpp | 2 +- apps/openmw/mwgui/race.cpp | 8 + apps/openmw/mwgui/race.hpp | 3 +- apps/openmw/mwgui/review.cpp | 76 +++++++++ apps/openmw/mwgui/review.hpp | 5 + 9 files changed, 322 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 3dfdd17627..bf495273be 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -271,4 +271,35 @@ namespace MWGui mSpellArea->setVisibleVScroll(true); mSpellArea->setViewOffset(MyGUI::IntPoint(0, 0)); } + + bool BirthDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + // Have A button do nothing so mouse controller still works. + return false; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_START) + { + onOkClicked(nullptr); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + { + onBackClicked(nullptr); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) + { + MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); + winMgr->setKeyFocusWidget(mBirthList); + winMgr->injectKeyPress(MyGUI::KeyCode::ArrowUp, 0, false); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + { + MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); + winMgr->setKeyFocusWidget(mBirthList); + winMgr->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); + } + + return true; + } } diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index db9e997b6c..20db2b70de 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -55,6 +55,8 @@ namespace MWGui std::vector mSpellItems; ESM::RefId mCurrentBirthId; + + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; }; } #endif diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 839f0f5072..25218c9e25 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "tooltips.hpp" @@ -46,15 +47,20 @@ namespace MWGui getWidget(mClassImage, "ClassImage"); getWidget(mClassName, "ClassName"); - MyGUI::Button* backButton; - getWidget(backButton, "BackButton"); - backButton->setCaptionWithReplacing("#{sMessageQuestionAnswer3}"); - backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onBackClicked); + getWidget(mBackButton, "BackButton"); + mBackButton->setCaptionWithReplacing("#{sMessageQuestionAnswer3}"); + mBackButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onBackClicked); - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->setCaptionWithReplacing("#{sMessageQuestionAnswer2}"); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked); + getWidget(mOkButton, "OKButton"); + mOkButton->setCaptionWithReplacing("#{sMessageQuestionAnswer2}"); + mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked); + + if (Settings::gui().mControllerMenus) + { + mOkButton->setStateSelected(true); + trackFocusEvents(mBackButton); + trackFocusEvents(mOkButton); + } center(); } @@ -71,6 +77,33 @@ namespace MWGui center(); } + bool GenerateClassResultDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + if (mMouseFocus != nullptr) + return false; + + if (mOkButtonFocus) + onOkClicked(mOkButton); + else + onBackClicked(mBackButton); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + { + onBackClicked(mBackButton); + } + else if ((arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && mOkButtonFocus) || + (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && !mOkButtonFocus)) + { + mOkButtonFocus = !mOkButtonFocus; + mOkButton->setStateSelected(mOkButtonFocus); + mBackButton->setStateSelected(!mOkButtonFocus); + } + + return true; + } + // widget controls void GenerateClassResultDialog::onOkClicked(MyGUI::Widget* _sender) @@ -278,6 +311,37 @@ namespace MWGui setClassImage(mClassImage, mCurrentClassId); } + bool PickClassDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + // Have A button do nothing so mouse controller still works. + return false; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_START) + { + onOkClicked(nullptr); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + { + onBackClicked(nullptr); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) + { + MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); + winMgr->setKeyFocusWidget(mClassList); + winMgr->injectKeyPress(MyGUI::KeyCode::ArrowUp, 0, false); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + { + MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); + winMgr->setKeyFocusWidget(mClassList); + winMgr->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); + } + + return true; + } + /* InfoBoxDialog */ void InfoBoxDialog::fitToText(MyGUI::TextBox* widget) @@ -353,6 +417,14 @@ namespace MWGui fitToText(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &InfoBoxDialog::onButtonClicked); coord.top += button->getHeight(); + + if (Settings::gui().mControllerMenus && buttons.size() > 1 && this->mButtons.empty()) + { + // First button is selected by default + button->setStateSelected(true); + } + trackFocusEvents(button); + this->mButtons.push_back(button); } } @@ -382,6 +454,53 @@ namespace MWGui } } + bool InfoBoxDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + if (mMouseFocus != nullptr) + return false; + + onButtonClicked(mButtons[mControllerFocus]); + return true; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + { + if (mButtons.size() == 1) + onButtonClicked(mButtons[0]); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) + { + if (mButtons.size() <= 1) + return true; + if (mButtons.size() == 2 && mControllerFocus == 0) + return true; + + mButtons[mControllerFocus]->setStateSelected(false); + if (mControllerFocus == 0) + mControllerFocus = mButtons.size() - 1; + else + mControllerFocus--; + mButtons[mControllerFocus]->setStateSelected(true); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + { + if (mButtons.size() <= 1) + return true; + if (mButtons.size() == 2 && mControllerFocus == mButtons.size() - 1) + return true; + + mButtons[mControllerFocus]->setStateSelected(false); + if (mControllerFocus == mButtons.size() - 1) + mControllerFocus = 0; + else + mControllerFocus++; + mButtons[mControllerFocus]->setStateSelected(true); + } + + return true; + } + /* ClassChoiceDialog */ ClassChoiceDialog::ClassChoiceDialog() @@ -552,6 +671,24 @@ namespace MWGui MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", {}))); } + bool CreateClassDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + // Have A button do nothing so mouse controller still works. + return false; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_START) + { + onOkClicked(nullptr); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + { + onBackClicked(nullptr); + } + return true; + } + // widget controls void CreateClassDialog::onDialogCancel() @@ -739,6 +876,16 @@ namespace MWGui return true; } + bool SelectSpecializationDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_B) + { + onCancelClicked(nullptr); + return true; + } + return false; + } + /* SelectAttributeDialog */ SelectAttributeDialog::SelectAttributeDialog() @@ -791,6 +938,16 @@ namespace MWGui return true; } + bool SelectAttributeDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_B) + { + onCancelClicked(nullptr); + return true; + } + return false; + } + /* SelectSkillDialog */ SelectSkillDialog::SelectSkillDialog() @@ -855,6 +1012,16 @@ namespace MWGui return true; } + bool SelectSkillDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_B) + { + onCancelClicked(nullptr); + return true; + } + return false; + } + /* DescriptionDialog */ DescriptionDialog::DescriptionDialog() @@ -904,4 +1071,13 @@ namespace MWGui imageBox->setImageTexture(classImage); } + bool DescriptionDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A || arg.button == SDL_CONTROLLER_BUTTON_B) + { + onOkClicked(nullptr); + return true; + } + return false; + } } diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index f89a0c7d88..4567776beb 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -42,6 +42,7 @@ namespace MWGui protected: void onButtonClicked(MyGUI::Widget* _sender); + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; private: void fitToText(MyGUI::TextBox* widget); @@ -50,6 +51,7 @@ namespace MWGui MyGUI::TextBox* mText; MyGUI::Widget* mButtonBar; std::vector mButtons; + int mControllerFocus = 0; }; // Lets the player choose between 3 ways of creating a class @@ -92,10 +94,14 @@ namespace MWGui protected: void onOkClicked(MyGUI::Widget* _sender); void onBackClicked(MyGUI::Widget* _sender); + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + bool mOkButtonFocus = true; private: MyGUI::ImageBox* mClassImage; MyGUI::TextBox* mClassName; + MyGUI::Button* mBackButton; + MyGUI::Button* mOkButton; ESM::RefId mCurrentClassId; }; @@ -132,6 +138,7 @@ namespace MWGui void onOkClicked(MyGUI::Widget* _sender); void onBackClicked(MyGUI::Widget* _sender); + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; private: void updateClasses(); @@ -173,6 +180,7 @@ namespace MWGui protected: void onSpecializationClicked(MyGUI::Widget* _sender); void onCancelClicked(MyGUI::Widget* _sender); + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; private: MyGUI::TextBox *mSpecialization0, *mSpecialization1, *mSpecialization2; @@ -206,6 +214,7 @@ namespace MWGui protected: void onAttributeClicked(Widgets::MWAttributePtr _sender); void onCancelClicked(MyGUI::Widget* _sender); + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; private: ESM::RefId mAttributeId; @@ -237,6 +246,7 @@ namespace MWGui protected: void onSkillClicked(Widgets::MWSkillPtr _sender); void onCancelClicked(MyGUI::Widget* _sender); + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; private: ESM::RefId mSkillId; @@ -258,6 +268,7 @@ namespace MWGui protected: void onOkClicked(MyGUI::Widget* _sender); + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; private: MyGUI::EditBox* mTextEdit; @@ -329,6 +340,8 @@ namespace MWGui Widgets::MWAttributePtr mAffectedAttribute; Widgets::MWSkillPtr mAffectedSkill; + + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; }; } #endif diff --git a/apps/openmw/mwgui/confirmationdialog.hpp b/apps/openmw/mwgui/confirmationdialog.hpp index 93d7f360c5..9b26e3a3c9 100644 --- a/apps/openmw/mwgui/confirmationdialog.hpp +++ b/apps/openmw/mwgui/confirmationdialog.hpp @@ -29,7 +29,7 @@ namespace MWGui void onOkButtonClicked(MyGUI::Widget* _sender); bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - int mOkButtonFocus = true; + bool mOkButtonFocus = true; }; } diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 6d7ec19f88..6a62fb3b47 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -501,6 +501,14 @@ namespace MWGui winMgr->setKeyFocusWidget(mRaceList); winMgr->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) + { + onPreviewScroll(nullptr, 5); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + { + onPreviewScroll(nullptr, -5); + } return true; } diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index 5452753747..8589743b9e 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -3,6 +3,7 @@ #include "windowbase.hpp" #include +#include #include namespace MWRender @@ -100,7 +101,7 @@ namespace MWGui MyGUI::ImageBox* mPreviewImage; MyGUI::ListBox* mRaceList; - MyGUI::ScrollBar* mHeadRotate; + Gui::ScrollBar* mHeadRotate; MyGUI::Widget* mSkillList; std::vector mSkillItems; diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index ddce2c5f50..b113ace2be 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -46,21 +46,29 @@ namespace MWGui getWidget(button, "NameButton"); adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onNameClicked); + trackFocusEvents(button); + mButtons.push_back(button); getWidget(mRaceWidget, "RaceText"); getWidget(button, "RaceButton"); adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onRaceClicked); + trackFocusEvents(button); + mButtons.push_back(button); getWidget(mClassWidget, "ClassText"); getWidget(button, "ClassButton"); adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onClassClicked); + trackFocusEvents(button); + mButtons.push_back(button); getWidget(mBirthSignWidget, "SignText"); getWidget(button, "SignButton"); adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBirthSignClicked); + trackFocusEvents(button); + mButtons.push_back(button); // Setup dynamic stats getWidget(mHealth, "Health"); @@ -108,10 +116,17 @@ namespace MWGui MyGUI::Button* backButton; getWidget(backButton, "BackButton"); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBackClicked); + trackFocusEvents(backButton); + mButtons.push_back(backButton); MyGUI::Button* okButton; getWidget(okButton, "OKButton"); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onOkClicked); + trackFocusEvents(okButton); + mButtons.push_back(okButton); + + if (Settings::gui().mControllerMenus) + mButtons[mControllerFocus]->setStateSelected(true); } void ReviewDialog::onOpen() @@ -522,4 +537,65 @@ namespace MWGui MyGUI::IntPoint(0, static_cast(mSkillView->getViewOffset().top + _rel * 0.3))); } + bool ReviewDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + if (mMouseFocus != nullptr) + return false; + + switch(mControllerFocus) + { + case 0: + onNameClicked(mButtons[0]); + break; + case 1: + onRaceClicked(mButtons[1]); + break; + case 2: + onClassClicked(mButtons[2]); + break; + case 3: + onBirthSignClicked(mButtons[3]); + break; + case 4: + onBackClicked(mButtons[4]); + break; + case 5: + onOkClicked(mButtons[5]); + break; + } + return true; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_START) + { + onOkClicked(mButtons[5]); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + { + onBackClicked(mButtons[4]); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP || + arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) + { + mButtons[mControllerFocus]->setStateSelected(false); + if (mControllerFocus == 0) + mControllerFocus = mButtons.size() - 1; + else + mControllerFocus--; + mButtons[mControllerFocus]->setStateSelected(true); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN || + arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + { + mButtons[mControllerFocus]->setStateSelected(false); + if (mControllerFocus == mButtons.size() - 1) + mControllerFocus = 0; + else + mControllerFocus++; + mButtons[mControllerFocus]->setStateSelected(true); + } + + return true; + } } diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index 7226ad628d..fe53787fe3 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -72,6 +72,7 @@ namespace MWGui void onBirthSignClicked(MyGUI::Widget* _sender); void onMouseWheel(MyGUI::Widget* _sender, int _rel); + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; private: void addSkills(const std::vector& skills, const std::string& titleId, @@ -100,6 +101,10 @@ namespace MWGui std::vector mSkillWidgets; //< Skills and other information bool mUpdateSkillArea; + + // 0 = Name, 1 = Race, 2 = Class, 3 = BirthSign, 4 = Back, 5 = OK + std::vector mButtons; + int mControllerFocus = 5; }; } #endif From 4bad7a30741efed63a19da9fa93098736b67924c Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Mon, 12 May 2025 02:20:28 -0700 Subject: [PATCH 025/330] Update character creation controller support to work better with gamepad mouse mode --- apps/openmw/mwgui/birth.cpp | 48 ++++++++++++----- apps/openmw/mwgui/birth.hpp | 5 ++ apps/openmw/mwgui/class.cpp | 102 +++++++++++++++++++++++++++++------- apps/openmw/mwgui/class.hpp | 12 ++++- apps/openmw/mwgui/race.cpp | 49 ++++++++++------- apps/openmw/mwgui/race.hpp | 4 ++ 6 files changed, 168 insertions(+), 52 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index bf495273be..b121c1978b 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -50,15 +50,16 @@ namespace MWGui mBirthList->eventListSelectAccept += MyGUI::newDelegate(this, &BirthDialog::onAccept); mBirthList->eventListChangePosition += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); - MyGUI::Button* backButton; - getWidget(backButton, "BackButton"); - backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onBackClicked); + getWidget(mBackButton, "BackButton"); + mBackButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onBackClicked); - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->setCaption( + getWidget(mOkButton, "OKButton"); + mOkButton->setCaption( MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", {}))); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked); + mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked); + + if (Settings::gui().mControllerMenus) + mOkButton->setStateSelected(true); updateBirths(); updateSpells(); @@ -277,29 +278,50 @@ namespace MWGui if (arg.button == SDL_CONTROLLER_BUTTON_A) { // Have A button do nothing so mouse controller still works. - return false; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_START) - { - onOkClicked(nullptr); + if (mUsingGamepadGuiCursor) + return false; + + if (mOkButtonFocus) + onOkClicked(mOkButton); + else + onBackClicked(mBackButton); } else if (arg.button == SDL_CONTROLLER_BUTTON_B) { - onBackClicked(nullptr); + onBackClicked(mBackButton); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) { MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); winMgr->setKeyFocusWidget(mBirthList); winMgr->injectKeyPress(MyGUI::KeyCode::ArrowUp, 0, false); + mUsingGamepadGuiCursor = false; } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) { MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); winMgr->setKeyFocusWidget(mBirthList); winMgr->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); + mUsingGamepadGuiCursor = false; + } + else if ((arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && mOkButtonFocus) || + (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && !mOkButtonFocus)) + { + mOkButtonFocus = !mOkButtonFocus; + mOkButton->setStateSelected(mOkButtonFocus); + mBackButton->setStateSelected(!mOkButtonFocus); + mUsingGamepadGuiCursor = false; } return true; } + + bool BirthDialog::onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) + { + if (arg.axis == SDL_CONTROLLER_AXIS_LEFTX || arg.axis == SDL_CONTROLLER_AXIS_LEFTY) + { + mUsingGamepadGuiCursor = true; + } + return false; + } } diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index 20db2b70de..8a7190b934 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -53,10 +53,15 @@ namespace MWGui MyGUI::ScrollView* mSpellArea; MyGUI::ImageBox* mBirthImage; std::vector mSpellItems; + MyGUI::Button* mBackButton; + MyGUI::Button* mOkButton; ESM::RefId mCurrentBirthId; bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) override; + bool mOkButtonFocus = true; + bool mUsingGamepadGuiCursor = false; }; } #endif diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 25218c9e25..a7b5b36aa5 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -143,13 +143,14 @@ namespace MWGui getWidget(mClassImage, "ClassImage"); - MyGUI::Button* backButton; - getWidget(backButton, "BackButton"); - backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onBackClicked); + getWidget(mBackButton, "BackButton"); + mBackButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onBackClicked); - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onOkClicked); + getWidget(mOkButton, "OKButton"); + mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onOkClicked); + + if (Settings::gui().mControllerMenus) + mOkButton->setStateSelected(true); updateClasses(); updateStats(); @@ -316,32 +317,53 @@ namespace MWGui if (arg.button == SDL_CONTROLLER_BUTTON_A) { // Have A button do nothing so mouse controller still works. - return false; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_START) - { - onOkClicked(nullptr); + if (mUsingGamepadGuiCursor) + return false; + + if (mOkButtonFocus) + onOkClicked(mOkButton); + else + onBackClicked(mBackButton); } else if (arg.button == SDL_CONTROLLER_BUTTON_B) { - onBackClicked(nullptr); + onBackClicked(mBackButton); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) { MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); winMgr->setKeyFocusWidget(mClassList); winMgr->injectKeyPress(MyGUI::KeyCode::ArrowUp, 0, false); + mUsingGamepadGuiCursor = false; } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) { MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); winMgr->setKeyFocusWidget(mClassList); winMgr->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); + mUsingGamepadGuiCursor = false; + } + else if ((arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && mOkButtonFocus) || + (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && !mOkButtonFocus)) + { + mOkButtonFocus = !mOkButtonFocus; + mOkButton->setStateSelected(mOkButtonFocus); + mBackButton->setStateSelected(!mOkButtonFocus); + mUsingGamepadGuiCursor = false; } return true; } + bool PickClassDialog::onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) + { + if (arg.axis == SDL_CONTROLLER_AXIS_LEFTX || arg.axis == SDL_CONTROLLER_AXIS_LEFTY) + { + mUsingGamepadGuiCursor = true; + } + return false; + } + /* InfoBoxDialog */ void InfoBoxDialog::fitToText(MyGUI::TextBox* widget) @@ -569,14 +591,20 @@ namespace MWGui MyGUI::Button* descriptionButton; getWidget(descriptionButton, "DescriptionButton"); descriptionButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionClicked); + mButtons.push_back(descriptionButton); MyGUI::Button* backButton; getWidget(backButton, "BackButton"); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onBackClicked); + mButtons.push_back(backButton); MyGUI::Button* okButton; getWidget(okButton, "OKButton"); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onOkClicked); + mButtons.push_back(okButton); + + if (Settings::gui().mControllerMenus) + okButton->setStateSelected(true); // Set default skills, attributes @@ -676,19 +704,57 @@ namespace MWGui if (arg.button == SDL_CONTROLLER_BUTTON_A) { // Have A button do nothing so mouse controller still works. - return false; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_START) - { - onOkClicked(nullptr); + if (mUsingGamepadGuiCursor) + return false; + + if (mControllerFocus == 0) + onDescriptionClicked(mButtons[0]); + else if (mControllerFocus == 1) + onBackClicked(mButtons[1]); + else + onOkClicked(mButtons[2]); } else if (arg.button == SDL_CONTROLLER_BUTTON_B) { - onBackClicked(nullptr); + onBackClicked(mButtons[1]); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP || + arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + { + mUsingGamepadGuiCursor = false; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) + { + mButtons[mControllerFocus]->setStateSelected(false); + if (mControllerFocus == 0) + mControllerFocus = mButtons.size() - 1; + else + mControllerFocus--; + mButtons[mControllerFocus]->setStateSelected(true); + mUsingGamepadGuiCursor = false; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + { + mButtons[mControllerFocus]->setStateSelected(false); + if (mControllerFocus == mButtons.size() - 1) + mControllerFocus = 0; + else + mControllerFocus++; + mButtons[mControllerFocus]->setStateSelected(true); + mUsingGamepadGuiCursor = false; } return true; } + bool CreateClassDialog::onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) + { + if (arg.axis == SDL_CONTROLLER_AXIS_LEFTX || arg.axis == SDL_CONTROLLER_AXIS_LEFTY) + { + mUsingGamepadGuiCursor = true; + } + return false; + } + // widget controls void CreateClassDialog::onDialogCancel() diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index 4567776beb..e2566ce6c0 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -138,7 +138,6 @@ namespace MWGui void onOkClicked(MyGUI::Widget* _sender); void onBackClicked(MyGUI::Widget* _sender); - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; private: void updateClasses(); @@ -147,11 +146,18 @@ namespace MWGui MyGUI::ImageBox* mClassImage; MyGUI::ListBox* mClassList; MyGUI::TextBox* mSpecializationName; + MyGUI::Button* mBackButton; + MyGUI::Button* mOkButton; Widgets::MWAttributePtr mFavoriteAttribute[2]; Widgets::MWSkillPtr mMajorSkill[5]; Widgets::MWSkillPtr mMinorSkill[5]; ESM::RefId mCurrentClassId; + + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) override; + bool mOkButtonFocus = true; + bool mUsingGamepadGuiCursor = false; }; class SelectSpecializationDialog : public WindowModal @@ -325,6 +331,7 @@ namespace MWGui private: MyGUI::EditBox* mEditName; MyGUI::TextBox* mSpecializationName; + std::vector mButtons; Widgets::MWAttributePtr mFavoriteAttribute0, mFavoriteAttribute1; std::array mMajorSkill; std::array mMinorSkill; @@ -342,6 +349,9 @@ namespace MWGui Widgets::MWSkillPtr mAffectedSkill; bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) override; + int mControllerFocus = 2; + bool mUsingGamepadGuiCursor = false; }; } #endif diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 6a62fb3b47..1ff5cc4784 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -108,15 +108,16 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu7", "Specials")); getWidget(mSpellPowerList, "SpellPowerList"); - MyGUI::Button* backButton; - getWidget(backButton, "BackButton"); - backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onBackClicked); + getWidget(mBackButton, "BackButton"); + mBackButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onBackClicked); - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->setCaption( + getWidget(mOkButton, "OKButton"); + mOkButton->setCaption( MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", {}))); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onOkClicked); + mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onOkClicked); + + if (Settings::gui().mControllerMenus) + mOkButton->setStateSelected(true); updateRaces(); updateSkills(); @@ -467,15 +468,17 @@ namespace MWGui if (arg.button == SDL_CONTROLLER_BUTTON_A) { // Have A button do nothing so mouse controller still works. - return false; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_START) - { - onOkClicked(nullptr); + if (mUsingGamepadGuiCursor) + return false; + + if (mOkButtonFocus) + onOkClicked(mOkButton); + else + onBackClicked(mBackButton); } else if (arg.button == SDL_CONTROLLER_BUTTON_B) { - onBackClicked(nullptr); + onBackClicked(mBackButton); } else if (arg.button == SDL_CONTROLLER_BUTTON_X) { @@ -494,20 +497,22 @@ namespace MWGui MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); winMgr->setKeyFocusWidget(mRaceList); winMgr->injectKeyPress(MyGUI::KeyCode::ArrowUp, 0, false); + mUsingGamepadGuiCursor = false; } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) { MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); winMgr->setKeyFocusWidget(mRaceList); winMgr->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); + mUsingGamepadGuiCursor = false; } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) + else if ((arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && mOkButtonFocus) || + (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && !mOkButtonFocus)) { - onPreviewScroll(nullptr, 5); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) - { - onPreviewScroll(nullptr, -5); + mOkButtonFocus = !mOkButtonFocus; + mOkButton->setStateSelected(mOkButtonFocus); + mBackButton->setStateSelected(!mOkButtonFocus); + mUsingGamepadGuiCursor = false; } return true; @@ -515,7 +520,11 @@ namespace MWGui bool RaceDialog::onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) { - if (arg.axis == SDL_CONTROLLER_AXIS_RIGHTX) + if (arg.axis == SDL_CONTROLLER_AXIS_LEFTX || arg.axis == SDL_CONTROLLER_AXIS_LEFTY) + { + mUsingGamepadGuiCursor = true; + } + else if (arg.axis == SDL_CONTROLLER_AXIS_RIGHTX) { if (arg.value < -1000 || arg.value > 1000) onPreviewScroll(nullptr, arg.value < 0 ? 1 : -1); diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index 8589743b9e..c3b322ba8b 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -102,6 +102,8 @@ namespace MWGui MyGUI::ImageBox* mPreviewImage; MyGUI::ListBox* mRaceList; Gui::ScrollBar* mHeadRotate; + MyGUI::Button* mBackButton; + MyGUI::Button* mOkButton; MyGUI::Widget* mSkillList; std::vector mSkillItems; @@ -122,6 +124,8 @@ namespace MWGui bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) override; + bool mOkButtonFocus = true; + bool mUsingGamepadGuiCursor = false; }; } #endif From a78bdee941b0b1f585cf4702b356c90444a63bf8 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Mon, 12 May 2025 20:08:47 -0700 Subject: [PATCH 026/330] Reset selected button when confirmation dialog is reopened --- apps/openmw/mwgui/confirmationdialog.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index 67da1f94a7..b284db16b2 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -22,7 +22,6 @@ namespace MWGui if (Settings::gui().mControllerMenus) { - mOkButton->setStateSelected(true); trackFocusEvents(mOkButton); trackFocusEvents(mCancelButton); } @@ -44,6 +43,13 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mOkButton); + if (Settings::gui().mControllerMenus) + { + mOkButtonFocus = true; + mOkButton->setStateSelected(true); + mCancelButton->setStateSelected(false); + } + center(); } From fa52fea59b2a5bca2f4574a430f76fb7ee91495b Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Mon, 12 May 2025 20:09:24 -0700 Subject: [PATCH 027/330] Better joystick/mouse coordination in save game diaglog --- apps/openmw/mwgui/savegamedialog.cpp | 44 +++++++++++++++++++++------- apps/openmw/mwgui/savegamedialog.hpp | 7 +++-- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 51fa4c6717..37ed137b23 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -161,6 +161,13 @@ namespace MWGui mSaveList->removeAllItems(); onSlotSelected(mSaveList, MyGUI::ITEM_NONE); + if (Settings::gui().mControllerMenus) + { + mOkButtonFocus = true; + mOkButton->setStateSelected(true); + mCancelButton->setStateSelected(false); + } + MWBase::StateManager* mgr = MWBase::Environment::get().getStateManager(); if (mgr->characterBegin() == mgr->characterEnd()) return; @@ -501,30 +508,40 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - if (mMouseFocus != nullptr) + // Have A button do nothing so mouse controller still works. + if (mUsingGamepadGuiCursor) return false; - onOkButtonClicked(mOkButton); - return true; + if (mOkButtonFocus) + onOkButtonClicked(mOkButton); + else + onCancelButtonClicked(mCancelButton); } else if (arg.button == SDL_CONTROLLER_BUTTON_B) { onCancelButtonClicked(mCancelButton); - return true; } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) { MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); winMgr->setKeyFocusWidget(mSaveList); winMgr->injectKeyPress(MyGUI::KeyCode::ArrowUp, 0, false); - return true; + mUsingGamepadGuiCursor = false; } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) { MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); winMgr->setKeyFocusWidget(mSaveList); winMgr->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); - return true; + mUsingGamepadGuiCursor = false; + } + else if ((arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && !mOkButtonFocus) || + (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && mOkButtonFocus)) + { + mOkButtonFocus = !mOkButtonFocus; + mOkButton->setStateSelected(mOkButtonFocus); + mCancelButton->setStateSelected(!mOkButtonFocus); + mUsingGamepadGuiCursor = false; } else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) { @@ -534,8 +551,7 @@ namespace MWGui else index--; mCharacterSelection->setIndexSelected(index); - - return true; + mUsingGamepadGuiCursor = false; } else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) { @@ -545,10 +561,18 @@ namespace MWGui else index++; mCharacterSelection->setIndexSelected(index); - - return true; + mUsingGamepadGuiCursor = false; } + return true; + } + + bool SaveGameDialog::onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) + { + if (arg.axis == SDL_CONTROLLER_AXIS_LEFTX || arg.axis == SDL_CONTROLLER_AXIS_LEFTY) + { + mUsingGamepadGuiCursor = true; + } return false; } } diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index caabff2431..2561fc60f6 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -24,8 +24,6 @@ namespace MWGui void setLoadOrSave(bool load); - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - private: void confirmDeleteSave(); @@ -68,6 +66,11 @@ namespace MWGui const MWState::Character* mCurrentCharacter; const MWState::Slot* mCurrentSlot; + + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) override; + bool mOkButtonFocus = true; + bool mUsingGamepadGuiCursor = false; }; } From 07be682b885940ad80b244de8f5b7a323b984223 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Mon, 12 May 2025 20:10:13 -0700 Subject: [PATCH 028/330] Better controller support for journal; mouse for topic index A-Z --- apps/openmw/mwgui/journalwindow.cpp | 163 +++++++++++++++++++++++----- apps/openmw/mwgui/journalwindow.hpp | 4 + 2 files changed, 139 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 7fd6e3d995..3dc46459b4 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -248,6 +248,8 @@ namespace } updateShowingPages(); + mSelectedQuest = 0; + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(getWidget(CloseBTN)); } @@ -469,6 +471,20 @@ namespace MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("book page")); } + void addControllerButtons(Gui::MWList* _list, int _selectedIndex) + { + mButtons.clear(); + for (int i = 0; i < _list->getItemCount(); i++) + { + MyGUI::Button* listItem = _list->getItemWidget(_list->getItemNameAt(i)); + if (listItem) + { + listItem->setStateSelected(mButtons.size() == _selectedIndex); + mButtons.push_back(listItem); + } + } + } + void notifyIndexLinkClicked(MWGui::TypesetBook::InteractiveId index) { setVisible(LeftTopicIndex, false); @@ -487,6 +503,9 @@ namespace list->adjustSize(); + if (Settings::gui().mControllerMenus) + addControllerButtons(list, mSelectedQuest); + MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("book page")); } @@ -554,6 +573,9 @@ namespace list->sort(); list->adjustSize(); + if (Settings::gui().mControllerMenus) + addControllerButtons(list, mSelectedQuest); + if (mAllQuests) { SetNamesInactive setInactive(list); @@ -642,64 +664,149 @@ namespace bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override { - if (arg.button == SDL_CONTROLLER_BUTTON_A) + if (arg.button == SDL_CONTROLLER_BUTTON_A) // A: Mouse click or Select { // Fall through to mouse click - return false; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - { - if (mOptionsMode) - notifyCancel(getWidget(CancelBTN)); - else if (mStates.size() > 1) - notifyJournal(getWidget(JournalBTN)); - else - notifyClose(getWidget(CloseBTN)); - return true; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_X) - { - if (mQuestMode) + if (mUsingGamepadGuiCursor) + return false; + + if (mOptionsMode && mQuestMode) { - if (!mOptionsMode) - notifyOptions(getWidget(OptionsBTN)); - notifyTopics(getWidget(TopicsBTN)); + // Choose a quest + Gui::MWList* list = getWidget(QuestsList); + notifyQuestClicked(list->getItemNameAt(mSelectedQuest), 0); + } + else if (mOptionsMode && mTopicsMode) + { + // Choose a topic + Gui::MWList* list = getWidget(TopicsList); + notifyTopicSelected(list->getItemNameAt(mSelectedQuest), 0); } return true; } - else if (arg.button == SDL_CONTROLLER_BUTTON_Y) + else if (arg.button == SDL_CONTROLLER_BUTTON_B) // B: Back { - if (!mQuestMode) + if (mOptionsMode) { + // Hide the options overlay + notifyCancel(getWidget(CancelBTN)); + mQuestMode = false; + } + else if (mStates.size() > 1) + { + // Pop the current book. If in quest mode, reopen the quest list. + notifyJournal(getWidget(JournalBTN)); + if (mQuestMode) + { + notifyOptions(getWidget(OptionsBTN)); + notifyQuests(getWidget(QuestsBTN)); + } + } + else + { + // Close the journal window + notifyClose(getWidget(CloseBTN)); + } + return true; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_Y) // Y: Quests + { + if (mOptionsMode && mQuestMode) + { + // Hide the quest overlay if visible + notifyCancel(getWidget(CancelBTN)); + mQuestMode = false; + } + else { + // Show the quest overlay if viewing a journal entry or the topics if (!mOptionsMode) notifyOptions(getWidget(OptionsBTN)); - notifyQuests(getWidget(QuestsBTN)); + if (!mQuestMode) + notifyQuests(getWidget(QuestsBTN)); + } + return true; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_X) // X: Topics + { + if (mOptionsMode && !mQuestMode) + { + // Hide the topics overlay if visible + notifyCancel(getWidget(CancelBTN)); + mQuestMode = false; + } + else { + // Show the topics overlay if viewing a journal entry or the quest list + if (!mOptionsMode) + notifyOptions(getWidget(OptionsBTN)); + if (mQuestMode) + notifyTopics(getWidget(TopicsBTN)); } return true; } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) { + if (mOptionsMode && (mQuestMode || mTopicsMode)) + { + // Scroll through the list of quests or topics + mButtons[mSelectedQuest]->setStateSelected(false); + mSelectedQuest--; + if (mSelectedQuest < 0) + mSelectedQuest = mButtons.size() - 1; + mButtons[mSelectedQuest]->setStateSelected(true); + } + mUsingGamepadGuiCursor = false; return true; } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) { + if (mOptionsMode && (mQuestMode || mTopicsMode)) + { + // Scroll through the list of quests or topics + mButtons[mSelectedQuest]->setStateSelected(false); + mSelectedQuest++; + if (mSelectedQuest > mButtons.size() - 1) + mSelectedQuest = 0; + mButtons[mSelectedQuest]->setStateSelected(true); + } + mUsingGamepadGuiCursor = false; return true; } - else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER || - arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) { - notifyPrevPage(getWidget(PrevPageBTN)); + if (!mOptionsMode) + notifyPrevPage(getWidget(PrevPageBTN)); + mUsingGamepadGuiCursor = false; return true; } - else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER || - arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) { - notifyNextPage(getWidget(NextPageBTN)); + if (!mOptionsMode) + notifyNextPage(getWidget(NextPageBTN)); + mUsingGamepadGuiCursor = false; + return true; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) // LB: Previous Page + { + if (!mOptionsMode) + notifyPrevPage(getWidget(PrevPageBTN)); + return true; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) // RB: Next Page + { + if (!mOptionsMode) + notifyNextPage(getWidget(NextPageBTN)); return true; } return false; } + + bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) override + { + if (arg.axis == SDL_CONTROLLER_AXIS_LEFTX || arg.axis == SDL_CONTROLLER_AXIS_LEFTY) + mUsingGamepadGuiCursor = true; + return false; + } }; } diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index 22e7048acf..5da2038575 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -31,6 +31,10 @@ namespace MWGui void setVisible(bool newValue) override = 0; std::string_view getWindowIdForLua() const override { return "Journal"; } + + std::vector mButtons; + int mSelectedQuest = 0; + bool mUsingGamepadGuiCursor = false; }; } From 9aff9cb48e728dd0f71223ea20f070b9b3ba58c3 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Mon, 12 May 2025 20:31:15 -0700 Subject: [PATCH 029/330] Swap Topics and Quests buttons --- apps/openmw/mwgui/journalwindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 3dc46459b4..907de6f515 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -709,7 +709,7 @@ namespace } return true; } - else if (arg.button == SDL_CONTROLLER_BUTTON_Y) // Y: Quests + else if (arg.button == SDL_CONTROLLER_BUTTON_X) // X: Quests { if (mOptionsMode && mQuestMode) { @@ -726,7 +726,7 @@ namespace } return true; } - else if (arg.button == SDL_CONTROLLER_BUTTON_X) // X: Topics + else if (arg.button == SDL_CONTROLLER_BUTTON_Y) // Y: Topics { if (mOptionsMode && !mQuestMode) { From 9a72ecb61c2f045d9945cdf6e646c37c0a7e8754 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Mon, 12 May 2025 20:32:59 -0700 Subject: [PATCH 030/330] Don't close a book with A --- apps/openmw/mwgui/bookwindow.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 91b1af615e..90d3c4143a 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -231,8 +231,6 @@ namespace MWGui if (mTakeButton->getVisible()) onTakeButtonClicked(mTakeButton); - else - onCloseButtonClicked(mCloseButton); return true; } else if (arg.button == SDL_CONTROLLER_BUTTON_B) From 65bab3858a2570f66bd78719ac4469c19c444e88 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Mon, 12 May 2025 22:36:28 -0700 Subject: [PATCH 031/330] Add basic controller support to scrolls --- apps/openmw/mwgui/scrollwindow.cpp | 43 ++++++++++++++++++++++++++++++ apps/openmw/mwgui/scrollwindow.hpp | 3 +++ 2 files changed, 46 insertions(+) diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 0b1658fd84..7c7ad338ce 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -7,6 +7,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/inputmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwmechanics/actorutil.hpp" @@ -28,9 +29,11 @@ namespace MWGui getWidget(mCloseButton, "CloseButton"); mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ScrollWindow::onCloseButtonClicked); + trackFocusEvents(mCloseButton); getWidget(mTakeButton, "TakeButton"); mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ScrollWindow::onTakeButtonClicked); + trackFocusEvents(mTakeButton); adjustButton("CloseButton"); adjustButton("TakeButton"); @@ -115,4 +118,44 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); } + + void ScrollWindow::onClose() + { + if (Settings::gui().mControllerMenus) + MWBase::Environment::get().getInputManager()->setGamepadGuiCursorEnabled(true); + BookWindowBase::onClose(); + } + + bool ScrollWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + if (mMouseFocus != nullptr) + return false; + + if (mTakeButton->getVisible()) + onTakeButtonClicked(mTakeButton); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + onCloseButtonClicked(mCloseButton); + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) + onKeyButtonPressed(nullptr, MyGUI::KeyCode::ArrowUp, 0); + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + onKeyButtonPressed(nullptr, MyGUI::KeyCode::ArrowDown, 0); + + return true; + } + + bool ScrollWindow::onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) + { + if (arg.axis == SDL_CONTROLLER_AXIS_RIGHTY) + { + MWBase::Environment::get().getInputManager()->setGamepadGuiCursorEnabled(false); + + int scroll = -30.0f * arg.value / 32767; + mTextView->setViewOffset(mTextView->getViewOffset() + MyGUI::IntPoint(0, scroll)); + return true; + } + return false; + } } diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 7daea98894..fa3ca5b25d 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -20,6 +20,7 @@ namespace MWGui void setPtr(const MWWorld::Ptr& scroll) override; void setInventoryAllowed(bool allowed); + void onClose() override; void onResChange(int, int) override { center(); } std::string_view getWindowIdForLua() const override { return "Scroll"; } @@ -29,6 +30,8 @@ namespace MWGui void onTakeButtonClicked(MyGUI::Widget* _sender); void setTakeButtonShow(bool show); void onKeyButtonPressed(MyGUI::Widget* sender, MyGUI::KeyCode key, MyGUI::Char character); + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) override; private: Gui::ImageButton* mCloseButton; From 77e17743f7d216d3d5d6a8392e735b7deb3a655b Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Mon, 12 May 2025 22:37:11 -0700 Subject: [PATCH 032/330] Only use bumpers to turn pages in books --- apps/openmw/mwgui/bookwindow.cpp | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 90d3c4143a..79cfb9fa88 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -231,31 +231,14 @@ namespace MWGui if (mTakeButton->getVisible()) onTakeButtonClicked(mTakeButton); - return true; } else if (arg.button == SDL_CONTROLLER_BUTTON_B) - { onCloseButtonClicked(mCloseButton); - return true; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP || - arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - { - return true; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER || - arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) - { + else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) prevPage(); - return true; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER || - arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) - { + else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) nextPage(); - return true; - } - return false; + return true; } } From f055ccf5bac2525177492e749cead48e5f253aa1 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Wed, 14 May 2025 02:31:32 -0700 Subject: [PATCH 033/330] Update item view to allow controller support; test it in Container menu --- apps/openmw/mwgui/container.cpp | 80 ++++++++++++++++++- apps/openmw/mwgui/container.hpp | 5 ++ apps/openmw/mwgui/itemview.cpp | 71 ++++++++++++++-- apps/openmw/mwgui/itemview.hpp | 10 +++ apps/openmw/mwgui/itemwidget.cpp | 13 +++ apps/openmw/mwgui/itemwidget.hpp | 3 + files/data/CMakeLists.txt | 1 + files/data/mygui/openmw_resources.xml | 4 + files/data/textures/omw_menu_icon_active.dds | Bin 0 -> 5616 bytes 9 files changed, 181 insertions(+), 6 deletions(-) create mode 100644 files/data/textures/omw_menu_icon_active.dds diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 6ab2c862d4..658eedfcd2 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -3,6 +3,8 @@ #include #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/scriptmanager.hpp" @@ -88,8 +90,13 @@ namespace MWGui name += MWGui::ToolTips::getSoulString(object.getCellRef()); dialog->openCountDialog(name, "#{sTake}", count); dialog->eventOkClicked.clear(); - dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerWindow::dragItem); + if (Settings::gui().mControllerMenus && !mUsingGamepadGuiCursor) + dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerWindow::takeItem); + else + dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerWindow::dragItem); } + else if (Settings::gui().mControllerMenus && !mUsingGamepadGuiCursor) + takeItem(nullptr, count); else dragItem(nullptr, count); } @@ -105,6 +112,30 @@ namespace MWGui mDragAndDrop->startDrag(mSelectedItem, mSortModel, mModel, mItemView, count); } + void ContainerWindow::takeItem(MyGUI::Widget* sender, int count) + { + if (!mModel) + return; + + const ItemStack& item = mModel->getItem(mSelectedItem); + if (!onTakeItem(item, count)) + return; + + MWGui::InventoryWindow* inventoryWindow + = MWBase::Environment::get().getWindowManager()->getInventoryWindow(); + ItemModel* playerModel = inventoryWindow->getModel(); + + mModel->moveItem(item, count, playerModel); + + inventoryWindow->updateItemView(); + mItemView->update(); + + // play the item's sound + MWWorld::Ptr itemBase = item.mBase; + const ESM::RefId& sound = itemBase.getClass().getUpSoundId(itemBase); + MWBase::Environment::get().getWindowManager()->playSound(sound); + } + void ContainerWindow::dropItem() { if (!mModel) @@ -320,4 +351,51 @@ namespace MWGui if (mModel && mModel->usesContainer(ptr)) MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); } + + bool ContainerWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + if (mUsingGamepadGuiCursor) + return false; + + int index = mItemView->getControllerFocus(); + if (index >= 0 && index < mItemView->getItemCount()) + { + onItemSelected(index); + } + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + { + onCloseButtonClicked(mCloseButton); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_X) + { + onTakeAllButtonClicked(mTakeButton); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) + { + if (mDisposeCorpseButton->getVisible()) + onDisposeCorpseButtonClicked(mDisposeCorpseButton); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP || + arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN || + arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT || + arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + { + mItemView->onControllerButtonEvent(arg); + mUsingGamepadGuiCursor = false; + } + + return true; + } + + bool ContainerWindow::onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) + { + if (arg.axis == SDL_CONTROLLER_AXIS_LEFTX || arg.axis == SDL_CONTROLLER_AXIS_LEFTY) + { + mUsingGamepadGuiCursor = true; + } + return false; + } } diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 555fa8e1ae..5d49b4c3ff 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -55,6 +55,7 @@ namespace MWGui void onItemSelected(int index); void onBackgroundSelected(); void dragItem(MyGUI::Widget* sender, int count); + void takeItem(MyGUI::Widget* sender, int count); void dropItem(); void onCloseButtonClicked(MyGUI::Widget* _sender); void onTakeAllButtonClicked(MyGUI::Widget* _sender); @@ -64,6 +65,10 @@ namespace MWGui bool onTakeItem(const ItemStack& item, int count); void onReferenceUnavailable() override; + + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) override; + bool mUsingGamepadGuiCursor = false; }; } #endif // CONTAINER_H diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index ff05a8b2d6..e568da5900 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -7,6 +7,8 @@ #include #include +#include + #include "itemmodel.hpp" #include "itemwidget.hpp" @@ -46,13 +48,14 @@ namespace MWGui MyGUI::Widget* dragArea = mScrollView->getChildAt(0); int maxHeight = mScrollView->getHeight(); - int rows = maxHeight / 42; - rows = std::max(rows, 1); - bool showScrollbar = int(std::ceil(dragArea->getChildCount() / float(rows))) > mScrollView->getWidth() / 42; + mRows = maxHeight / 42; + mRows = std::max(mRows, 1); + mItemCount = dragArea->getChildCount(); + bool showScrollbar = int(std::ceil(mItemCount / float(mRows))) > mScrollView->getWidth() / 42; if (showScrollbar) maxHeight -= 18; - for (unsigned int i = 0; i < dragArea->getChildCount(); ++i) + for (unsigned int i = 0; i < mItemCount; ++i) { MyGUI::Widget* w = dragArea->getChildAt(i); @@ -60,7 +63,7 @@ namespace MWGui y += 42; - if (y > maxHeight - 42 && i < dragArea->getChildCount() - 1) + if (y > maxHeight - 42 && i < mItemCount - 1) { x += 42; y = 0; @@ -70,6 +73,13 @@ namespace MWGui MyGUI::IntSize size = MyGUI::IntSize(std::max(mScrollView->getSize().width, x), mScrollView->getSize().height); + if (Settings::gui().mControllerMenus) + { + if (mControllerFocus >= mItemCount) + mControllerFocus = mItemCount - 1; + updateControllerFocus(-1, mControllerFocus); + } + // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the // scrollbar is hidden mScrollView->setVisibleVScroll(false); @@ -122,6 +132,11 @@ namespace MWGui void ItemView::resetScrollBars() { mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); + if (Settings::gui().mControllerMenus) + { + updateControllerFocus(mControllerFocus, 0); + mControllerFocus = 0; + } } void ItemView::onSelectedItem(MyGUI::Widget* sender) @@ -165,4 +180,50 @@ namespace MWGui MyGUI::FactoryManager::getInstance().registerFactory("Widget"); } + void ItemView::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (!mItemCount) + return; + + int prevFocus = mControllerFocus; + + if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP && mControllerFocus % mRows != 0) + mControllerFocus--; + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN && mControllerFocus % mRows != mRows - 1) + mControllerFocus++; + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && mControllerFocus >= mRows) + mControllerFocus -= mRows; + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && mControllerFocus + mRows < mItemCount) + mControllerFocus += mRows; + + if (mControllerFocus < 0) + mControllerFocus = 0; + else if (mControllerFocus >= mItemCount - 1) + mControllerFocus = mItemCount - 1; + + if (prevFocus != mControllerFocus) + updateControllerFocus(prevFocus, mControllerFocus); + } + + void ItemView::updateControllerFocus(int _prevFocus, int _newFocus) + { + if (!mItemCount) + return; + + MyGUI::Widget* dragArea = mScrollView->getChildAt(0); + + if (_prevFocus >= 0 && _prevFocus < mItemCount) + { + ItemWidget* prev = (ItemWidget *)dragArea->getChildAt(_prevFocus); + if (prev) + prev->setControllerFocus(false); + } + + if (_newFocus >= 0 && _newFocus < mItemCount) + { + ItemWidget* focused = (ItemWidget *)dragArea->getChildAt(_newFocus); + if (focused) + focused->setControllerFocus(true); + } + } } diff --git a/apps/openmw/mwgui/itemview.hpp b/apps/openmw/mwgui/itemview.hpp index cfbc8a37ac..8a53d3678e 100644 --- a/apps/openmw/mwgui/itemview.hpp +++ b/apps/openmw/mwgui/itemview.hpp @@ -2,6 +2,7 @@ #define MWGUI_ITEMVIEW_H #include +#include #include "itemmodel.hpp" @@ -31,6 +32,10 @@ namespace MWGui void resetScrollBars(); + int getControllerFocus() { return mControllerFocus; } + int getItemCount() { return mItemCount; } + void onControllerButtonEvent(const SDL_ControllerButtonEvent& arg); + private: void initialiseOverride() override; @@ -45,6 +50,11 @@ namespace MWGui std::unique_ptr mModel; MyGUI::ScrollView* mScrollView; + + int mItemCount = 0; + int mRows; + int mControllerFocus = 0; + void updateControllerFocus(int prevFocus, int newFocus); }; } diff --git a/apps/openmw/mwgui/itemwidget.cpp b/apps/openmw/mwgui/itemwidget.cpp index 05fff2d40f..5e47577b27 100644 --- a/apps/openmw/mwgui/itemwidget.cpp +++ b/apps/openmw/mwgui/itemwidget.cpp @@ -58,6 +58,7 @@ namespace MWGui : mItem(nullptr) , mItemShadow(nullptr) , mFrame(nullptr) + , mControllerBorder(nullptr) , mText(nullptr) { } @@ -82,10 +83,22 @@ namespace MWGui assignWidget(mText, "Text"); if (mText) mText->setNeedMouseFocus(false); + if (Settings::gui().mControllerMenus) + { + assignWidget(mControllerBorder, "ControllerBorder"); + if (mControllerBorder) + mControllerBorder->setNeedMouseFocus(false); + } Base::initialiseOverride(); } + void ItemWidget::setControllerFocus(bool focus) + { + if (mControllerBorder) + mControllerBorder->setVisible(focus); + } + void ItemWidget::setCount(int count) { if (!mText) diff --git a/apps/openmw/mwgui/itemwidget.hpp b/apps/openmw/mwgui/itemwidget.hpp index 63837ae92f..1191a23342 100644 --- a/apps/openmw/mwgui/itemwidget.hpp +++ b/apps/openmw/mwgui/itemwidget.hpp @@ -40,12 +40,15 @@ namespace MWGui void setIcon(const MWWorld::Ptr& ptr); void setFrame(const std::string& frame, const MyGUI::IntCoord& coord); + void setControllerFocus(bool focus); + protected: void initialiseOverride() override; MyGUI::ImageBox* mItem; MyGUI::ImageBox* mItemShadow; MyGUI::ImageBox* mFrame; + MyGUI::ImageBox* mControllerBorder; MyGUI::TextBox* mText; std::string mCurrentIcon; diff --git a/files/data/CMakeLists.txt b/files/data/CMakeLists.txt index d9218b45b2..0290519806 100644 --- a/files/data/CMakeLists.txt +++ b/files/data/CMakeLists.txt @@ -9,6 +9,7 @@ set(BUILTIN_DATA_FILES textures/omw_menu_scroll_right.dds textures/omw_menu_scroll_center_h.dds textures/omw_menu_scroll_center_v.dds + textures/omw_menu_icon_active.dds textures/omw/water_nm.png fonts/DejaVuFontLicense.txt diff --git a/files/data/mygui/openmw_resources.xml b/files/data/mygui/openmw_resources.xml index 4c32512004..08586ea75c 100644 --- a/files/data/mygui/openmw_resources.xml +++ b/files/data/mygui/openmw_resources.xml @@ -144,6 +144,10 @@ + + + + diff --git a/files/data/textures/omw_menu_icon_active.dds b/files/data/textures/omw_menu_icon_active.dds new file mode 100644 index 0000000000000000000000000000000000000000..be743ace7f84a7e9fa9a9dfa43097909bfec2ff1 GIT binary patch literal 5616 zcmeHLy-piJ5MG~;VCP3VMZy#yamA&K1Vy4qm%@NA$zqQak_g2V3BuM2l<)==79b?L z(-lY*yaS|gO-V_K^MJ^a`{1BN4gji01% z#K+`>J>b51)%pr%wwYm5fALlFWy(K>4#V5;4lXhA`J+DzB!7qagUDG7FU>!SZ+iXH z`?<#++W++?^a|JTodFn`AUc>f3GOGB6MX7crL|C@H-{15AaAekRy zyc$v_?QbsOC2@Y#s_s4_{G}zW9oz47GmU=%B)Y>` literal 0 HcmV?d00001 From 8c2ecc2a884dafe8ed59b59c89bbafb9fb012ef8 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Thu, 15 May 2025 00:46:02 -0700 Subject: [PATCH 034/330] Allow LT and RT to toggle between open gui windows --- apps/openmw/mwbase/windowmanager.hpp | 5 +- apps/openmw/mwgui/container.cpp | 6 ++ apps/openmw/mwgui/container.hpp | 2 + apps/openmw/mwgui/itemview.cpp | 8 +++ apps/openmw/mwgui/itemview.hpp | 1 + apps/openmw/mwgui/windowbase.hpp | 2 + apps/openmw/mwgui/windowmanagerimp.cpp | 70 ++++++++++++++++++++--- apps/openmw/mwgui/windowmanagerimp.hpp | 5 +- apps/openmw/mwinput/controllermanager.cpp | 17 +++++- 9 files changed, 103 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index d2f1fc6514..e00837265f 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -382,7 +382,10 @@ namespace MWBase /// Same as viewer->getCamera()->getCullMask(), provided for consistency. virtual uint32_t getCullMask() = 0; - virtual MWGui::WindowBase* getTopWindow() = 0; + /// Return the window that should receive controller events + virtual MWGui::WindowBase* getActiveControllerWindow() = 0; + /// Cycle to the next window to receive controller events + virtual void cycleActiveControllerWindow(bool next) = 0; // Used in Lua bindings virtual const std::vector& getGuiModeStack() const = 0; diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 658eedfcd2..c47000d753 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -398,4 +398,10 @@ namespace MWGui } return false; } + + void ContainerWindow::setActiveControllerWindow(bool active) + { + mItemView->setActiveControllerWindow(active); + WindowBase::setActiveControllerWindow(active); + } } diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 5d49b4c3ff..f7f4ef3c31 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -40,6 +40,8 @@ namespace MWGui std::string_view getWindowIdForLua() const override { return "Container"; } + void setActiveControllerWindow(bool active) override; + private: DragAndDrop* mDragAndDrop; diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index e568da5900..526f231956 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -180,6 +180,14 @@ namespace MWGui MyGUI::FactoryManager::getInstance().registerFactory("Widget"); } + void ItemView::setActiveControllerWindow(bool active) + { + if (active) + updateControllerFocus(-1, mControllerFocus); + else + updateControllerFocus(mControllerFocus, -1); + } + void ItemView::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (!mItemCount) diff --git a/apps/openmw/mwgui/itemview.hpp b/apps/openmw/mwgui/itemview.hpp index 8a53d3678e..b1fa941ef4 100644 --- a/apps/openmw/mwgui/itemview.hpp +++ b/apps/openmw/mwgui/itemview.hpp @@ -32,6 +32,7 @@ namespace MWGui void resetScrollBars(); + void setActiveControllerWindow(bool active); int getControllerFocus() { return mControllerFocus; } int getItemCount() { return mItemCount; } void onControllerButtonEvent(const SDL_ControllerButtonEvent& arg); diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index 3db4399d85..fd1c743c62 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -62,11 +62,13 @@ namespace MWGui // REMOVEME // virtual bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) = 0; // virtual bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) = 0; + virtual void setActiveControllerWindow(bool active) { mActiveControllerWindow = active; } protected: virtual void onTitleDoubleClicked(); MyGUI::Widget* mMouseFocus = nullptr; + bool mActiveControllerWindow = false; void trackFocusEvents(MyGUI::Widget* widget); private: diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index b328176014..d52a71a417 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -859,7 +859,7 @@ namespace MWGui mHud->setPlayerPos(x, y, u, v); } - WindowBase* WindowManager::getTopWindow() + WindowBase* WindowManager::getActiveControllerWindow() { if (!mCurrentModals.empty()) return mCurrentModals.back(); @@ -869,15 +869,18 @@ namespace MWGui if (!mGuiModes.empty()) { - GuiModeState& state = mGuiModeStates[mGuiModes.back()]; + GuiMode mode = mGuiModes.back(); + GuiModeState& state = mGuiModeStates[mode]; + int activeIndex = std::clamp(mActiveControllerWindows[mode], 0, (int)state.mWindows.size() - 1); + // REMOVEME - Log(Debug::Error) << "getTopWindow: " << state.mWindows.size() << " windows in state " << mGuiModes.back(); - // find the topmost window - for (WindowBase* window : state.mWindows) - if (window->isVisible()) - return window; - else - Log(Debug::Error) << "-- Skipping hidden window " << window; + Log(Debug::Error) << "getActiveControllerWindow: " << state.mWindows.size() << " windows in state, mActiveControllerWindows[mode] = " << mActiveControllerWindows[mode]; + + // If the active window is no longer visible, find the next visible window. + if (!state.mWindows[activeIndex]->isVisible()) + cycleActiveControllerWindow(true); + + return state.mWindows[activeIndex]; } else { @@ -893,6 +896,48 @@ namespace MWGui return nullptr; } + void WindowManager::cycleActiveControllerWindow(bool next) + { + if (mGuiModes.empty()) + return; + + GuiMode mode = mGuiModes.back(); + int winCount = mGuiModeStates[mode].mWindows.size(); + + int activeIndex = 0; + if (winCount > 1) + { + // Find next/previous visible window + activeIndex = mActiveControllerWindows[mode]; + int delta = next ? 1 : -1; + + for (int i = 0; i < winCount; i++) + { + activeIndex += delta; + if (activeIndex < 0) + activeIndex = winCount - 1; + else if (activeIndex >= winCount) + activeIndex = 0; + + if (mGuiModeStates[mode].mWindows[activeIndex]->isVisible()) + break; + } + } + + // REMOVEME + Log(Debug::Error) << "focusNextWindow: mode=" << mode << ", activeIndex=" << activeIndex; + + if (mActiveControllerWindows[mode] != activeIndex) + { + mActiveControllerWindows[mode] = activeIndex; + for (int i = 0; i < winCount; i++) + { + mGuiModeStates[mode].mWindows[i]->setActiveControllerWindow(i == activeIndex); + } + playSound(ESM::RefId::stringRefId("Menu Click")); + } + } + void WindowManager::update(float frameDuration) { handleScheduledMessageBoxes(); @@ -1316,6 +1361,13 @@ namespace MWGui { for (WindowBase* window : mGuiModeStates[mode].mWindows) window->setPtr(arg); + + // Activate first visible window + mActiveControllerWindows[mode] = -1; + cycleActiveControllerWindow(true); + + // REMOVEME + Log(Debug::Error) << "pushGuiMode: mode=" << mode << ", activeIndex=" << mActiveControllerWindows[mode]; } catch (...) { diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index fd035ed12e..a1c01f6fa6 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -387,7 +387,8 @@ namespace MWGui void asyncPrepareSaveMap() override; - WindowBase* getTopWindow() override; + WindowBase* getActiveControllerWindow() override; + void cycleActiveControllerWindow(bool next) override; // Used in Lua bindings const std::vector& getGuiModeStack() const override { return mGuiModes; } @@ -495,6 +496,8 @@ namespace MWGui std::map mGuiModeStates; // The currently active stack of GUI modes (top mode is the one we are in). std::vector mGuiModes; + // The active window for controller mode for each GUI mode. + std::map mActiveControllerWindows; std::unique_ptr mCursorManager; diff --git a/apps/openmw/mwinput/controllermanager.cpp b/apps/openmw/mwinput/controllermanager.cpp index 7aff8172ce..f12c9a31ce 100644 --- a/apps/openmw/mwinput/controllermanager.cpp +++ b/apps/openmw/mwinput/controllermanager.cpp @@ -243,7 +243,7 @@ namespace MWInput { if (Settings::gui().mControllerMenus) { - MWGui::WindowBase* topWin = MWBase::Environment::get().getWindowManager()->getTopWindow(); + MWGui::WindowBase* topWin = MWBase::Environment::get().getWindowManager()->getActiveControllerWindow(); if (topWin && topWin->onControllerButtonEvent(arg)) return true; } @@ -311,7 +311,20 @@ namespace MWInput { if (Settings::gui().mControllerMenus) { - MWGui::WindowBase* topWin = MWBase::Environment::get().getWindowManager()->getTopWindow(); + // Left and right triggers toggle through open GUI windows. + if (arg.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT) + { + if (arg.value == 32767) // Treat like a button. + MWBase::Environment::get().getWindowManager()->cycleActiveControllerWindow(true); + return true; + } + else if (arg.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT) + { + if (arg.value == 32767) // Treat like a button. + MWBase::Environment::get().getWindowManager()->cycleActiveControllerWindow(false); + return true; + } + MWGui::WindowBase* topWin = MWBase::Environment::get().getWindowManager()->getActiveControllerWindow(); if (topWin && topWin->onControllerThumbstickEvent(arg)) return true; } From c0694d3c0edfb5e2e90406c291646f1d4e05c1ab Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Fri, 16 May 2025 21:41:28 -0700 Subject: [PATCH 035/330] Add overlay showing what controller buttons do --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwbase/windowmanager.hpp | 1 + apps/openmw/mwgui/birth.cpp | 9 ++++ apps/openmw/mwgui/birth.hpp | 2 + apps/openmw/mwgui/bookwindow.cpp | 8 +++ apps/openmw/mwgui/bookwindow.hpp | 1 + apps/openmw/mwgui/class.cpp | 43 +++++++++++++++ apps/openmw/mwgui/class.hpp | 14 +++++ apps/openmw/mwgui/confirmationdialog.cpp | 5 ++ apps/openmw/mwgui/confirmationdialog.hpp | 2 + apps/openmw/mwgui/container.cpp | 8 +++ apps/openmw/mwgui/container.hpp | 1 + .../openmw/mwgui/controllerbuttonsoverlay.cpp | 26 ++++++++++ .../openmw/mwgui/controllerbuttonsoverlay.hpp | 20 +++++++ apps/openmw/mwgui/journalwindow.cpp | 17 ++++++ apps/openmw/mwgui/mainmenu.cpp | 5 ++ apps/openmw/mwgui/mainmenu.hpp | 2 + apps/openmw/mwgui/messagebox.cpp | 5 ++ apps/openmw/mwgui/messagebox.hpp | 1 + apps/openmw/mwgui/race.cpp | 9 ++++ apps/openmw/mwgui/race.hpp | 2 + apps/openmw/mwgui/review.cpp | 13 +++-- apps/openmw/mwgui/review.hpp | 2 + apps/openmw/mwgui/savegamedialog.cpp | 38 +++++++------- apps/openmw/mwgui/savegamedialog.hpp | 2 + apps/openmw/mwgui/scrollwindow.cpp | 8 +++ apps/openmw/mwgui/scrollwindow.hpp | 2 + apps/openmw/mwgui/settingswindow.cpp | 7 ++- apps/openmw/mwgui/settingswindow.hpp | 1 + apps/openmw/mwgui/textinput.cpp | 5 ++ apps/openmw/mwgui/textinput.hpp | 2 + apps/openmw/mwgui/waitdialog.cpp | 13 +++++ apps/openmw/mwgui/waitdialog.hpp | 2 + apps/openmw/mwgui/windowbase.cpp | 1 + apps/openmw/mwgui/windowbase.hpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 52 ++++++++++++++++++- apps/openmw/mwgui/windowmanagerimp.hpp | 4 ++ files/data/CMakeLists.txt | 1 + .../mygui/openmw_controllerbuttons.layout | 19 +++++++ files/data/mygui/openmw_layers.xml | 1 + 40 files changed, 330 insertions(+), 27 deletions(-) create mode 100644 apps/openmw/mwgui/controllerbuttonsoverlay.cpp create mode 100644 apps/openmw/mwgui/controllerbuttonsoverlay.hpp create mode 100644 files/data/mygui/openmw_controllerbuttons.layout diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 37de0abeab..eeb46edce0 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -44,7 +44,7 @@ add_openmw_dir (mwgui tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview draganddrop timeadvancer jailscreen itemchargeview keyboardnavigation textcolours statswatcher - postprocessorhud settings + postprocessorhud settings controllerbuttonsoverlay ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index e00837265f..5302270ee0 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -386,6 +386,7 @@ namespace MWBase virtual MWGui::WindowBase* getActiveControllerWindow() = 0; /// Cycle to the next window to receive controller events virtual void cycleActiveControllerWindow(bool next) = 0; + virtual void updateControllerButtonsOverlay() = 0; // Used in Lua bindings virtual const std::vector& getGuiModeStack() const = 0; diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index b121c1978b..bc6b37df50 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -273,6 +273,11 @@ namespace MWGui mSpellArea->setViewOffset(MyGUI::IntPoint(0, 0)); } + std::string BirthDialog::getButtonStr() + { + return "(A) #{sSelect} (X) #{sDone} (B) #{sBack}"; + } + bool BirthDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) @@ -290,6 +295,10 @@ namespace MWGui { onBackClicked(mBackButton); } + else if (arg.button == SDL_CONTROLLER_BUTTON_X) + { + onOkClicked(mOkButton); + } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) { MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index 8a7190b934..841ff872b0 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -38,6 +38,8 @@ namespace MWGui */ EventHandle_WindowBase eventDone; + std::string getButtonStr() override; + protected: void onSelectBirth(MyGUI::ListBox* _sender, size_t _index); diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 79cfb9fa88..6f6a6187b9 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -222,6 +222,14 @@ namespace MWGui } } + std::string BookWindow::getButtonStr() + { + if (mTakeButton->getVisible()) + return "(A) #{sTake} (LB) #{sPrev} (RB) #{sNext} (B) #{sClose}"; + else + return "(LB) #{sPrev} (RB) #{sNext} (B) #{sClose}"; + } + bool BookWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index 062c6e9dbd..f6b1fa7bc9 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -21,6 +21,7 @@ namespace MWGui bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; std::string_view getWindowIdForLua() const override { return "Book"; } + std::string getButtonStr() override; protected: void onNextPageButtonClicked(MyGUI::Widget* sender); diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index a7b5b36aa5..7c9d7c724e 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -77,6 +77,11 @@ namespace MWGui center(); } + std::string GenerateClassResultDialog::getButtonStr() + { + return "(A) #{sSelect} (B) #{sBack}"; + } + bool GenerateClassResultDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) @@ -312,6 +317,11 @@ namespace MWGui setClassImage(mClassImage, mCurrentClassId); } + std::string PickClassDialog::getButtonStr() + { + return "(A) #{sSelect} (X) #{sDone} (B) #{sBack}"; + } + bool PickClassDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) @@ -329,6 +339,10 @@ namespace MWGui { onBackClicked(mBackButton); } + else if (arg.button == SDL_CONTROLLER_BUTTON_X) + { + onOkClicked(mOkButton); + } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) { MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); @@ -476,6 +490,11 @@ namespace MWGui } } + std::string InfoBoxDialog::getButtonStr() + { + return "(A) #{sSelect}"; + } + bool InfoBoxDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) @@ -699,6 +718,11 @@ namespace MWGui MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", {}))); } + std::string CreateClassDialog::getButtonStr() + { + return "(A) #{sSelect} (X) #{sDone} (B) #{sCancel}"; + } + bool CreateClassDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) @@ -718,6 +742,10 @@ namespace MWGui { onBackClicked(mButtons[1]); } + else if (arg.button == SDL_CONTROLLER_BUTTON_X) + { + onOkClicked(mButtons[2]); + } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP || arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) { @@ -942,6 +970,11 @@ namespace MWGui return true; } + std::string SelectSpecializationDialog::getButtonStr() + { + return "(A) #{sSelect} (B) #{sCancel}"; + } + bool SelectSpecializationDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_B) @@ -1004,6 +1037,11 @@ namespace MWGui return true; } + std::string SelectAttributeDialog::getButtonStr() + { + return "(A) #{sSelect} (B) #{sCancel}"; + } + bool SelectAttributeDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_B) @@ -1078,6 +1116,11 @@ namespace MWGui return true; } + std::string SelectSkillDialog::getButtonStr() + { + return "(A) #{sSelect} (B) #{sCancel}"; + } + bool SelectSkillDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_B) diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index e2566ce6c0..af18e5d660 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -40,6 +40,8 @@ namespace MWGui */ EventHandle_Int eventButtonSelected; + std::string getButtonStr() override; + protected: void onButtonClicked(MyGUI::Widget* _sender); bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; @@ -91,6 +93,8 @@ namespace MWGui */ EventHandle_WindowBase eventDone; + std::string getButtonStr() override; + protected: void onOkClicked(MyGUI::Widget* _sender); void onBackClicked(MyGUI::Widget* _sender); @@ -132,6 +136,8 @@ namespace MWGui */ EventHandle_WindowBase eventDone; + std::string getButtonStr() override; + protected: void onSelectClass(MyGUI::ListBox* _sender, size_t _index); void onAccept(MyGUI::ListBox* _sender, size_t _index); @@ -183,6 +189,8 @@ namespace MWGui */ EventHandle_Void eventItemSelected; + std::string getButtonStr() override; + protected: void onSpecializationClicked(MyGUI::Widget* _sender); void onCancelClicked(MyGUI::Widget* _sender); @@ -217,6 +225,8 @@ namespace MWGui */ EventHandle_Void eventItemSelected; + std::string getButtonStr() override; + protected: void onAttributeClicked(Widgets::MWAttributePtr _sender); void onCancelClicked(MyGUI::Widget* _sender); @@ -249,6 +259,8 @@ namespace MWGui */ EventHandle_Void eventItemSelected; + std::string getButtonStr() override; + protected: void onSkillClicked(Widgets::MWSkillPtr _sender); void onCancelClicked(MyGUI::Widget* _sender); @@ -310,6 +322,8 @@ namespace MWGui */ EventHandle_WindowBase eventDone; + std::string getButtonStr() override; + protected: void onOkClicked(MyGUI::Widget* _sender); void onBackClicked(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index b284db16b2..8fa4afab16 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -72,6 +72,11 @@ namespace MWGui eventOkClicked(); } + std::string ConfirmationDialog::getButtonStr() + { + return "(A) #{sOk} (B) #{sCancel}"; + } + bool ConfirmationDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) diff --git a/apps/openmw/mwgui/confirmationdialog.hpp b/apps/openmw/mwgui/confirmationdialog.hpp index 9b26e3a3c9..2e2f7df0af 100644 --- a/apps/openmw/mwgui/confirmationdialog.hpp +++ b/apps/openmw/mwgui/confirmationdialog.hpp @@ -20,6 +20,8 @@ namespace MWGui EventHandle_Void eventOkClicked; EventHandle_Void eventCancelClicked; + std::string getButtonStr() override; + private: MyGUI::EditBox* mMessage; MyGUI::Button* mOkButton; diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index c47000d753..05e56d10ee 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -352,6 +352,14 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); } + std::string ContainerWindow::getButtonStr() + { + if (mDisposeCorpseButton->getVisible()) + return "(A) #{sTake} (X) #{sTakeAll} (LB) #{sDisposeofCorpse} (Y) #{sInfo} [LT] #{sInventory} (B) #{sClose}"; + else + return "(A) #{sTake} (X) #{sTakeAll} (Y) #{sInfo} [LT] #{sInventory} (B) #{sClose}"; + } + bool ContainerWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index f7f4ef3c31..22f5f2425a 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -40,6 +40,7 @@ namespace MWGui std::string_view getWindowIdForLua() const override { return "Container"; } + std::string getButtonStr() override; void setActiveControllerWindow(bool active) override; private: diff --git a/apps/openmw/mwgui/controllerbuttonsoverlay.cpp b/apps/openmw/mwgui/controllerbuttonsoverlay.cpp new file mode 100644 index 0000000000..2e7ec3ffcd --- /dev/null +++ b/apps/openmw/mwgui/controllerbuttonsoverlay.cpp @@ -0,0 +1,26 @@ +#include "controllerbuttonsoverlay.hpp" + +#include +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" + +namespace MWGui +{ + ControllerButtonsOverlay::ControllerButtonsOverlay() + : WindowBase("openmw_controllerbuttons.layout") + { + getWidget(mButtonStr, "ButtonStr"); + } + + void ControllerButtonsOverlay::setButtonStr(const std::string& buttonStr) + { + mButtonStr->setCaptionWithReplacing(buttonStr); + + // int height = mMessage->getTextSize().height + 60; + // int width = mMessage->getTextSize().width + 24; + // mMainWidget->setSize(width, height); + // mMessage->setSize(mMessage->getWidth(), mMessage->getTextSize().height + 24); + } +} diff --git a/apps/openmw/mwgui/controllerbuttonsoverlay.hpp b/apps/openmw/mwgui/controllerbuttonsoverlay.hpp new file mode 100644 index 0000000000..c2a9b110bf --- /dev/null +++ b/apps/openmw/mwgui/controllerbuttonsoverlay.hpp @@ -0,0 +1,20 @@ +#ifndef MWGUI_CONTROLLERBUTTONSOVERLAY_H +#define MWGUI_CONTROLLERBUTTONSOVERLAY_H + +#include "windowbase.hpp" + +namespace MWGui +{ + class ControllerButtonsOverlay : public WindowBase + { + public: + ControllerButtonsOverlay(); + + void setButtonStr(const std::string& buttonStr); + + private: + MyGUI::TextBox* mButtonStr; + }; +} + +#endif diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 907de6f515..029104d27c 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -309,6 +309,8 @@ namespace notifyQuests(getWidget(QuestsList)); else notifyTopics(getWidget(TopicsList)); + + MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay(); } void pushBook(Book& book, unsigned int page) @@ -340,6 +342,7 @@ namespace { setVisible(CloseBTN, mStates.size() < 2); setVisible(JournalBTN, mStates.size() >= 2); + MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay(); } void updateShowingPages() @@ -382,6 +385,8 @@ namespace setText(PageOneNum, page + 1); setText(PageTwoNum, page + 2); + + MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay(); } void notifyKeyPress(MyGUI::Widget* sender, MyGUI::KeyCode key, MyGUI::Char character) @@ -409,6 +414,7 @@ namespace mTopicsMode = false; MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("book page")); + MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay(); } void notifyTopicSelected(const std::string& topicIdString, int id) @@ -441,6 +447,7 @@ namespace mOptionsMode = false; MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("book page")); + MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay(); } void notifyOptions(MyGUI::Widget* _sender) @@ -662,6 +669,16 @@ namespace } } + std::string getButtonStr() override + { + if (mOptionsMode) + return "(A) #{sSelect} (X) Quests (Y) #{sTopics} (B) #{sBack}"; + else if (mStates.size() > 1) + return "(A) #{sSelect} (LB) #{sPrev} (RB) #{sNext} (X) Quests (Y) #{sTopics} (B) #{sBack}"; + else + return "(A) #{sSelect} (LB) #{sPrev} (RB) #{sNext} (X) Quests (Y) #{sTopics} (B) #{sClose}"; + } + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override { if (arg.button == SDL_CONTROLLER_BUTTON_A) // A: Mouse click or Select diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index cfcb63e4d5..62740c030d 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -207,6 +207,11 @@ namespace MWGui } } + std::string MainMenu::getButtonStr() + { + return ""; + } + bool MainMenu::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { // REMOVEME diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index 453a16b5e4..aa4cba4257 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -55,6 +55,8 @@ namespace MWGui bool exit() override; + std::string getButtonStr() override; + private: const VFS::Manager* mVFS; diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index be0f284b04..00c49e44d0 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -439,6 +439,11 @@ namespace MWGui return mButtonPressed; } + std::string InteractiveMessageBox::getButtonStr() + { + return "InteractiveMessageBox (A) #{sOk}"; + } + bool InteractiveMessageBox::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index e6128ee0d1..3bc3127828 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -103,6 +103,7 @@ namespace MWGui bool mMarkedToDelete; + std::string getButtonStr() override; bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; private: diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 1ff5cc4784..c26d42f0f7 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -463,6 +463,11 @@ namespace MWGui } } + std::string RaceDialog::getButtonStr() + { + return "(A) #{sSelect} (Y) #{sSex} (LB) #{sHair} (RB) #{sFace} (X) #{sDone} (B) #{sBack}"; + } + bool RaceDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) @@ -481,6 +486,10 @@ namespace MWGui onBackClicked(mBackButton); } else if (arg.button == SDL_CONTROLLER_BUTTON_X) + { + onOkClicked(mOkButton); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_Y) { onSelectNextGender(nullptr); } diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index c3b322ba8b..b5eafb51f1 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -65,6 +65,8 @@ namespace MWGui */ EventHandle_WindowBase eventDone; + std::string getButtonStr() override; + protected: void onPreviewScroll(MyGUI::Widget* _sender, int _delta); void onHeadRotate(MyGUI::ScrollBar* _sender, size_t _position); diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index b113ace2be..40be524daf 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -537,6 +537,11 @@ namespace MWGui MyGUI::IntPoint(0, static_cast(mSkillView->getViewOffset().top + _rel * 0.3))); } + std::string ReviewDialog::getButtonStr() + { + return "(A) #{sSelect} (X) #{sDone} (B) #{sBack}"; + } + bool ReviewDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) @@ -567,14 +572,14 @@ namespace MWGui } return true; } - else if (arg.button == SDL_CONTROLLER_BUTTON_START) - { - onOkClicked(mButtons[5]); - } else if (arg.button == SDL_CONTROLLER_BUTTON_B) { onBackClicked(mButtons[4]); } + else if (arg.button == SDL_CONTROLLER_BUTTON_X) + { + onOkClicked(mButtons[5]); + } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP || arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) { diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index fe53787fe3..e14bf834cd 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -62,6 +62,8 @@ namespace MWGui EventHandle_Int eventActivateDialog; + std::string getButtonStr() override; + protected: void onOkClicked(MyGUI::Widget* _sender); void onBackClicked(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 37ed137b23..9db28afc10 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -504,6 +504,14 @@ namespace MWGui mScreenshot->setRenderItemTexture(mScreenshotTexture.get()); } + std::string SaveGameDialog::getButtonStr() + { + if (mSaving) + return "(A) #{sSelect} (B) #{sClose}"; + else + return "(A) #{sSelect} (Y) Select Character (B) #{sClose}"; + } + bool SaveGameDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) @@ -521,6 +529,16 @@ namespace MWGui { onCancelButtonClicked(mCancelButton); } + else if (arg.button == SDL_CONTROLLER_BUTTON_Y) + { + uint32_t index = mCharacterSelection->getIndexSelected(); + if (index >= mCharacterSelection->getItemCount() - 1) + index = 0; + else + index++; + mCharacterSelection->setIndexSelected(index); + mUsingGamepadGuiCursor = false; + } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) { MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); @@ -543,26 +561,6 @@ namespace MWGui mCancelButton->setStateSelected(!mOkButtonFocus); mUsingGamepadGuiCursor = false; } - else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) - { - uint32_t index = mCharacterSelection->getIndexSelected(); - if (index <= 0) - index = mCharacterSelection->getItemCount() - 1; - else - index--; - mCharacterSelection->setIndexSelected(index); - mUsingGamepadGuiCursor = false; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) - { - uint32_t index = mCharacterSelection->getIndexSelected(); - if (index >= mCharacterSelection->getItemCount() - 1) - index = 0; - else - index++; - mCharacterSelection->setIndexSelected(index); - mUsingGamepadGuiCursor = false; - } return true; } diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index 2561fc60f6..e9872a0d49 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -24,6 +24,8 @@ namespace MWGui void setLoadOrSave(bool load); + std::string getButtonStr() override; + private: void confirmDeleteSave(); diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 7c7ad338ce..5b7ef4238a 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -126,6 +126,14 @@ namespace MWGui BookWindowBase::onClose(); } + std::string ScrollWindow::getButtonStr() + { + if (mTakeButton->getVisible()) + return "(A) #{sTake} (RS) #{sScrolldown} (B) #{sClose}"; + else + return "(A) #{sTake} (RS) #{sScrolldown} (B) #{sClose}"; + } + bool ScrollWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index fa3ca5b25d..4e447707d0 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -25,6 +25,8 @@ namespace MWGui std::string_view getWindowIdForLua() const override { return "Scroll"; } + std::string getButtonStr() override; + protected: void onCloseButtonClicked(MyGUI::Widget* _sender); void onTakeButtonClicked(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 7f8d98ee05..201204bc74 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -468,7 +468,7 @@ namespace MWGui void SettingsWindow::onOkButtonClicked(MyGUI::Widget* _sender) { - setVisible(false); + MWBase::Environment::get().getWindowManager()->toggleSettingsWindow(); } void SettingsWindow::onResolutionSelected(MyGUI::ListBox* _sender, size_t index) @@ -1129,6 +1129,11 @@ namespace MWGui mControlsBox->setViewOffset(MyGUI::IntPoint(0, 0)); } + std::string SettingsWindow::getButtonStr() + { + return "(A) #{sSelect} (LB) #{sPrev} Tab (RB) #{sNext} Tab (B) #{sOk}"; + } + bool SettingsWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_B) diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 555468d806..e8d7f248cb 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -26,6 +26,7 @@ namespace MWGui void onResChange(int, int) override; + std::string getButtonStr() override; bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; protected: diff --git a/apps/openmw/mwgui/textinput.cpp b/apps/openmw/mwgui/textinput.cpp index 44e0defef6..e6352c928e 100644 --- a/apps/openmw/mwgui/textinput.cpp +++ b/apps/openmw/mwgui/textinput.cpp @@ -83,6 +83,11 @@ namespace MWGui mTextEdit->setCaption(text); } + std::string TextInputDialog::getButtonStr() + { + return "(A) #{sOk}"; + } + bool TextInputDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) diff --git a/apps/openmw/mwgui/textinput.hpp b/apps/openmw/mwgui/textinput.hpp index ad7896ff27..67ca8ba757 100644 --- a/apps/openmw/mwgui/textinput.hpp +++ b/apps/openmw/mwgui/textinput.hpp @@ -24,6 +24,8 @@ namespace MWGui */ EventHandle_WindowBase eventDone; + std::string getButtonStr() override; + protected: void onOkClicked(MyGUI::Widget* _sender); void onTextAccepted(MyGUI::EditBox* _sender); diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 5b92699982..9886f036e4 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -332,6 +332,19 @@ namespace MWGui } } + std::string WaitDialog::getButtonStr() + { + if (mSleeping) + { + if (mUntilHealedButton->getVisible()) + return "(X) #{sUntilHealed} (A) #{sRest} (B) #{sCancel}"; + else + return "(A) #{sRest} (B) #{sCancel}"; + } + else + return "(A) #{sWait} (B) #{sCancel}"; + } + bool WaitDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 0d6d2a82d2..77593c3049 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -47,6 +47,8 @@ namespace MWGui std::string_view getWindowIdForLua() const override { return "WaitDialog"; } + std::string getButtonStr() override; + protected: MyGUI::TextBox* mDateTimeText; MyGUI::TextBox* mRestText; diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index d01822f704..a3d1b27fb4 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -147,6 +147,7 @@ void WindowModal::onOpen() void WindowModal::onClose() { MWBase::Environment::get().getWindowManager()->removeCurrentModal(this); + MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay(); MyGUI::InputManager::getInstance().removeWidgetModal(mMainWidget); } diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index fd1c743c62..cd4d2874ca 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -62,6 +62,7 @@ namespace MWGui // REMOVEME // virtual bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) = 0; // virtual bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) = 0; + virtual std::string getButtonStr() { return ""; } virtual void setActiveControllerWindow(bool active) { mActiveControllerWindow = active; } protected: diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index d52a71a417..b9df5b0b4e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -181,6 +181,7 @@ namespace MWGui , mPostProcessorHud(nullptr) , mJailScreen(nullptr) , mContainerWindow(nullptr) + , mControllerButtonsOverlay(nullptr) , mTranslationDataStorage(translationDataStorage) , mInputBlocker(nullptr) , mHudEnabled(true) @@ -505,6 +506,10 @@ namespace MWGui mWindows.push_back(std::move(postProcessorHud)); trackWindow(mPostProcessorHud, makePostprocessorWindowSettingValues()); + auto controllerButtonsOverlay = std::make_unique(); + mControllerButtonsOverlay = controllerButtonsOverlay.get(); + mWindows.push_back(std::move(controllerButtonsOverlay)); + mInputBlocker = MyGUI::Gui::getInstance().createWidget( {}, 0, 0, w, h, MyGUI::Align::Stretch, "InputBlocker"); @@ -662,6 +667,9 @@ namespace MWGui && !(mForceHidden & GW_Inventory) && (mAllowed & GW_Inventory)); mSpellWindow->setVisible( mSpellWindow->pinned() && !isConsoleMode() && !(mForceHidden & GW_Magic) && (mAllowed & GW_Magic)); + + if (Settings::gui().mControllerMenus && mControllerButtonsOverlay) + mControllerButtonsOverlay->setVisible(false); return; } else if (getMode() != GM_Inventory) @@ -691,6 +699,8 @@ namespace MWGui mStatsWindow->setVisible(eff & GW_Stats); } + updateControllerButtonsOverlay(); + switch (mode) { // FIXME: refactor chargen windows to use modes properly (or not use them at all) @@ -720,6 +730,7 @@ namespace MWGui return; dialog->setVisible(false); mGarbageDialogs.push_back(std::move(dialog)); + updateControllerButtonsOverlay(); } void WindowManager::exitCurrentGuiMode() @@ -871,10 +882,13 @@ namespace MWGui { GuiMode mode = mGuiModes.back(); GuiModeState& state = mGuiModeStates[mode]; + if (state.mWindows.size() == 0) + return nullptr; + int activeIndex = std::clamp(mActiveControllerWindows[mode], 0, (int)state.mWindows.size() - 1); // REMOVEME - Log(Debug::Error) << "getActiveControllerWindow: " << state.mWindows.size() << " windows in state, mActiveControllerWindows[mode] = " << mActiveControllerWindows[mode]; + Log(Debug::Error) << "getActiveControllerWindow: " << state.mWindows.size() << " windows in state, mActiveControllerWindows[mode] = " << mActiveControllerWindows[mode] << ", activeIndex=" << activeIndex; // If the active window is no longer visible, find the next visible window. if (!state.mWindows[activeIndex]->isVisible()) @@ -1001,6 +1015,9 @@ namespace MWGui if (isSettingsWindowVisible()) mSettingsWindow->onFrame(frameDuration); + if (mControllerButtonsOverlay && mControllerButtonsOverlay->isVisible()) + mControllerButtonsOverlay->onFrame(frameDuration); + if (!gameRunning) return; @@ -2046,6 +2063,7 @@ namespace MWGui if (!window->exit()) return; window->setVisible(false); + updateControllerButtonsOverlay(); } } @@ -2059,6 +2077,8 @@ namespace MWGui mKeyboardNavigation->setModalWindow(input->mMainWidget); mKeyboardNavigation->setDefaultFocus(input->mMainWidget, input->getDefaultKeyFocus()); + + updateControllerButtonsOverlay(); } void WindowManager::removeCurrentModal(WindowModal* input) @@ -2526,4 +2546,34 @@ namespace MWGui } return res; } + + void WindowManager::updateControllerButtonsOverlay() + { + if (!Settings::gui().mControllerMenus ||!mControllerButtonsOverlay) + return; + + WindowBase* topWin = this->getActiveControllerWindow(); + if (!topWin || !topWin->isVisible()) + { + // REMOVEME + Log(Debug::Error) << "WindowManager::updateControllerButtonsOverlay: hiding overlay"; + mControllerButtonsOverlay->setVisible(false); + return; + } + + std::string buttonStr = topWin->getButtonStr(); + // REMOVEME + Log(Debug::Error) << "WindowManager::updateControllerButtonsOverlay: showing overlay: " << buttonStr; + if (buttonStr.length() > 0) + { + mControllerButtonsOverlay->setButtonStr(buttonStr); + mControllerButtonsOverlay->setVisible(true); + } + else + { + // REMOVEME + Log(Debug::Error) << "WindowManager::updateControllerButtonsOverlay: ...psych, hiding it"; + mControllerButtonsOverlay->setVisible(false); + } + } } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index a1c01f6fa6..5dbf3c4689 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -25,6 +25,7 @@ #include #include "charactercreation.hpp" +#include "controllerbuttonsoverlay.hpp" #include "draganddrop.hpp" #include "mapwindow.hpp" #include "messagebox.hpp" @@ -118,6 +119,7 @@ namespace MWGui class PostProcessorHud; class JailScreen; class KeyboardNavigation; + class ControllerButtonsOverlay; class WindowManager : public MWBase::WindowManager { @@ -389,6 +391,7 @@ namespace MWGui WindowBase* getActiveControllerWindow() override; void cycleActiveControllerWindow(bool next) override; + void updateControllerButtonsOverlay() override; // Used in Lua bindings const std::vector& getGuiModeStack() const override { return mGuiModes; } @@ -457,6 +460,7 @@ namespace MWGui PostProcessorHud* mPostProcessorHud; JailScreen* mJailScreen; ContainerWindow* mContainerWindow; + ControllerButtonsOverlay* mControllerButtonsOverlay; std::vector> mWindows; diff --git a/files/data/CMakeLists.txt b/files/data/CMakeLists.txt index 0290519806..97b49d1002 100644 --- a/files/data/CMakeLists.txt +++ b/files/data/CMakeLists.txt @@ -147,6 +147,7 @@ set(BUILTIN_DATA_FILES mygui/openmw_console.layout mygui/openmw_console.skin.xml mygui/openmw_container_window.layout + mygui/openmw_controllerbuttons.layout mygui/openmw_count_window.layout mygui/openmw_dialogue_window.layout mygui/openmw_dialogue_window.skin.xml diff --git a/files/data/mygui/openmw_controllerbuttons.layout b/files/data/mygui/openmw_controllerbuttons.layout new file mode 100644 index 0000000000..d12785f0fc --- /dev/null +++ b/files/data/mygui/openmw_controllerbuttons.layout @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/files/data/mygui/openmw_layers.xml b/files/data/mygui/openmw_layers.xml index 459db3fcb9..597ba0de4c 100644 --- a/files/data/mygui/openmw_layers.xml +++ b/files/data/mygui/openmw_layers.xml @@ -20,6 +20,7 @@ + From e01291ec4a7c8ef9fa77c5e439083776dec55251 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sat, 17 May 2025 22:32:03 -0700 Subject: [PATCH 036/330] Add whole set of button icons --- apps/openmw/mwgui/birth.cpp | 10 +- apps/openmw/mwgui/birth.hpp | 2 - apps/openmw/mwgui/bookwindow.cpp | 12 +- apps/openmw/mwgui/bookwindow.hpp | 2 +- apps/openmw/mwgui/class.cpp | 58 +++--- apps/openmw/mwgui/class.hpp | 14 -- apps/openmw/mwgui/confirmationdialog.cpp | 7 +- apps/openmw/mwgui/confirmationdialog.hpp | 2 - apps/openmw/mwgui/container.cpp | 14 +- apps/openmw/mwgui/container.hpp | 2 +- .../openmw/mwgui/controllerbuttonsoverlay.cpp | 95 ++++++++- .../openmw/mwgui/controllerbuttonsoverlay.hpp | 53 ++++- apps/openmw/mwgui/journalwindow.cpp | 16 +- apps/openmw/mwgui/mainmenu.cpp | 5 - apps/openmw/mwgui/mainmenu.hpp | 2 - apps/openmw/mwgui/messagebox.cpp | 12 +- apps/openmw/mwgui/messagebox.hpp | 1 - apps/openmw/mwgui/race.cpp | 13 +- apps/openmw/mwgui/race.hpp | 2 - apps/openmw/mwgui/review.cpp | 10 +- apps/openmw/mwgui/review.hpp | 2 - apps/openmw/mwgui/savegamedialog.cpp | 10 +- apps/openmw/mwgui/savegamedialog.hpp | 2 +- apps/openmw/mwgui/scrollwindow.cpp | 11 +- apps/openmw/mwgui/scrollwindow.hpp | 2 +- apps/openmw/mwgui/settingswindow.cpp | 10 +- apps/openmw/mwgui/settingswindow.hpp | 1 - apps/openmw/mwgui/textinput.cpp | 7 +- apps/openmw/mwgui/textinput.hpp | 2 - apps/openmw/mwgui/waitdialog.cpp | 16 +- apps/openmw/mwgui/waitdialog.hpp | 2 +- apps/openmw/mwgui/windowbase.hpp | 21 +- apps/openmw/mwgui/windowmanagerimp.cpp | 16 +- files/data/CMakeLists.txt | 14 ++ .../mygui/openmw_controllerbuttons.layout | 187 +++++++++++++++++- files/data/textures/omw_steam_button_a.dds | Bin 0 -> 22000 bytes files/data/textures/omw_steam_button_b.dds | Bin 0 -> 22000 bytes files/data/textures/omw_steam_button_l1.dds | Bin 0 -> 22000 bytes files/data/textures/omw_steam_button_l2.dds | Bin 0 -> 22000 bytes files/data/textures/omw_steam_button_l3.dds | Bin 0 -> 22000 bytes .../data/textures/omw_steam_button_lstick.dds | Bin 0 -> 22000 bytes files/data/textures/omw_steam_button_menu.dds | Bin 0 -> 22000 bytes files/data/textures/omw_steam_button_r1.dds | Bin 0 -> 22000 bytes files/data/textures/omw_steam_button_r2.dds | Bin 0 -> 22000 bytes files/data/textures/omw_steam_button_r3.dds | Bin 0 -> 22000 bytes .../data/textures/omw_steam_button_rstick.dds | Bin 0 -> 22000 bytes files/data/textures/omw_steam_button_view.dds | Bin 0 -> 22000 bytes files/data/textures/omw_steam_button_x.dds | Bin 0 -> 22000 bytes files/data/textures/omw_steam_button_y.dds | Bin 0 -> 22000 bytes 49 files changed, 457 insertions(+), 178 deletions(-) create mode 100644 files/data/textures/omw_steam_button_a.dds create mode 100644 files/data/textures/omw_steam_button_b.dds create mode 100644 files/data/textures/omw_steam_button_l1.dds create mode 100644 files/data/textures/omw_steam_button_l2.dds create mode 100644 files/data/textures/omw_steam_button_l3.dds create mode 100644 files/data/textures/omw_steam_button_lstick.dds create mode 100644 files/data/textures/omw_steam_button_menu.dds create mode 100644 files/data/textures/omw_steam_button_r1.dds create mode 100644 files/data/textures/omw_steam_button_r2.dds create mode 100644 files/data/textures/omw_steam_button_r3.dds create mode 100644 files/data/textures/omw_steam_button_rstick.dds create mode 100644 files/data/textures/omw_steam_button_view.dds create mode 100644 files/data/textures/omw_steam_button_x.dds create mode 100644 files/data/textures/omw_steam_button_y.dds diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index bc6b37df50..53f0f9793b 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -59,7 +59,12 @@ namespace MWGui mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked); if (Settings::gui().mControllerMenus) + { mOkButton->setStateSelected(true); + mControllerButtons.a = "#{sSelect}"; + mControllerButtons.b = "#{sBack}"; + mControllerButtons.x = "#{sDone}"; + } updateBirths(); updateSpells(); @@ -273,11 +278,6 @@ namespace MWGui mSpellArea->setViewOffset(MyGUI::IntPoint(0, 0)); } - std::string BirthDialog::getButtonStr() - { - return "(A) #{sSelect} (X) #{sDone} (B) #{sBack}"; - } - bool BirthDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index 841ff872b0..8a7190b934 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -38,8 +38,6 @@ namespace MWGui */ EventHandle_WindowBase eventDone; - std::string getButtonStr() override; - protected: void onSelectBirth(MyGUI::ListBox* _sender, size_t _index); diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 6f6a6187b9..c48493c1b4 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -70,6 +70,10 @@ namespace MWGui MyGUI::IntCoord(0, 0, (64 - 7) * scale, mNextPageButton->getSize().height * scale)); } + mControllerButtons.l1 = "#{sPrev}"; + mControllerButtons.r1 = "#{sNext}"; + mControllerButtons.b = "#{sClose}"; + center(); } @@ -222,12 +226,10 @@ namespace MWGui } } - std::string BookWindow::getButtonStr() + ControllerButtonStr* BookWindow::getControllerButtons() { - if (mTakeButton->getVisible()) - return "(A) #{sTake} (LB) #{sPrev} (RB) #{sNext} (B) #{sClose}"; - else - return "(LB) #{sPrev} (RB) #{sNext} (B) #{sClose}"; + mControllerButtons.a = mTakeButton->getVisible() ? "#{sTake}" : ""; + return &mControllerButtons; } bool BookWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index f6b1fa7bc9..0a1beb7342 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -21,7 +21,7 @@ namespace MWGui bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; std::string_view getWindowIdForLua() const override { return "Book"; } - std::string getButtonStr() override; + ControllerButtonStr* getControllerButtons() override; protected: void onNextPageButtonClicked(MyGUI::Widget* sender); diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 7c9d7c724e..0ac39e4bac 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -60,6 +60,8 @@ namespace MWGui mOkButton->setStateSelected(true); trackFocusEvents(mBackButton); trackFocusEvents(mOkButton); + mControllerButtons.a = "#{sSelect}"; + mControllerButtons.b = "#{sBack}"; } center(); @@ -77,11 +79,6 @@ namespace MWGui center(); } - std::string GenerateClassResultDialog::getButtonStr() - { - return "(A) #{sSelect} (B) #{sBack}"; - } - bool GenerateClassResultDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) @@ -155,7 +152,12 @@ namespace MWGui mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onOkClicked); if (Settings::gui().mControllerMenus) + { mOkButton->setStateSelected(true); + mControllerButtons.a = "#{sSelect}"; + mControllerButtons.b = "#{sBack}"; + mControllerButtons.x = "#{sDone}"; + } updateClasses(); updateStats(); @@ -317,11 +319,6 @@ namespace MWGui setClassImage(mClassImage, mCurrentClassId); } - std::string PickClassDialog::getButtonStr() - { - return "(A) #{sSelect} (X) #{sDone} (B) #{sBack}"; - } - bool PickClassDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) @@ -419,6 +416,8 @@ namespace MWGui getWidget(mButtonBar, "ButtonBar"); center(); + + mControllerButtons.a = "#{sSelect}"; } void InfoBoxDialog::setText(const std::string& str) @@ -490,11 +489,6 @@ namespace MWGui } } - std::string InfoBoxDialog::getButtonStr() - { - return "(A) #{sSelect}"; - } - bool InfoBoxDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) @@ -623,7 +617,12 @@ namespace MWGui mButtons.push_back(okButton); if (Settings::gui().mControllerMenus) + { okButton->setStateSelected(true); + mControllerButtons.a = "#{sSelect}"; + mControllerButtons.b = "#{sBack}"; + mControllerButtons.x = "#{sDone}"; + } // Set default skills, attributes @@ -718,11 +717,6 @@ namespace MWGui MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", {}))); } - std::string CreateClassDialog::getButtonStr() - { - return "(A) #{sSelect} (X) #{sDone} (B) #{sCancel}"; - } - bool CreateClassDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) @@ -939,6 +933,9 @@ namespace MWGui MyGUI::Button* cancelButton; getWidget(cancelButton, "CancelButton"); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onCancelClicked); + + mControllerButtons.a = "#{sSelect}"; + mControllerButtons.b = "#{sCancel}"; } SelectSpecializationDialog::~SelectSpecializationDialog() {} @@ -970,11 +967,6 @@ namespace MWGui return true; } - std::string SelectSpecializationDialog::getButtonStr() - { - return "(A) #{sSelect} (B) #{sCancel}"; - } - bool SelectSpecializationDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_B) @@ -1016,6 +1008,9 @@ namespace MWGui MyGUI::Button* cancelButton; getWidget(cancelButton, "CancelButton"); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectAttributeDialog::onCancelClicked); + + mControllerButtons.a = "#{sSelect}"; + mControllerButtons.b = "#{sCancel}"; } // widget controls @@ -1037,11 +1032,6 @@ namespace MWGui return true; } - std::string SelectAttributeDialog::getButtonStr() - { - return "(A) #{sSelect} (B) #{sCancel}"; - } - bool SelectAttributeDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_B) @@ -1093,6 +1083,9 @@ namespace MWGui MyGUI::Button* cancelButton; getWidget(cancelButton, "CancelButton"); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSkillDialog::onCancelClicked); + + mControllerButtons.a = "#{sSelect}"; + mControllerButtons.b = "#{sCancel}"; } SelectSkillDialog::~SelectSkillDialog() {} @@ -1116,11 +1109,6 @@ namespace MWGui return true; } - std::string SelectSkillDialog::getButtonStr() - { - return "(A) #{sSelect} (B) #{sCancel}"; - } - bool SelectSkillDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_B) diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index af18e5d660..e2566ce6c0 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -40,8 +40,6 @@ namespace MWGui */ EventHandle_Int eventButtonSelected; - std::string getButtonStr() override; - protected: void onButtonClicked(MyGUI::Widget* _sender); bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; @@ -93,8 +91,6 @@ namespace MWGui */ EventHandle_WindowBase eventDone; - std::string getButtonStr() override; - protected: void onOkClicked(MyGUI::Widget* _sender); void onBackClicked(MyGUI::Widget* _sender); @@ -136,8 +132,6 @@ namespace MWGui */ EventHandle_WindowBase eventDone; - std::string getButtonStr() override; - protected: void onSelectClass(MyGUI::ListBox* _sender, size_t _index); void onAccept(MyGUI::ListBox* _sender, size_t _index); @@ -189,8 +183,6 @@ namespace MWGui */ EventHandle_Void eventItemSelected; - std::string getButtonStr() override; - protected: void onSpecializationClicked(MyGUI::Widget* _sender); void onCancelClicked(MyGUI::Widget* _sender); @@ -225,8 +217,6 @@ namespace MWGui */ EventHandle_Void eventItemSelected; - std::string getButtonStr() override; - protected: void onAttributeClicked(Widgets::MWAttributePtr _sender); void onCancelClicked(MyGUI::Widget* _sender); @@ -259,8 +249,6 @@ namespace MWGui */ EventHandle_Void eventItemSelected; - std::string getButtonStr() override; - protected: void onSkillClicked(Widgets::MWSkillPtr _sender); void onCancelClicked(MyGUI::Widget* _sender); @@ -322,8 +310,6 @@ namespace MWGui */ EventHandle_WindowBase eventDone; - std::string getButtonStr() override; - protected: void onOkClicked(MyGUI::Widget* _sender); void onBackClicked(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index 8fa4afab16..1d8f14176a 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -24,6 +24,8 @@ namespace MWGui { trackFocusEvents(mOkButton); trackFocusEvents(mCancelButton); + mControllerButtons.a = "#{sOk}"; + mControllerButtons.b = "#{sCancel}"; } } @@ -72,11 +74,6 @@ namespace MWGui eventOkClicked(); } - std::string ConfirmationDialog::getButtonStr() - { - return "(A) #{sOk} (B) #{sCancel}"; - } - bool ConfirmationDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) diff --git a/apps/openmw/mwgui/confirmationdialog.hpp b/apps/openmw/mwgui/confirmationdialog.hpp index 2e2f7df0af..9b26e3a3c9 100644 --- a/apps/openmw/mwgui/confirmationdialog.hpp +++ b/apps/openmw/mwgui/confirmationdialog.hpp @@ -20,8 +20,6 @@ namespace MWGui EventHandle_Void eventOkClicked; EventHandle_Void eventCancelClicked; - std::string getButtonStr() override; - private: MyGUI::EditBox* mMessage; MyGUI::Button* mOkButton; diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 05e56d10ee..615c4801d3 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -56,6 +56,12 @@ namespace MWGui mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onTakeAllButtonClicked); setCoord(200, 0, 600, 300); + + mControllerButtons.a = "#{sTake}"; + mControllerButtons.b = "#{sClose}"; + mControllerButtons.x = "#{sTakeAll}"; + mControllerButtons.y = "#{sInfo}"; + mControllerButtons.l2 = "#{sInventory}"; } void ContainerWindow::onItemSelected(int index) @@ -352,12 +358,10 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); } - std::string ContainerWindow::getButtonStr() + ControllerButtonStr* ContainerWindow::getControllerButtons() { - if (mDisposeCorpseButton->getVisible()) - return "(A) #{sTake} (X) #{sTakeAll} (LB) #{sDisposeofCorpse} (Y) #{sInfo} [LT] #{sInventory} (B) #{sClose}"; - else - return "(A) #{sTake} (X) #{sTakeAll} (Y) #{sInfo} [LT] #{sInventory} (B) #{sClose}"; + mControllerButtons.l1 = mDisposeCorpseButton->getVisible() ? "#{sDisposeofCorpse}" : ""; + return &mControllerButtons; } bool ContainerWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 22f5f2425a..d2d8c9f4aa 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -40,7 +40,7 @@ namespace MWGui std::string_view getWindowIdForLua() const override { return "Container"; } - std::string getButtonStr() override; + ControllerButtonStr* getControllerButtons() override; void setActiveControllerWindow(bool active) override; private: diff --git a/apps/openmw/mwgui/controllerbuttonsoverlay.cpp b/apps/openmw/mwgui/controllerbuttonsoverlay.cpp index 2e7ec3ffcd..f4b35ac4de 100644 --- a/apps/openmw/mwgui/controllerbuttonsoverlay.cpp +++ b/apps/openmw/mwgui/controllerbuttonsoverlay.cpp @@ -1,8 +1,5 @@ #include "controllerbuttonsoverlay.hpp" -#include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" @@ -11,16 +8,94 @@ namespace MWGui ControllerButtonsOverlay::ControllerButtonsOverlay() : WindowBase("openmw_controllerbuttons.layout") { - getWidget(mButtonStr, "ButtonStr"); + getWidget(mImageA, "BtnAImage"); + getWidget(mTextA, "BtnAText"); + + getWidget(mImageB, "BtnBImage"); + getWidget(mTextB, "BtnBText"); + + getWidget(mImageL1, "BtnL1Image"); + getWidget(mTextL1, "BtnL1Text"); + + getWidget(mImageL2, "BtnL2Image"); + getWidget(mTextL2, "BtnL2Text"); + + getWidget(mImageL3, "BtnL3Image"); + getWidget(mTextL3, "BtnL3Text"); + + getWidget(mImageLStick, "BtnLStickImage"); + getWidget(mTextLStick, "BtnLStickText"); + + getWidget(mImageMenu, "BtnMenuImage"); + getWidget(mTextMenu, "BtnMenuText"); + + getWidget(mImageR1, "BtnR1Image"); + getWidget(mTextR1, "BtnR1Text"); + + getWidget(mImageR2, "BtnR2Image"); + getWidget(mTextR2, "BtnR2Text"); + + getWidget(mImageR3, "BtnR3Image"); + getWidget(mTextR3, "BtnR3Text"); + + getWidget(mImageRStick, "BtnRStickImage"); + getWidget(mTextRStick, "BtnRStickText"); + + getWidget(mImageView, "BtnViewImage"); + getWidget(mTextView, "BtnViewText"); + + getWidget(mImageX, "BtnXImage"); + getWidget(mTextX, "BtnXText"); + + getWidget(mImageY, "BtnYImage"); + getWidget(mTextY, "BtnYText"); + + getWidget(mHBox, "ButtonBox"); } - void ControllerButtonsOverlay::setButtonStr(const std::string& buttonStr) + void ControllerButtonsOverlay::setButtons(ControllerButtonStr* buttons) { - mButtonStr->setCaptionWithReplacing(buttonStr); + int buttonCount = 0; + buttonCount += updateButton(mTextA, mImageA, buttons->a); + buttonCount += updateButton(mTextB, mImageB, buttons->b); + buttonCount += updateButton(mTextL1, mImageL1, buttons->l1); + buttonCount += updateButton(mTextL2, mImageL2, buttons->l2); + buttonCount += updateButton(mTextL3, mImageL3, buttons->l3); + buttonCount += updateButton(mTextLStick, mImageLStick, buttons->lStick); + buttonCount += updateButton(mTextMenu, mImageMenu, buttons->menu); + buttonCount += updateButton(mTextR1, mImageR1, buttons->r1); + buttonCount += updateButton(mTextR2, mImageR2, buttons->r2); + buttonCount += updateButton(mTextR3, mImageR3, buttons->r3); + buttonCount += updateButton(mTextRStick, mImageRStick, buttons->rStick); + buttonCount += updateButton(mTextView, mImageView, buttons->view); + buttonCount += updateButton(mTextX, mImageX, buttons->x); + buttonCount += updateButton(mTextY, mImageY, buttons->y); + mHBox->notifyChildrenSizeChanged(); - // int height = mMessage->getTextSize().height + 60; - // int width = mMessage->getTextSize().width + 24; - // mMainWidget->setSize(width, height); - // mMessage->setSize(mMessage->getWidth(), mMessage->getTextSize().height + 24); + setVisible(buttonCount > 0); + } + + int ControllerButtonsOverlay::updateButton(MyGUI::TextBox* text, MyGUI::ImageBox* image, const std::string& buttonStr) + { + if (buttonStr.length() > 0) + { + image->setVisible(true); + image->setUserString("Hidden", "false"); + + text->setCaptionWithReplacing(buttonStr); + text->setVisible(true); + text->setUserString("Hidden", "false"); + text->setSize(text->getTextSize().width + 16, 48); + return 1; + } + else + { + image->setVisible(false); + image->setUserString("Hidden", "true"); + + text->setVisible(false); + text->setUserString("Hidden", "true"); + return 0; + } } } diff --git a/apps/openmw/mwgui/controllerbuttonsoverlay.hpp b/apps/openmw/mwgui/controllerbuttonsoverlay.hpp index c2a9b110bf..7663bbed44 100644 --- a/apps/openmw/mwgui/controllerbuttonsoverlay.hpp +++ b/apps/openmw/mwgui/controllerbuttonsoverlay.hpp @@ -1,6 +1,11 @@ #ifndef MWGUI_CONTROLLERBUTTONSOVERLAY_H #define MWGUI_CONTROLLERBUTTONSOVERLAY_H +#include +#include + +#include + #include "windowbase.hpp" namespace MWGui @@ -10,10 +15,54 @@ namespace MWGui public: ControllerButtonsOverlay(); - void setButtonStr(const std::string& buttonStr); + void setButtons(ControllerButtonStr* buttons); private: - MyGUI::TextBox* mButtonStr; + MyGUI::ImageBox* mImageA; + MyGUI::TextBox* mTextA; + + MyGUI::ImageBox* mImageB; + MyGUI::TextBox* mTextB; + + MyGUI::ImageBox* mImageL1; + MyGUI::TextBox* mTextL1; + + MyGUI::ImageBox* mImageL2; + MyGUI::TextBox* mTextL2; + + MyGUI::ImageBox* mImageL3; + MyGUI::TextBox* mTextL3; + + MyGUI::ImageBox* mImageLStick; + MyGUI::TextBox* mTextLStick; + + MyGUI::ImageBox* mImageMenu; + MyGUI::TextBox* mTextMenu; + + MyGUI::ImageBox* mImageR1; + MyGUI::TextBox* mTextR1; + + MyGUI::ImageBox* mImageR2; + MyGUI::TextBox* mTextR2; + + MyGUI::ImageBox* mImageR3; + MyGUI::TextBox* mTextR3; + + MyGUI::ImageBox* mImageRStick; + MyGUI::TextBox* mTextRStick; + + MyGUI::ImageBox* mImageView; + MyGUI::TextBox* mTextView; + + MyGUI::ImageBox* mImageX; + MyGUI::TextBox* mTextX; + + MyGUI::ImageBox* mImageY; + MyGUI::TextBox* mTextY; + + Gui::HBox* mHBox; + + int updateButton(MyGUI::TextBox* text, MyGUI::ImageBox* image, const std::string& buttonStr); }; } diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 029104d27c..abb1843178 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -218,6 +218,10 @@ namespace } } + mControllerButtons.a = "#{sSelect}"; + mControllerButtons.x = "Quests"; + mControllerButtons.y = "#{sTopics}"; + mQuestMode = false; mAllQuests = false; mOptionsMode = false; @@ -669,14 +673,12 @@ namespace } } - std::string getButtonStr() override + MWGui::ControllerButtonStr* getControllerButtons() override { - if (mOptionsMode) - return "(A) #{sSelect} (X) Quests (Y) #{sTopics} (B) #{sBack}"; - else if (mStates.size() > 1) - return "(A) #{sSelect} (LB) #{sPrev} (RB) #{sNext} (X) Quests (Y) #{sTopics} (B) #{sBack}"; - else - return "(A) #{sSelect} (LB) #{sPrev} (RB) #{sNext} (X) Quests (Y) #{sTopics} (B) #{sClose}"; + mControllerButtons.b = mOptionsMode || mStates.size() > 1 ? "#{sBack}" : "#{sClose}"; + mControllerButtons.l1 = mOptionsMode ? "" : "#{sPrev}"; + mControllerButtons.r1 = mOptionsMode ? "" : "#{sNext}"; + return &mControllerButtons; } bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 62740c030d..cfcb63e4d5 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -207,11 +207,6 @@ namespace MWGui } } - std::string MainMenu::getButtonStr() - { - return ""; - } - bool MainMenu::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { // REMOVEME diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index aa4cba4257..453a16b5e4 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -55,8 +55,6 @@ namespace MWGui bool exit() override; - std::string getButtonStr() override; - private: const VFS::Manager* mVFS; diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 00c49e44d0..8c5a968c99 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -282,10 +282,13 @@ namespace MWGui } } - if (Settings::gui().mControllerMenus && mButtons.size() > 1) + if (Settings::gui().mControllerMenus) { + mControllerButtons.a = "#{sOk}"; + // If we have more than one button, we need to set the focus to the first one. - mButtons[0]->setStateSelected(true); + if (mButtons.size() > 1) + mButtons[0]->setStateSelected(true); } MyGUI::IntSize mainWidgetSize; @@ -439,11 +442,6 @@ namespace MWGui return mButtonPressed; } - std::string InteractiveMessageBox::getButtonStr() - { - return "InteractiveMessageBox (A) #{sOk}"; - } - bool InteractiveMessageBox::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index 3bc3127828..e6128ee0d1 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -103,7 +103,6 @@ namespace MWGui bool mMarkedToDelete; - std::string getButtonStr() override; bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; private: diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index c26d42f0f7..9b97dfbb53 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -117,7 +117,15 @@ namespace MWGui mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onOkClicked); if (Settings::gui().mControllerMenus) + { mOkButton->setStateSelected(true); + mControllerButtons.a = "#{sSelect}"; + mControllerButtons.b = "#{sBack}"; + mControllerButtons.x = "#{sDone}"; + mControllerButtons.y = "#{sSex}"; + mControllerButtons.l1 = "#{sHair}"; + mControllerButtons.r1 = "#{sFace}"; + } updateRaces(); updateSkills(); @@ -463,11 +471,6 @@ namespace MWGui } } - std::string RaceDialog::getButtonStr() - { - return "(A) #{sSelect} (Y) #{sSex} (LB) #{sHair} (RB) #{sFace} (X) #{sDone} (B) #{sBack}"; - } - bool RaceDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index b5eafb51f1..c3b322ba8b 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -65,8 +65,6 @@ namespace MWGui */ EventHandle_WindowBase eventDone; - std::string getButtonStr() override; - protected: void onPreviewScroll(MyGUI::Widget* _sender, int _delta); void onHeadRotate(MyGUI::ScrollBar* _sender, size_t _position); diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 40be524daf..4d0d9d4d2c 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -126,7 +126,12 @@ namespace MWGui mButtons.push_back(okButton); if (Settings::gui().mControllerMenus) + { mButtons[mControllerFocus]->setStateSelected(true); + mControllerButtons.a = "#{sSelect}"; + mControllerButtons.b = "#{sBack}"; + mControllerButtons.x = "#{sDone}"; + } } void ReviewDialog::onOpen() @@ -537,11 +542,6 @@ namespace MWGui MyGUI::IntPoint(0, static_cast(mSkillView->getViewOffset().top + _rel * 0.3))); } - std::string ReviewDialog::getButtonStr() - { - return "(A) #{sSelect} (X) #{sDone} (B) #{sBack}"; - } - bool ReviewDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index e14bf834cd..fe53787fe3 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -62,8 +62,6 @@ namespace MWGui EventHandle_Int eventActivateDialog; - std::string getButtonStr() override; - protected: void onOkClicked(MyGUI::Widget* _sender); void onBackClicked(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 9db28afc10..568c12d00d 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -66,6 +66,8 @@ namespace MWGui trackFocusEvents(mCancelButton); trackFocusEvents(mDeleteButton); + mControllerButtons.a = "#{sSelect}"; + mControllerButtons.b = "#{sClose}"; } void SaveGameDialog::onSlotActivated(MyGUI::ListBox* sender, size_t pos) @@ -504,12 +506,10 @@ namespace MWGui mScreenshot->setRenderItemTexture(mScreenshotTexture.get()); } - std::string SaveGameDialog::getButtonStr() + ControllerButtonStr* SaveGameDialog::getControllerButtons() { - if (mSaving) - return "(A) #{sSelect} (B) #{sClose}"; - else - return "(A) #{sSelect} (Y) Select Character (B) #{sClose}"; + mControllerButtons.y = mSaving ? "" : "Select Character"; + return &mControllerButtons; } bool SaveGameDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index e9872a0d49..fbe319aed1 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -24,7 +24,7 @@ namespace MWGui void setLoadOrSave(bool load); - std::string getButtonStr() override; + ControllerButtonStr* getControllerButtons() override; private: void confirmDeleteSave(); diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 5b7ef4238a..5146d77e5d 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -41,6 +41,9 @@ namespace MWGui mCloseButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &ScrollWindow::onKeyButtonPressed); mTakeButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &ScrollWindow::onKeyButtonPressed); + mControllerButtons.b = "#{sClose}"; + mControllerButtons.rStick = "#{sScrolldown}"; + center(); } @@ -126,12 +129,10 @@ namespace MWGui BookWindowBase::onClose(); } - std::string ScrollWindow::getButtonStr() + ControllerButtonStr* ScrollWindow::getControllerButtons() { - if (mTakeButton->getVisible()) - return "(A) #{sTake} (RS) #{sScrolldown} (B) #{sClose}"; - else - return "(A) #{sTake} (RS) #{sScrolldown} (B) #{sClose}"; + mControllerButtons.a = mTakeButton->getVisible() ? "#{sTake}" : ""; + return &mControllerButtons; } bool ScrollWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 4e447707d0..f1047fdeba 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -25,7 +25,7 @@ namespace MWGui std::string_view getWindowIdForLua() const override { return "Scroll"; } - std::string getButtonStr() override; + ControllerButtonStr* getControllerButtons() override; protected: void onCloseButtonClicked(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 201204bc74..2fa6a72fd8 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -459,6 +459,11 @@ namespace MWGui i++; } + + mControllerButtons.a = "#{sSelect}"; + mControllerButtons.b = "#{sOk}"; + mControllerButtons.l1 = "#{sPrev} Tab"; + mControllerButtons.r1 = "#{sNext} Tab"; } void SettingsWindow::onTabChanged(MyGUI::TabControl* /*_sender*/, size_t /*index*/) @@ -1129,11 +1134,6 @@ namespace MWGui mControlsBox->setViewOffset(MyGUI::IntPoint(0, 0)); } - std::string SettingsWindow::getButtonStr() - { - return "(A) #{sSelect} (LB) #{sPrev} Tab (RB) #{sNext} Tab (B) #{sOk}"; - } - bool SettingsWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_B) diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index e8d7f248cb..555468d806 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -26,7 +26,6 @@ namespace MWGui void onResChange(int, int) override; - std::string getButtonStr() override; bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; protected: diff --git a/apps/openmw/mwgui/textinput.cpp b/apps/openmw/mwgui/textinput.cpp index e6352c928e..6ef8f1ef8e 100644 --- a/apps/openmw/mwgui/textinput.cpp +++ b/apps/openmw/mwgui/textinput.cpp @@ -25,6 +25,8 @@ namespace MWGui // Make sure the edit box has focus MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit); + + mControllerButtons.a = "#{sOk}"; } void TextInputDialog::setNextButtonShow(bool shown) @@ -83,11 +85,6 @@ namespace MWGui mTextEdit->setCaption(text); } - std::string TextInputDialog::getButtonStr() - { - return "(A) #{sOk}"; - } - bool TextInputDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) diff --git a/apps/openmw/mwgui/textinput.hpp b/apps/openmw/mwgui/textinput.hpp index 67ca8ba757..ad7896ff27 100644 --- a/apps/openmw/mwgui/textinput.hpp +++ b/apps/openmw/mwgui/textinput.hpp @@ -24,8 +24,6 @@ namespace MWGui */ EventHandle_WindowBase eventDone; - std::string getButtonStr() override; - protected: void onOkClicked(MyGUI::Widget* _sender); void onTextAccepted(MyGUI::EditBox* _sender); diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 9886f036e4..fa5cefb238 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -86,6 +86,8 @@ namespace MWGui trackFocusEvents(mCancelButton); for (MyGUI::Widget* widget : mHourSlider->getAllWidgets()) trackFocusEvents(widget); + + mControllerButtons.b = "#{sCancel}"; } void WaitDialog::setPtr(const MWWorld::Ptr& ptr) @@ -332,17 +334,11 @@ namespace MWGui } } - std::string WaitDialog::getButtonStr() + ControllerButtonStr* WaitDialog::getControllerButtons() { - if (mSleeping) - { - if (mUntilHealedButton->getVisible()) - return "(X) #{sUntilHealed} (A) #{sRest} (B) #{sCancel}"; - else - return "(A) #{sRest} (B) #{sCancel}"; - } - else - return "(A) #{sWait} (B) #{sCancel}"; + mControllerButtons.a = mSleeping ? "#{sRest}" : "#{sWait}"; + mControllerButtons.x = mSleeping && mUntilHealedButton->getVisible() ? "#{sUntilHealed}" : ""; + return &mControllerButtons; } bool WaitDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 77593c3049..4a7ccfcd00 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -47,7 +47,7 @@ namespace MWGui std::string_view getWindowIdForLua() const override { return "WaitDialog"; } - std::string getButtonStr() override; + ControllerButtonStr* getControllerButtons() override; protected: MyGUI::TextBox* mDateTimeText; diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index cd4d2874ca..2a9d4592d3 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -14,6 +14,24 @@ namespace MWGui { class DragAndDrop; + struct ControllerButtonStr + { + std::string a; + std::string b; + std::string l1; + std::string l2; + std::string l3; + std::string lStick; + std::string menu; + std::string r1; + std::string r2; + std::string r3; + std::string rStick; + std::string view; + std::string x; + std::string y; + }; + class WindowBase : public Layout { public: @@ -62,12 +80,13 @@ namespace MWGui // REMOVEME // virtual bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) = 0; // virtual bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) = 0; - virtual std::string getButtonStr() { return ""; } + virtual ControllerButtonStr* getControllerButtons() { return &mControllerButtons; } virtual void setActiveControllerWindow(bool active) { mActiveControllerWindow = active; } protected: virtual void onTitleDoubleClicked(); + ControllerButtonStr mControllerButtons; MyGUI::Widget* mMouseFocus = nullptr; bool mActiveControllerWindow = false; void trackFocusEvents(MyGUI::Widget* widget); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index b9df5b0b4e..ff2e9754af 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -2561,19 +2561,7 @@ namespace MWGui return; } - std::string buttonStr = topWin->getButtonStr(); - // REMOVEME - Log(Debug::Error) << "WindowManager::updateControllerButtonsOverlay: showing overlay: " << buttonStr; - if (buttonStr.length() > 0) - { - mControllerButtonsOverlay->setButtonStr(buttonStr); - mControllerButtonsOverlay->setVisible(true); - } - else - { - // REMOVEME - Log(Debug::Error) << "WindowManager::updateControllerButtonsOverlay: ...psych, hiding it"; - mControllerButtonsOverlay->setVisible(false); - } + // setButtons will handle setting visibility based on if any buttons are defined. + mControllerButtonsOverlay->setButtons(topWin->getControllerButtons()); } } diff --git a/files/data/CMakeLists.txt b/files/data/CMakeLists.txt index 97b49d1002..6339344500 100644 --- a/files/data/CMakeLists.txt +++ b/files/data/CMakeLists.txt @@ -10,6 +10,20 @@ set(BUILTIN_DATA_FILES textures/omw_menu_scroll_center_h.dds textures/omw_menu_scroll_center_v.dds textures/omw_menu_icon_active.dds + textures/omw_steam_button_a.dds + textures/omw_steam_button_b.dds + textures/omw_steam_button_l1.dds + textures/omw_steam_button_l2.dds + textures/omw_steam_button_l3.dds + textures/omw_steam_button_lstick.dds + textures/omw_steam_button_menu.dds + textures/omw_steam_button_r1.dds + textures/omw_steam_button_r2.dds + textures/omw_steam_button_r3.dds + textures/omw_steam_button_rstick.dds + textures/omw_steam_button_view.dds + textures/omw_steam_button_x.dds + textures/omw_steam_button_y.dds textures/omw/water_nm.png fonts/DejaVuFontLicense.txt diff --git a/files/data/mygui/openmw_controllerbuttons.layout b/files/data/mygui/openmw_controllerbuttons.layout index d12785f0fc..42c89e10b4 100644 --- a/files/data/mygui/openmw_controllerbuttons.layout +++ b/files/data/mygui/openmw_controllerbuttons.layout @@ -4,15 +4,194 @@ - + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/data/textures/omw_steam_button_a.dds b/files/data/textures/omw_steam_button_a.dds new file mode 100644 index 0000000000000000000000000000000000000000..447aa6081540c570208bd37a9338954feaf6990d GIT binary patch literal 22000 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 literal 0 HcmV?d00001 diff --git a/files/data/textures/omw_steam_button_b.dds b/files/data/textures/omw_steam_button_b.dds new file mode 100644 index 0000000000000000000000000000000000000000..0be30636439019f9695ca56f5abfa614474cef26 GIT binary patch literal 22000 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 literal 0 HcmV?d00001 diff --git a/files/data/textures/omw_steam_button_l1.dds b/files/data/textures/omw_steam_button_l1.dds new file mode 100644 index 0000000000000000000000000000000000000000..2b79a67b985b3e73eef56c54a3bb66e895456044 GIT binary patch literal 22000 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 I6!LiXe`A%mtpET3 literal 0 HcmV?d00001 diff --git a/files/data/textures/omw_steam_button_l2.dds b/files/data/textures/omw_steam_button_l2.dds new file mode 100644 index 0000000000000000000000000000000000000000..156b1ca96c57d9a3120871fd7994214482d2f7a5 GIT binary patch literal 22000 zcmeHP4OCQB9=~sf8D$V=6vmIzFvU{S1XI*XXH>TBoeqdAv)Z;5A}N_5eHgmhLg~>w zrop)NWN%7NeH2N}r+LS5m9kDvJ4-@p$)`6=OVSNrG> zi9zraHzR5E<(})RGhX^z&09+c#E^* zbQmq~X%*j8n^6@^@thF82@eWJ6sL6q92LN~N*}W|p#RhmBdvd`lK%<+J@j3Qxqdmr z(JEa6;WrUXK(Np4!@m>wHYFuSb5+HkmiG#$&+BbD>UZyXESBOk&zAqsvThXElW0-R zf2pdqtO{cMHy7}SY?c6K`nk#aXj+jy$!1YAKI-{jCLcbcNu%vq8}jE#hLYTa6m$I) zkAD_nhW-p;rV*i;>hgl=i}Z|t$LyF338l#z`aJ$=$hX1a{aN{~F8kpqk_Z>^C>OEi z8yjyC{uIDBUmv*T{J?ZjJmuq{>$v$9zI7AD_59Y7^SwhE|5KIc9xLG2XKJ>Xng4HfeOc!GGS@}Zk&1j1FT!^KQ*DU-;a2Mdx7ZbDa=O8IF1Dv> z#SG)ICRq}#%CiEx%+g?AKYsB0`(JS z#OreX?;_^&li(&#ko4v?iOSJ%Q=HZf$oJqsnp>1Ny}a;Kntm{*z9B3|&-izJ9Z|I`TGDLM04VGIX-T-elFp^;OhKyJ$9#jusn^$3md~7nbTg*&ms~LdD=>f z>w-6%A$}C`MI65;>ZOejP<*rHyV>+*9LK3QTLcmW`}DUy`SW-L;V)<~tFIb2@A*ioKXU$?WIcqnN18uV`AL2$ z{=%rtTK6$z}!sgbmyT01i zT<78W&9wfG>QA2EU;d@`BBVE&Ouf;fyl2X#cyPzyMqPMJch>*g4_Grb8@%FyLs9Y9 z9}nDY{}&XJs*=g+Q}e^CnvDY`FD84Nd-XH!&6ci=yqV&|7Yz8C*M{vE`>p(6K< zBi1)y{Y&Ie&W{`$Dq=I5U(fhidY*g}FQPL;8E!OqV0nIDIJ=^?L;kF@`ak8r2P)5h zraZ3~5sCb5v&g@eVv+w$HXnp|@Xq4DdPVyV556iYZJ|Oi=ayHFt+lZU^&Zd5^*yB) zV*_rDB##I>Wb5tMhO;YRFmqZVH+^3CdfoVX`#-7OWYX*Vpz?xe7UeVkZ9`-9(El0# z?RMz=n;TgCC-CnP@5uGz3*T)2@2frjrW+jD&g$H2_a~87Tl!+#tfQU9x4gX_;UB_3 z{ZOvFV6g}P)nj2X075|8Ue^yB8iLo`*?xe$et+?u#=o{2`g?Z6ZmN&m)!VN+KY;kp zy`L)f?-7pI9qs$9B)i*R2wyu5`^!J<2hF_K_QEXE8kI`LB`M1b7cW}C#`_a9V$LTx zr2T+1uH=8zzjWYOXSM%!=O5;8gl`rvI?%$VC@+5}j+|5pb z z2R76N7aN(shw&cPf2I9CU+wXg?l1p_>?cz^`N&>|lCOph*3^unu^Cq!Z;3z0xS6f* zY0Gl^)qqQv`19`H@_1gG9qU(nE^Tj%1G~VDVN5|5ZBP5h z5%%Cx&;4K6{GX?|VdFtZ<-gnWU&6nS^B}NI-enRlZ#WsVGszxNozQj-qatBaodB~zBknGgMTPu z^TGXtRwZU+71q-FPd=yE9sjU|8@J(1u!U(=-*#`G_64W zUrcR#km|pl&nexOnr@(YZAkC&7tbAK>0G};BNsjl)~`uza01-DUqz5`$*|l%aNTsu zCu5TZ`v42k59f|&?y9mf{-y@4s#}94JTth5-Qt1ggrG!EoYoD&%R|!h0qmbXW@}KK z%|m}vmG*r{T#`Pyem{;1Rv_5#7T8VX)Ni@hGvR%ZB$J8qPtpOwCV*%L*NVOD1M+if z^K9xrNLie^rmN?9E=~9!EYe*g?vR$zb5+-WFa4Jd%s&S*AL!*RR;&g`1Xl;vR4L$uHkcD_+wo}&dfN8-jv zT3*+kFFuAo9`BwHB_(yOO$|Hu#C$l_ORS6IZi4v}LB_=K z=!0T$e;pv4$6kT5@)(8#+88P7fU+gx^KfLt$9}Od`4v54Q%YjzmXPw`{Ew=2EC|0v zl3#wl6V5Ax@RIyflIZz;@Re}s%AUwL1~(}W)Okt!a0t?z*sX}B@~cDW`6kct_+wRm zU$^|+#c?3~7SH`pa=ukM@6b{C)18J!VKVOKKkWiC1Np)Q;v)Q7AM%UIgOPpdptO%5 z3z@AO6SEKq&#w(47{ph7*wRvlomQ4#ZV$fXHzI!Rx~hWSq&z~G>vtP6HP*T-_WzE` zFK?e5LoiH&L@~a$A%#U6^TUu+R!ej4mkTV4z%BFJl+aC^HZ8_1SP?Ivugn~UNC8KJ>e4UtWz#e{(KG1zXdJ)DT*He z>%YYNT|<6Z`8oT^`3Wm2PH2z6{GSZH;5Gg?y4q{;SHGU|-p%xJYn&8sbwdA64`KfLcEflM3Q9Y4gsuPEx%bK@c&rD@=X+e&y(x74 zj#HUT6HuwS7ED0wU7SfdEq(y+;m@GUC)coaWV+q(RAiq^OxW!mOyQ{ED2u0zNo@U7 zux-J<**EdauY5i{mdp?N9x(qS{+dI|N4@=bXJc+Ol%LZN;%ic$5#jKd3tS|L_e6$1 zcY4P|osDrwiL!Bb*jKbZj5g~+TFq?yKP^mkrT9F;1^xT$p+bBN1`%}fEXj!@$psUGwwalwojFeA?BT7uhPs*Ae?i4j2eG zDJ=-Dx$WT0vRlaG?)s~WB8o`72)ov6^{qOu8mU2`M$?H^@)^zZFJ& z$}Tt7!|$E#Efv_~eNB1&?eM;K_{su7K6sp40DR;4xALfbpA%2dE0}-pD8?bXyPeS) zm_Jr&JoevV{xc4(H#7ePJw*8^RPK%kNss9$=0UfP7%{{GR1B8neEF?KEl=;^4hY^UEZ*> z@fi2*lR8nA#Po}Y#F(cakp7=sTc6~Au5)QwdY*HUy~`4_lppofO%e7Vp)t^;!QXnv z+j0!e9{eA?iuPAiV;_DbUzup4?QQMF4_MhZ?kS3!)vE{1%U?|(WJSo)Yt)X3mR}4M cAAV`4p?gaAHj0bh@0O#0=O`}TNODQ||4q~$wg3PC literal 0 HcmV?d00001 diff --git a/files/data/textures/omw_steam_button_l3.dds b/files/data/textures/omw_steam_button_l3.dds new file mode 100644 index 0000000000000000000000000000000000000000..3b6b174e482c790cf00896e35d34f2683af53313 GIT binary patch literal 22000 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 literal 0 HcmV?d00001 diff --git a/files/data/textures/omw_steam_button_menu.dds b/files/data/textures/omw_steam_button_menu.dds new file mode 100644 index 0000000000000000000000000000000000000000..ef0a0a501c8c3cc085b8de4b369fb96c36640bfb GIT binary patch literal 22000 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 LO#U@*1mph)YI8aW literal 0 HcmV?d00001 diff --git a/files/data/textures/omw_steam_button_r1.dds b/files/data/textures/omw_steam_button_r1.dds new file mode 100644 index 0000000000000000000000000000000000000000..bdd93de2b2975c69b7d431ad106dcbad015f1b02 GIT binary patch literal 22000 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 C_0qNg literal 0 HcmV?d00001 diff --git a/files/data/textures/omw_steam_button_r2.dds b/files/data/textures/omw_steam_button_r2.dds new file mode 100644 index 0000000000000000000000000000000000000000..052e97ebe1aca5f4511a54f5170c846435b01567 GIT binary patch literal 22000 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 X>*CL)FkD_ag@hq*KV=oP9*+MXXwoi9 literal 0 HcmV?d00001 diff --git a/files/data/textures/omw_steam_button_r3.dds b/files/data/textures/omw_steam_button_r3.dds new file mode 100644 index 0000000000000000000000000000000000000000..73b4bea1f7bb3ecb45eb2df16d2e84757b7d2075 GIT binary patch literal 22000 zcmeHP4_s7LzCUM%8D>CWhRxynYr(G?r_eXxuqkiZSAM~x#E21 zoO{mi|M{Iicb<4+M#wURkh{tQ8Q_2N4{6CCgcR^kH|_CXKMDVIQ=aC(yWO7*VzB{NQhueWM)|rx&(ReB z-)LR@kvcV|_}F8*_^K*7lizU>J|V&%i*V^g=jTtkz~cJi_Qd^(=@HZWp;|Y+Dp;97 z`B|lGKi2td8sitc_f}!I5GgJH_t(E6v2xXdrzyV%q{~>T+Y(A~Rj;?gm0MI%6n9j< z|K+q?6^jpF+mJR>m&xjLb-KxmGToScT(+We6NC`@{5K+8?*fbKi`#?#9?f*;b!?3>|n@#aw(UOcD2mRiZ_=e*EqlA`s*cuL8iSxcfF_Mu__RF5XP(;VC`-?j{ zU6$|Q3}4a<>HphcgIj_@5l%7Ae@Bm{y-Fw^1LK|LjVe zKeu>*-O2baA4d66W8IdE#aEfWvph?!M;`et^XE$w3SY{)JW5IH|E4{E+WG4_b1A+F z@nMI9JtWz5TP)u$w9xW@wf?!GBwZKu{Vl3I7Un>26Vh$j*ff`oXO||lAG;9b`68u1 z%X9g3ZjKkr2h=#KHmudb9^4^6NXuo<|J3XOE5W%}$%j*ZBvHsMp?o)se@BBlmS#P2 zj_J2OdCAqJoKcLQu7@*25R$X_*w3QdK7iS^h8QZbC0CnWbyCx zfWoCIH~zus>q?K97nu_-=o@0>?v2O7=<~Z#LUX7ta~Z`P#K(<;LfCjd@p^0?DI*t& zuNfQiU$4|y`cr(r?ZG}Nma};Nka@t=DhGW}y@Totucr@|)^+pXL4lY73@H06K zd1)!$4e_i_cZl)dg^(UM8FOfPSNittXUhe9I6a`Ppz~S59wH^nr)wH~+G&04o)7V% z-%*P1wLOT(?@_okx2Q0M*?&n8=zGNT%$~nT--__KkC^?-_v9xAo917p^m3?4kBOY% zBJy$-&x^~rmi}B*e_9_8I_Om?U%>L``BrtjV|#O)UQNDxz<)+y%J}~`YdBM8#Cl<`1?ThW< zMUg!OG(k;=c&<9^9M7@BG-t+@Pnm!Dn5_r6D|c>BV*15+%zLSg8bT~wL>{uerU6wM z){iI#duYW6jm#d~lD2PeQ+ckVR?+AK5Ul^I0JtXz=TkH4RSjz^f{MIP(v&yu?_6 zN;l`MS^og-|21V{c1pzmuz26PxT)29XF2nCY}I9yugPKd3gg{|KxKv}eg1CcA%5PK z{>A(N_O5}O(lh65ffc6;>jU0r)%nwOt9{qNz255u(F7nNo&E)?{?v+t4zW<)fx zcyB4Vn(VPf(7z4Etr(QNg5@*%GbhZ}8)lXd-D`RDRR5YMObfeA3xg?tnlkc9%JOp# zl}IK|6V_u~$wyPBPBOombl>put=uAjLigZY2a@Q47vCL`0o?X!21J@RUp|I7T+U$1=A z%H(;q1%ZoqsR7{3iR)NnwA$0-zFWuQCMFN!p#FU^>?oS2Qet$LH{LVn^Zn<)AnuE z@2EWBrg%v9o3EeWCFoy&=8W0))lWzN3;#g$m&p9zmA*A*Q{qT<(oD)V<;-t5wnnxG8-lV>hOagPY<9F(|(W`VS)dhY&!YFB*PT z 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 C+cc5@ literal 0 HcmV?d00001 diff --git a/files/data/textures/omw_steam_button_view.dds b/files/data/textures/omw_steam_button_view.dds new file mode 100644 index 0000000000000000000000000000000000000000..8fb56f847fef49cf612c21ff664e4e25d661c561 GIT binary patch literal 22000 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 literal 0 HcmV?d00001 diff --git a/files/data/textures/omw_steam_button_x.dds b/files/data/textures/omw_steam_button_x.dds new file mode 100644 index 0000000000000000000000000000000000000000..9619ed243cfa4a27a4d5a4cfccd8a0f0551f12bd GIT binary patch literal 22000 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 Date: Sun, 18 May 2025 01:27:38 -0700 Subject: [PATCH 037/330] Consolidate all gamepad cursor listening in controllermanager --- apps/openmw/mwgui/birth.cpp | 16 ------ apps/openmw/mwgui/birth.hpp | 2 - apps/openmw/mwgui/class.cpp | 38 +------------ apps/openmw/mwgui/class.hpp | 4 -- apps/openmw/mwgui/confirmationdialog.cpp | 1 + apps/openmw/mwgui/container.cpp | 19 +------ apps/openmw/mwgui/container.hpp | 2 - apps/openmw/mwgui/journalwindow.cpp | 15 ------ apps/openmw/mwgui/journalwindow.hpp | 1 - apps/openmw/mwgui/mainmenu.cpp | 1 + apps/openmw/mwgui/messagebox.cpp | 1 + apps/openmw/mwgui/race.cpp | 13 +---- apps/openmw/mwgui/race.hpp | 1 - apps/openmw/mwgui/savegamedialog.cpp | 17 ------ apps/openmw/mwgui/savegamedialog.hpp | 2 - apps/openmw/mwgui/waitdialog.cpp | 1 + apps/openmw/mwgui/windowbase.cpp | 18 +++---- apps/openmw/mwgui/windowbase.hpp | 14 ++--- apps/openmw/mwinput/controllermanager.cpp | 65 +++++++++++++++++------ 19 files changed, 76 insertions(+), 155 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 53f0f9793b..b047f6dc5f 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -282,10 +282,6 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - // Have A button do nothing so mouse controller still works. - if (mUsingGamepadGuiCursor) - return false; - if (mOkButtonFocus) onOkClicked(mOkButton); else @@ -304,14 +300,12 @@ namespace MWGui MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); winMgr->setKeyFocusWidget(mBirthList); winMgr->injectKeyPress(MyGUI::KeyCode::ArrowUp, 0, false); - mUsingGamepadGuiCursor = false; } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) { MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); winMgr->setKeyFocusWidget(mBirthList); winMgr->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); - mUsingGamepadGuiCursor = false; } else if ((arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && mOkButtonFocus) || (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && !mOkButtonFocus)) @@ -319,18 +313,8 @@ namespace MWGui mOkButtonFocus = !mOkButtonFocus; mOkButton->setStateSelected(mOkButtonFocus); mBackButton->setStateSelected(!mOkButtonFocus); - mUsingGamepadGuiCursor = false; } return true; } - - bool BirthDialog::onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) - { - if (arg.axis == SDL_CONTROLLER_AXIS_LEFTX || arg.axis == SDL_CONTROLLER_AXIS_LEFTY) - { - mUsingGamepadGuiCursor = true; - } - return false; - } } diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index 8a7190b934..09a0b7b1b5 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -59,9 +59,7 @@ namespace MWGui ESM::RefId mCurrentBirthId; bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) override; bool mOkButtonFocus = true; - bool mUsingGamepadGuiCursor = false; }; } #endif diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 0ac39e4bac..cc44de7b0c 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -58,6 +58,7 @@ namespace MWGui if (Settings::gui().mControllerMenus) { mOkButton->setStateSelected(true); + mDisableGamepadCursor = true; trackFocusEvents(mBackButton); trackFocusEvents(mOkButton); mControllerButtons.a = "#{sSelect}"; @@ -323,10 +324,6 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - // Have A button do nothing so mouse controller still works. - if (mUsingGamepadGuiCursor) - return false; - if (mOkButtonFocus) onOkClicked(mOkButton); else @@ -345,14 +342,12 @@ namespace MWGui MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); winMgr->setKeyFocusWidget(mClassList); winMgr->injectKeyPress(MyGUI::KeyCode::ArrowUp, 0, false); - mUsingGamepadGuiCursor = false; } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) { MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); winMgr->setKeyFocusWidget(mClassList); winMgr->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); - mUsingGamepadGuiCursor = false; } else if ((arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && mOkButtonFocus) || (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && !mOkButtonFocus)) @@ -360,21 +355,11 @@ namespace MWGui mOkButtonFocus = !mOkButtonFocus; mOkButton->setStateSelected(mOkButtonFocus); mBackButton->setStateSelected(!mOkButtonFocus); - mUsingGamepadGuiCursor = false; } return true; } - bool PickClassDialog::onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) - { - if (arg.axis == SDL_CONTROLLER_AXIS_LEFTX || arg.axis == SDL_CONTROLLER_AXIS_LEFTY) - { - mUsingGamepadGuiCursor = true; - } - return false; - } - /* InfoBoxDialog */ void InfoBoxDialog::fitToText(MyGUI::TextBox* widget) @@ -417,6 +402,7 @@ namespace MWGui center(); + mDisableGamepadCursor = Settings::gui().mControllerMenus; mControllerButtons.a = "#{sSelect}"; } @@ -721,10 +707,6 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - // Have A button do nothing so mouse controller still works. - if (mUsingGamepadGuiCursor) - return false; - if (mControllerFocus == 0) onDescriptionClicked(mButtons[0]); else if (mControllerFocus == 1) @@ -740,11 +722,6 @@ namespace MWGui { onOkClicked(mButtons[2]); } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP || - arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - { - mUsingGamepadGuiCursor = false; - } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) { mButtons[mControllerFocus]->setStateSelected(false); @@ -753,7 +730,6 @@ namespace MWGui else mControllerFocus--; mButtons[mControllerFocus]->setStateSelected(true); - mUsingGamepadGuiCursor = false; } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) { @@ -763,20 +739,10 @@ namespace MWGui else mControllerFocus++; mButtons[mControllerFocus]->setStateSelected(true); - mUsingGamepadGuiCursor = false; } return true; } - bool CreateClassDialog::onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) - { - if (arg.axis == SDL_CONTROLLER_AXIS_LEFTX || arg.axis == SDL_CONTROLLER_AXIS_LEFTY) - { - mUsingGamepadGuiCursor = true; - } - return false; - } - // widget controls void CreateClassDialog::onDialogCancel() diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index e2566ce6c0..515416973e 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -155,9 +155,7 @@ namespace MWGui ESM::RefId mCurrentClassId; bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) override; bool mOkButtonFocus = true; - bool mUsingGamepadGuiCursor = false; }; class SelectSpecializationDialog : public WindowModal @@ -349,9 +347,7 @@ namespace MWGui Widgets::MWSkillPtr mAffectedSkill; bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) override; int mControllerFocus = 2; - bool mUsingGamepadGuiCursor = false; }; } #endif diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index 1d8f14176a..6a65b0b3ec 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -22,6 +22,7 @@ namespace MWGui if (Settings::gui().mControllerMenus) { + mDisableGamepadCursor = true; trackFocusEvents(mOkButton); trackFocusEvents(mCancelButton); mControllerButtons.a = "#{sOk}"; diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 615c4801d3..54eb6122c5 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -96,12 +96,12 @@ namespace MWGui name += MWGui::ToolTips::getSoulString(object.getCellRef()); dialog->openCountDialog(name, "#{sTake}", count); dialog->eventOkClicked.clear(); - if (Settings::gui().mControllerMenus && !mUsingGamepadGuiCursor) + if (Settings::gui().mControllerMenus) dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerWindow::takeItem); else dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerWindow::dragItem); } - else if (Settings::gui().mControllerMenus && !mUsingGamepadGuiCursor) + else if (Settings::gui().mControllerMenus) takeItem(nullptr, count); else dragItem(nullptr, count); @@ -368,14 +368,9 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - if (mUsingGamepadGuiCursor) - return false; - int index = mItemView->getControllerFocus(); if (index >= 0 && index < mItemView->getItemCount()) - { onItemSelected(index); - } } else if (arg.button == SDL_CONTROLLER_BUTTON_B) { @@ -396,21 +391,11 @@ namespace MWGui arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) { mItemView->onControllerButtonEvent(arg); - mUsingGamepadGuiCursor = false; } return true; } - bool ContainerWindow::onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) - { - if (arg.axis == SDL_CONTROLLER_AXIS_LEFTX || arg.axis == SDL_CONTROLLER_AXIS_LEFTY) - { - mUsingGamepadGuiCursor = true; - } - return false; - } - void ContainerWindow::setActiveControllerWindow(bool active) { mItemView->setActiveControllerWindow(active); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index d2d8c9f4aa..08497e0369 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -70,8 +70,6 @@ namespace MWGui void onReferenceUnavailable() override; bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) override; - bool mUsingGamepadGuiCursor = false; }; } #endif // CONTAINER_H diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index abb1843178..20b7acbd9b 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -685,10 +685,6 @@ namespace { if (arg.button == SDL_CONTROLLER_BUTTON_A) // A: Mouse click or Select { - // Fall through to mouse click - if (mUsingGamepadGuiCursor) - return false; - if (mOptionsMode && mQuestMode) { // Choose a quest @@ -773,7 +769,6 @@ namespace mSelectedQuest = mButtons.size() - 1; mButtons[mSelectedQuest]->setStateSelected(true); } - mUsingGamepadGuiCursor = false; return true; } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) @@ -787,21 +782,18 @@ namespace mSelectedQuest = 0; mButtons[mSelectedQuest]->setStateSelected(true); } - mUsingGamepadGuiCursor = false; return true; } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) { if (!mOptionsMode) notifyPrevPage(getWidget(PrevPageBTN)); - mUsingGamepadGuiCursor = false; return true; } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) { if (!mOptionsMode) notifyNextPage(getWidget(NextPageBTN)); - mUsingGamepadGuiCursor = false; return true; } else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) // LB: Previous Page @@ -819,13 +811,6 @@ namespace return false; } - - bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) override - { - if (arg.axis == SDL_CONTROLLER_AXIS_LEFTX || arg.axis == SDL_CONTROLLER_AXIS_LEFTY) - mUsingGamepadGuiCursor = true; - return false; - } }; } diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index 5da2038575..45c4100563 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -34,7 +34,6 @@ namespace MWGui std::vector mButtons; int mSelectedQuest = 0; - bool mUsingGamepadGuiCursor = false; }; } diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index cfcb63e4d5..286167a61e 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -106,6 +106,7 @@ namespace MWGui constexpr VFS::Path::NormalizedView menuBackgroundVideo("video/menu_background.bik"); mHasAnimatedMenu = mVFS->exists(menuBackgroundVideo); + mDisableGamepadCursor = Settings::gui().mControllerMenus; updateMenu(); } diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 8c5a968c99..7e372fa215 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -284,6 +284,7 @@ namespace MWGui if (Settings::gui().mControllerMenus) { + mDisableGamepadCursor = true; mControllerButtons.a = "#{sOk}"; // If we have more than one button, we need to set the focus to the first one. diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 9b97dfbb53..6aecaa0b88 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -475,10 +475,6 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - // Have A button do nothing so mouse controller still works. - if (mUsingGamepadGuiCursor) - return false; - if (mOkButtonFocus) onOkClicked(mOkButton); else @@ -509,14 +505,12 @@ namespace MWGui MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); winMgr->setKeyFocusWidget(mRaceList); winMgr->injectKeyPress(MyGUI::KeyCode::ArrowUp, 0, false); - mUsingGamepadGuiCursor = false; } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) { MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); winMgr->setKeyFocusWidget(mRaceList); winMgr->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); - mUsingGamepadGuiCursor = false; } else if ((arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && mOkButtonFocus) || (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && !mOkButtonFocus)) @@ -524,7 +518,6 @@ namespace MWGui mOkButtonFocus = !mOkButtonFocus; mOkButton->setStateSelected(mOkButtonFocus); mBackButton->setStateSelected(!mOkButtonFocus); - mUsingGamepadGuiCursor = false; } return true; @@ -532,11 +525,7 @@ namespace MWGui bool RaceDialog::onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) { - if (arg.axis == SDL_CONTROLLER_AXIS_LEFTX || arg.axis == SDL_CONTROLLER_AXIS_LEFTY) - { - mUsingGamepadGuiCursor = true; - } - else if (arg.axis == SDL_CONTROLLER_AXIS_RIGHTX) + if (arg.axis == SDL_CONTROLLER_AXIS_RIGHTX) { if (arg.value < -1000 || arg.value > 1000) onPreviewScroll(nullptr, arg.value < 0 ? 1 : -1); diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index c3b322ba8b..3652343308 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -125,7 +125,6 @@ namespace MWGui bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) override; bool mOkButtonFocus = true; - bool mUsingGamepadGuiCursor = false; }; } #endif diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 568c12d00d..b07c307d60 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -516,10 +516,6 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - // Have A button do nothing so mouse controller still works. - if (mUsingGamepadGuiCursor) - return false; - if (mOkButtonFocus) onOkButtonClicked(mOkButton); else @@ -537,21 +533,18 @@ namespace MWGui else index++; mCharacterSelection->setIndexSelected(index); - mUsingGamepadGuiCursor = false; } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) { MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); winMgr->setKeyFocusWidget(mSaveList); winMgr->injectKeyPress(MyGUI::KeyCode::ArrowUp, 0, false); - mUsingGamepadGuiCursor = false; } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) { MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); winMgr->setKeyFocusWidget(mSaveList); winMgr->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); - mUsingGamepadGuiCursor = false; } else if ((arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && !mOkButtonFocus) || (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && mOkButtonFocus)) @@ -559,18 +552,8 @@ namespace MWGui mOkButtonFocus = !mOkButtonFocus; mOkButton->setStateSelected(mOkButtonFocus); mCancelButton->setStateSelected(!mOkButtonFocus); - mUsingGamepadGuiCursor = false; } return true; } - - bool SaveGameDialog::onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) - { - if (arg.axis == SDL_CONTROLLER_AXIS_LEFTX || arg.axis == SDL_CONTROLLER_AXIS_LEFTY) - { - mUsingGamepadGuiCursor = true; - } - return false; - } } diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index fbe319aed1..4717279dfb 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -70,9 +70,7 @@ namespace MWGui const MWState::Slot* mCurrentSlot; bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) override; bool mOkButtonFocus = true; - bool mUsingGamepadGuiCursor = false; }; } diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index fa5cefb238..c57e813767 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -88,6 +88,7 @@ namespace MWGui trackFocusEvents(widget); mControllerButtons.b = "#{sCancel}"; + mDisableGamepadCursor = Settings::gui().mControllerMenus; } void WaitDialog::setPtr(const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index a3d1b27fb4..d1ce72f067 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -109,25 +109,25 @@ void WindowBase::clampWindowCoordinates(MyGUI::Window* window) void WindowBase::focusGain(MyGUI::Widget* _new, MyGUI::Widget* _old) { // REMOVEME - Log(Debug::Verbose) << "WindowBase::focusGain new=" << _new << ", old=" << _old; - mMouseFocus = _new; + //Log(Debug::Verbose) << "WindowBase::focusGain new=" << _new << ", old=" << _old; + //mMouseFocus = _new; } void WindowBase::focusLoss(MyGUI::Widget* _old, MyGUI::Widget* _new) { // REMOVEME - Log(Debug::Verbose) << "WindowBase::focusLoss old=" << _old << ", new=" << _new; - if (mMouseFocus == _old) - mMouseFocus = nullptr; + //Log(Debug::Verbose) << "WindowBase::focusLoss old=" << _old << ", new=" << _new; + //if (mMouseFocus == _old) + // mMouseFocus = nullptr; } void WindowBase::trackFocusEvents(MyGUI::Widget* widget) { - if (!Settings::gui().mControllerMenus) - return; + // if (!Settings::gui().mControllerMenus) + // return; - widget->eventMouseSetFocus += MyGUI::newDelegate(this, &WindowBase::focusGain); - widget->eventMouseLostFocus += MyGUI::newDelegate(this, &WindowBase::focusLoss); + // widget->eventMouseSetFocus += MyGUI::newDelegate(this, &WindowBase::focusGain); + // widget->eventMouseLostFocus += MyGUI::newDelegate(this, &WindowBase::focusLoss); } WindowModal::WindowModal(const std::string& parLayout) diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index 2a9d4592d3..25d97d9308 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -74,28 +74,30 @@ namespace MWGui static void clampWindowCoordinates(MyGUI::Window* window); - /// Called by controllermanager to handle controller events + virtual ControllerButtonStr* getControllerButtons() { return &mControllerButtons; } + bool isGamepadCursorAllowed() { return !mDisableGamepadCursor; } virtual bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { return true; }; virtual bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) { return true; }; - // REMOVEME - // virtual bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) = 0; - // virtual bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) = 0; - virtual ControllerButtonStr* getControllerButtons() { return &mControllerButtons; } virtual void setActiveControllerWindow(bool active) { mActiveControllerWindow = active; } protected: virtual void onTitleDoubleClicked(); ControllerButtonStr mControllerButtons; - MyGUI::Widget* mMouseFocus = nullptr; bool mActiveControllerWindow = false; + bool mDisableGamepadCursor = false; + + // REMOVEME void trackFocusEvents(MyGUI::Widget* widget); + // REMOVEME + MyGUI::Widget* mMouseFocus = nullptr; private: void onDoubleClick(MyGUI::Widget* _sender); bool mDisabledByLua = false; + // REMOVEME void focusGain(MyGUI::Widget* _new, MyGUI::Widget* _old); void focusLoss(MyGUI::Widget* _old, MyGUI::Widget* _new); }; diff --git a/apps/openmw/mwinput/controllermanager.cpp b/apps/openmw/mwinput/controllermanager.cpp index f12c9a31ce..d1deef5011 100644 --- a/apps/openmw/mwinput/controllermanager.cpp +++ b/apps/openmw/mwinput/controllermanager.cpp @@ -241,11 +241,26 @@ namespace MWInput bool ControllerManager::gamepadToGuiControl(const SDL_ControllerButtonEvent& arg) { + MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); + if (Settings::gui().mControllerMenus) { - MWGui::WindowBase* topWin = MWBase::Environment::get().getWindowManager()->getActiveControllerWindow(); - if (topWin && topWin->onControllerButtonEvent(arg)) - return true; + // Update cursor state. + bool treatAsMouse = winMgr->getCursorVisible(); + winMgr->setCursorActive(false); + + MWGui::WindowBase* topWin = winMgr->getActiveControllerWindow(); + if (topWin) + { + mGamepadGuiCursorEnabled = topWin->isGamepadCursorAllowed(); + + // Fall through to mouse click + if (mGamepadGuiCursorEnabled && treatAsMouse && arg.button == SDL_CONTROLLER_BUTTON_A) + return false; + + if (topWin->onControllerButtonEvent(arg)) + return true; + } } // Presumption of GUI mode will be removed in the future. @@ -273,9 +288,9 @@ namespace MWInput break; case SDL_CONTROLLER_BUTTON_B: if (MyGUI::InputManager::getInstance().isModalAny()) - MWBase::Environment::get().getWindowManager()->exitCurrentModal(); + winMgr->exitCurrentModal(); else - MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); + winMgr->exitCurrentGuiMode(); return true; case SDL_CONTROLLER_BUTTON_X: key = MyGUI::KeyCode::Semicolon; @@ -285,7 +300,7 @@ namespace MWInput break; case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::LeftShift); - MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Tab, 0, false); + winMgr->injectKeyPress(MyGUI::KeyCode::Tab, 0, false); MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::LeftShift); return true; case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: @@ -293,7 +308,7 @@ namespace MWInput return true; case SDL_CONTROLLER_BUTTON_LEFTSTICK: mGamepadGuiCursorEnabled = !mGamepadGuiCursorEnabled; - MWBase::Environment::get().getWindowManager()->setCursorActive(mGamepadGuiCursorEnabled); + winMgr->setCursorActive(mGamepadGuiCursorEnabled); return true; default: return false; @@ -303,41 +318,61 @@ namespace MWInput if (SDL_IsTextInputActive()) return false; - MWBase::Environment::get().getWindowManager()->injectKeyPress(key, 0, false); + winMgr->injectKeyPress(key, 0, false); return true; } bool ControllerManager::gamepadToGuiControl(const SDL_ControllerAxisEvent& arg) { + MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); + if (Settings::gui().mControllerMenus) { // Left and right triggers toggle through open GUI windows. if (arg.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT) { if (arg.value == 32767) // Treat like a button. - MWBase::Environment::get().getWindowManager()->cycleActiveControllerWindow(true); + winMgr->cycleActiveControllerWindow(true); return true; } else if (arg.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT) { if (arg.value == 32767) // Treat like a button. - MWBase::Environment::get().getWindowManager()->cycleActiveControllerWindow(false); + winMgr->cycleActiveControllerWindow(false); return true; } - MWGui::WindowBase* topWin = MWBase::Environment::get().getWindowManager()->getActiveControllerWindow(); - if (topWin && topWin->onControllerThumbstickEvent(arg)) - return true; + + MWGui::WindowBase* topWin = winMgr->getActiveControllerWindow(); + if (topWin) + { + // Update cursor state + mGamepadGuiCursorEnabled = topWin->isGamepadCursorAllowed(); + if (!mGamepadGuiCursorEnabled) + winMgr->setCursorActive(false); + + if (mGamepadGuiCursorEnabled + && (arg.axis == SDL_CONTROLLER_AXIS_LEFTX || arg.axis == SDL_CONTROLLER_AXIS_LEFTY)) + { + // Treat the left stick like a cursor. Fall through. + return false; + } + else if (topWin->onControllerThumbstickEvent(arg)) + { + // Window handled the event. + return true; + } + } } switch (arg.axis) { case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: if (arg.value == 32767) // Treat like a button. - MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Minus, 0, false); + winMgr->injectKeyPress(MyGUI::KeyCode::Minus, 0, false); break; case SDL_CONTROLLER_AXIS_TRIGGERLEFT: if (arg.value == 32767) // Treat like a button. - MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Equals, 0, false); + winMgr->injectKeyPress(MyGUI::KeyCode::Equals, 0, false); break; case SDL_CONTROLLER_AXIS_LEFTX: case SDL_CONTROLLER_AXIS_LEFTY: From f15cc663aeb224685328796347b08583a7cab4b2 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 18 May 2025 01:42:11 -0700 Subject: [PATCH 038/330] Remove old way of listening for gamepad mouse events --- apps/openmw/mwgui/bookwindow.cpp | 7 ---- apps/openmw/mwgui/class.cpp | 10 ----- apps/openmw/mwgui/confirmationdialog.cpp | 5 --- apps/openmw/mwgui/mainmenu.cpp | 49 +++++++++--------------- apps/openmw/mwgui/messagebox.cpp | 5 --- apps/openmw/mwgui/review.cpp | 9 ----- apps/openmw/mwgui/savegamedialog.cpp | 8 ---- apps/openmw/mwgui/scrollwindow.cpp | 5 --- apps/openmw/mwgui/waitdialog.cpp | 11 ------ apps/openmw/mwgui/windowbase.cpp | 24 ------------ apps/openmw/mwgui/windowbase.hpp | 9 ----- 11 files changed, 19 insertions(+), 123 deletions(-) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index c48493c1b4..beba6e5968 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -27,19 +27,15 @@ namespace MWGui { getWidget(mCloseButton, "CloseButton"); mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onCloseButtonClicked); - trackFocusEvents(mCloseButton); getWidget(mTakeButton, "TakeButton"); mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onTakeButtonClicked); - trackFocusEvents(mTakeButton); getWidget(mNextPageButton, "NextPageBTN"); mNextPageButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onNextPageButtonClicked); - trackFocusEvents(mNextPageButton); getWidget(mPrevPageButton, "PrevPageBTN"); mPrevPageButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onPrevPageButtonClicked); - trackFocusEvents(mPrevPageButton); getWidget(mLeftPageNumber, "LeftPageNumber"); getWidget(mRightPageNumber, "RightPageNumber"); @@ -236,9 +232,6 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - if (mMouseFocus != nullptr) - return false; - if (mTakeButton->getVisible()) onTakeButtonClicked(mTakeButton); } diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index cc44de7b0c..d4de67dbec 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -59,8 +59,6 @@ namespace MWGui { mOkButton->setStateSelected(true); mDisableGamepadCursor = true; - trackFocusEvents(mBackButton); - trackFocusEvents(mOkButton); mControllerButtons.a = "#{sSelect}"; mControllerButtons.b = "#{sBack}"; } @@ -84,9 +82,6 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - if (mMouseFocus != nullptr) - return false; - if (mOkButtonFocus) onOkClicked(mOkButton); else @@ -444,7 +439,6 @@ namespace MWGui // First button is selected by default button->setStateSelected(true); } - trackFocusEvents(button); this->mButtons.push_back(button); } @@ -479,11 +473,7 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - if (mMouseFocus != nullptr) - return false; - onButtonClicked(mButtons[mControllerFocus]); - return true; } else if (arg.button == SDL_CONTROLLER_BUTTON_B) { diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index 6a65b0b3ec..36b01112e5 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -23,8 +23,6 @@ namespace MWGui if (Settings::gui().mControllerMenus) { mDisableGamepadCursor = true; - trackFocusEvents(mOkButton); - trackFocusEvents(mCancelButton); mControllerButtons.a = "#{sOk}"; mControllerButtons.b = "#{sCancel}"; } @@ -79,9 +77,6 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - if (mMouseFocus != nullptr) - return false; - if (mOkButtonFocus) onOkButtonClicked(mOkButton); else diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 286167a61e..d9d5b5c33b 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -210,37 +210,27 @@ namespace MWGui bool MainMenu::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { - // REMOVEME - Log(Debug::Verbose) << "MainMenu::onControllerButtonEvent " << arg.button; - - MyGUI::KeyCode key = MyGUI::KeyCode::None; - switch (arg.button) + if (arg.button == SDL_CONTROLLER_BUTTON_A) { - case SDL_CONTROLLER_BUTTON_DPAD_UP: - MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::LeftShift); - MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Tab, 0, false); - MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::LeftShift); - return true; - case SDL_CONTROLLER_BUTTON_DPAD_DOWN: - key = MyGUI::KeyCode::Tab; - break; - case SDL_CONTROLLER_BUTTON_A: - if (mMouseFocus != nullptr) - return false; - key = MyGUI::KeyCode::Space; - break; - case SDL_CONTROLLER_BUTTON_B: - case SDL_CONTROLLER_BUTTON_START: - if (mButtons["return"]->getVisible()) - { - onButtonClicked(mButtons["return"]); - return true; - } - else - key = MyGUI::KeyCode::Escape; - break; + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Space, 0, false); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B || arg.button == SDL_CONTROLLER_BUTTON_START) + { + if (mButtons["return"]->getVisible()) + onButtonClicked(mButtons["return"]); + else + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Escape, 0, false); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) + { + MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::LeftShift); + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Tab, 0, false); + MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::LeftShift); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + { + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Tab, 0, false); } - MWBase::Environment::get().getWindowManager()->injectKeyPress(key, 0, false); return true; } @@ -344,7 +334,6 @@ namespace MWGui button->setProperty("ImagePushed", "textures\\menu_" + buttonId + "_pressed.dds"); button->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::onButtonClicked); button->setUserData(buttonId); - trackFocusEvents(button); } } diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 7e372fa215..311743fd36 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -260,7 +260,6 @@ namespace MWGui button->setCaptionWithReplacing(buttonId); button->eventMouseButtonClick += MyGUI::newDelegate(this, &InteractiveMessageBox::mousePressed); - trackFocusEvents(button); mButtons.push_back(button); @@ -447,11 +446,7 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - if (mMouseFocus != nullptr) - return false; - buttonActivated(mButtons[mControllerFocus]); - return true; } else if (arg.button == SDL_CONTROLLER_BUTTON_B) { diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 4d0d9d4d2c..19dcda90e4 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -46,28 +46,24 @@ namespace MWGui getWidget(button, "NameButton"); adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onNameClicked); - trackFocusEvents(button); mButtons.push_back(button); getWidget(mRaceWidget, "RaceText"); getWidget(button, "RaceButton"); adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onRaceClicked); - trackFocusEvents(button); mButtons.push_back(button); getWidget(mClassWidget, "ClassText"); getWidget(button, "ClassButton"); adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onClassClicked); - trackFocusEvents(button); mButtons.push_back(button); getWidget(mBirthSignWidget, "SignText"); getWidget(button, "SignButton"); adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBirthSignClicked); - trackFocusEvents(button); mButtons.push_back(button); // Setup dynamic stats @@ -116,13 +112,11 @@ namespace MWGui MyGUI::Button* backButton; getWidget(backButton, "BackButton"); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBackClicked); - trackFocusEvents(backButton); mButtons.push_back(backButton); MyGUI::Button* okButton; getWidget(okButton, "OKButton"); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onOkClicked); - trackFocusEvents(okButton); mButtons.push_back(okButton); if (Settings::gui().mControllerMenus) @@ -546,9 +540,6 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - if (mMouseFocus != nullptr) - return false; - switch(mControllerFocus) { case 0: diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index b07c307d60..2484b0b1d2 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -64,8 +64,6 @@ namespace MWGui // To avoid accidental deletions mDeleteButton->setNeedKeyFocus(false); - trackFocusEvents(mCancelButton); - trackFocusEvents(mDeleteButton); mControllerButtons.a = "#{sSelect}"; mControllerButtons.b = "#{sClose}"; } @@ -371,12 +369,6 @@ namespace MWGui } else onSlotSelected(mSaveList, MyGUI::ITEM_NONE); - - if (Settings::gui().mControllerMenus) - { - for (int i = 0; i < mSaveList->getItemCount(); i++) - trackFocusEvents(mSaveList->getWidgetByIndex(i)); - } } std::string formatTimeplayed(const double timeInSeconds) diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 5146d77e5d..ae47a361a2 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -29,11 +29,9 @@ namespace MWGui getWidget(mCloseButton, "CloseButton"); mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ScrollWindow::onCloseButtonClicked); - trackFocusEvents(mCloseButton); getWidget(mTakeButton, "TakeButton"); mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ScrollWindow::onTakeButtonClicked); - trackFocusEvents(mTakeButton); adjustButton("CloseButton"); adjustButton("TakeButton"); @@ -139,9 +137,6 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - if (mMouseFocus != nullptr) - return false; - if (mTakeButton->getVisible()) onTakeButtonClicked(mTakeButton); } diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index c57e813767..8df47e7d58 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -81,12 +81,6 @@ namespace MWGui mTimeAdvancer.eventInterrupted += MyGUI::newDelegate(this, &WaitDialog::onWaitingInterrupted); mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &WaitDialog::onWaitingFinished); - trackFocusEvents(mUntilHealedButton); - trackFocusEvents(mWaitButton); - trackFocusEvents(mCancelButton); - for (MyGUI::Widget* widget : mHourSlider->getAllWidgets()) - trackFocusEvents(widget); - mControllerButtons.b = "#{sCancel}"; mDisableGamepadCursor = Settings::gui().mControllerMenus; } @@ -345,12 +339,7 @@ namespace MWGui bool WaitDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - if (mMouseFocus != nullptr) - return false; - onWaitButtonClicked(mWaitButton); - } else if (arg.button == SDL_CONTROLLER_BUTTON_B) onCancelButtonClicked(mCancelButton); else if (arg.button == SDL_CONTROLLER_BUTTON_X && mUntilHealedButton->getVisible()) diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index d1ce72f067..ae12076d2d 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -106,30 +106,6 @@ void WindowBase::clampWindowCoordinates(MyGUI::Window* window) window->setPosition(left, top); } -void WindowBase::focusGain(MyGUI::Widget* _new, MyGUI::Widget* _old) -{ - // REMOVEME - //Log(Debug::Verbose) << "WindowBase::focusGain new=" << _new << ", old=" << _old; - //mMouseFocus = _new; -} - -void WindowBase::focusLoss(MyGUI::Widget* _old, MyGUI::Widget* _new) -{ - // REMOVEME - //Log(Debug::Verbose) << "WindowBase::focusLoss old=" << _old << ", new=" << _new; - //if (mMouseFocus == _old) - // mMouseFocus = nullptr; -} - -void WindowBase::trackFocusEvents(MyGUI::Widget* widget) -{ - // if (!Settings::gui().mControllerMenus) - // return; - - // widget->eventMouseSetFocus += MyGUI::newDelegate(this, &WindowBase::focusGain); - // widget->eventMouseLostFocus += MyGUI::newDelegate(this, &WindowBase::focusLoss); -} - WindowModal::WindowModal(const std::string& parLayout) : WindowBase(parLayout) { diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index 25d97d9308..f14c41dca1 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -87,19 +87,10 @@ namespace MWGui bool mActiveControllerWindow = false; bool mDisableGamepadCursor = false; - // REMOVEME - void trackFocusEvents(MyGUI::Widget* widget); - // REMOVEME - MyGUI::Widget* mMouseFocus = nullptr; - private: void onDoubleClick(MyGUI::Widget* _sender); bool mDisabledByLua = false; - - // REMOVEME - void focusGain(MyGUI::Widget* _new, MyGUI::Widget* _old); - void focusLoss(MyGUI::Widget* _old, MyGUI::Widget* _new); }; /* From f80d46dc94af710079d66bbc2351e76f4229c26e Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 18 May 2025 15:34:22 -0700 Subject: [PATCH 039/330] Add controller support to count dialog --- apps/openmw/mwgui/countdialog.cpp | 17 +++++++++++++++++ apps/openmw/mwgui/countdialog.hpp | 1 + 2 files changed, 18 insertions(+) diff --git a/apps/openmw/mwgui/countdialog.cpp b/apps/openmw/mwgui/countdialog.cpp index 2ca6657a17..75a2fc6034 100644 --- a/apps/openmw/mwgui/countdialog.cpp +++ b/apps/openmw/mwgui/countdialog.cpp @@ -27,6 +27,9 @@ namespace MWGui mSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &CountDialog::onSliderMoved); // make sure we read the enter key being pressed to accept multiple items mItemEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &CountDialog::onEnterKeyPressed); + + mControllerButtons.a = "#{sOk}"; + mControllerButtons.b = "#{sCancel}"; } void CountDialog::openCountDialog(const std::string& item, const std::string& message, const int maxCount) @@ -86,4 +89,18 @@ namespace MWGui { mItemEdit->setValue(_position + 1); } + + bool CountDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + onOkButtonClicked(mOkButton); + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + onCancelButtonClicked(mCancelButton); + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::ArrowUp, 0, false); + + return true; + } } diff --git a/apps/openmw/mwgui/countdialog.hpp b/apps/openmw/mwgui/countdialog.hpp index 95d4a9a8d4..695de09215 100644 --- a/apps/openmw/mwgui/countdialog.hpp +++ b/apps/openmw/mwgui/countdialog.hpp @@ -38,6 +38,7 @@ namespace MWGui void onEditValueChanged(int value); void onSliderMoved(MyGUI::ScrollBar* _sender, size_t _position); void onEnterKeyPressed(MyGUI::EditBox* _sender); + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; }; } From a144793753a489a067da28ffbd6019bc3617a5e9 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 18 May 2025 22:45:03 -0700 Subject: [PATCH 040/330] Fix Y button changing character --- apps/openmw/mwgui/savegamedialog.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 2484b0b1d2..fe45fa8729 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -525,6 +525,7 @@ namespace MWGui else index++; mCharacterSelection->setIndexSelected(index); + onCharacterSelected(mCharacterSelection, index); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) { From 0aad0d379aafe41352b55b1f10657fb51134d23d Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 18 May 2025 22:45:22 -0700 Subject: [PATCH 041/330] Minimal controller support for dialog window --- apps/openmw/mwgui/dialogue.cpp | 135 +++++++++++++++++++++++++++++++++ apps/openmw/mwgui/dialogue.hpp | 11 +++ components/widgets/list.cpp | 5 ++ components/widgets/list.hpp | 1 + 4 files changed, 152 insertions(+) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index e14c400978..3633c90e6a 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -88,6 +88,10 @@ namespace MWGui mBribe10Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); mBribe100Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); mBribe1000Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + + mDisableGamepadCursor = Settings::gui().mControllerMenus; + mControllerButtons.a = "#{sSelect}"; + mControllerButtons.b = "#{sBack}"; } void PersuasionDialog::adjustAction(MyGUI::Widget* action, int& totalHeight) @@ -144,6 +148,24 @@ namespace MWGui else mMainWidget->setSize(mInitialMainWidgetWidth, mMainWidget->getSize().height); + if (Settings::gui().mControllerMenus) + { + mControllerFocus = 0; + mButtons.clear(); + mButtons.push_back(mAdmireButton); + mButtons.push_back(mIntimidateButton); + mButtons.push_back(mTauntButton); + if (mBribe10Button->getEnabled()) + mButtons.push_back(mBribe10Button); + if (mBribe100Button->getEnabled()) + mButtons.push_back(mBribe100Button); + if (mBribe1000Button->getEnabled()) + mButtons.push_back(mBribe1000Button); + + for (int i = 0; i < mButtons.size(); i++) + mButtons[i]->setStateSelected(i == 0); + } + WindowModal::onOpen(); } @@ -152,6 +174,34 @@ namespace MWGui return mAdmireButton; } + bool PersuasionDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + onPersuade(mButtons[mControllerFocus]); + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + onCancel(mCancelButton); + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) + { + mButtons[mControllerFocus]->setStateSelected(false); + if (mControllerFocus == 0) + mControllerFocus = mButtons.size() - 1; + else + mControllerFocus--; + mButtons[mControllerFocus]->setStateSelected(true); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + { + mButtons[mControllerFocus]->setStateSelected(false); + if (mControllerFocus == mButtons.size() - 1) + mControllerFocus = 0; + else + mControllerFocus++; + mButtons[mControllerFocus]->setStateSelected(true); + } + + return true; + } + // -------------------------------------------------------------------------------------------------- Response::Response(std::string_view text, std::string_view title, bool needMargin) @@ -335,6 +385,9 @@ namespace MWGui mMainWidget->castType()->eventWindowChangeCoord += MyGUI::newDelegate(this, &DialogueWindow::onWindowResize); + + mControllerButtons.a = "#{sAsk}"; + mControllerButtons.b = "#{sGoodbye}"; } void DialogueWindow::onTradeComplete() @@ -488,6 +541,14 @@ namespace MWGui updateTopics(); updateTopicsPane(); // force update for new services + if (Settings::gui().mControllerMenus && !sameActor) + { + setControllerFocus(mControllerFocus, false); + // Reset focus to very top. Maybe change this to mTopicsList->getItemCount() - mKeywords.size()? + mControllerFocus = 0; + setControllerFocus(mControllerFocus, true); + } + updateDisposition(); restock(); } @@ -601,6 +662,9 @@ namespace MWGui redrawTopicsList(); updateHistory(); + + if (Settings::gui().mControllerMenus) + setControllerFocus(mControllerFocus, true); } void DialogueWindow::updateHistory(bool scrollbar) @@ -847,4 +911,75 @@ namespace MWGui && actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion"); } + void DialogueWindow::setControllerFocus(int index, bool focused) + { + // List is mTopicsList + "Goodbye" button below the list. + if (index < 0 || index > mTopicsList->getItemCount()) + return; + + if (index == mTopicsList->getItemCount()) + { + mGoodbyeButton->setStateSelected(focused); + } + else { + std::string keyword = mTopicsList->getItemNameAt(mControllerFocus); + if (keyword.length() == 0) + return; + + MyGUI::Button* button = mTopicsList->getItemWidget(keyword); + button->setStateSelected(focused); + } + + if (focused) + { + // Scroll the side bar to keep the active item in view + if (index <= 5) + mTopicsList->setViewOffset(0); + else + mTopicsList->setViewOffset(-20 * (index - 5)); + } + } + + bool DialogueWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + if (mControllerFocus == mTopicsList->getItemCount()) + onGoodbyeActivated(); + else + onSelectListItem(mTopicsList->getItemNameAt(mControllerFocus), mControllerFocus); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + { + onGoodbyeActivated(); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) + { + // Number of items is mTopicsList.length+1 because of "Goodbye" button. + setControllerFocus(mControllerFocus, false); + if (mControllerFocus <= 0) + mControllerFocus = mTopicsList->getItemCount(); + else if (mTopicsList->getItemNameAt(mControllerFocus - 1).length() == 0) + mControllerFocus -= 2; // Skip separator + else + mControllerFocus--; + setControllerFocus(mControllerFocus, true); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + { + // Number of items is mTopicsList.length+1 because of "Goodbye" button. + setControllerFocus(mControllerFocus, false); + if (mControllerFocus >= mTopicsList->getItemCount()) + mControllerFocus = 0; + else if (mControllerFocus == mTopicsList->getItemCount() - 1) + mControllerFocus = mTopicsList->getItemCount(); + else if (mTopicsList->getItemNameAt(mControllerFocus + 1).length() == 0) + mControllerFocus += 2; // Skip separator + else + mControllerFocus++; + setControllerFocus(mControllerFocus, true); + } + + return true; + } } diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 8a8b309401..68de4b73d7 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -49,6 +49,9 @@ namespace MWGui MyGUI::Widget* getDefaultKeyFocus() override; + protected: + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + private: std::unique_ptr mCallback; @@ -65,6 +68,9 @@ namespace MWGui MyGUI::Widget* mActionsBox; Gui::AutoSizedTextBox* mGoldLabel; + std::vector mButtons; + int mControllerFocus = 0; + void adjustAction(MyGUI::Widget* action, int& totalHeight); void onCancel(MyGUI::Widget* sender); @@ -186,6 +192,8 @@ namespace MWGui void onReferenceUnavailable() override; + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + private: void updateDisposition(); void restock(); @@ -220,6 +228,9 @@ namespace MWGui std::unique_ptr mCallback; std::unique_ptr mGreetingCallback; + void setControllerFocus(int index, bool focused); + int mControllerFocus = 0; + void updateTopicFormat(); }; } diff --git a/components/widgets/list.cpp b/components/widgets/list.cpp index 896057443c..28fa48e081 100644 --- a/components/widgets/list.cpp +++ b/components/widgets/list.cpp @@ -173,4 +173,9 @@ namespace Gui { mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); } + + void MWList::setViewOffset(int offset) + { + mScrollView->setViewOffset(MyGUI::IntPoint(0, offset)); + } } diff --git a/components/widgets/list.hpp b/components/widgets/list.hpp index 3d5e320cf7..022214dd1c 100644 --- a/components/widgets/list.hpp +++ b/components/widgets/list.hpp @@ -48,6 +48,7 @@ namespace Gui ///< get widget for an item name, useful to set up tooltip void scrollToTop(); + void setViewOffset(int offset); void setPropertyOverride(std::string_view _key, std::string_view _value) override; From f36401438fa915b10d82b9fcef6e0b3c2408536b Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Mon, 19 May 2025 23:43:28 -0700 Subject: [PATCH 042/330] Move wrap function to windowbase so all windows can use it --- apps/openmw/mwgui/race.cpp | 10 ---------- apps/openmw/mwgui/windowbase.cpp | 10 ++++++++++ apps/openmw/mwgui/windowbase.hpp | 2 ++ 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 6aecaa0b88..172812bf47 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -23,16 +23,6 @@ namespace { - int wrap(int index, int max) - { - if (index < 0) - return max - 1; - else if (index >= max) - return 0; - else - return index; - } - bool sortRaces(const std::pair& left, const std::pair& right) { return left.second.compare(right.second) < 0; diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index ae12076d2d..995731a775 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -15,6 +15,16 @@ using namespace MWGui; +int MWGui::wrap(int index, int max) +{ + if (index < 0) + return max - 1; + else if (index >= max) + return 0; + else + return index; +} + WindowBase::WindowBase(std::string_view parLayout) : Layout(parLayout) { diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index f14c41dca1..2b1afbda85 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -14,6 +14,8 @@ namespace MWGui { class DragAndDrop; + int wrap(int index, int max); + struct ControllerButtonStr { std::string a; From f03f242e4a9016ac1dcfc0d72aae7480825a8ef2 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Tue, 20 May 2025 00:12:34 -0700 Subject: [PATCH 043/330] Allow controller to select choice text in dialogue --- apps/openmw/mwgui/bookpage.cpp | 6 ++++ apps/openmw/mwgui/bookpage.hpp | 2 ++ apps/openmw/mwgui/dialogue.cpp | 64 ++++++++++++++++++++++++---------- apps/openmw/mwgui/dialogue.hpp | 2 ++ 4 files changed, 55 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 47e85b1f4b..cb0717edf3 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -1288,6 +1288,12 @@ namespace MWGui void unadviseLinkClicked() override { mPageDisplay->mLinkClicked = std::function(); } + void setFocusItem(BookTypesetter::Style* itemStyle) override + { + mPageDisplay->mFocusItem = (TypesetBookImpl::StyleImpl*)itemStyle; + mPageDisplay->dirtyFocusItem(); + } + protected: void initialiseOverride() override { diff --git a/apps/openmw/mwgui/bookpage.hpp b/apps/openmw/mwgui/bookpage.hpp index d42fb4783f..43de2c09ac 100644 --- a/apps/openmw/mwgui/bookpage.hpp +++ b/apps/openmw/mwgui/bookpage.hpp @@ -164,6 +164,8 @@ namespace MWGui /// Register the widget and associated sub-widget with MyGUI. Should be /// called once near the beginning of the program. static void registerMyGUIComponents(); + + virtual void setFocusItem(BookTypesetter::Style* itemStyle) = 0; }; } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 3633c90e6a..5472f02f04 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -691,6 +691,8 @@ namespace MWGui // choices const TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); mChoices = MWBase::Environment::get().getDialogueManager()->getChoices(); + mChoiceStyles.clear(); + mControllerChoice = -1; // -1 so you must make a choice (and can't accidentally pick the first answer) for (std::pair& choice : mChoices) { auto link = std::make_unique(choice.second); @@ -702,6 +704,7 @@ namespace MWGui BookTypesetter::Style* questionStyle = typesetter->createHotStyle( body, textColours.answer, textColours.answerOver, textColours.answerPressed, interactiveId); typesetter->write(questionStyle, to_utf8_span(choice.first)); + mChoiceStyles.push_back(questionStyle); } mGoodbye = MWBase::Environment::get().getDialogueManager()->isGoodbye(); @@ -944,7 +947,12 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - if (mControllerFocus == mTopicsList->getItemCount()) + if (mChoices.size() > 0) + { + if (mControllerChoice >= 0 && mControllerChoice < mChoices.size()) + onChoiceActivated(mControllerChoice + 1); // +1 because choices are indexed starting at 1 + } + else if (mControllerFocus == mTopicsList->getItemCount()) onGoodbyeActivated(); else onSelectListItem(mTopicsList->getItemNameAt(mControllerFocus), mControllerFocus); @@ -955,29 +963,47 @@ namespace MWGui } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) { - // Number of items is mTopicsList.length+1 because of "Goodbye" button. - setControllerFocus(mControllerFocus, false); - if (mControllerFocus <= 0) - mControllerFocus = mTopicsList->getItemCount(); - else if (mTopicsList->getItemNameAt(mControllerFocus - 1).length() == 0) - mControllerFocus -= 2; // Skip separator + if (mChoices.size() > 0) + { + // In-dialogue choice (red text) + mControllerChoice = std::clamp(mControllerChoice - 1, 0, (int)mChoices.size() - 1); + mHistory->setFocusItem(mChoiceStyles.at(mControllerChoice)); + } else - mControllerFocus--; - setControllerFocus(mControllerFocus, true); + { + // Number of items is mTopicsList.length+1 because of "Goodbye" button. + setControllerFocus(mControllerFocus, false); + if (mControllerFocus <= 0) + mControllerFocus = mTopicsList->getItemCount(); // "Goodbye" button + else if (mTopicsList->getItemNameAt(mControllerFocus - 1).length() == 0) + mControllerFocus -= 2; // Skip separator + else + mControllerFocus--; + setControllerFocus(mControllerFocus, true); + } } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) { - // Number of items is mTopicsList.length+1 because of "Goodbye" button. - setControllerFocus(mControllerFocus, false); - if (mControllerFocus >= mTopicsList->getItemCount()) - mControllerFocus = 0; - else if (mControllerFocus == mTopicsList->getItemCount() - 1) - mControllerFocus = mTopicsList->getItemCount(); - else if (mTopicsList->getItemNameAt(mControllerFocus + 1).length() == 0) - mControllerFocus += 2; // Skip separator + if (mChoices.size() > 0) + { + // In-dialogue choice (red text) + mControllerChoice = std::clamp(mControllerChoice + 1, 0, (int)mChoices.size() - 1); + mHistory->setFocusItem(mChoiceStyles.at(mControllerChoice)); + } else - mControllerFocus++; - setControllerFocus(mControllerFocus, true); + { + // Number of items is mTopicsList.length+1 because of "Goodbye" button. + setControllerFocus(mControllerFocus, false); + if (mControllerFocus >= mTopicsList->getItemCount()) + mControllerFocus = 0; + else if (mControllerFocus == mTopicsList->getItemCount() - 1) + mControllerFocus = mTopicsList->getItemCount(); // "Goodbye" button + else if (mTopicsList->getItemNameAt(mControllerFocus + 1).length() == 0) + mControllerFocus += 2; // Skip separator + else + mControllerFocus++; + setControllerFocus(mControllerFocus, true); + } } return true; diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 68de4b73d7..9a19617425 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -205,6 +205,7 @@ namespace MWGui std::vector> mHistoryContents; std::vector> mChoices; + std::vector mChoiceStyles; bool mGoodbye; std::vector> mLinks; @@ -230,6 +231,7 @@ namespace MWGui void setControllerFocus(int index, bool focused); int mControllerFocus = 0; + int mControllerChoice = -1; void updateTopicFormat(); }; From 23c733ef947c067d32118878b7e2149d687279fc Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Tue, 20 May 2025 00:27:14 -0700 Subject: [PATCH 044/330] Use wrap helper function to simplify some controller handler logic --- apps/openmw/mwgui/class.cpp | 20 ++++---------------- apps/openmw/mwgui/dialogue.cpp | 10 ++-------- apps/openmw/mwgui/journalwindow.cpp | 8 ++------ apps/openmw/mwgui/messagebox.cpp | 10 ++-------- apps/openmw/mwgui/savegamedialog.cpp | 5 +---- apps/openmw/mwgui/settingswindow.cpp | 10 ++-------- 6 files changed, 13 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index d4de67dbec..e658001e5a 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -488,10 +488,7 @@ namespace MWGui return true; mButtons[mControllerFocus]->setStateSelected(false); - if (mControllerFocus == 0) - mControllerFocus = mButtons.size() - 1; - else - mControllerFocus--; + mControllerFocus = wrap(mControllerFocus - 1, mButtons.size()); mButtons[mControllerFocus]->setStateSelected(true); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) @@ -502,10 +499,7 @@ namespace MWGui return true; mButtons[mControllerFocus]->setStateSelected(false); - if (mControllerFocus == mButtons.size() - 1) - mControllerFocus = 0; - else - mControllerFocus++; + mControllerFocus = wrap(mControllerFocus + 1, mButtons.size()); mButtons[mControllerFocus]->setStateSelected(true); } @@ -715,19 +709,13 @@ namespace MWGui else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) { mButtons[mControllerFocus]->setStateSelected(false); - if (mControllerFocus == 0) - mControllerFocus = mButtons.size() - 1; - else - mControllerFocus--; + mControllerFocus = wrap(mControllerFocus - 1, mButtons.size()); mButtons[mControllerFocus]->setStateSelected(true); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) { mButtons[mControllerFocus]->setStateSelected(false); - if (mControllerFocus == mButtons.size() - 1) - mControllerFocus = 0; - else - mControllerFocus++; + mControllerFocus = wrap(mControllerFocus + 1, mButtons.size()); mButtons[mControllerFocus]->setStateSelected(true); } return true; diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 5472f02f04..a76e793d81 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -183,19 +183,13 @@ namespace MWGui else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) { mButtons[mControllerFocus]->setStateSelected(false); - if (mControllerFocus == 0) - mControllerFocus = mButtons.size() - 1; - else - mControllerFocus--; + mControllerFocus = wrap(mControllerFocus - 1, mButtons.size()); mButtons[mControllerFocus]->setStateSelected(true); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) { mButtons[mControllerFocus]->setStateSelected(false); - if (mControllerFocus == mButtons.size() - 1) - mControllerFocus = 0; - else - mControllerFocus++; + mControllerFocus = wrap(mControllerFocus + 1, mButtons.size()); mButtons[mControllerFocus]->setStateSelected(true); } diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 20b7acbd9b..69004171db 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -764,9 +764,7 @@ namespace { // Scroll through the list of quests or topics mButtons[mSelectedQuest]->setStateSelected(false); - mSelectedQuest--; - if (mSelectedQuest < 0) - mSelectedQuest = mButtons.size() - 1; + mSelectedQuest = MWGui::wrap(mSelectedQuest - 1, mButtons.size()); mButtons[mSelectedQuest]->setStateSelected(true); } return true; @@ -777,9 +775,7 @@ namespace { // Scroll through the list of quests or topics mButtons[mSelectedQuest]->setStateSelected(false); - mSelectedQuest++; - if (mSelectedQuest > mButtons.size() - 1) - mSelectedQuest = 0; + mSelectedQuest = MWGui::wrap(mSelectedQuest + 1, mButtons.size()); mButtons[mSelectedQuest]->setStateSelected(true); } return true; diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 311743fd36..94807dd54c 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -461,10 +461,7 @@ namespace MWGui return true; mButtons[mControllerFocus]->setStateSelected(false); - if (mControllerFocus == 0) - mControllerFocus = mButtons.size() - 1; - else - mControllerFocus--; + mControllerFocus = wrap(mControllerFocus - 1, mButtons.size()); mButtons[mControllerFocus]->setStateSelected(true); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) @@ -475,10 +472,7 @@ namespace MWGui return true; mButtons[mControllerFocus]->setStateSelected(false); - if (mControllerFocus == mButtons.size() - 1) - mControllerFocus = 0; - else - mControllerFocus++; + mControllerFocus = wrap(mControllerFocus + 1, mButtons.size()); mButtons[mControllerFocus]->setStateSelected(true); } diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index fe45fa8729..9e215637a0 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -520,10 +520,7 @@ namespace MWGui else if (arg.button == SDL_CONTROLLER_BUTTON_Y) { uint32_t index = mCharacterSelection->getIndexSelected(); - if (index >= mCharacterSelection->getItemCount() - 1) - index = 0; - else - index++; + index = wrap(index + 1, mCharacterSelection->getItemCount()); mCharacterSelection->setIndexSelected(index); onCharacterSelected(mCharacterSelection, index); } diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 2fa6a72fd8..70f2ab8ff3 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -1144,10 +1144,7 @@ namespace MWGui else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) { uint32_t index = mSettingsTab->getIndexSelected(); - if (index <= 0) - index = mSettingsTab->getItemCount() - 1; - else - index--; + index = wrap(index - 1, mSettingsTab->getItemCount()); mSettingsTab->setIndexSelected(index); return true; @@ -1155,10 +1152,7 @@ namespace MWGui else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) { uint32_t index = mSettingsTab->getIndexSelected(); - if (index >= mSettingsTab->getItemCount() - 1) - index = 0; - else - index++; + index = wrap(index + 1, mSettingsTab->getItemCount()); mSettingsTab->setIndexSelected(index); return true; From ba0a57937128528c14b3b654ca9a28f6f62a27b2 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Tue, 20 May 2025 19:32:13 -0700 Subject: [PATCH 045/330] Play correct sound and update button overlay when swapping between menus --- apps/openmw/mwgui/windowmanagerimp.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index ff2e9754af..2fefe8f249 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -948,7 +948,9 @@ namespace MWGui { mGuiModeStates[mode].mWindows[i]->setActiveControllerWindow(i == activeIndex); } - playSound(ESM::RefId::stringRefId("Menu Click")); + updateControllerButtonsOverlay(); + if (winCount > 1) + playSound(ESM::RefId::stringRefId("Menu Size")); } } From 5e3a49ade5ebe93e1e2ef91643a310401bc88bd8 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Tue, 20 May 2025 22:41:17 -0700 Subject: [PATCH 046/330] Make right stick scroll dialog history --- apps/openmw/mwgui/dialogue.cpp | 2 ++ apps/openmw/mwgui/scrollwindow.cpp | 1 + apps/openmw/mwgui/windowbase.hpp | 2 ++ apps/openmw/mwinput/controllermanager.cpp | 9 +++++++-- apps/openmw/mwinput/mousemanager.cpp | 13 +++++++++++++ apps/openmw/mwinput/mousemanager.hpp | 1 + 6 files changed, 26 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index a76e793d81..1dd3f051ef 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -380,8 +380,10 @@ namespace MWGui mMainWidget->castType()->eventWindowChangeCoord += MyGUI::newDelegate(this, &DialogueWindow::onWindowResize); + mControllerScrollWidget = mHistory->getParent(); mControllerButtons.a = "#{sAsk}"; mControllerButtons.b = "#{sGoodbye}"; + mControllerButtons.rStick = "#{sScrollup}"; } void DialogueWindow::onTradeComplete() diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index ae47a361a2..d032963417 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -39,6 +39,7 @@ namespace MWGui mCloseButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &ScrollWindow::onKeyButtonPressed); mTakeButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &ScrollWindow::onKeyButtonPressed); + mControllerScrollWidget = mTextView; mControllerButtons.b = "#{sClose}"; mControllerButtons.rStick = "#{sScrolldown}"; diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index 2b1afbda85..8fb499ec7e 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -77,6 +77,7 @@ namespace MWGui static void clampWindowCoordinates(MyGUI::Window* window); virtual ControllerButtonStr* getControllerButtons() { return &mControllerButtons; } + MyGUI::Widget* getControllerScrollWidget() { return mControllerScrollWidget; } bool isGamepadCursorAllowed() { return !mDisableGamepadCursor; } virtual bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { return true; }; virtual bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) { return true; }; @@ -88,6 +89,7 @@ namespace MWGui ControllerButtonStr mControllerButtons; bool mActiveControllerWindow = false; bool mDisableGamepadCursor = false; + MyGUI::Widget* mControllerScrollWidget = nullptr; private: void onDoubleClick(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwinput/controllermanager.cpp b/apps/openmw/mwinput/controllermanager.cpp index d1deef5011..48034cae01 100644 --- a/apps/openmw/mwinput/controllermanager.cpp +++ b/apps/openmw/mwinput/controllermanager.cpp @@ -353,10 +353,15 @@ namespace MWInput if (mGamepadGuiCursorEnabled && (arg.axis == SDL_CONTROLLER_AXIS_LEFTX || arg.axis == SDL_CONTROLLER_AXIS_LEFTY)) { - // Treat the left stick like a cursor. Fall through. + // Treat the left stick like a cursor, which is the default behavior. return false; } - else if (topWin->onControllerThumbstickEvent(arg)) + + // On some windows, treat right stick like a scroll wheel. + if (arg.axis == SDL_CONTROLLER_AXIS_RIGHTY && topWin->getControllerScrollWidget() != nullptr) + mMouseManager->warpMouseToWidget(topWin->getControllerScrollWidget()); + + if (topWin->onControllerThumbstickEvent(arg)) { // Window handled the event. return true; diff --git a/apps/openmw/mwinput/mousemanager.cpp b/apps/openmw/mwinput/mousemanager.cpp index eed95cf1c9..2c6798406b 100644 --- a/apps/openmw/mwinput/mousemanager.cpp +++ b/apps/openmw/mwinput/mousemanager.cpp @@ -263,4 +263,17 @@ namespace MWInput mInputWrapper->warpMouse( static_cast(mGuiCursorX * guiUiScale), static_cast(mGuiCursorY * guiUiScale)); } + + void MouseManager::warpMouseToWidget(MyGUI::Widget* widget) + { + float widgetX = widget->getAbsoluteCoord().left + 4; + float widgetY = widget->getAbsoluteCoord().top + 4; + if (std::abs(mGuiCursorX - widgetX) > 1 || std::abs(mGuiCursorY - widgetY) > 1) + { + mGuiCursorX = widgetX; + mGuiCursorY = widgetY; + warpMouse(); + } + } + } diff --git a/apps/openmw/mwinput/mousemanager.hpp b/apps/openmw/mwinput/mousemanager.hpp index 5de8a8f3bc..0a9c4eccd7 100644 --- a/apps/openmw/mwinput/mousemanager.hpp +++ b/apps/openmw/mwinput/mousemanager.hpp @@ -32,6 +32,7 @@ namespace MWInput bool injectMouseButtonRelease(Uint8 button); void injectMouseMove(float xMove, float yMove, float mouseWheelMove); void warpMouse(); + void warpMouseToWidget(MyGUI::Widget* widget); void setMouseLookEnabled(bool enabled) { mMouseLookEnabled = enabled; } void setGuiCursorEnabled(bool enabled) { mGuiCursorEnabled = enabled; } From 2df7ded814e3fd3f8e997ad29ab609cf7c8df23f Mon Sep 17 00:00:00 2001 From: Kuyondo Date: Fri, 23 May 2025 18:15:24 +0800 Subject: [PATCH 047/330] respawning npc respawns in origin cell --- apps/openmw/mwclass/npc.cpp | 3 ++- apps/openmw/mwworld/cellstore.cpp | 9 +++++++++ apps/openmw/mwworld/cellstore.hpp | 2 ++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 0b61436d11..c03d132503 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1427,7 +1427,8 @@ namespace MWClass ptr.getRefData().setCustomData(nullptr); // Reset to original position - MWBase::Environment::get().getWorld()->moveObject(ptr, ptr.getCellRef().getPosition().asVec3()); + MWBase::Environment::get().getWorld()->moveObject( + ptr, ptr.getCell()->getOriginCell(ptr), ptr.getCellRef().getPosition().asVec3()); MWBase::Environment::get().getWorld()->rotateObject( ptr, ptr.getCellRef().getPosition().asRotationVec3(), MWBase::RotationFlag_none); } diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index fca0135e13..61618c001e 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -1354,6 +1354,15 @@ namespace MWWorld return {}; } + CellStore* MWWorld::CellStore::getOriginCell(const Ptr& object) const + { + MovedRefTracker::const_iterator found = mMovedHere.find(object.getBase()); + if (found != mMovedHere.end()) + return found->second; + + return object.getCell(); + } + Ptr CellStore::getPtr(ESM::RefId id) { if (mState == CellStore::State_Unloaded) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 126935ace5..59127d6186 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -338,6 +338,8 @@ namespace MWWorld Ptr getMovedActor(int actorId) const; + CellStore* getOriginCell(const Ptr& object) const; + Ptr getPtr(ESM::RefId id); private: From 86783e87580fe6e73a0852ed71d76ff34ade824e Mon Sep 17 00:00:00 2001 From: Kuyondo Date: Fri, 23 May 2025 23:46:42 +0800 Subject: [PATCH 048/330] also for creatures --- apps/openmw/mwclass/creature.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 9224f6f0d8..324ba5f98b 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -871,7 +871,8 @@ namespace MWClass ptr.getRefData().setCustomData(nullptr); // Reset to original position - MWBase::Environment::get().getWorld()->moveObject(ptr, ptr.getCellRef().getPosition().asVec3()); + MWBase::Environment::get().getWorld()->moveObject( + ptr, ptr.getCell()->getOriginCell(ptr), ptr.getCellRef().getPosition().asVec3()); MWBase::Environment::get().getWorld()->rotateObject( ptr, ptr.getCellRef().getPosition().asRotationVec3(), MWBase::RotationFlag_none); } From d759418f016c79885c9607a488e9ccc9668cff13 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sat, 24 May 2025 14:17:41 -0700 Subject: [PATCH 049/330] Add controller support for all four inventory menus --- apps/openmw/mwbase/inputmanager.hpp | 2 + apps/openmw/mwbase/windowmanager.hpp | 3 + apps/openmw/mwgui/companionwindow.hpp | 5 + apps/openmw/mwgui/container.cpp | 9 +- apps/openmw/mwgui/container.hpp | 6 +- apps/openmw/mwgui/hud.cpp | 16 ++- apps/openmw/mwgui/hud.hpp | 2 + apps/openmw/mwgui/inventorywindow.cpp | 157 ++++++++++++++++++++++- apps/openmw/mwgui/inventorywindow.hpp | 4 + apps/openmw/mwgui/itemview.cpp | 55 ++++++-- apps/openmw/mwgui/itemview.hpp | 4 +- apps/openmw/mwgui/mapwindow.cpp | 54 ++++++++ apps/openmw/mwgui/mapwindow.hpp | 5 + apps/openmw/mwgui/spellview.cpp | 92 +++++++++++++ apps/openmw/mwgui/spellview.hpp | 14 ++ apps/openmw/mwgui/spellwindow.cpp | 28 ++++ apps/openmw/mwgui/spellwindow.hpp | 2 + apps/openmw/mwgui/statswindow.cpp | 25 ++++ apps/openmw/mwgui/statswindow.hpp | 4 + apps/openmw/mwgui/windowmanagerimp.cpp | 69 +++++----- apps/openmw/mwgui/windowmanagerimp.hpp | 2 + apps/openmw/mwinput/inputmanagerimp.cpp | 7 + apps/openmw/mwinput/inputmanagerimp.hpp | 1 + components/widgets/sharedstatebutton.hpp | 5 +- 24 files changed, 515 insertions(+), 56 deletions(-) diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index 5ee20476b3..f5adc42340 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -61,6 +62,7 @@ namespace MWBase virtual float getControllerAxisValue(SDL_GameControllerAxis axis) const = 0; // returns value in range [-1, 1] virtual int getMouseMoveX() const = 0; virtual int getMouseMoveY() const = 0; + virtual void warpMouseToWidget(MyGUI::Widget* widget) = 0; /// Actions available for binding to keyboard buttons virtual const std::initializer_list& getActionKeySorting() = 0; diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 5302270ee0..27331699cf 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -11,6 +11,7 @@ #include +#include "../mwgui/hud.hpp" #include "../mwgui/mode.hpp" #include "../mwgui/windowbase.hpp" @@ -158,7 +159,9 @@ namespace MWBase virtual MWGui::CountDialog* getCountDialog() = 0; virtual MWGui::ConfirmationDialog* getConfirmationDialog() = 0; virtual MWGui::TradeWindow* getTradeWindow() = 0; + virtual MWGui::HUD* getHud() = 0; virtual MWGui::PostProcessorHud* getPostProcessorHud() = 0; + virtual std::vector getGuiModeWindows(MWGui::GuiMode mode) = 0; /// Make the player use an item, while updating GUI state accordingly virtual void useItem(const MWWorld::Ptr& item, bool force = false) = 0; diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index 97f3a0072e..21869c58f5 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_MWGUI_COMPANIONWINDOW_H #define OPENMW_MWGUI_COMPANIONWINDOW_H +#include "companionitemmodel.hpp" +#include "itemmodel.hpp" #include "referenceinterface.hpp" #include "windowbase.hpp" @@ -32,6 +34,9 @@ namespace MWGui std::string_view getWindowIdForLua() const override { return "Companion"; } + MWGui::ItemView* getItemView() { return mItemView; } + ItemModel* getModel() { return mModel; } + private: ItemView* mItemView; SortFilterItemModel* mSortModel; diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 54eb6122c5..c0896d5b5e 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -58,9 +58,9 @@ namespace MWGui setCoord(200, 0, 600, 300); mControllerButtons.a = "#{sTake}"; - mControllerButtons.b = "#{sClose}"; + mControllerButtons.b = "#{sBack}"; mControllerButtons.x = "#{sTakeAll}"; - mControllerButtons.y = "#{sInfo}"; + mControllerButtons.r3 = "#{sInfo}"; mControllerButtons.l2 = "#{sInventory}"; } @@ -385,12 +385,13 @@ namespace MWGui if (mDisposeCorpseButton->getVisible()) onDisposeCorpseButtonClicked(mDisposeCorpseButton); } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP || + else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK || + arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP || arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN || arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT || arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) { - mItemView->onControllerButtonEvent(arg); + mItemView->onControllerButtonEvent(arg.button); } return true; diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 08497e0369..96ee6a6380 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -41,8 +41,12 @@ namespace MWGui std::string_view getWindowIdForLua() const override { return "Container"; } ControllerButtonStr* getControllerButtons() override; + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; void setActiveControllerWindow(bool active) override; + MWGui::ItemView* getItemView() { return mItemView; } + ItemModel* getModel() { return mModel; } + private: DragAndDrop* mDragAndDrop; @@ -68,8 +72,6 @@ namespace MWGui bool onTakeItem(const ItemStack& item, int count); void onReferenceUnavailable() override; - - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; }; } #endif // CONTAINER_H diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 0a37c93b4f..a62120fc10 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -243,6 +243,17 @@ namespace MWGui mDrowningBar->setVisible(visible); } + void HUD::dropDraggedItem(float mouseX, float mouseY) + { + if (!mDragAndDrop->mIsOnDragAndDrop) + return; + + MWBase::Environment::get().getWorld()->breakInvisibility(MWMechanics::getPlayer()); + + WorldItemModel drop(mouseX, mouseY); + mDragAndDrop->drop(&drop, nullptr); + } + void HUD::onWorldClicked(MyGUI::Widget* _sender) { if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) @@ -252,15 +263,12 @@ namespace MWGui if (mDragAndDrop->mIsOnDragAndDrop) { // drop item into the gameworld - MWBase::Environment::get().getWorld()->breakInvisibility(MWMechanics::getPlayer()); - MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition(); float mouseX = cursorPosition.left / float(viewSize.width); float mouseY = cursorPosition.top / float(viewSize.height); - WorldItemModel drop(mouseX, mouseY); - mDragAndDrop->drop(&drop, nullptr); + dropDraggedItem(mouseX, mouseY); winMgr->changePointer("arrow"); } diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 8dd98628c4..1a1076ff68 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -61,6 +61,8 @@ namespace MWGui void clear() override; + void dropDraggedItem(float mouseX, float mouseY); + private: MyGUI::ProgressBar *mHealth, *mMagicka, *mStamina, *mEnemyHealth, *mDrowning; MyGUI::Widget* mHealthFrame; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index a773b4635b..27c4bbf57d 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -31,8 +31,11 @@ #include "../mwmechanics/actorutil.hpp" #include "../mwmechanics/npcstats.hpp" +#include "companionwindow.hpp" +#include "container.hpp" #include "countdialog.hpp" #include "draganddrop.hpp" +#include "hud.hpp" #include "inventoryitemmodel.hpp" #include "itemview.hpp" #include "settings.hpp" @@ -127,6 +130,13 @@ namespace MWGui setGuiMode(mGuiMode); + if (Settings::gui().mControllerMenus) + { + mControllerButtons.b = "#{sBack}"; + mControllerButtons.r1 = "Filter"; + mControllerButtons.r3 = "#{sInfo}"; + } + adjustPanes(); } @@ -302,7 +312,9 @@ namespace MWGui } } - if (count > 1 && !shift) + // Show a dialog to select a count of items, but not when using an item from the inventory + // in controller mode. In that case, we skip the dialog and just use one item immediately. + if (count > 1 && !shift && !(Settings::gui().mControllerMenus && mGuiMode == MWGui::GM_Inventory)) { CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); std::string message = mTrading ? "#{sQuanityMenuMessage01}" : "#{sTake}"; @@ -866,4 +878,147 @@ namespace MWGui const MyGUI::IntSize viewport = getPreviewViewportSize(); return osg::Vec2f(normalisedX * float(viewport.width - 1), (1.0 - normalisedY) * float(viewport.height - 1)); } + + ControllerButtonStr* InventoryWindow::getControllerButtons() + { + switch (mGuiMode) + { + case MWGui::GM_Companion: + case MWGui::GM_Container: + mControllerButtons.a = "Put"; + mControllerButtons.x = "#{sTakeAll}"; + mControllerButtons.y = ""; + mControllerButtons.r2 = "#{sContainer}"; + break; + case MWGui::GM_Barter: + mControllerButtons.a = "#{sSell}"; + mControllerButtons.x = ""; + mControllerButtons.y = ""; + mControllerButtons.r2 = "#{sBarter}"; + break; + case MWGui::GM_Inventory: + default: + mControllerButtons.a = "#{sEquip}"; + mControllerButtons.x = "#{sDrop}"; + mControllerButtons.y = "#{sUnequip}"; + mControllerButtons.r2 = ""; + break; + } + return &mControllerButtons; + } + + bool InventoryWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_B) + { + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + mItemView->onControllerButtonEvent(SDL_CONTROLLER_BUTTON_A); + // The following actions are done here, not in onItemSelectedFromSourceModel, because we + // want the mouse to work even in controller mode. + if (mGuiMode == MWGui::GM_Inventory && mDragAndDrop->mIsOnDragAndDrop) + { + // Drag and drop the item on the avatar to activate it. + onAvatarClicked(nullptr); // Equip or use + // Drop any remaining items back in inventory. This is needed when clicking on a + // stack of items; we only want to use the first item. + onBackgroundSelected(); + } + else if (mGuiMode == MWGui::GM_Companion && mDragAndDrop->mIsOnDragAndDrop) + { + // Drag and drop the item on the companion's window. + MWGui::CompanionWindow* companionWindow = + (MWGui::CompanionWindow *)MWBase::Environment::get().getWindowManager()->getGuiModeWindows(mGuiMode).at(0); + mDragAndDrop->drop(companionWindow->getModel(), companionWindow->getItemView()); + } + else if (mGuiMode == MWGui::GM_Container && mDragAndDrop->mIsOnDragAndDrop) + { + // Drag and drop the item on the container window. + MWGui::ContainerWindow* containerWindow = + (MWGui::ContainerWindow *)MWBase::Environment::get().getWindowManager()->getGuiModeWindows(mGuiMode).at(0); + mDragAndDrop->drop(containerWindow->getModel(), containerWindow->getItemView()); + } + // GM_Barter is handled by onControllerButtonEvent. No other steps are necessary. + } + else if (arg.button == SDL_CONTROLLER_BUTTON_X) + { + if (mGuiMode == MWGui::GM_Inventory) + { + // Drop the item into the gameworld + mItemView->onControllerButtonEvent(SDL_CONTROLLER_BUTTON_A); + if (mDragAndDrop->mIsOnDragAndDrop) + MWBase::Environment::get().getWindowManager()->getHud()->dropDraggedItem(0.5f, 0.5f); + } + else if (mGuiMode == MWGui::GM_Container) + { + // Take all. Pass the button press to the container window and let it do the + // logic of taking all. + MWGui::ContainerWindow* containerWindow = + (MWGui::ContainerWindow *)MWBase::Environment::get().getWindowManager()->getGuiModeWindows(mGuiMode).at(0); + containerWindow->onControllerButtonEvent(arg); + } + } + else if (arg.button == SDL_CONTROLLER_BUTTON_Y) + { + if (mGuiMode == MWGui::GM_Inventory) + { + // Unequip an item. + mItemView->onControllerButtonEvent(SDL_CONTROLLER_BUTTON_A); + onBackgroundSelected(); // Drop on inventory background to unequip + } + } + else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) + { + if (mFilterAll->getStateSelected()) + onFilterChanged(mFilterMisc); + else if (mFilterWeapon->getStateSelected()) + onFilterChanged(mFilterAll); + else if (mFilterApparel->getStateSelected()) + onFilterChanged(mFilterWeapon); + else if (mFilterMagic->getStateSelected()) + onFilterChanged(mFilterApparel); + else if (mFilterMisc->getStateSelected()) + onFilterChanged(mFilterMagic); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) + { + if (mFilterAll->getStateSelected()) + onFilterChanged(mFilterWeapon); + else if (mFilterWeapon->getStateSelected()) + onFilterChanged(mFilterApparel); + else if (mFilterApparel->getStateSelected()) + onFilterChanged(mFilterMagic); + else if (mFilterMagic->getStateSelected()) + onFilterChanged(mFilterMisc); + else if (mFilterMisc->getStateSelected()) + onFilterChanged(mFilterAll); + } + else + { + mItemView->onControllerButtonEvent(arg.button); + } + + return true; + } + + void InventoryWindow::setActiveControllerWindow(bool active) + { + if (!Settings::gui().mControllerMenus) + return; + + if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Inventory) + { + MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + MyGUI::Window* window = mMainWidget->castType(); + window->setCoord(0, active ? 0 : viewSize.height + 1, viewSize.width, viewSize.height - 48); + + adjustPanes(); + updatePreviewSize(); + } + + mItemView->setActiveControllerWindow(active); + WindowBase::setActiveControllerWindow(active); + } } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 9fc77ceec5..5b4d61f272 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -67,8 +67,12 @@ namespace MWGui std::string_view getWindowIdForLua() const override { return "Inventory"; } + ControllerButtonStr* getControllerButtons() override; + protected: void onTitleDoubleClicked() override; + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + void setActiveControllerWindow(bool active) override; private: DragAndDrop* mDragAndDrop; diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index 526f231956..a223bde5e0 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -9,6 +9,10 @@ #include +#include "../mwbase/environment.hpp" +#include "../mwbase/inputmanager.hpp" +#include "../mwbase/windowmanager.hpp" + #include "itemmodel.hpp" #include "itemwidget.hpp" @@ -75,8 +79,8 @@ namespace MWGui if (Settings::gui().mControllerMenus) { - if (mControllerFocus >= mItemCount) - mControllerFocus = mItemCount - 1; + mControllerTooltip = false; + mControllerFocus = std::clamp(mControllerFocus, 0, mItemCount - 1); updateControllerFocus(-1, mControllerFocus); } @@ -182,26 +186,49 @@ namespace MWGui void ItemView::setActiveControllerWindow(bool active) { + mControllerActiveWindow = active; + + if (mControllerTooltip) + { + MWBase::Environment::get().getWindowManager()->setCursorActive(false); + mControllerTooltip = false; + } + if (active) updateControllerFocus(-1, mControllerFocus); else updateControllerFocus(mControllerFocus, -1); } - void ItemView::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + void ItemView::onControllerButtonEvent(const unsigned char button) { if (!mItemCount) return; int prevFocus = mControllerFocus; - if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP && mControllerFocus % mRows != 0) + if (button == SDL_CONTROLLER_BUTTON_A) + { + // Select the focused item, if any. + if (mControllerFocus >= 0 && mControllerFocus < mItemCount) + { + MyGUI::Widget* dragArea = mScrollView->getChildAt(0); + onSelectedItem(dragArea->getChildAt(mControllerFocus)); + } + } + else if (button == SDL_CONTROLLER_BUTTON_RIGHTSTICK) + { + // Toggle info tooltip + mControllerTooltip = !mControllerTooltip; + updateControllerFocus(-1, mControllerFocus); + } + else if (button == SDL_CONTROLLER_BUTTON_DPAD_UP && mControllerFocus % mRows != 0) mControllerFocus--; - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN && mControllerFocus % mRows != mRows - 1) + else if (button == SDL_CONTROLLER_BUTTON_DPAD_DOWN && mControllerFocus % mRows != mRows - 1) mControllerFocus++; - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && mControllerFocus >= mRows) + else if (button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && mControllerFocus >= mRows) mControllerFocus -= mRows; - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && mControllerFocus + mRows < mItemCount) + else if (button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && mControllerFocus + mRows < mItemCount) mControllerFocus += mRows; if (mControllerFocus < 0) @@ -213,25 +240,29 @@ namespace MWGui updateControllerFocus(prevFocus, mControllerFocus); } - void ItemView::updateControllerFocus(int _prevFocus, int _newFocus) + void ItemView::updateControllerFocus(int prevFocus, int newFocus) { if (!mItemCount) return; MyGUI::Widget* dragArea = mScrollView->getChildAt(0); - if (_prevFocus >= 0 && _prevFocus < mItemCount) + if (prevFocus >= 0 && prevFocus < mItemCount) { - ItemWidget* prev = (ItemWidget *)dragArea->getChildAt(_prevFocus); + ItemWidget* prev = (ItemWidget *)dragArea->getChildAt(prevFocus); if (prev) prev->setControllerFocus(false); } - if (_newFocus >= 0 && _newFocus < mItemCount) + if (mControllerActiveWindow && newFocus >= 0 && newFocus < mItemCount) { - ItemWidget* focused = (ItemWidget *)dragArea->getChildAt(_newFocus); + ItemWidget* focused = (ItemWidget *)dragArea->getChildAt(newFocus); if (focused) + { focused->setControllerFocus(true); + if (mControllerTooltip) + MWBase::Environment::get().getInputManager()->warpMouseToWidget(focused); + } } } } diff --git a/apps/openmw/mwgui/itemview.hpp b/apps/openmw/mwgui/itemview.hpp index b1fa941ef4..091436ab05 100644 --- a/apps/openmw/mwgui/itemview.hpp +++ b/apps/openmw/mwgui/itemview.hpp @@ -35,7 +35,7 @@ namespace MWGui void setActiveControllerWindow(bool active); int getControllerFocus() { return mControllerFocus; } int getItemCount() { return mItemCount; } - void onControllerButtonEvent(const SDL_ControllerButtonEvent& arg); + void onControllerButtonEvent(const unsigned char button); private: void initialiseOverride() override; @@ -55,6 +55,8 @@ namespace MWGui int mItemCount = 0; int mRows; int mControllerFocus = 0; + bool mControllerTooltip; + bool mControllerActiveWindow; void updateControllerFocus(int prevFocus, int newFocus); }; diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index bf4bd7644c..ec9c509797 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -832,6 +833,14 @@ namespace MWGui mGlobalMap->setVisible(global); mLocalMap->setVisible(!global); + + if (Settings::gui().mControllerMenus) + { + mControllerButtons.b = "#{sBack}"; + mControllerButtons.x = global ? "#{sLocal}" : "#{sWorld}"; + mControllerButtons.y = "#{sCenter}"; + mControllerButtons.rStick = "#{sMove}"; + } } void MapWindow::onNoteEditOk() @@ -1208,6 +1217,8 @@ namespace MWGui mLocalMap->setVisible(!global); mButton->setCaptionWithReplacing(global ? "#{sLocal}" : "#{sWorld}"); + mControllerButtons.x = global ? "#{sLocal}" : "#{sWorld}"; + MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay(); } void MapWindow::onPinToggled() @@ -1368,6 +1379,49 @@ namespace MWGui mGlobalMapRender->asyncWritePng(); } + bool MapWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_B) + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); + else if (arg.button == SDL_CONTROLLER_BUTTON_X) + onWorldButtonClicked(mButton); + else if (arg.button == SDL_CONTROLLER_BUTTON_Y) + centerView(); + + return true; + } + + bool MapWindow::onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) + { + int dx = arg.axis == SDL_CONTROLLER_AXIS_RIGHTX ? -10.0f * arg.value / 32767 : 0; + int dy = arg.axis == SDL_CONTROLLER_AXIS_RIGHTY ? -10.0f * arg.value / 32767 : 0; + if (dx == 0 && dy == 0) + return true; + else if (!Settings::map().mGlobal) + { + mNeedDoorMarkersUpdate = true; + mLocalMap->setViewOffset( + MyGUI::IntPoint( + mLocalMap->getViewOffset().left + dx, mLocalMap->getViewOffset().top + dy)); + } + else + { + mGlobalMap->setViewOffset( + MyGUI::IntPoint( + mGlobalMap->getViewOffset().left + dx, mGlobalMap->getViewOffset().top + dy)); + } + return true; + } + + void MapWindow::setActiveControllerWindow(bool active) + { + MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + MyGUI::Window* window = mMainWidget->castType(); + window->setCoord(0, active ? 0 : viewSize.height + 1, viewSize.width, viewSize.height - 48); + + WindowBase::setActiveControllerWindow(active); + } + // ------------------------------------------------------------------- EditNoteDialog::EditNoteDialog() diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index ed070c5407..31fe971c60 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -265,6 +265,11 @@ namespace MWGui std::string_view getWindowIdForLua() const override { return "Map"; } + protected: + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) override; + void setActiveControllerWindow(bool active) override; + private: void onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); void onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index 678f6ffe1f..739699f35c 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -9,6 +9,9 @@ #include #include +#include "../mwbase/environment.hpp" +#include "../mwbase/inputmanager.hpp" + #include "tooltips.hpp" namespace MWGui @@ -88,6 +91,9 @@ namespace MWGui const int spellHeight = Settings::gui().mFontSize + 2; mLines.clear(); + mButtons.clear(); + mGroupIndices.clear(); + mControllerTooltip = false; while (mScrollView->getChildCount()) MyGUI::Gui::getInstance().destroyWidget(mScrollView->getChildAt(0)); @@ -115,6 +121,7 @@ namespace MWGui t->setCaption(spell.mName + captionSuffix); t->setTextAlign(MyGUI::Align::Left); adjustSpellWidget(spell, i, t); + mButtons.emplace_back(t); if (!spell.mCostColumn.empty() && mShowCostColumn) { @@ -256,6 +263,8 @@ namespace MWGui } else mLines.emplace_back(groupWidget, (MyGUI::Widget*)nullptr, NoSpellIndex); + + mGroupIndices.push_back(mButtons.size()); } void SpellView::setSize(const MyGUI::IntSize& _value) @@ -316,4 +325,87 @@ namespace MWGui { mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); } + + void SpellView::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (mButtons.empty()) + return; + + int prevFocus = mControllerFocus; + + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + // Select the focused item, if any. + if (mControllerFocus >= 0 && mControllerFocus < mButtons.size()) + onSpellSelected(mButtons.at(mControllerFocus)); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK) + { + // Toggle info tooltip + mControllerTooltip = !mControllerTooltip; + if (mControllerTooltip && mControllerFocus >= 0 && mControllerFocus < mButtons.size()) + MWBase::Environment::get().getInputManager()->warpMouseToWidget(mButtons.at(mControllerFocus)); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) + mControllerFocus--; + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + mControllerFocus++; + else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) + { + // Jump to first item in previous group + int prevGroupIndex = 0; + for (int groupIndex : mGroupIndices) + { + if (groupIndex >= mControllerFocus) + break; + else + prevGroupIndex = groupIndex; + } + mControllerFocus = prevGroupIndex; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) + { + // Jump to first item in next group + for (int groupIndex : mGroupIndices) + { + if (groupIndex > mControllerFocus) + { + mControllerFocus = groupIndex; + break; + } + } + } + + if (mControllerFocus < 0) + mControllerFocus = mButtons.size() - 1; + else if (mControllerFocus >= mButtons.size()) + mControllerFocus = 0; + + if (prevFocus != mControllerFocus) + updateControllerFocus(prevFocus, mControllerFocus); + } + + void SpellView::updateControllerFocus(int prevFocus, int newFocus) + { + if (mButtons.empty()) + return; + + if (prevFocus >= 0 && prevFocus < mButtons.size()) + { + Gui::SharedStateButton* prev = mButtons.at(prevFocus); + if (prev) + prev->onMouseLostFocus(nullptr); + } + + if (newFocus >= 0 && newFocus < mButtons.size()) + { + Gui::SharedStateButton* focused = mButtons.at(newFocus); + if (focused) + { + focused->onMouseSetFocus(nullptr); + if (mControllerTooltip) + MWBase::Environment::get().getInputManager()->warpMouseToWidget(focused); + } + } + } } diff --git a/apps/openmw/mwgui/spellview.hpp b/apps/openmw/mwgui/spellview.hpp index caff43a33e..cf3a43354f 100644 --- a/apps/openmw/mwgui/spellview.hpp +++ b/apps/openmw/mwgui/spellview.hpp @@ -5,6 +5,9 @@ #include #include +#include + +#include #include "spellmodel.hpp" @@ -54,6 +57,8 @@ namespace MWGui void resetScrollbars(); + void onControllerButtonEvent(const SDL_ControllerButtonEvent& arg); + private: MyGUI::ScrollView* mScrollView; @@ -89,6 +94,15 @@ namespace MWGui void addGroup(const std::string& label1, const std::string& label2); void adjustSpellWidget(const Spell& spell, SpellModel::ModelIndex index, MyGUI::Widget* widget); + /// Keep a list of buttons for controller navigation + std::vector mButtons; + /// Keep a list of group offsets for controller navigation + std::vector mGroupIndices; + + int mControllerFocus; + bool mControllerTooltip; + void updateControllerFocus(int prevFocus, int newFocus); + void onSpellSelected(MyGUI::Widget* _sender); void onMouseWheelMoved(MyGUI::Widget* _sender, int _rel); diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index d183a00273..63ba83a895 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -2,6 +2,8 @@ #include #include +#include +#include #include #include @@ -55,6 +57,13 @@ namespace MWGui // Adjust the spell filtering widget size because of MyGUI limitations. int filterWidth = mSpellView->getSize().width - deleteButton->getSize().width - 3; mFilterEdit->setSize(filterWidth, mFilterEdit->getSize().height); + + if (Settings::gui().mControllerMenus) + { + mControllerButtons.a = "#{sSelect}"; + mControllerButtons.b = "#{sBack}"; + mControllerButtons.r3 = "#{sInfo}"; + } } void SpellWindow::onPinToggled() @@ -259,4 +268,23 @@ namespace MWGui else onSpellSelected(spell.mId); } + + bool SpellWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_B) + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); + else + mSpellView->onControllerButtonEvent(arg); + + return true; + } + + void SpellWindow::setActiveControllerWindow(bool active) + { + MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + MyGUI::Window* window = mMainWidget->castType(); + window->setCoord(0, active ? 0 : viewSize.height + 1, viewSize.width, viewSize.height - 48); + + WindowBase::setActiveControllerWindow(active); + } } diff --git a/apps/openmw/mwgui/spellwindow.hpp b/apps/openmw/mwgui/spellwindow.hpp index e35c5cdc4c..c27ec276a3 100644 --- a/apps/openmw/mwgui/spellwindow.hpp +++ b/apps/openmw/mwgui/spellwindow.hpp @@ -41,6 +41,8 @@ namespace MWGui void onPinToggled() override; void onTitleDoubleClicked() override; void onOpen() override; + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + void setActiveControllerWindow(bool active) override; SpellView* mSpellView; std::unique_ptr mSpellIcons; diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index 69f0b4b449..cc5c934662 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -80,6 +81,11 @@ namespace MWGui MyGUI::Window* t = mMainWidget->castType(); t->eventWindowChangeCoord += MyGUI::newDelegate(this, &StatsWindow::onWindowResize); + if (Settings::gui().mControllerMenus) + { + mControllerButtons.b = "#{sBack}"; + } + onWindowResize(t); } @@ -723,4 +729,23 @@ namespace MWGui else if (!mPinned) MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Stats); } + + bool StatsWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_B) + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); + + return true; + } + + void StatsWindow::setActiveControllerWindow(bool active) + { + MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + MyGUI::Window* window = mMainWidget->castType(); + window->setCoord(0, active ? 0 : viewSize.height + 1, viewSize.width, viewSize.height - 48); + + onWindowResize(window); + + WindowBase::setActiveControllerWindow(active); + } } diff --git a/apps/openmw/mwgui/statswindow.hpp b/apps/openmw/mwgui/statswindow.hpp index a3fc3157c5..3021873aa8 100644 --- a/apps/openmw/mwgui/statswindow.hpp +++ b/apps/openmw/mwgui/statswindow.hpp @@ -47,6 +47,10 @@ namespace MWGui std::string_view getWindowIdForLua() const override { return "Stats"; } + protected: + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + void setActiveControllerWindow(bool active) override; + private: void addSkills(const std::vector& skills, const std::string& titleId, const std::string& titleDefault, MyGUI::IntCoord& coord1, MyGUI::IntCoord& coord2); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 2fefe8f249..ac58f1e589 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -896,23 +896,13 @@ namespace MWGui return state.mWindows[activeIndex]; } - else - { - // return pinned windows if visible - // REMOVEME - Log(Debug::Error) << "getTopWindow: " << mGuiModeStates[GM_Inventory].mWindows.size() << " pinned windows"; - for (WindowBase* window : mGuiModeStates[GM_Inventory].mWindows) - if (window->isVisible()) - return window; - else - Log(Debug::Error) << "-- Skipping hidden window " << window; - } + return nullptr; } void WindowManager::cycleActiveControllerWindow(bool next) { - if (mGuiModes.empty()) + if (!Settings::gui().mControllerMenus || mGuiModes.empty()) return; GuiMode mode = mGuiModes.back(); @@ -1380,13 +1370,6 @@ namespace MWGui { for (WindowBase* window : mGuiModeStates[mode].mWindows) window->setPtr(arg); - - // Activate first visible window - mActiveControllerWindows[mode] = -1; - cycleActiveControllerWindow(true); - - // REMOVEME - Log(Debug::Error) << "pushGuiMode: mode=" << mode << ", activeIndex=" << mActiveControllerWindows[mode]; } catch (...) { @@ -1398,6 +1381,13 @@ namespace MWGui updateVisible(); MWBase::Environment::get().getLuaManager()->uiModeChanged(arg); + + if (Settings::gui().mControllerMenus) + { + // Activate first visible window. This needs to be called after updateVisible. + mActiveControllerWindows[mode] = std::max(mActiveControllerWindows[mode] - 1, -1); + cycleActiveControllerWindow(true); + } } void WindowManager::setCullMask(uint32_t mask) @@ -1452,6 +1442,15 @@ namespace MWGui // To make sure that console window get focus again if (mConsole && mConsole->isVisible()) mConsole->onOpen(); + + if (Settings::gui().mControllerMenus && !mGuiModes.empty()) + { + // Re-apply any controller-specific window changes. + const GuiMode mode = mGuiModes.back(); + int winCount = mGuiModeStates[mode].mWindows.size(); + for (int i = 0; i < winCount; i++) + mGuiModeStates[mode].mWindows[i]->setActiveControllerWindow(i == mActiveControllerWindows[mode]); + } } void WindowManager::removeGuiMode(GuiMode mode) @@ -1577,6 +1576,10 @@ namespace MWGui mConsole->executeFile(path); } + std::vector WindowManager::getGuiModeWindows(GuiMode mode) + { + return mGuiModeStates[mode].mWindows; + } MWGui::InventoryWindow* WindowManager::getInventoryWindow() { return mInventoryWindow; @@ -1589,6 +1592,10 @@ namespace MWGui { return mConfirmationDialog; } + MWGui::HUD* WindowManager::getHud() + { + return mHud; + } MWGui::TradeWindow* WindowManager::getTradeWindow() { return mTradeWindow; @@ -2119,20 +2126,22 @@ namespace MWGui void WindowManager::updatePinnedWindows() { mInventoryWindow->setPinned(Settings::windows().mInventoryPin); - if (Settings::windows().mInventoryHidden) - mShown = (GuiWindow)(mShown ^ GW_Inventory); - mMap->setPinned(Settings::windows().mMapPin); - if (Settings::windows().mMapHidden) - mShown = (GuiWindow)(mShown ^ GW_Map); - mSpellWindow->setPinned(Settings::windows().mSpellsPin); - if (Settings::windows().mSpellsHidden) - mShown = (GuiWindow)(mShown ^ GW_Magic); - mStatsWindow->setPinned(Settings::windows().mStatsPin); - if (Settings::windows().mStatsHidden) - mShown = (GuiWindow)(mShown ^ GW_Stats); + + // Hide hidden inventory windows, but not in controller mode. + if (!Settings::gui().mControllerMenus) + { + if (Settings::windows().mInventoryHidden) + mShown = (GuiWindow)(mShown ^ GW_Inventory); + if (Settings::windows().mMapHidden) + mShown = (GuiWindow)(mShown ^ GW_Map); + if (Settings::windows().mSpellsHidden) + mShown = (GuiWindow)(mShown ^ GW_Magic); + if (Settings::windows().mStatsHidden) + mShown = (GuiWindow)(mShown ^ GW_Stats); + } } void WindowManager::pinWindow(GuiWindow window) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 5dbf3c4689..54695e8234 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -185,7 +185,9 @@ namespace MWGui MWGui::CountDialog* getCountDialog() override; MWGui::ConfirmationDialog* getConfirmationDialog() override; MWGui::TradeWindow* getTradeWindow() override; + MWGui::HUD* getHud() override; MWGui::PostProcessorHud* getPostProcessorHud() override; + std::vector getGuiModeWindows(GuiMode mode) override; /// Make the player use an item, while updating GUI state accordingly void useItem(const MWWorld::Ptr& item, bool bypassBeastRestrictions = false) override; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 328757a954..12d56a3321 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -189,6 +189,13 @@ namespace MWInput return mMouseManager->getMouseMoveY(); } + void InputManager::warpMouseToWidget(MyGUI::Widget* widget) + { + mMouseManager->warpMouseToWidget(widget); + mMouseManager->injectMouseMove(1, 0, 0); + MWBase::Environment::get().getWindowManager()->setCursorActive(true); + } + const std::initializer_list& InputManager::getActionKeySorting() { return mBindingsManager->getActionKeySorting(); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 39a1133db5..b2899e6831 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -81,6 +81,7 @@ namespace MWInput float getControllerAxisValue(SDL_GameControllerAxis axis) const override; int getMouseMoveX() const override; int getMouseMoveY() const override; + void warpMouseToWidget(MyGUI::Widget* widget) override; int getNumActions() override { return A_Last; } const std::initializer_list& getActionKeySorting() override; diff --git a/components/widgets/sharedstatebutton.hpp b/components/widgets/sharedstatebutton.hpp index 33dd70c763..1cf7364bf0 100644 --- a/components/widgets/sharedstatebutton.hpp +++ b/components/widgets/sharedstatebutton.hpp @@ -21,13 +21,14 @@ namespace Gui public: SharedStateButton(); + void onMouseSetFocus(MyGUI::Widget* _old) override; + void onMouseLostFocus(MyGUI::Widget* _new) override; + protected: void updateButtonState(); void onMouseButtonPressed(int _left, int _top, MyGUI::MouseButton _id) override; void onMouseButtonReleased(int _left, int _top, MyGUI::MouseButton _id) override; - void onMouseSetFocus(MyGUI::Widget* _old) override; - void onMouseLostFocus(MyGUI::Widget* _new) override; void baseUpdateEnable() override; void shutdownOverride() override; From f1c34ea7b1bef0ad9be2bb8ee156d14536c6a3d6 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sat, 24 May 2025 16:00:13 -0700 Subject: [PATCH 050/330] Add a tab bar above inventory to show active tab and change tabs with mouse --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwbase/windowmanager.hpp | 1 + apps/openmw/mwgui/inventorytabsoverlay.cpp | 49 ++++++++++++++++ apps/openmw/mwgui/inventorytabsoverlay.hpp | 24 ++++++++ apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 2 +- apps/openmw/mwgui/spellwindow.cpp | 2 +- apps/openmw/mwgui/statswindow.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 58 ++++++++++++++----- apps/openmw/mwgui/windowmanagerimp.hpp | 4 ++ files/data/CMakeLists.txt | 1 + files/data/mygui/openmw_inventory_tabs.layout | 51 ++++++++++++++++ 12 files changed, 177 insertions(+), 21 deletions(-) create mode 100644 apps/openmw/mwgui/inventorytabsoverlay.cpp create mode 100644 apps/openmw/mwgui/inventorytabsoverlay.hpp create mode 100644 files/data/mygui/openmw_inventory_tabs.layout diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index eeb46edce0..399514cab4 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -44,7 +44,7 @@ add_openmw_dir (mwgui tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview draganddrop timeadvancer jailscreen itemchargeview keyboardnavigation textcolours statswatcher - postprocessorhud settings controllerbuttonsoverlay + postprocessorhud settings controllerbuttonsoverlay inventorytabsoverlay ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 27331699cf..180c9bfee3 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -389,6 +389,7 @@ namespace MWBase virtual MWGui::WindowBase* getActiveControllerWindow() = 0; /// Cycle to the next window to receive controller events virtual void cycleActiveControllerWindow(bool next) = 0; + virtual void setActiveControllerWindow(MWGui::GuiMode mode, int activeIndex) = 0; virtual void updateControllerButtonsOverlay() = 0; // Used in Lua bindings diff --git a/apps/openmw/mwgui/inventorytabsoverlay.cpp b/apps/openmw/mwgui/inventorytabsoverlay.cpp new file mode 100644 index 0000000000..21254c7840 --- /dev/null +++ b/apps/openmw/mwgui/inventorytabsoverlay.cpp @@ -0,0 +1,49 @@ +#include "inventorytabsoverlay.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" + +namespace MWGui +{ + InventoryTabsOverlay::InventoryTabsOverlay() + : WindowBase("openmw_inventory_tabs.layout") + { + MyGUI::Button* tab; + + getWidget(tab, "TabMap"); + tab->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryTabsOverlay::onTabClicked); + mTabs.push_back(tab); + + getWidget(tab, "TabInventory"); + tab->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryTabsOverlay::onTabClicked); + mTabs.push_back(tab); + + getWidget(tab, "TabSpells"); + tab->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryTabsOverlay::onTabClicked); + mTabs.push_back(tab); + + getWidget(tab, "TabStats"); + tab->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryTabsOverlay::onTabClicked); + mTabs.push_back(tab); + } + + void InventoryTabsOverlay::onTabClicked(MyGUI::Widget* sender) + { + for (int i = 0; i < mTabs.size(); i++) + { + if (mTabs[i] == sender) + { + Log(Debug::Verbose) << "InventoryTabsOverlay::onTabClicked " << i; + MWBase::Environment::get().getWindowManager()->setActiveControllerWindow(GM_Inventory, i); + //setTab(i); + break; + } + } + } + + void InventoryTabsOverlay::setTab(int index) + { + for (int i = 0; i < mTabs.size(); i++) + mTabs[i]->setStateSelected(i == index); + } +} diff --git a/apps/openmw/mwgui/inventorytabsoverlay.hpp b/apps/openmw/mwgui/inventorytabsoverlay.hpp new file mode 100644 index 0000000000..5368d9710f --- /dev/null +++ b/apps/openmw/mwgui/inventorytabsoverlay.hpp @@ -0,0 +1,24 @@ +#ifndef MWGUI_INVENTORYTABSSOVERLAY_H +#define MWGUI_INVENTORYTABSSOVERLAY_H + +#include + +#include "windowbase.hpp" + +namespace MWGui +{ + class InventoryTabsOverlay : public WindowBase + { + public: + InventoryTabsOverlay(); + + void setTab(int index); + + private: + std::vector mTabs; + + void onTabClicked(MyGUI::Widget* sender); + }; +} + +#endif diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 27c4bbf57d..6b5bbde324 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -1012,7 +1012,7 @@ namespace MWGui { MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); MyGUI::Window* window = mMainWidget->castType(); - window->setCoord(0, active ? 0 : viewSize.height + 1, viewSize.width, viewSize.height - 48); + window->setCoord(0, active ? 48 : viewSize.height + 49, viewSize.width, viewSize.height - 48 - 48); adjustPanes(); updatePreviewSize(); diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index ec9c509797..ce3524d052 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -1417,7 +1417,7 @@ namespace MWGui { MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); MyGUI::Window* window = mMainWidget->castType(); - window->setCoord(0, active ? 0 : viewSize.height + 1, viewSize.width, viewSize.height - 48); + window->setCoord(0, active ? 48 : viewSize.height + 49, viewSize.width, viewSize.height - 48 - 48); WindowBase::setActiveControllerWindow(active); } diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 63ba83a895..fb61b59ed9 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -283,7 +283,7 @@ namespace MWGui { MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); MyGUI::Window* window = mMainWidget->castType(); - window->setCoord(0, active ? 0 : viewSize.height + 1, viewSize.width, viewSize.height - 48); + window->setCoord(0, active ? 48 : viewSize.height + 49, viewSize.width, viewSize.height - 48 - 48); WindowBase::setActiveControllerWindow(active); } diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index cc5c934662..e67417f60e 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -742,7 +742,7 @@ namespace MWGui { MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); MyGUI::Window* window = mMainWidget->castType(); - window->setCoord(0, active ? 0 : viewSize.height + 1, viewSize.width, viewSize.height - 48); + window->setCoord(0, active ? 48 : viewSize.height + 49, viewSize.width, viewSize.height - 48 - 48); onWindowResize(window); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index ac58f1e589..732ff405d3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -182,6 +182,7 @@ namespace MWGui , mJailScreen(nullptr) , mContainerWindow(nullptr) , mControllerButtonsOverlay(nullptr) + , mInventoryTabsOverlay(nullptr) , mTranslationDataStorage(translationDataStorage) , mInputBlocker(nullptr) , mHudEnabled(true) @@ -510,6 +511,10 @@ namespace MWGui mControllerButtonsOverlay = controllerButtonsOverlay.get(); mWindows.push_back(std::move(controllerButtonsOverlay)); + auto inventoryTabsOverlay = std::make_unique(); + mInventoryTabsOverlay = inventoryTabsOverlay.get(); + mWindows.push_back(std::move(inventoryTabsOverlay)); + mInputBlocker = MyGUI::Gui::getInstance().createWidget( {}, 0, 0, w, h, MyGUI::Align::Stretch, "InputBlocker"); @@ -668,8 +673,13 @@ namespace MWGui mSpellWindow->setVisible( mSpellWindow->pinned() && !isConsoleMode() && !(mForceHidden & GW_Magic) && (mAllowed & GW_Magic)); - if (Settings::gui().mControllerMenus && mControllerButtonsOverlay) - mControllerButtonsOverlay->setVisible(false); + if (Settings::gui().mControllerMenus) + { + if (mControllerButtonsOverlay) + mControllerButtonsOverlay->setVisible(false); + if (mInventoryTabsOverlay) + mInventoryTabsOverlay->setVisible(false); + } return; } else if (getMode() != GM_Inventory) @@ -929,19 +939,27 @@ namespace MWGui } // REMOVEME - Log(Debug::Error) << "focusNextWindow: mode=" << mode << ", activeIndex=" << activeIndex; + Log(Debug::Error) << "cycleActiveControllerWindow: mode=" << mode << ", activeIndex=" << activeIndex; if (mActiveControllerWindows[mode] != activeIndex) - { - mActiveControllerWindows[mode] = activeIndex; - for (int i = 0; i < winCount; i++) - { - mGuiModeStates[mode].mWindows[i]->setActiveControllerWindow(i == activeIndex); - } - updateControllerButtonsOverlay(); - if (winCount > 1) - playSound(ESM::RefId::stringRefId("Menu Size")); - } + setActiveControllerWindow(mode, activeIndex); + } + + void WindowManager::setActiveControllerWindow(GuiMode mode, int activeIndex) + { + int winCount = mGuiModeStates[mode].mWindows.size(); + if (winCount == 0) + return; + + mActiveControllerWindows[mode] = std::clamp(activeIndex, 0, winCount - 1); + + for (int i = 0; i < winCount; i++) + mGuiModeStates[mode].mWindows[i]->setActiveControllerWindow(i == activeIndex); + + updateControllerButtonsOverlay(); + + if (winCount > 1) + playSound(ESM::RefId::stringRefId("Menu Size")); } void WindowManager::update(float frameDuration) @@ -1010,6 +1028,9 @@ namespace MWGui if (mControllerButtonsOverlay && mControllerButtonsOverlay->isVisible()) mControllerButtonsOverlay->onFrame(frameDuration); + if (mInventoryTabsOverlay && mInventoryTabsOverlay->isVisible()) + mInventoryTabsOverlay->onFrame(frameDuration); + if (!gameRunning) return; @@ -2560,19 +2581,24 @@ namespace MWGui void WindowManager::updateControllerButtonsOverlay() { - if (!Settings::gui().mControllerMenus ||!mControllerButtonsOverlay) + if (!Settings::gui().mControllerMenus || !mControllerButtonsOverlay) return; WindowBase* topWin = this->getActiveControllerWindow(); if (!topWin || !topWin->isVisible()) { - // REMOVEME - Log(Debug::Error) << "WindowManager::updateControllerButtonsOverlay: hiding overlay"; mControllerButtonsOverlay->setVisible(false); + mInventoryTabsOverlay->setVisible(false); return; } // setButtons will handle setting visibility based on if any buttons are defined. mControllerButtonsOverlay->setButtons(topWin->getControllerButtons()); + if (getMode() == GM_Inventory) { + mInventoryTabsOverlay->setVisible(true); + mInventoryTabsOverlay->setTab(mActiveControllerWindows[GM_Inventory]); + } + else + mInventoryTabsOverlay->setVisible(false); } } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 54695e8234..d5e36a0971 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -27,6 +27,7 @@ #include "charactercreation.hpp" #include "controllerbuttonsoverlay.hpp" #include "draganddrop.hpp" +#include "inventorytabsoverlay.hpp" #include "mapwindow.hpp" #include "messagebox.hpp" #include "settings.hpp" @@ -120,6 +121,7 @@ namespace MWGui class JailScreen; class KeyboardNavigation; class ControllerButtonsOverlay; + class InventoryTabsOverlay; class WindowManager : public MWBase::WindowManager { @@ -393,6 +395,7 @@ namespace MWGui WindowBase* getActiveControllerWindow() override; void cycleActiveControllerWindow(bool next) override; + void setActiveControllerWindow(GuiMode mode, int activeIndex) override; void updateControllerButtonsOverlay() override; // Used in Lua bindings @@ -463,6 +466,7 @@ namespace MWGui JailScreen* mJailScreen; ContainerWindow* mContainerWindow; ControllerButtonsOverlay* mControllerButtonsOverlay; + InventoryTabsOverlay* mInventoryTabsOverlay; std::vector> mWindows; diff --git a/files/data/CMakeLists.txt b/files/data/CMakeLists.txt index 6339344500..2b8ea7a568 100644 --- a/files/data/CMakeLists.txt +++ b/files/data/CMakeLists.txt @@ -172,6 +172,7 @@ set(BUILTIN_DATA_FILES mygui/openmw_infobox.layout mygui/openmw_interactive_messagebox.layout mygui/openmw_interactive_messagebox_notransp.layout + mygui/openmw_inventory_tabs.layout mygui/openmw_inventory_window.layout mygui/openmw_journal.layout mygui/openmw_journal.skin.xml diff --git a/files/data/mygui/openmw_inventory_tabs.layout b/files/data/mygui/openmw_inventory_tabs.layout new file mode 100644 index 0000000000..3787452586 --- /dev/null +++ b/files/data/mygui/openmw_inventory_tabs.layout @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 3eec24b2a63fb07ac40edcc033f2f0b74d15a0cc Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sat, 24 May 2025 20:08:45 -0700 Subject: [PATCH 051/330] Limit the size of controller-focused inventory windows on large screens --- apps/openmw/mwgui/inventorywindow.cpp | 8 +++++++- apps/openmw/mwgui/mapwindow.cpp | 9 ++++++++- apps/openmw/mwgui/spellwindow.cpp | 9 ++++++++- apps/openmw/mwgui/statswindow.cpp | 9 ++++++++- 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 6b5bbde324..5258c12db5 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -1010,9 +1010,15 @@ namespace MWGui if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Inventory) { + // Fill the screen, or limit to a certain size on large screens. MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + int width = std::min(viewSize.width, 2200); + int height = std::min(viewSize.height - 48 - 48, 1200); + int x = (viewSize.width - width) / 2; + int y = (viewSize.height - height) / 2; + MyGUI::Window* window = mMainWidget->castType(); - window->setCoord(0, active ? 48 : viewSize.height + 49, viewSize.width, viewSize.height - 48 - 48); + window->setCoord(x, active ? y : viewSize.height + 1, width, height); adjustPanes(); updatePreviewSize(); diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index ce3524d052..9c43b44572 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -1415,9 +1415,16 @@ namespace MWGui void MapWindow::setActiveControllerWindow(bool active) { + // Fill the screen, or limit to a certain size on large screens. Size chosen to + // show the entire local map without scrolling. MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + int width = std::min(viewSize.width, 1552); + int height = std::min(viewSize.height - 48 - 48, 1572); + int x = (viewSize.width - width) / 2; + int y = (viewSize.height - height) / 2; + MyGUI::Window* window = mMainWidget->castType(); - window->setCoord(0, active ? 48 : viewSize.height + 49, viewSize.width, viewSize.height - 48 - 48); + window->setCoord(x, active ? y : viewSize.height + 1, width, height); WindowBase::setActiveControllerWindow(active); } diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index fb61b59ed9..fbeb6f35c3 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -281,9 +281,16 @@ namespace MWGui void SpellWindow::setActiveControllerWindow(bool active) { + // Fill the screen, or limit to a certain size on large screens. Size chosen to + // match the size of the stats window. MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + int width = std::min(viewSize.width, 600); + int height = std::min(viewSize.height - 48 - 48, 750); + int x = (viewSize.width - width) / 2; + int y = (viewSize.height - height) / 2; + MyGUI::Window* window = mMainWidget->castType(); - window->setCoord(0, active ? 48 : viewSize.height + 49, viewSize.width, viewSize.height - 48 - 48); + window->setCoord(x, active ? y : viewSize.height + 1, width, height); WindowBase::setActiveControllerWindow(active); } diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index e67417f60e..9971b15799 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -740,9 +740,16 @@ namespace MWGui void StatsWindow::setActiveControllerWindow(bool active) { + // Fill the screen, or limit to a certain size on large screens. Size chosen to + // show all stats. MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + int width = std::min(viewSize.width, 600); + int height = std::min(viewSize.height - 48 - 48, 750); + int x = (viewSize.width - width) / 2; + int y = (viewSize.height - height) / 2; + MyGUI::Window* window = mMainWidget->castType(); - window->setCoord(0, active ? 48 : viewSize.height + 49, viewSize.width, viewSize.height - 48 - 48); + window->setCoord(x, active ? y : viewSize.height + 1, width, height); onWindowResize(window); From cf26020ed6b0ad40162d9a3471be206e790c3135 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sat, 24 May 2025 20:56:43 -0700 Subject: [PATCH 052/330] Fix several minor issues with controller inventory menus --- apps/openmw/mwgui/mapwindow.cpp | 31 +++++++++++++++++++++----- apps/openmw/mwgui/mapwindow.hpp | 1 + apps/openmw/mwgui/spellview.cpp | 4 ++++ apps/openmw/mwgui/spellwindow.cpp | 3 +++ apps/openmw/mwgui/statswindow.cpp | 5 ++++- apps/openmw/mwgui/windowmanagerimp.cpp | 1 + 6 files changed, 39 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 9c43b44572..ab55d261df 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -1384,20 +1384,42 @@ namespace MWGui if (arg.button == SDL_CONTROLLER_BUTTON_B) MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); else if (arg.button == SDL_CONTROLLER_BUTTON_X) + { onWorldButtonClicked(mButton); + MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); + } else if (arg.button == SDL_CONTROLLER_BUTTON_Y) + { centerView(); + MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) + shiftMap(0, 100); + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + shiftMap(0, -100); + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) + shiftMap(100, 0); + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + shiftMap(-100, 0); return true; } bool MapWindow::onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) { - int dx = arg.axis == SDL_CONTROLLER_AXIS_RIGHTX ? -10.0f * arg.value / 32767 : 0; - int dy = arg.axis == SDL_CONTROLLER_AXIS_RIGHTY ? -10.0f * arg.value / 32767 : 0; + int dx = arg.axis == SDL_CONTROLLER_AXIS_RIGHTX ? -30.0f * arg.value / 32767 : 0; + int dy = arg.axis == SDL_CONTROLLER_AXIS_RIGHTY ? -30.0f * arg.value / 32767 : 0; + shiftMap(dx, dy); + + return true; + } + + void MapWindow::shiftMap(int dx, int dy) + { if (dx == 0 && dy == 0) - return true; - else if (!Settings::map().mGlobal) + return; + + if (!Settings::map().mGlobal) { mNeedDoorMarkersUpdate = true; mLocalMap->setViewOffset( @@ -1410,7 +1432,6 @@ namespace MWGui MyGUI::IntPoint( mGlobalMap->getViewOffset().left + dx, mGlobalMap->getViewOffset().top + dy)); } - return true; } void MapWindow::setActiveControllerWindow(bool active) diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 31fe971c60..f7e1fcc52f 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -288,6 +288,7 @@ namespace MWGui void setGlobalMapMarkerTooltip(MyGUI::Widget* widget, int x, int y); float getMarkerSize(size_t agregatedWeight) const; void resizeGlobalMap(); + void shiftMap(int dx, int dy); void worldPosToGlobalMapImageSpace(float x, float z, float& imageX, float& imageY) const; MyGUI::IntCoord createMarkerCoords(float x, float y, float agregatedWeight) const; MyGUI::Widget* createMarker(const std::string& name, float x, float y, float agregatedWeight); diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index 739699f35c..2ebd1751da 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -11,6 +11,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/inputmanager.hpp" +#include "../mwbase/windowmanager.hpp" #include "tooltips.hpp" @@ -337,7 +338,10 @@ namespace MWGui { // Select the focused item, if any. if (mControllerFocus >= 0 && mControllerFocus < mButtons.size()) + { onSpellSelected(mButtons.at(mControllerFocus)); + MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); + } } else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK) { diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index fbeb6f35c3..e218b9beed 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -292,6 +292,9 @@ namespace MWGui MyGUI::Window* window = mMainWidget->castType(); window->setCoord(x, active ? y : viewSize.height + 1, width, height); + if (active) + mSpellView->update(); + WindowBase::setActiveControllerWindow(active); } } diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index 9971b15799..1d0af185d4 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -83,6 +83,8 @@ namespace MWGui if (Settings::gui().mControllerMenus) { + mControllerButtons.lStick = "#{sInfo}"; + mControllerButtons.rStick = "#{sScrolldown}"; mControllerButtons.b = "#{sBack}"; } @@ -751,7 +753,8 @@ namespace MWGui MyGUI::Window* window = mMainWidget->castType(); window->setCoord(x, active ? y : viewSize.height + 1, width, height); - onWindowResize(window); + if (active) + onWindowResize(window); WindowBase::setActiveControllerWindow(active); } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 732ff405d3..96b4303bbb 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -957,6 +957,7 @@ namespace MWGui mGuiModeStates[mode].mWindows[i]->setActiveControllerWindow(i == activeIndex); updateControllerButtonsOverlay(); + setCursorActive(false); if (winCount > 1) playSound(ESM::RefId::stringRefId("Menu Size")); From d6c23f7664a60bde3ad363249ab9f44c75be9b5a Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sat, 24 May 2025 21:28:43 -0700 Subject: [PATCH 053/330] Add controller support to map's node dialog --- apps/openmw/mwgui/mapwindow.cpp | 85 +++++++++++++++++++++++++++++++++ apps/openmw/mwgui/mapwindow.hpp | 5 ++ 2 files changed, 90 insertions(+) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index ab55d261df..f8063657b8 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -1463,6 +1463,12 @@ namespace MWGui mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EditNoteDialog::onCancelButtonClicked); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EditNoteDialog::onOkButtonClicked); mDeleteButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EditNoteDialog::onDeleteButtonClicked); + + if (Settings::gui().mControllerMenus) + { + mControllerButtons.a = "#{sOk}"; + mControllerButtons.b = "#{sCancel}"; + } } void EditNoteDialog::showDeleteButton(bool show) @@ -1490,6 +1496,13 @@ namespace MWGui WindowModal::onOpen(); center(); MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit); + + if (Settings::gui().mControllerMenus) + { + mControllerFocus = getDeleteButtonShown() ? 1 : 0; + mOkButton->setStateSelected(true); + mCancelButton->setStateSelected(false); + } } void EditNoteDialog::onCancelButtonClicked(MyGUI::Widget* sender) @@ -1507,6 +1520,78 @@ namespace MWGui eventDeleteClicked(); } + ControllerButtonStr* EditNoteDialog::getControllerButtons() + { + mControllerButtons.x = getDeleteButtonShown() ? "#{sDelete}" : ""; + return &mControllerButtons; + } + + bool EditNoteDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + if (getDeleteButtonShown()) + { + if (mControllerFocus == 0) + onDeleteButtonClicked(mDeleteButton); + else if (mControllerFocus == 1) + onOkButtonClicked(mOkButton); + else + onCancelButtonClicked(mCancelButton); + } + else + { + if (mControllerFocus == 0) + onOkButtonClicked(mOkButton); + else + onCancelButtonClicked(mCancelButton); + } + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + { + onCancelButtonClicked(mCancelButton); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_X) + { + if (getDeleteButtonShown()) + onDeleteButtonClicked(mDeleteButton); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) + { + if (getDeleteButtonShown()) + { + mControllerFocus = wrap(mControllerFocus - 1, 3); + mDeleteButton->setStateSelected(mControllerFocus == 0); + mOkButton->setStateSelected(mControllerFocus == 1); + mCancelButton->setStateSelected(mControllerFocus == 2); + } + else + { + mControllerFocus = 0; + mOkButton->setStateSelected(mControllerFocus == 0); + mCancelButton->setStateSelected(mControllerFocus == 1); + } + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + { + if (getDeleteButtonShown()) + { + mControllerFocus = wrap(mControllerFocus + 1, 3); + mDeleteButton->setStateSelected(mControllerFocus == 0); + mOkButton->setStateSelected(mControllerFocus == 1); + mCancelButton->setStateSelected(mControllerFocus == 2); + } + else + { + mControllerFocus = 1; + mOkButton->setStateSelected(mControllerFocus == 0); + mCancelButton->setStateSelected(mControllerFocus == 1); + } + } + + return true; + } + bool LocalMapBase::MarkerUserData::isPositionExplored() const { if (!mLocalMapRender) diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index f7e1fcc52f..240c30adc0 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -212,6 +212,8 @@ namespace MWGui EventHandle_Void eventDeleteClicked; EventHandle_Void eventOkClicked; + ControllerButtonStr* getControllerButtons() override; + private: void onCancelButtonClicked(MyGUI::Widget* sender); void onOkButtonClicked(MyGUI::Widget* sender); @@ -221,6 +223,9 @@ namespace MWGui MyGUI::Button* mOkButton; MyGUI::Button* mCancelButton; MyGUI::Button* mDeleteButton; + + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + int mControllerFocus; }; class MapWindow : public MWGui::WindowPinnableBase, public LocalMapBase, public NoDrop From 45de167b6b8fbd85db7738296d906c2f86176ff1 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sat, 24 May 2025 21:29:06 -0700 Subject: [PATCH 054/330] Adjust layer of controller button overlay so it doesn't hide tooltips --- files/data/mygui/openmw_layers.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/data/mygui/openmw_layers.xml b/files/data/mygui/openmw_layers.xml index 597ba0de4c..f2eed488e1 100644 --- a/files/data/mygui/openmw_layers.xml +++ b/files/data/mygui/openmw_layers.xml @@ -14,13 +14,13 @@ + - From d6ed4164028e1caec48625001d52a8045d1be930 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 25 May 2025 16:12:19 -0700 Subject: [PATCH 055/330] Allow pinning map window in controller mode --- apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 36 +++++++++++++++------ apps/openmw/mwgui/spellwindow.cpp | 22 +++++++------ apps/openmw/mwgui/statswindow.cpp | 26 +++++++++------- apps/openmw/mwgui/windowmanagerimp.cpp | 43 +++++++++++++++++--------- 5 files changed, 83 insertions(+), 46 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 5258c12db5..7f314fed14 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -216,7 +216,7 @@ namespace MWGui { mGuiMode = mode; const WindowSettingValues settings = getModeSettings(mGuiMode); - setPinButtonVisible(mode == GM_Inventory); + setPinButtonVisible(mode == GM_Inventory && !Settings::gui().mControllerMenus); const WindowRectSettingValues& rect = settings.mIsMaximized ? settings.mMaximized : settings.mRegular; diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index f8063657b8..f90180fb44 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -1029,7 +1029,20 @@ namespace MWGui void MapWindow::setVisible(bool visible) { WindowBase::setVisible(visible); - mButton->setVisible(visible && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_None); + MWGui::GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode(); + mButton->setVisible(visible && mode != MWGui::GM_None); + + if (Settings::gui().mControllerMenus && mode == MWGui::GM_None && pinned() && visible) + { + // Restore the window to pinned size. + MyGUI::Window* window = mMainWidget->castType(); + MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + const float x = Settings::windows().mMapX * viewSize.width; + const float y = Settings::windows().mMapY * viewSize.height; + const float w = Settings::windows().mMapW * viewSize.width; + const float h = Settings::windows().mMapH * viewSize.height; + window->setCoord(x, y, w, h); + } } void MapWindow::renderGlobalMap() @@ -1436,16 +1449,19 @@ namespace MWGui void MapWindow::setActiveControllerWindow(bool active) { - // Fill the screen, or limit to a certain size on large screens. Size chosen to - // show the entire local map without scrolling. - MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - int width = std::min(viewSize.width, 1552); - int height = std::min(viewSize.height - 48 - 48, 1572); - int x = (viewSize.width - width) / 2; - int y = (viewSize.height - height) / 2; + if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Inventory) + { + // Fill the screen, or limit to a certain size on large screens. Size chosen to + // show the entire local map without scrolling. + MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + int width = std::min(viewSize.width, 1552); + int height = std::min(viewSize.height - 48 - 48, 1572); + int x = (viewSize.width - width) / 2; + int y = (viewSize.height - height) / 2; - MyGUI::Window* window = mMainWidget->castType(); - window->setCoord(x, active ? y : viewSize.height + 1, width, height); + MyGUI::Window* window = mMainWidget->castType(); + window->setCoord(x, active ? y : viewSize.height + 1, width, height); + } WindowBase::setActiveControllerWindow(active); } diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index e218b9beed..3eb041f6ab 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -60,6 +60,7 @@ namespace MWGui if (Settings::gui().mControllerMenus) { + setPinButtonVisible(false); mControllerButtons.a = "#{sSelect}"; mControllerButtons.b = "#{sBack}"; mControllerButtons.r3 = "#{sInfo}"; @@ -281,16 +282,19 @@ namespace MWGui void SpellWindow::setActiveControllerWindow(bool active) { - // Fill the screen, or limit to a certain size on large screens. Size chosen to - // match the size of the stats window. - MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - int width = std::min(viewSize.width, 600); - int height = std::min(viewSize.height - 48 - 48, 750); - int x = (viewSize.width - width) / 2; - int y = (viewSize.height - height) / 2; + if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Inventory) + { + // Fill the screen, or limit to a certain size on large screens. Size chosen to + // match the size of the stats window. + MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + int width = std::min(viewSize.width, 600); + int height = std::min(viewSize.height - 48 - 48, 750); + int x = (viewSize.width - width) / 2; + int y = (viewSize.height - height) / 2; - MyGUI::Window* window = mMainWidget->castType(); - window->setCoord(x, active ? y : viewSize.height + 1, width, height); + MyGUI::Window* window = mMainWidget->castType(); + window->setCoord(x, active ? y : viewSize.height + 1, width, height); + } if (active) mSpellView->update(); diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index 1d0af185d4..e71b35e364 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -83,6 +83,7 @@ namespace MWGui if (Settings::gui().mControllerMenus) { + setPinButtonVisible(false); mControllerButtons.lStick = "#{sInfo}"; mControllerButtons.rStick = "#{sScrolldown}"; mControllerButtons.b = "#{sBack}"; @@ -742,19 +743,22 @@ namespace MWGui void StatsWindow::setActiveControllerWindow(bool active) { - // Fill the screen, or limit to a certain size on large screens. Size chosen to - // show all stats. - MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - int width = std::min(viewSize.width, 600); - int height = std::min(viewSize.height - 48 - 48, 750); - int x = (viewSize.width - width) / 2; - int y = (viewSize.height - height) / 2; + if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Inventory) + { + // Fill the screen, or limit to a certain size on large screens. Size chosen to + // show all stats. + MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + int width = std::min(viewSize.width, 600); + int height = std::min(viewSize.height - 48 - 48, 750); + int x = (viewSize.width - width) / 2; + int y = (viewSize.height - height) / 2; - MyGUI::Window* window = mMainWidget->castType(); - window->setCoord(x, active ? y : viewSize.height + 1, width, height); + MyGUI::Window* window = mMainWidget->castType(); + window->setCoord(x, active ? y : viewSize.height + 1, width, height); - if (active) - onWindowResize(window); + if (active) + onWindowResize(window); + } WindowBase::setActiveControllerWindow(active); } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 96b4303bbb..77224790dd 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1901,6 +1901,11 @@ namespace MWGui void WindowManager::onWindowChangeCoord(MyGUI::Window* window) { + // If using controller menus, don't persist changes to size of the stats or magic + // windows. + if (Settings::gui().mControllerMenus && (window == (MyGUI::Window*)mStatsWindow || window == (MyGUI::Window*)mSpellWindow)) + return; + const auto it = mTrackedWindows.find(window); if (it == mTrackedWindows.end()) return; @@ -2147,23 +2152,31 @@ namespace MWGui void WindowManager::updatePinnedWindows() { - mInventoryWindow->setPinned(Settings::windows().mInventoryPin); - mMap->setPinned(Settings::windows().mMapPin); - mSpellWindow->setPinned(Settings::windows().mSpellsPin); - mStatsWindow->setPinned(Settings::windows().mStatsPin); - - // Hide hidden inventory windows, but not in controller mode. - if (!Settings::gui().mControllerMenus) + if (Settings::gui().mControllerMenus) { - if (Settings::windows().mInventoryHidden) - mShown = (GuiWindow)(mShown ^ GW_Inventory); - if (Settings::windows().mMapHidden) - mShown = (GuiWindow)(mShown ^ GW_Map); - if (Settings::windows().mSpellsHidden) - mShown = (GuiWindow)(mShown ^ GW_Magic); - if (Settings::windows().mStatsHidden) - mShown = (GuiWindow)(mShown ^ GW_Stats); + // In controller mode, don't hide any menus and only allow pinning the map. + mInventoryWindow->setPinned(false); + mMap->setPinned(Settings::windows().mMapPin); + mSpellWindow->setPinned(false); + mStatsWindow->setPinned(false); + return; } + + mInventoryWindow->setPinned(Settings::windows().mInventoryPin); + if (Settings::windows().mInventoryHidden) + mShown = (GuiWindow)(mShown ^ GW_Inventory); + + mMap->setPinned(Settings::windows().mMapPin); + if (Settings::windows().mMapHidden) + mShown = (GuiWindow)(mShown ^ GW_Map); + + mSpellWindow->setPinned(Settings::windows().mSpellsPin); + if (Settings::windows().mSpellsHidden) + mShown = (GuiWindow)(mShown ^ GW_Magic); + + mStatsWindow->setPinned(Settings::windows().mStatsPin); + if (Settings::windows().mStatsHidden) + mShown = (GuiWindow)(mShown ^ GW_Stats); } void WindowManager::pinWindow(GuiWindow window) From 25fa9484d3da1604c44488879a60297ffdb4a997 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 25 May 2025 22:08:43 -0700 Subject: [PATCH 056/330] Add a default save game name in controller mode --- apps/openmw/mwgui/savegamedialog.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 9e215637a0..af75152e4b 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,7 @@ #include "../mwbase/world.hpp" #include "../mwworld/datetimemanager.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwworld/timestamp.hpp" #include "../mwstate/character.hpp" @@ -147,6 +149,27 @@ namespace MWGui WindowModal::onOpen(); mSaveNameEdit->setCaption({}); + if (Settings::gui().mControllerMenus && mSaving) + { + // For controller mode, set a default save file name. The format is + // "Day 24 - Last Steed 7 p.m." + const MWWorld::DateTimeManager& timeManager = *MWBase::Environment::get().getWorld()->getTimeManager(); + std::string_view month = timeManager.getMonthName(); + int hour = static_cast(timeManager.getTimeStamp().getHour()); + bool pm = hour >= 12; + if (hour >= 13) + hour -= 12; + if (hour == 0) + hour = 12; + + ESM::EpochTimeStamp currentDate = timeManager.getEpochTimeStamp(); + std::string daysPassed = Misc::StringUtils::format("#{Calendar:day} %i", timeManager.getTimeStamp().getDay()); + std::string_view formattedHour(pm ? "#{Calendar:pm}" : "#{Calendar:am}"); + std::string autoFilename + = Misc::StringUtils::format("%s - %i %s %i %s", daysPassed, currentDate.mDay, month, hour, formattedHour); + + mSaveNameEdit->setCaptionWithReplacing(autoFilename); + } if (mSaving) MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveNameEdit); else From cd745c7df3b96029753c375c0ca2f58dfc4b340e Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 25 May 2025 22:51:43 -0700 Subject: [PATCH 057/330] Swap some controller button assignments --- apps/openmw/mwgui/container.cpp | 4 ++-- apps/openmw/mwgui/journalwindow.cpp | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index c0896d5b5e..1657225343 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -360,7 +360,7 @@ namespace MWGui ControllerButtonStr* ContainerWindow::getControllerButtons() { - mControllerButtons.l1 = mDisposeCorpseButton->getVisible() ? "#{sDisposeofCorpse}" : ""; + mControllerButtons.r1 = mDisposeCorpseButton->getVisible() ? "#{sDisposeofCorpse}" : ""; return &mControllerButtons; } @@ -380,7 +380,7 @@ namespace MWGui { onTakeAllButtonClicked(mTakeButton); } - else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) + else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) { if (mDisposeCorpseButton->getVisible()) onDisposeCorpseButtonClicked(mDisposeCorpseButton); diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 69004171db..8fbeb161ec 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -281,6 +281,8 @@ namespace updateShowingPages(); updateCloseJournalButton(); + + MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay(); } void setOptionsMode() @@ -480,6 +482,7 @@ namespace popBook(); MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("book page")); + MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay(); } void addControllerButtons(Gui::MWList* _list, int _selectedIndex) @@ -518,6 +521,7 @@ namespace addControllerButtons(list, mSelectedQuest); MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("book page")); + MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay(); } void notifyTopics(MyGUI::Widget* _sender) @@ -533,6 +537,7 @@ namespace setVisible(ShowActiveBTN, false); MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("book page")); + MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay(); } struct AddNamesToList @@ -594,6 +599,7 @@ namespace } MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("book page")); + MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay(); } void notifyShowAll(MyGUI::Widget* _sender) @@ -678,6 +684,7 @@ namespace mControllerButtons.b = mOptionsMode || mStates.size() > 1 ? "#{sBack}" : "#{sClose}"; mControllerButtons.l1 = mOptionsMode ? "" : "#{sPrev}"; mControllerButtons.r1 = mOptionsMode ? "" : "#{sNext}"; + mControllerButtons.r3 = mOptionsMode && mQuestMode ? "Show All" : ""; return &mControllerButtons; } @@ -758,6 +765,13 @@ namespace } return true; } + else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK) // R3: Show All/Some + { + if (mAllQuests) + notifyShowActive(getWidget(ShowActiveBTN)); + else + notifyShowAll(getWidget(ShowAllBTN)); + } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) { if (mOptionsMode && (mQuestMode || mTopicsMode)) From 71fd8b8840e25d6cd3857beb9f24555fc854af0e Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 25 May 2025 23:14:13 -0700 Subject: [PATCH 058/330] Add controller support to spell buying and training windows --- apps/openmw/mwgui/spellbuyingwindow.cpp | 55 +++++++++++++++++++++++++ apps/openmw/mwgui/spellbuyingwindow.hpp | 3 ++ apps/openmw/mwgui/trainingwindow.cpp | 49 ++++++++++++++++++++++ apps/openmw/mwgui/trainingwindow.hpp | 4 ++ 4 files changed, 111 insertions(+) diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 9fca86caba..e1f12ae6e0 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -31,6 +31,13 @@ namespace MWGui getWidget(mSpellsView, "SpellsView"); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellBuyingWindow::onCancelButtonClicked); + + if (Settings::gui().mControllerMenus) + { + mDisableGamepadCursor = true; + mControllerButtons.a = "#{sBuy}"; + mControllerButtons.b = "#{sBack}"; + } } bool SpellBuyingWindow::sortSpells(const ESM::Spell* left, const ESM::Spell* right) @@ -70,6 +77,8 @@ namespace MWGui toAdd->setUserString("SpellCost", std::to_string(spell.mData.mCost)); toAdd->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellBuyingWindow::onSpellButtonClick); mSpellsWidgetMap.insert(std::make_pair(toAdd, spell.mId)); + if (price <= playerGold) + mSpellButtons.emplace_back(toAdd); } void SpellBuyingWindow::clearSpells() @@ -79,6 +88,7 @@ namespace MWGui while (mSpellsView->getChildCount()) MyGUI::Gui::getInstance().destroyWidget(mSpellsView->getChildAt(0)); mSpellsWidgetMap.clear(); + mSpellButtons.clear(); } void SpellBuyingWindow::setPtr(const MWWorld::Ptr& actor) @@ -129,6 +139,13 @@ namespace MWGui updateLabels(); + if (Settings::gui().mControllerMenus) + { + mControllerFocus = 0; + if (mSpellButtons.size() > 0) + mSpellButtons[0]->setStateSelected(true); + } + // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the // scrollbar is hidden mSpellsView->setVisibleVScroll(false); @@ -199,4 +216,42 @@ namespace MWGui mSpellsView->setViewOffset( MyGUI::IntPoint(0, static_cast(mSpellsView->getViewOffset().top + _rel * 0.3f))); } + + bool SpellBuyingWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + onSpellButtonClick(mSpellButtons[mControllerFocus]); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + { + onCancelButtonClicked(mCancelButton); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) + { + if (mSpellButtons.size() <= 1) + return true; + + mSpellButtons[mControllerFocus]->setStateSelected(false); + mControllerFocus = wrap(mControllerFocus - 1, mSpellButtons.size()); + mSpellButtons[mControllerFocus]->setStateSelected(true); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + { + if (mSpellButtons.size() <= 1) + return true; + + mSpellButtons[mControllerFocus]->setStateSelected(false); + mControllerFocus = wrap(mControllerFocus + 1, mSpellButtons.size()); + mSpellButtons[mControllerFocus]->setStateSelected(true); + } + + // Scroll the list to keep the active item in view + if (mControllerFocus <= 5) + mSpellsView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mSpellsView->setViewOffset(MyGUI::IntPoint(0, -10 * (mControllerFocus - 5))); + + return true; + } } diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index 257b8a0df9..234dcb5b9d 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -39,6 +39,7 @@ namespace MWGui MyGUI::ScrollView* mSpellsView; std::map mSpellsWidgetMap; + std::vector mSpellButtons; void onCancelButtonClicked(MyGUI::Widget* _sender); void onSpellButtonClick(MyGUI::Widget* _sender); @@ -55,6 +56,8 @@ namespace MWGui private: static bool sortSpells(const ESM::Spell* left, const ESM::Spell* right); + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + int mControllerFocus; }; } diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 890aa0ba68..371f0e95aa 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -37,6 +37,13 @@ namespace MWGui mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &TrainingWindow::onTrainingProgressChanged); mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &TrainingWindow::onTrainingFinished); + + if (Settings::gui().mControllerMenus) + { + mDisableGamepadCursor = true; + mControllerButtons.a = "#{sBuy}"; + mControllerButtons.b = "#{sBack}"; + } } void TrainingWindow::onOpen() @@ -105,6 +112,7 @@ namespace MWGui const int lineHeight = Settings::gui().mFontSize + 2; + mTrainingButtons.clear(); for (size_t i = 0; i < skills.size(); ++i) { const ESM::Skill* skill = skills[i].first; @@ -128,6 +136,16 @@ namespace MWGui button->setSize(button->getTextSize().width + 12, button->getSize().height); ToolTips::createSkillToolTip(button, skill->mId); + + if (price <= playerGold) + mTrainingButtons.emplace_back(button); + } + + if (Settings::gui().mControllerMenus) + { + mControllerFocus = 0; + if (mTrainingButtons.size() > 0) + mTrainingButtons[0]->setStateSelected(true); } center(); @@ -229,4 +247,35 @@ namespace MWGui return !mTimeAdvancer.isRunning(); } + bool TrainingWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + onTrainingSelected(mTrainingButtons[mControllerFocus]); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + { + onCancelButtonClicked(mCancelButton); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) + { + if (mTrainingButtons.size() <= 1) + return true; + + mTrainingButtons[mControllerFocus]->setStateSelected(false); + mControllerFocus = wrap(mControllerFocus - 1, mTrainingButtons.size()); + mTrainingButtons[mControllerFocus]->setStateSelected(true); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + { + if (mTrainingButtons.size() <= 1) + return true; + + mTrainingButtons[mControllerFocus]->setStateSelected(false); + mControllerFocus = wrap(mControllerFocus + 1, mTrainingButtons.size()); + mTrainingButtons[mControllerFocus]->setStateSelected(true); + } + + return true; + } } diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index ee13f24b23..4f866f820e 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -49,9 +49,13 @@ namespace MWGui MyGUI::Widget* mTrainingOptions; MyGUI::Button* mCancelButton; MyGUI::TextBox* mPlayerGold; + std::vector mTrainingButtons; WaitDialogProgressBar mProgressBar; TimeAdvancer mTimeAdvancer; + + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + int mControllerFocus; }; } From 14b0c9afbee0740f04e3c097e532c67d6233b8a5 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Mon, 26 May 2025 21:08:05 -0700 Subject: [PATCH 059/330] Add controller support to barter window --- apps/openmw/mwgui/countdialog.cpp | 9 ++- apps/openmw/mwgui/countdialog.hpp | 1 + apps/openmw/mwgui/inventorywindow.cpp | 11 +++- apps/openmw/mwgui/itemview.cpp | 13 +++- apps/openmw/mwgui/tradewindow.cpp | 94 +++++++++++++++++++++++++++ apps/openmw/mwgui/tradewindow.hpp | 4 ++ 6 files changed, 127 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/countdialog.cpp b/apps/openmw/mwgui/countdialog.cpp index 75a2fc6034..d922b990cd 100644 --- a/apps/openmw/mwgui/countdialog.cpp +++ b/apps/openmw/mwgui/countdialog.cpp @@ -41,7 +41,7 @@ namespace MWGui MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); mSlider->setScrollRange(maxCount); - mItemText->setCaption(item); + mItemText->setCaptionWithReplacing(item); int width = std::max(mItemText->getTextSize().width + 160, 320); setCoord(viewSize.width / 2 - width / 2, viewSize.height / 2 - mMainWidget->getHeight() / 2, width, @@ -57,6 +57,13 @@ namespace MWGui mItemEdit->setValue(maxCount); } + void CountDialog::setCount(int count) + { + count = std::clamp(count, 1, (int)mSlider->getScrollRange()); + mSlider->setScrollPosition(count - 1); + mItemEdit->setValue(count); + } + void CountDialog::onCancelButtonClicked(MyGUI::Widget* _sender) { setVisible(false); diff --git a/apps/openmw/mwgui/countdialog.hpp b/apps/openmw/mwgui/countdialog.hpp index 695de09215..b3a1aab3b3 100644 --- a/apps/openmw/mwgui/countdialog.hpp +++ b/apps/openmw/mwgui/countdialog.hpp @@ -17,6 +17,7 @@ namespace MWGui public: CountDialog(); void openCountDialog(const std::string& item, const std::string& message, const int maxCount); + void setCount(int count); typedef MyGUI::delegates::MultiDelegate EventHandle_WidgetInt; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 7f314fed14..2e128f15f8 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -133,7 +133,6 @@ namespace MWGui if (Settings::gui().mControllerMenus) { mControllerButtons.b = "#{sBack}"; - mControllerButtons.r1 = "Filter"; mControllerButtons.r3 = "#{sInfo}"; } @@ -892,7 +891,7 @@ namespace MWGui break; case MWGui::GM_Barter: mControllerButtons.a = "#{sSell}"; - mControllerButtons.x = ""; + mControllerButtons.x = "#{sOffer}"; mControllerButtons.y = ""; mControllerButtons.r2 = "#{sBarter}"; break; @@ -959,6 +958,14 @@ namespace MWGui (MWGui::ContainerWindow *)MWBase::Environment::get().getWindowManager()->getGuiModeWindows(mGuiMode).at(0); containerWindow->onControllerButtonEvent(arg); } + else if (mGuiMode == MWGui::GM_Barter) + { + // Offer. Pass the button press to the barter window and let it do the logic + // of making an offer. + MWGui::TradeWindow* tradeWindow = + (MWGui::TradeWindow*)MWBase::Environment::get().getWindowManager()->getGuiModeWindows(mGuiMode).at(1); + tradeWindow->onControllerButtonEvent(arg); + } } else if (arg.button == SDL_CONTROLLER_BUTTON_Y) { diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index a223bde5e0..9cde52f0c2 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -52,12 +52,14 @@ namespace MWGui MyGUI::Widget* dragArea = mScrollView->getChildAt(0); int maxHeight = mScrollView->getHeight(); - mRows = maxHeight / 42; - mRows = std::max(mRows, 1); + mRows = std::max(maxHeight / 42, 1); mItemCount = dragArea->getChildCount(); bool showScrollbar = int(std::ceil(mItemCount / float(mRows))) > mScrollView->getWidth() / 42; if (showScrollbar) + { maxHeight -= 18; + mRows = std::max(maxHeight / 42, 1); + } for (unsigned int i = 0; i < mItemCount; ++i) { @@ -262,6 +264,13 @@ namespace MWGui focused->setControllerFocus(true); if (mControllerTooltip) MWBase::Environment::get().getInputManager()->warpMouseToWidget(focused); + + // Scroll the list to keep the active item in view + int column = newFocus / mRows; + if (column <= 3) + mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mScrollView->setViewOffset(MyGUI::IntPoint(-42 * (column - 3), 0)); } } } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index ba752303d2..3e4b8732bb 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -168,6 +168,12 @@ namespace MWGui std::numeric_limits::min() + 1); // disallow INT_MIN since abs(INT_MIN) is undefined setCoord(400, 0, 400, 300); + + mControllerButtons.a = "#{sBuy}"; + mControllerButtons.b = "#{sBack}"; + mControllerButtons.x = "#{sOffer}"; + mControllerButtons.r3 = "#{sInfo}"; + mControllerButtons.l2 = "#{sInventory}"; } void TradeWindow::setPtr(const MWWorld::Ptr& actor) @@ -201,6 +207,10 @@ namespace MWGui onFilterChanged(mFilterAll); mFilterEdit->setCaption({}); + + // Cycle to the buy window if it's not active. + if (Settings::gui().mControllerMenus && !mActiveControllerWindow) + MWBase::Environment::get().getWindowManager()->cycleActiveControllerWindow(true); } void TradeWindow::onFrame(float dt) @@ -339,6 +349,13 @@ namespace MWGui } } + void TradeWindow::onOfferSubmitted(MyGUI::Widget* _sender, int offerAmount) + { + mCurrentBalance = mCurrentBalance < 0 ? -offerAmount : offerAmount; + updateLabels(); + onOfferButtonClicked(mOfferButton); + } + void TradeWindow::onOfferButtonClicked(MyGUI::Widget* _sender) { TradeItemModel* playerItemModel @@ -643,4 +660,81 @@ namespace MWGui if (mTradeModel && mTradeModel->usesContainer(ptr)) MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); } + + bool TradeWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + int index = mItemView->getControllerFocus(); + if (index >= 0 && index < mItemView->getItemCount()) + onItemSelected(index); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + { + onCancelButtonClicked(mCancelButton); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_X) + { + if (mCurrentBalance == 0) + return true; + // Show a count dialog to allow for bartering. + CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); + if (mCurrentBalance < 0) + { + // Buying from the merchant + dialog->openCountDialog("#{sTotalcost}:", "#{sOffer}", -mCurrentMerchantOffer); + dialog->setCount(-mCurrentBalance); + } + else + { + // Selling to the merchant + dialog->openCountDialog("#{sTotalsold}:", "#{sOffer}", getMerchantGold()); + dialog->setCount(mCurrentBalance); + } + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &TradeWindow::onOfferSubmitted); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) + { + if (mFilterAll->getStateSelected()) + onFilterChanged(mFilterMisc); + else if (mFilterWeapon->getStateSelected()) + onFilterChanged(mFilterAll); + else if (mFilterApparel->getStateSelected()) + onFilterChanged(mFilterWeapon); + else if (mFilterMagic->getStateSelected()) + onFilterChanged(mFilterApparel); + else if (mFilterMisc->getStateSelected()) + onFilterChanged(mFilterMagic); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) + { + if (mFilterAll->getStateSelected()) + onFilterChanged(mFilterWeapon); + else if (mFilterWeapon->getStateSelected()) + onFilterChanged(mFilterApparel); + else if (mFilterApparel->getStateSelected()) + onFilterChanged(mFilterMagic); + else if (mFilterMagic->getStateSelected()) + onFilterChanged(mFilterMisc); + else if (mFilterMisc->getStateSelected()) + onFilterChanged(mFilterAll); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK || + arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP || + arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN || + arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT || + arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + { + mItemView->onControllerButtonEvent(arg.button); + } + + return true; + } + + void TradeWindow::setActiveControllerWindow(bool active) + { + mItemView->setActiveControllerWindow(active); + WindowBase::setActiveControllerWindow(active); + } } diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 33c39cb269..afd271ed2f 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -47,6 +47,9 @@ namespace MWGui std::string_view getWindowIdForLua() const override { return "Trade"; } + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + void setActiveControllerWindow(bool active) override; + private: ItemView* mItemView; SortFilterItemModel* mSortModel; @@ -102,6 +105,7 @@ namespace MWGui void onBalanceButtonReleased(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); void onBalanceValueChanged(int value); void onRepeatClick(MyGUI::Widget* widget, MyGUI::ControllerItem* controller); + void onOfferSubmitted(MyGUI::Widget* _sender, int offerAmount); void addRepeatController(MyGUI::Widget* widget); From 274434e0d61dbe9b2fff9a71a138857be9e13415 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Mon, 26 May 2025 22:52:10 -0700 Subject: [PATCH 060/330] Add controller support to travel window --- apps/openmw/mwgui/travelwindow.cpp | 59 ++++++++++++++++++++++++++++++ apps/openmw/mwgui/travelwindow.hpp | 5 +++ 2 files changed, 64 insertions(+) diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 6ba3a55286..f954daafff 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -42,6 +42,13 @@ namespace MWGui mDestinations->setCoord(450 / 2 - mDestinations->getTextSize().width / 2, mDestinations->getTop(), mDestinations->getTextSize().width, mDestinations->getHeight()); mSelect->setCoord(8, mSelect->getTop(), mSelect->getTextSize().width, mSelect->getHeight()); + + if (Settings::gui().mControllerMenus) + { + mDisableGamepadCursor = true; + mControllerButtons.a = "#{sTravel}"; + mControllerButtons.b = "#{sBack}"; + } } void TravelWindow::addDestination(const ESM::RefId& name, const ESM::Position& pos, bool interior) @@ -100,6 +107,8 @@ namespace MWGui toAdd->setUserString("Destination", nameString); toAdd->setUserData(pos); toAdd->eventMouseButtonClick += MyGUI::newDelegate(this, &TravelWindow::onTravelButtonClick); + if (price <= playerGold) + mDestinationButtons.emplace_back(toAdd); } void TravelWindow::clearDestinations() @@ -108,6 +117,7 @@ namespace MWGui mCurrentY = 0; while (mDestinationsView->getChildCount()) MyGUI::Gui::getInstance().destroyWidget(mDestinationsView->getChildAt(0)); + mDestinationButtons.clear(); } void TravelWindow::setPtr(const MWWorld::Ptr& actor) @@ -141,6 +151,14 @@ namespace MWGui } updateLabels(); + + if (Settings::gui().mControllerMenus) + { + mControllerFocus = 0; + if (mDestinationButtons.size() > 0) + mDestinationButtons[0]->setStateSelected(true); + } + // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the // scrollbar is hidden mDestinationsView->setVisibleVScroll(false); @@ -235,4 +253,45 @@ namespace MWGui mDestinationsView->setViewOffset( MyGUI::IntPoint(0, static_cast(mDestinationsView->getViewOffset().top + _rel * 0.3f))); } + + bool TravelWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + onTravelButtonClick(mDestinationButtons[mControllerFocus]); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + { + onCancelButtonClicked(mCancelButton); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) + { + if (mDestinationButtons.size() <= 1) + return true; + + mDestinationButtons[mControllerFocus]->setStateSelected(false); + mControllerFocus = wrap(mControllerFocus - 1, mDestinationButtons.size()); + mDestinationButtons[mControllerFocus]->setStateSelected(true); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + { + if (mDestinationButtons.size() <= 1) + return true; + + mDestinationButtons[mControllerFocus]->setStateSelected(false); + mControllerFocus = wrap(mControllerFocus + 1, mDestinationButtons.size()); + mDestinationButtons[mControllerFocus]->setStateSelected(true); + } + + // Scroll the list to keep the active item in view + if (mControllerFocus <= 5) + mDestinationsView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + { + const int lineHeight = Settings::gui().mFontSize + 2; + mDestinationsView->setViewOffset(MyGUI::IntPoint(0, -lineHeight * (mControllerFocus - 5))); + } + + return true; + } } diff --git a/apps/openmw/mwgui/travelwindow.hpp b/apps/openmw/mwgui/travelwindow.hpp index 6d7c1c7376..1136718e72 100644 --- a/apps/openmw/mwgui/travelwindow.hpp +++ b/apps/openmw/mwgui/travelwindow.hpp @@ -26,6 +26,7 @@ namespace MWGui MyGUI::TextBox* mPlayerGold; MyGUI::TextBox* mDestinations; MyGUI::TextBox* mSelect; + std::vector mDestinationButtons; MyGUI::ScrollView* mDestinationsView; @@ -39,6 +40,10 @@ namespace MWGui void updateLabels(); void onReferenceUnavailable() override; + + private: + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + int mControllerFocus; }; } From f67aae086a70a8af2bd231da9e573af489ebe1a7 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Mon, 26 May 2025 23:07:20 -0700 Subject: [PATCH 061/330] Improve scrolling in list windows and fix a crash in a few menus when no items are selectable --- apps/openmw/mwgui/class.cpp | 3 ++- apps/openmw/mwgui/messagebox.cpp | 1 + apps/openmw/mwgui/spellbuyingwindow.cpp | 23 ++++++++++++-------- apps/openmw/mwgui/spellbuyingwindow.hpp | 3 ++- apps/openmw/mwgui/spellview.cpp | 29 +++++++++++++++++-------- apps/openmw/mwgui/spellview.hpp | 4 ++-- apps/openmw/mwgui/trainingwindow.cpp | 3 ++- apps/openmw/mwgui/travelwindow.cpp | 3 ++- 8 files changed, 45 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index e658001e5a..b1e6b77ca0 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -473,7 +473,8 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - onButtonClicked(mButtons[mControllerFocus]); + if (mControllerFocus >= 0 && mControllerFocus < mButtons.size()) + onButtonClicked(mButtons[mControllerFocus]); } else if (arg.button == SDL_CONTROLLER_BUTTON_B) { diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 94807dd54c..ec42993f4d 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -446,6 +446,7 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { + mControllerFocus = std::clamp(mControllerFocus, 0, (int)mButtons.size() - 1); buttonActivated(mButtons[mControllerFocus]); } else if (arg.button == SDL_CONTROLLER_BUTTON_B) diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index e1f12ae6e0..1c986180a8 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -78,7 +78,7 @@ namespace MWGui toAdd->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellBuyingWindow::onSpellButtonClick); mSpellsWidgetMap.insert(std::make_pair(toAdd, spell.mId)); if (price <= playerGold) - mSpellButtons.emplace_back(toAdd); + mSpellButtons.emplace_back(std::make_pair(toAdd, mSpellsWidgetMap.size())); } void SpellBuyingWindow::clearSpells() @@ -143,7 +143,7 @@ namespace MWGui { mControllerFocus = 0; if (mSpellButtons.size() > 0) - mSpellButtons[0]->setStateSelected(true); + mSpellButtons[0].first->setStateSelected(true); } // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the @@ -221,7 +221,8 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - onSpellButtonClick(mSpellButtons[mControllerFocus]); + if (mControllerFocus >= 0 && mControllerFocus < mSpellButtons.size()) + onSpellButtonClick(mSpellButtons[mControllerFocus].first); } else if (arg.button == SDL_CONTROLLER_BUTTON_B) { @@ -232,25 +233,29 @@ namespace MWGui if (mSpellButtons.size() <= 1) return true; - mSpellButtons[mControllerFocus]->setStateSelected(false); + mSpellButtons[mControllerFocus].first->setStateSelected(false); mControllerFocus = wrap(mControllerFocus - 1, mSpellButtons.size()); - mSpellButtons[mControllerFocus]->setStateSelected(true); + mSpellButtons[mControllerFocus].first->setStateSelected(true); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) { if (mSpellButtons.size() <= 1) return true; - mSpellButtons[mControllerFocus]->setStateSelected(false); + mSpellButtons[mControllerFocus].first->setStateSelected(false); mControllerFocus = wrap(mControllerFocus + 1, mSpellButtons.size()); - mSpellButtons[mControllerFocus]->setStateSelected(true); + mSpellButtons[mControllerFocus].first->setStateSelected(true); } // Scroll the list to keep the active item in view - if (mControllerFocus <= 5) + int line = mSpellButtons[mControllerFocus].second; + if (line <= 5) mSpellsView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mSpellsView->setViewOffset(MyGUI::IntPoint(0, -10 * (mControllerFocus - 5))); + { + const int lineHeight = Settings::gui().mFontSize + 2; + mSpellsView->setViewOffset(MyGUI::IntPoint(0, -lineHeight * (line - 5))); + } return true; } diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index 234dcb5b9d..e67dfde76c 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -39,7 +39,8 @@ namespace MWGui MyGUI::ScrollView* mSpellsView; std::map mSpellsWidgetMap; - std::vector mSpellButtons; + /// List of enabled/purchasable spells and their index in the full list. + std::vector> mSpellButtons; void onCancelButtonClicked(MyGUI::Widget* _sender); void onSpellButtonClick(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index 2ebd1751da..6ef73c7794 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -122,7 +122,7 @@ namespace MWGui t->setCaption(spell.mName + captionSuffix); t->setTextAlign(MyGUI::Align::Left); adjustSpellWidget(spell, i, t); - mButtons.emplace_back(t); + mButtons.emplace_back(std::make_pair(t, i)); if (!spell.mCostColumn.empty() && mShowCostColumn) { @@ -339,7 +339,7 @@ namespace MWGui // Select the focused item, if any. if (mControllerFocus >= 0 && mControllerFocus < mButtons.size()) { - onSpellSelected(mButtons.at(mControllerFocus)); + onSpellSelected(mButtons[mControllerFocus].first); MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); } } @@ -348,12 +348,16 @@ namespace MWGui // Toggle info tooltip mControllerTooltip = !mControllerTooltip; if (mControllerTooltip && mControllerFocus >= 0 && mControllerFocus < mButtons.size()) - MWBase::Environment::get().getInputManager()->warpMouseToWidget(mButtons.at(mControllerFocus)); + MWBase::Environment::get().getInputManager()->warpMouseToWidget(mButtons[mControllerFocus].first); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) mControllerFocus--; else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) mControllerFocus++; + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) + mControllerFocus = std::max(0, mControllerFocus - 10); + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + mControllerFocus = std::min(mControllerFocus + 10, (int)mButtons.size() - 1); else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) { // Jump to first item in previous group @@ -380,10 +384,7 @@ namespace MWGui } } - if (mControllerFocus < 0) - mControllerFocus = mButtons.size() - 1; - else if (mControllerFocus >= mButtons.size()) - mControllerFocus = 0; + mControllerFocus = wrap(mControllerFocus, mButtons.size()); if (prevFocus != mControllerFocus) updateControllerFocus(prevFocus, mControllerFocus); @@ -396,19 +397,29 @@ namespace MWGui if (prevFocus >= 0 && prevFocus < mButtons.size()) { - Gui::SharedStateButton* prev = mButtons.at(prevFocus); + Gui::SharedStateButton* prev = mButtons[prevFocus].first; if (prev) prev->onMouseLostFocus(nullptr); } if (newFocus >= 0 && newFocus < mButtons.size()) { - Gui::SharedStateButton* focused = mButtons.at(newFocus); + Gui::SharedStateButton* focused = mButtons[newFocus].first; if (focused) { focused->onMouseSetFocus(nullptr); if (mControllerTooltip) MWBase::Environment::get().getInputManager()->warpMouseToWidget(focused); + + // Scroll the list to keep the active item in view + int line = mButtons[newFocus].second; + if (line <= 5) + mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + { + const int lineHeight = focused->getHeight(); + mScrollView->setViewOffset(MyGUI::IntPoint(0, -lineHeight * (line - 5))); + } } } } diff --git a/apps/openmw/mwgui/spellview.hpp b/apps/openmw/mwgui/spellview.hpp index cf3a43354f..222d5f1ba3 100644 --- a/apps/openmw/mwgui/spellview.hpp +++ b/apps/openmw/mwgui/spellview.hpp @@ -94,8 +94,8 @@ namespace MWGui void addGroup(const std::string& label1, const std::string& label2); void adjustSpellWidget(const Spell& spell, SpellModel::ModelIndex index, MyGUI::Widget* widget); - /// Keep a list of buttons for controller navigation - std::vector mButtons; + /// Keep a list of buttons for controller navigation and their index in the full list. + std::vector> mButtons; /// Keep a list of group offsets for controller navigation std::vector mGroupIndices; diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 371f0e95aa..fcead9d543 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -251,7 +251,8 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - onTrainingSelected(mTrainingButtons[mControllerFocus]); + if (mControllerFocus >= 0 && mControllerFocus < mTrainingButtons.size()) + onTrainingSelected(mTrainingButtons[mControllerFocus]); } else if (arg.button == SDL_CONTROLLER_BUTTON_B) { diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index f954daafff..083bba391b 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -258,7 +258,8 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - onTravelButtonClick(mDestinationButtons[mControllerFocus]); + if (mControllerFocus >= 0 && mControllerFocus < mDestinationButtons.size()) + onTravelButtonClick(mDestinationButtons[mControllerFocus]); } else if (arg.button == SDL_CONTROLLER_BUTTON_B) { From 451d68461ceb983694f7e359ce4701d5928b81f4 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Tue, 27 May 2025 22:40:00 -0700 Subject: [PATCH 062/330] Add controller support to skill and attribute menus --- apps/openmw/mwgui/class.cpp | 88 +++++++++++++++++++++++++++++++---- apps/openmw/mwgui/class.hpp | 4 ++ apps/openmw/mwgui/widgets.cpp | 26 +++++++++++ apps/openmw/mwgui/widgets.hpp | 8 ++++ 4 files changed, 116 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index b1e6b77ca0..c0660b5f02 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -943,6 +943,7 @@ namespace MWGui widget->setAttributeId(attribute.mId); widget->eventClicked += MyGUI::newDelegate(this, &SelectAttributeDialog::onAttributeClicked); ToolTips::createAttributeToolTip(widget, attribute.mId); + mAttributeButtons.emplace_back(widget); } attributes->setVisibleVScroll(false); @@ -954,8 +955,15 @@ namespace MWGui getWidget(cancelButton, "CancelButton"); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectAttributeDialog::onCancelClicked); - mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sCancel}"; + if (Settings::gui().mControllerMenus) + { + mControllerFocus = 0; + if (mAttributeButtons.size() > 0) + mAttributeButtons[0]->setStateSelected(true); + + mControllerButtons.a = "#{sSelect}"; + mControllerButtons.b = "#{sCancel}"; + } } // widget controls @@ -979,12 +987,29 @@ namespace MWGui bool SelectAttributeDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { - if (arg.button == SDL_CONTROLLER_BUTTON_B) + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + if (mControllerFocus >= 0 && mControllerFocus < mAttributeButtons.size()) + onAttributeClicked(mAttributeButtons[mControllerFocus]); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B) { onCancelClicked(nullptr); - return true; } - return false; + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) + { + mAttributeButtons[mControllerFocus]->setStateSelected(false); + mControllerFocus = wrap(mControllerFocus - 1, mAttributeButtons.size()); + mAttributeButtons[mControllerFocus]->setStateSelected(true); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + { + mAttributeButtons[mControllerFocus]->setStateSelected(false); + mControllerFocus = wrap(mControllerFocus + 1, mAttributeButtons.size()); + mAttributeButtons[mControllerFocus]->setStateSelected(true); + } + + return true; } /* SelectSkillDialog */ @@ -1016,6 +1041,7 @@ namespace MWGui skillWidget->setSkillId(skill.mId); skillWidget->eventClicked += MyGUI::newDelegate(this, &SelectSkillDialog::onSkillClicked); ToolTips::createSkillToolTip(skillWidget, skill.mId); + mSkillButtons.emplace_back(skillWidget); } for (const auto& [widget, coord] : specializations) { @@ -1029,8 +1055,15 @@ namespace MWGui getWidget(cancelButton, "CancelButton"); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSkillDialog::onCancelClicked); - mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sCancel}"; + if (Settings::gui().mControllerMenus) + { + mControllerFocus = 0; + if (mSkillButtons.size() > 0) + mSkillButtons[0]->setStateSelected(true); + + mControllerButtons.a = "#{sSelect}"; + mControllerButtons.b = "#{sCancel}"; + } } SelectSkillDialog::~SelectSkillDialog() {} @@ -1056,12 +1089,47 @@ namespace MWGui bool SelectSkillDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { - if (arg.button == SDL_CONTROLLER_BUTTON_B) + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + if (mControllerFocus >= 0 && mControllerFocus < mSkillButtons.size()) + onSkillClicked(mSkillButtons[mControllerFocus]); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B) { onCancelClicked(nullptr); - return true; } - return false; + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) + { + mSkillButtons[mControllerFocus]->setStateSelected(false); + mControllerFocus = wrap(mControllerFocus - 1, mSkillButtons.size()); + mSkillButtons[mControllerFocus]->setStateSelected(true); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + { + mSkillButtons[mControllerFocus]->setStateSelected(false); + mControllerFocus = wrap(mControllerFocus + 1, mSkillButtons.size()); + mSkillButtons[mControllerFocus]->setStateSelected(true); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) + { + mSkillButtons[mControllerFocus]->setStateSelected(false); + if (mControllerFocus < 9) + mControllerFocus += 18; + else + mControllerFocus -= 9; + mSkillButtons[mControllerFocus]->setStateSelected(true); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + { + mSkillButtons[mControllerFocus]->setStateSelected(false); + if (mControllerFocus >= 18) + mControllerFocus -= 18; + else + mControllerFocus += 9; + mSkillButtons[mControllerFocus]->setStateSelected(true); + } + + return true; } /* DescriptionDialog */ diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index 515416973e..9f04fa9e13 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -219,6 +219,8 @@ namespace MWGui void onAttributeClicked(Widgets::MWAttributePtr _sender); void onCancelClicked(MyGUI::Widget* _sender); bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + int mControllerFocus; + std::vector mAttributeButtons; private: ESM::RefId mAttributeId; @@ -251,6 +253,8 @@ namespace MWGui void onSkillClicked(Widgets::MWSkillPtr _sender); void onCancelClicked(MyGUI::Widget* _sender); bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + int mControllerFocus; + std::vector mSkillButtons; private: ESM::RefId mSkillId; diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 6cc5bdfdf5..8995f04b92 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -14,6 +14,8 @@ #include #include +#include "textcolours.hpp" + #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" @@ -66,6 +68,12 @@ namespace MWGui::Widgets } } + void MWSkill::setStateSelected(bool selected) + { + const TextColours& textColours{ MWBase::Environment::get().getWindowManager()->getTextColours() }; + mSkillNameWidget->setTextColour(selected ? textColours.link : textColours.normal); + } + void MWSkill::onClicked(MyGUI::Widget* _sender) { eventClicked(this); @@ -150,6 +158,12 @@ namespace MWGui::Widgets } } + void MWAttribute::setStateSelected(bool selected) + { + const TextColours& textColours{ MWBase::Environment::get().getWindowManager()->getTextColours() }; + mAttributeNameWidget->setTextColour(selected ? textColours.link : textColours.normal); + } + void MWAttribute::initialiseOverride() { Base::initialiseOverride(); @@ -231,6 +245,12 @@ namespace MWGui::Widgets } } + void MWSpell::setStateSelected(bool selected) + { + const TextColours& textColours{ MWBase::Environment::get().getWindowManager()->getTextColours() }; + mSpellNameWidget->setTextColour(selected ? textColours.link : textColours.normal); + } + void MWSpell::initialiseOverride() { Base::initialiseOverride(); @@ -461,6 +481,12 @@ namespace MWGui::Widgets MWSpellEffect::~MWSpellEffect() {} + void MWSpellEffect::setStateSelected(bool selected) + { + const TextColours& textColours{ MWBase::Environment::get().getWindowManager()->getTextColours() }; + mTextWidget->setTextColour(selected ? textColours.link : textColours.normal); + } + void MWSpellEffect::initialiseOverride() { Base::initialiseOverride(); diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index d562e4e07f..c51846d9df 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -110,6 +110,8 @@ namespace MWGui */ EventHandle_SkillVoid eventClicked; + void setStateSelected(bool selected); + protected: virtual ~MWSkill(); @@ -149,6 +151,8 @@ namespace MWGui */ EventHandle_AttributeVoid eventClicked; + void setStateSelected(bool selected); + protected: ~MWAttribute() override = default; @@ -191,6 +195,8 @@ namespace MWGui const ESM::RefId& getSpellId() const { return mId; } + void setStateSelected(bool selected); + protected: virtual ~MWSpell(); @@ -256,6 +262,8 @@ namespace MWGui int getRequestedWidth() const { return mRequestedWidth; } + void setStateSelected(bool selected); + protected: virtual ~MWSpellEffect(); From af27e9e5d61e64beb7f85d13319d310fb8d38b54 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Tue, 27 May 2025 22:51:03 -0700 Subject: [PATCH 063/330] Allow shoulder buttons to jump count slider to either extreme --- apps/openmw/mwgui/countdialog.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwgui/countdialog.cpp b/apps/openmw/mwgui/countdialog.cpp index d922b990cd..816d67921c 100644 --- a/apps/openmw/mwgui/countdialog.cpp +++ b/apps/openmw/mwgui/countdialog.cpp @@ -103,6 +103,10 @@ namespace MWGui onOkButtonClicked(mOkButton); else if (arg.button == SDL_CONTROLLER_BUTTON_B) onCancelButtonClicked(mCancelButton); + else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) + setCount(1); + else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) + setCount((int)mSlider->getScrollRange()); else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) From d18413f63a12bcc6a2e898fd22302041705c4b42 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Fri, 30 May 2025 01:10:57 -0700 Subject: [PATCH 064/330] Add controller support to spell making window --- apps/openmw/mwgui/spellcreationdialog.cpp | 353 +++++++++++++++++++++- apps/openmw/mwgui/spellcreationdialog.hpp | 18 +- 2 files changed, 368 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index d8302df87c..f096beddcb 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -25,8 +26,8 @@ #include "../mwmechanics/spellutil.hpp" #include "class.hpp" +#include "textcolours.hpp" #include "tooltips.hpp" -#include "widgets.hpp" namespace { @@ -95,6 +96,13 @@ namespace MWGui += MyGUI::newDelegate(this, &EditEffectDialog::onMagnitudeMaxChanged); mDurationSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &EditEffectDialog::onDurationChanged); mAreaSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &EditEffectDialog::onAreaChanged); + + if (Settings::gui().mControllerMenus) + { + mControllerButtons.a = "#{sSelect}"; + mControllerButtons.b = "#{sBack}"; + mControllerButtons.x = "#{sOk}"; + } } void EditEffectDialog::setConstantEffect(bool constant) @@ -154,6 +162,15 @@ namespace MWGui mMagnitudeMaxValue->setCaption(to + " 1"); mAreaValue->setCaption("0"); + if (Settings::gui().mControllerMenus) + { + mRangeButton->setStateSelected(true); + mDeleteButton->setStateSelected(false); + mOkButton->setStateSelected(false); + mCancelButton->setStateSelected(false); + mControllerFocus = 0; + } + setVisible(true); } @@ -187,6 +204,15 @@ namespace MWGui onDurationChanged(mDurationSlider, effect.mDuration - 1); eventEffectModified(mEffect); + if (Settings::gui().mControllerMenus) + { + mRangeButton->setStateSelected(true); + mDeleteButton->setStateSelected(false); + mOkButton->setStateSelected(false); + mCancelButton->setStateSelected(false); + mControllerFocus = 0; + } + updateBoxes(); } @@ -231,6 +257,25 @@ namespace MWGui mAreaBox->setVisible(true); // curY += mAreaBox->getSize().height; } + + if (Settings::gui().mControllerMenus) + { + mButtons.clear(); + mButtons.emplace_back(mRangeButton); + if (mMagnitudeBox->getVisible()) + { + mButtons.emplace_back(mMagnitudeMinValue); + mButtons.emplace_back(mMagnitudeMaxValue); + } + if (mDurationBox->getVisible()) + mButtons.emplace_back(mDurationValue); + if (mAreaBox->getVisible()) + mButtons.emplace_back(mAreaValue); + if (mDeleteButton->getVisible()) + mButtons.emplace_back(mDeleteButton); + mButtons.emplace_back(mOkButton); + mButtons.emplace_back(mCancelButton); + } } void EditEffectDialog::onRangeButtonClicked(MyGUI::Widget* sender) @@ -340,6 +385,195 @@ namespace MWGui eventEffectModified(mEffect); } + bool EditEffectDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + int prevFocus = mControllerFocus; + mControllerFocus = std::clamp(mControllerFocus, 0, (int)mButtons.size() - 1); + MyGUI::TextBox* button = mButtons[mControllerFocus]; + + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + if (button == mRangeButton) + onRangeButtonClicked(mRangeButton); + else if (button == mCancelButton) + onCancelButtonClicked(mCancelButton); + else if (button == mOkButton) + onOkButtonClicked(mOkButton); + else if (button == mDeleteButton) + onDeleteButtonClicked(mDeleteButton); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + onCancelButtonClicked(mCancelButton); + else if (arg.button == SDL_CONTROLLER_BUTTON_X) + onOkButtonClicked(mOkButton); + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) + { + if (mControllerFocus == 0) + mControllerFocus = (int)mButtons.size() - 2; + else if (button == mCancelButton && mDeleteButton->getVisible()) + mControllerFocus -= 3; + else if (button == mCancelButton || (button == mOkButton && mDeleteButton->getVisible())) + mControllerFocus -= 2; + else + mControllerFocus = std::max(mControllerFocus - 1, 0); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + { + if (button == mDeleteButton || button == mOkButton || button == mCancelButton) + mControllerFocus = 0; + else + mControllerFocus++; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) + { + if (button == mMagnitudeMinValue) + { + mMagnitudeMinSlider->setScrollPosition(0); + onMagnitudeMinChanged(nullptr, mMagnitudeMinSlider->getScrollPosition()); + } + else if (button == mMagnitudeMaxValue) + { + mMagnitudeMaxSlider->setScrollPosition(mMagnitudeMinSlider->getScrollPosition()); + onMagnitudeMaxChanged(nullptr, mMagnitudeMaxSlider->getScrollPosition()); + } + else if (button == mDurationValue) + { + mDurationSlider->setScrollPosition(0); + onDurationChanged(nullptr, mDurationSlider->getScrollPosition()); + } + else if (button == mAreaValue) + { + mAreaSlider->setScrollPosition(0); + onAreaChanged(nullptr, mAreaSlider->getScrollPosition()); + } + } + else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) + { + if (button == mMagnitudeMinValue) + { + mMagnitudeMinSlider->setScrollPosition(mMagnitudeMaxSlider->getScrollPosition()); + onMagnitudeMinChanged(nullptr, mMagnitudeMinSlider->getScrollPosition()); + } + else if (button == mMagnitudeMaxValue) + { + mMagnitudeMaxSlider->setScrollPosition(mMagnitudeMaxSlider->getScrollRange() - 1); + onMagnitudeMaxChanged(nullptr, mMagnitudeMaxSlider->getScrollPosition()); + } + else if (button == mDurationValue) + { + mDurationSlider->setScrollPosition(mDurationSlider->getScrollRange() - 1); + onDurationChanged(nullptr, mDurationSlider->getScrollPosition()); + } + else if (button == mAreaValue) + { + mAreaSlider->setScrollPosition(mAreaSlider->getScrollRange() - 1); + onAreaChanged(nullptr, mAreaSlider->getScrollPosition()); + } + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) + { + if (button == mRangeButton) + onRangeButtonClicked(mRangeButton); + else if (button == mCancelButton) + mControllerFocus--; + else if (button == mOkButton && mDeleteButton->getVisible()) + mControllerFocus--; + else if (button == mMagnitudeMinValue) + { + mMagnitudeMinSlider->setScrollPosition(mMagnitudeMinSlider->getScrollPosition() - 1); + onMagnitudeMinChanged(nullptr, mMagnitudeMinSlider->getScrollPosition()); + } + else if (button == mMagnitudeMaxValue) + { + mMagnitudeMaxSlider->setScrollPosition( + std::max(mMagnitudeMaxSlider->getScrollPosition() - 1, mMagnitudeMinSlider->getScrollPosition())); + onMagnitudeMaxChanged(nullptr, mMagnitudeMaxSlider->getScrollPosition()); + } + else if (button == mDurationValue) + { + mDurationSlider->setScrollPosition(mDurationSlider->getScrollPosition() - 1); + onDurationChanged(nullptr, mDurationSlider->getScrollPosition()); + } + else if (button == mAreaValue) + { + mAreaSlider->setScrollPosition(mAreaSlider->getScrollPosition() - 1); + onAreaChanged(nullptr, mAreaSlider->getScrollPosition()); + } + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + { + if (button == mRangeButton) + onRangeButtonClicked(mRangeButton); + else if (button == mDeleteButton) + mControllerFocus++; + else if (button == mOkButton) + mControllerFocus++; + else if (button == mMagnitudeMinValue) + { + mMagnitudeMinSlider->setScrollPosition( + std::min(mMagnitudeMinSlider->getScrollPosition() + 1, mMagnitudeMaxSlider->getScrollPosition())); + onMagnitudeMinChanged(nullptr, mMagnitudeMinSlider->getScrollPosition()); + } + else if (button == mMagnitudeMaxValue) + { + mMagnitudeMaxSlider->setScrollPosition(mMagnitudeMaxSlider->getScrollPosition() + 1); + onMagnitudeMaxChanged(nullptr, mMagnitudeMaxSlider->getScrollPosition()); + } + else if (button == mDurationValue) + { + mDurationSlider->setScrollPosition(mDurationSlider->getScrollPosition() + 1); + onDurationChanged(nullptr, mDurationSlider->getScrollPosition()); + } + else if (button == mAreaValue) + { + mAreaSlider->setScrollPosition(mAreaSlider->getScrollPosition() + 1); + onAreaChanged(nullptr, mAreaSlider->getScrollPosition()); + } + } + + if (prevFocus != mControllerFocus) + updateControllerFocus(prevFocus, mControllerFocus); + + return true; + } + + void EditEffectDialog::updateControllerFocus(int prevFocus, int newFocus) + { + const TextColours& textColours{ MWBase::Environment::get().getWindowManager()->getTextColours() }; + + if (prevFocus >= 0 && prevFocus < mButtons.size()) + { + MyGUI::TextBox* button = mButtons[prevFocus]; + if (button == mMagnitudeMinValue || + button == mMagnitudeMaxValue || + button == mDurationValue || + button == mAreaValue) + { + button->setTextColour(textColours.normal); + } + else + { + ((MyGUI::Button*)button)->setStateSelected(false); + } + } + + if (newFocus >= 0 && newFocus < mButtons.size()) + { + MyGUI::TextBox* button = mButtons[newFocus]; + if (button == mMagnitudeMinValue || + button == mMagnitudeMaxValue || + button == mDurationValue || + button == mAreaValue) + { + button->setTextColour(textColours.link); + } + else + { + ((MyGUI::Button*)button)->setStateSelected(true); + } + } + } + // ------------------------------------------------------------------------------------------------ SpellCreationDialog::SpellCreationDialog() @@ -360,6 +594,13 @@ namespace MWGui mNameEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &SpellCreationDialog::onAccept); setWidgets(mAvailableEffectsList, mUsedEffectsView); + + if (Settings::gui().mControllerMenus) + { + mControllerButtons.a = "#{sSelect}"; + mControllerButtons.b = "#{sBack}"; + mControllerButtons.x = "#{sBuy}"; + } } void SpellCreationDialog::setPtr(const MWWorld::Ptr& actor) @@ -490,6 +731,24 @@ namespace MWGui mSuccessChance->setCaption(MyGUI::utility::toString(intChance)); } + + bool SpellCreationDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_B) + { + onCancelButtonClicked(mCancelButton); + return true; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_X) + { + onBuyButtonClicked(mBuyButton); + return true; + } + else + return EffectEditorBase::onControllerButtonEvent(arg); + } + + // ------------------------------------------------------------------------------------------------ EffectEditorBase::EffectEditorBase(Type type) @@ -561,6 +820,7 @@ namespace MWGui mAvailableEffectsList->adjustSize(); mAvailableEffectsList->scrollToTop(); + mAvailableButtons.clear(); for (const short effectId : knownEffects) { const std::string& name = MWBase::Environment::get() @@ -568,13 +828,23 @@ namespace MWGui ->get() .find(ESM::MagicEffect::indexToGmstString(effectId)) ->mValue.getString(); - MyGUI::Widget* w = mAvailableEffectsList->getItemWidget(name); + MyGUI::Button* w = mAvailableEffectsList->getItemWidget(name); + mAvailableButtons.emplace_back(w); ToolTips::createMagicEffectToolTip(w, effectId); } mEffects.clear(); updateEffectsView(); + + if (Settings::gui().mControllerMenus) + { + mAvailableFocus = 0; + mEffectFocus = 0; + mRightColumn = false; + if (mAvailableButtons.size() > 0) + mAvailableButtons[0]->setStateSelected(true); + } } void EffectEditorBase::setWidgets(Gui::MWList* availableEffectsList, MyGUI::ScrollView* usedEffectsView) @@ -686,6 +956,7 @@ namespace MWGui MyGUI::IntSize size(0, 0); + mEffectButtons.clear(); int i = 0; for (const ESM::ENAMstruct& effectInfo : mEffects) { @@ -718,6 +989,8 @@ namespace MWGui size.width = std::max(size.width, effect->getRequestedWidth()); size.height += 24; ++i; + + mEffectButtons.emplace_back(std::pair(effect, button)); } // Canvas size must be expressed with HScroll disabled, otherwise MyGUI would expand the scroll area when the @@ -755,4 +1028,80 @@ namespace MWGui effect.mRange = ESM::RT_Self; mConstantEffect = constant; } + + bool EffectEditorBase::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + if (!mRightColumn && mAvailableFocus >= 0 && mAvailableFocus < mAvailableButtons.size()) + { + onAvailableEffectClicked(mAvailableButtons[mAvailableFocus]); + } + else if (mRightColumn && mEffectFocus >= 0 && mEffectFocus < mEffectButtons.size()) + { + onEditEffect(mEffectButtons[mEffectFocus].second); + } + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) + { + if (mRightColumn && mEffectButtons.size() > 0) + { + if (mEffectFocus >= 0 && mEffectFocus < mEffectButtons.size()) + mEffectButtons[mEffectFocus].first->setStateSelected(false); + mEffectFocus = wrap(mEffectFocus - 1, mEffectButtons.size()); + mEffectButtons[mEffectFocus].first->setStateSelected(true); + } + else if (!mRightColumn && mAvailableButtons.size() > 0) + { + if (mAvailableFocus >= 0 && mAvailableFocus < mAvailableButtons.size()) + mAvailableButtons[mAvailableFocus]->setStateSelected(false); + mAvailableFocus = wrap(mAvailableFocus - 1, mAvailableButtons.size()); + mAvailableButtons[mAvailableFocus]->setStateSelected(true); + } + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + { + if (mRightColumn && mEffectButtons.size() > 0) + { + if (mEffectFocus >= 0 && mEffectFocus < mEffectButtons.size()) + mEffectButtons[mEffectFocus].first->setStateSelected(false); + mEffectFocus = wrap(mEffectFocus + 1, mEffectButtons.size()); + mEffectButtons[mEffectFocus].first->setStateSelected(true); + } + else if (!mRightColumn && mAvailableButtons.size() > 0) + { + if (mAvailableFocus >= 0 && mAvailableFocus < mAvailableButtons.size()) + mAvailableButtons[mAvailableFocus]->setStateSelected(false); + mAvailableFocus = wrap(mAvailableFocus + 1, mAvailableButtons.size()); + mAvailableButtons[mAvailableFocus]->setStateSelected(true); + } + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && mRightColumn) + { + mRightColumn = false; + if (mEffectFocus >= 0 && mEffectFocus < mEffectButtons.size()) + mEffectButtons[mEffectFocus].first->setStateSelected(false); + if (mAvailableFocus >= 0 && mAvailableFocus < mAvailableButtons.size()) + mAvailableButtons[mAvailableFocus]->setStateSelected(true); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && !mRightColumn && mEffectButtons.size() > 0) + { + mRightColumn = true; + if (mAvailableFocus >= 0 && mAvailableFocus < mAvailableButtons.size()) + mAvailableButtons[mAvailableFocus]->setStateSelected(false); + if (mEffectFocus >= 0 && mEffectFocus < mEffectButtons.size()) + mEffectButtons[mEffectFocus].first->setStateSelected(true); + } + + // Scroll the list to keep the active item in view + if (mAvailableFocus <= 5) + mAvailableEffectsList->setViewOffset(0); + else + { + const int lineHeight = Settings::gui().mFontSize + 3; + mAvailableEffectsList->setViewOffset(-lineHeight * (mAvailableFocus - 5)); + } + + return true; + } } diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index b2bd71d9c4..cbd57014ce 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -2,12 +2,14 @@ #define MWGUI_SPELLCREATION_H #include +#include #include #include #include #include "referenceinterface.hpp" +#include "widgets.hpp" #include "windowbase.hpp" namespace Gui @@ -84,13 +86,18 @@ namespace MWGui void updateBoxes(); - protected: + private: ESM::ENAMstruct mEffect; ESM::ENAMstruct mOldEffect; const ESM::MagicEffect* mMagicEffect; bool mConstantEffect; + + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + void updateControllerFocus(int prevFocus, int newFocus); + int mControllerFocus; + std::vector mButtons; }; class EffectEditorBase @@ -143,8 +150,16 @@ namespace MWGui virtual void notifyEffectsChanged() {} + virtual bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg); + private: Type mType; + + int mAvailableFocus; + int mEffectFocus; + bool mRightColumn; + std::vector mAvailableButtons; + std::vector> mEffectButtons; }; class SpellCreationDialog : public WindowBase, public ReferenceInterface, public EffectEditorBase @@ -167,6 +182,7 @@ namespace MWGui void onCancelButtonClicked(MyGUI::Widget* sender); void onBuyButtonClicked(MyGUI::Widget* sender); void onAccept(MyGUI::EditBox* sender); + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; void notifyEffectsChanged() override; From 40441a065a54daf5e4d0f2bdc48c5343d84c8712 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sat, 31 May 2025 11:58:35 -0700 Subject: [PATCH 065/330] Add controller support to alcmhemy menu --- apps/openmw/mwgui/alchemywindow.cpp | 95 ++++++++++++++++++++++++++++- apps/openmw/mwgui/alchemywindow.hpp | 2 + 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 5a6245fca0..fe82ead93f 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -91,6 +92,15 @@ namespace MWGui mFilterValue->eventEditTextChange += MyGUI::newDelegate(this, &AlchemyWindow::onFilterEdited); mFilterType->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::switchFilterType); + if (Settings::gui().mControllerMenus) + { + mControllerButtons.a = "#{sSelect}"; + mControllerButtons.b = "#{sBack}"; + mControllerButtons.x = "#{sCreate}"; + mControllerButtons.y = "#{sMagicEffects}"; + mControllerButtons.r3 = "#{sInfo}"; + } + center(); } @@ -109,6 +119,8 @@ namespace MWGui void AlchemyWindow::onCreateButtonClicked(MyGUI::Widget* _sender) { + if (Settings::gui().mControllerMenus && mNameEdit->getCaption().length() == 0) + mNameEdit->setCaption("Unknown potion"); mAlchemy->setPotionName(mNameEdit->getCaption()); int count = mAlchemy->countPotionsToBrew(); count = std::min(count, mBrewCountEdit->getValue()); @@ -165,7 +177,12 @@ namespace MWGui std::string_view ingredient = wm->getGameSettingString("sIngredients", "Ingredients"); if (mFilterType->getCaption() == ingredient) - mCurrentFilter = FilterType::ByName; + { + if (Settings::gui().mControllerMenus) + switchFilterType(mFilterType); + else + mCurrentFilter = FilterType::ByName; + } else mCurrentFilter = FilterType::ByEffect; updateFilters(); @@ -291,6 +308,9 @@ namespace MWGui initFilter(); MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mNameEdit); + + if (Settings::gui().mControllerMenus) + mItemView->setActiveControllerWindow(true); } void AlchemyWindow::onIngredientSelected(MyGUI::Widget* _sender) @@ -528,4 +548,77 @@ namespace MWGui if (currentCount > 1) mBrewCountEdit->setValue(currentCount - 1); } + + bool AlchemyWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + bool isFilterListOpen = focus != nullptr && focus->getParent() != nullptr && focus->getParent()->getParent() == mFilterValue; + + if (isFilterListOpen) + { + // When the filter list combo box is open, send all inputs to it. + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + // Select the highlighted entry in the combo box and close it. + int index = mFilterValue->getIndexSelected(); + mFilterValue->setIndexSelected(index); + onFilterChanged(mFilterValue, index); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mNameEdit); // Close list + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B || arg.button == SDL_CONTROLLER_BUTTON_Y) + { + // Close the list without selecting anything + mFilterValue->clearIndexSelected(); + onFilterEdited(mFilterValue); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mNameEdit); // Close list + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::ArrowUp, 0, false); + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); + } + else + { + if (arg.button == SDL_CONTROLLER_BUTTON_B) + { + // Remove active ingredients or close the window + if (mIngredients[3]->isUserString("ToolTipType")) + onIngredientSelected(mIngredients[3]); + else if (mIngredients[2]->isUserString("ToolTipType")) + onIngredientSelected(mIngredients[2]); + else if (mIngredients[1]->isUserString("ToolTipType")) + onIngredientSelected(mIngredients[1]); + else if (mIngredients[0]->isUserString("ToolTipType")) + onIngredientSelected(mIngredients[0]); + else + onCancelButtonClicked(mCancelButton); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_X) + onCreateButtonClicked(mCreateButton); + else if (arg.button == SDL_CONTROLLER_BUTTON_Y && mFilterValue->getItemCount() > 0) + { + // Magical effects/ingredients filter + if (mFilterValue->getIndexSelected() != MyGUI::ITEM_NONE) + { + // Clear the active filter + mFilterValue->clearIndexSelected(); + onFilterEdited(mFilterValue); + } + else + { + // Open the combo box to choose the a filter + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mFilterValue); + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); + } + } + else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) + onDecreaseButtonTriggered(); + else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) + onIncreaseButtonTriggered(); + else + mItemView->onControllerButtonEvent(arg.button); + } + + return true; + } } diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 82e5c3f583..e79c41b659 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -99,6 +99,8 @@ namespace MWGui std::vector mApparatus; std::vector mIngredients; + + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; }; } From 2d532100ebbe32418be1ff4f23c0c840f0b1e2a9 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sat, 31 May 2025 15:28:13 -0700 Subject: [PATCH 066/330] Add controller supoprt to enchanting menu --- apps/openmw/mwgui/enchantingdialog.cpp | 26 ++++++++++++++++++++++++++ apps/openmw/mwgui/enchantingdialog.hpp | 2 ++ apps/openmw/mwgui/itemselection.cpp | 16 ++++++++++++++++ apps/openmw/mwgui/itemselection.hpp | 1 + 4 files changed, 45 insertions(+) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index af4a3e8ce3..d0d9fb7401 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -59,6 +59,12 @@ namespace MWGui mBuyButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onBuyButtonClicked); mTypeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onTypeButtonClicked); mName->eventEditSelectAccept += MyGUI::newDelegate(this, &EnchantingDialog::onAccept); + + mControllerButtons.a = "#{sSelect}"; + mControllerButtons.b = "#{sBack}"; + mControllerButtons.y = "Cast Type"; + mControllerButtons.l1 = "#{sItem}"; + mControllerButtons.r1 = "#{sSoulGem}"; } void EnchantingDialog::onOpen() @@ -152,6 +158,7 @@ namespace MWGui mEnchanting.setSelfEnchanting(false); mEnchanting.setEnchanter(ptr); mBuyButton->setCaptionWithReplacing("#{sBuy}"); + mControllerButtons.x = "#{sBuy}"; mChanceLayout->setVisible(false); mPtr = ptr; setSoulGem(MWWorld::Ptr()); @@ -163,6 +170,7 @@ namespace MWGui mEnchanting.setSelfEnchanting(true); mEnchanting.setEnchanter(MWMechanics::getPlayer()); mBuyButton->setCaptionWithReplacing("#{sCreate}"); + mControllerButtons.x = "#{sCreate}"; mChanceLayout->setVisible(Settings::game().mShowEnchantChance); mPtr = MWMechanics::getPlayer(); setSoulGem(ptr); @@ -382,4 +390,22 @@ namespace MWGui } } } + + bool EnchantingDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_B) + onCancelButtonClicked(mCancelButton); + else if (arg.button == SDL_CONTROLLER_BUTTON_X) + onBuyButtonClicked(mBuyButton); + else if (arg.button == SDL_CONTROLLER_BUTTON_Y) + onTypeButtonClicked(mTypeButton); + else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) + onSelectItem(mItemBox); + else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) + onSelectSoul(mSoulBox); + else + return EffectEditorBase::onControllerButtonEvent(arg); + + return true; + } } diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 4c720a11fc..3cda350152 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -73,6 +73,8 @@ namespace MWGui MWMechanics::Enchanting mEnchanting; ESM::EffectList mEffectList; + + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; }; } diff --git a/apps/openmw/mwgui/itemselection.cpp b/apps/openmw/mwgui/itemselection.cpp index 4fe40ce693..86d584f24d 100644 --- a/apps/openmw/mwgui/itemselection.cpp +++ b/apps/openmw/mwgui/itemselection.cpp @@ -3,6 +3,8 @@ #include #include +#include + #include "inventoryitemmodel.hpp" #include "itemview.hpp" #include "sortfilteritemmodel.hpp" @@ -26,6 +28,9 @@ namespace MWGui cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ItemSelectionDialog::onCancelButtonClicked); center(); + + mControllerButtons.a = "#{sSelect}"; + mControllerButtons.b = "#{sBack}"; } bool ItemSelectionDialog::exit() @@ -40,6 +45,8 @@ namespace MWGui mSortModel = sortModel.get(); mItemView->setModel(std::move(sortModel)); mItemView->resetScrollBars(); + if (Settings::gui().mControllerMenus) + mItemView->setActiveControllerWindow(true); } void ItemSelectionDialog::setCategory(int category) @@ -65,4 +72,13 @@ namespace MWGui exit(); } + bool ItemSelectionDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_B) + onCancelButtonClicked(nullptr); + else + mItemView->onControllerButtonEvent(arg.button); + + return true; + } } diff --git a/apps/openmw/mwgui/itemselection.hpp b/apps/openmw/mwgui/itemselection.hpp index fe87d7e38a..83af6d4840 100644 --- a/apps/openmw/mwgui/itemselection.hpp +++ b/apps/openmw/mwgui/itemselection.hpp @@ -41,6 +41,7 @@ namespace MWGui void onSelectedItem(int index); void onCancelButtonClicked(MyGUI::Widget* sender); + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; }; } From 5276d7bab2aae7ffeeed2932d77bd6a531fb65c1 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sat, 31 May 2025 16:02:13 -0700 Subject: [PATCH 067/330] Several tweaks to the inventory menu --- apps/openmw/mwgui/inventorytabsoverlay.cpp | 6 ++++-- apps/openmw/mwgui/statswindow.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 8 ++------ 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/inventorytabsoverlay.cpp b/apps/openmw/mwgui/inventorytabsoverlay.cpp index 21254c7840..14fd110830 100644 --- a/apps/openmw/mwgui/inventorytabsoverlay.cpp +++ b/apps/openmw/mwgui/inventorytabsoverlay.cpp @@ -29,13 +29,15 @@ namespace MWGui void InventoryTabsOverlay::onTabClicked(MyGUI::Widget* sender) { + if (!MWBase::Environment::get().getWindowManager()->getJournalAllowed()) + return; + for (int i = 0; i < mTabs.size(); i++) { if (mTabs[i] == sender) { - Log(Debug::Verbose) << "InventoryTabsOverlay::onTabClicked " << i; MWBase::Environment::get().getWindowManager()->setActiveControllerWindow(GM_Inventory, i); - //setTab(i); + setTab(i); break; } } diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index e71b35e364..430101f069 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -84,7 +84,7 @@ namespace MWGui if (Settings::gui().mControllerMenus) { setPinButtonVisible(false); - mControllerButtons.lStick = "#{sInfo}"; + mControllerButtons.lStick = "#{sMouse}"; mControllerButtons.rStick = "#{sScrolldown}"; mControllerButtons.b = "#{sBack}"; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 77224790dd..00a35df774 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -514,6 +514,7 @@ namespace MWGui auto inventoryTabsOverlay = std::make_unique(); mInventoryTabsOverlay = inventoryTabsOverlay.get(); mWindows.push_back(std::move(inventoryTabsOverlay)); + mActiveControllerWindows[GM_Inventory] = 1; // Start on Inventory page mInputBlocker = MyGUI::Gui::getInstance().createWidget( {}, 0, 0, w, h, MyGUI::Align::Stretch, "InputBlocker"); @@ -927,12 +928,7 @@ namespace MWGui for (int i = 0; i < winCount; i++) { - activeIndex += delta; - if (activeIndex < 0) - activeIndex = winCount - 1; - else if (activeIndex >= winCount) - activeIndex = 0; - + activeIndex = wrap(activeIndex + delta, winCount); if (mGuiModeStates[mode].mWindows[activeIndex]->isVisible()) break; } From d3c7904e64d35f07c71de10cab2ae4c080231ba6 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sat, 31 May 2025 16:34:07 -0700 Subject: [PATCH 068/330] Rename controller help function in item view --- apps/openmw/mwgui/alchemywindow.cpp | 2 +- apps/openmw/mwgui/container.cpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 8 ++++---- apps/openmw/mwgui/itemselection.cpp | 2 +- apps/openmw/mwgui/itemview.cpp | 2 +- apps/openmw/mwgui/itemview.hpp | 2 +- apps/openmw/mwgui/tradewindow.cpp | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index fe82ead93f..32334962fb 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -616,7 +616,7 @@ namespace MWGui else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) onIncreaseButtonTriggered(); else - mItemView->onControllerButtonEvent(arg.button); + mItemView->onControllerButton(arg.button); } return true; diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 1657225343..c6c810c80e 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -391,7 +391,7 @@ namespace MWGui arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT || arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) { - mItemView->onControllerButtonEvent(arg.button); + mItemView->onControllerButton(arg.button); } return true; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 2e128f15f8..da071cb753 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -914,7 +914,7 @@ namespace MWGui } else if (arg.button == SDL_CONTROLLER_BUTTON_A) { - mItemView->onControllerButtonEvent(SDL_CONTROLLER_BUTTON_A); + mItemView->onControllerButton(SDL_CONTROLLER_BUTTON_A); // The following actions are done here, not in onItemSelectedFromSourceModel, because we // want the mouse to work even in controller mode. if (mGuiMode == MWGui::GM_Inventory && mDragAndDrop->mIsOnDragAndDrop) @@ -946,7 +946,7 @@ namespace MWGui if (mGuiMode == MWGui::GM_Inventory) { // Drop the item into the gameworld - mItemView->onControllerButtonEvent(SDL_CONTROLLER_BUTTON_A); + mItemView->onControllerButton(SDL_CONTROLLER_BUTTON_A); if (mDragAndDrop->mIsOnDragAndDrop) MWBase::Environment::get().getWindowManager()->getHud()->dropDraggedItem(0.5f, 0.5f); } @@ -972,7 +972,7 @@ namespace MWGui if (mGuiMode == MWGui::GM_Inventory) { // Unequip an item. - mItemView->onControllerButtonEvent(SDL_CONTROLLER_BUTTON_A); + mItemView->onControllerButton(SDL_CONTROLLER_BUTTON_A); onBackgroundSelected(); // Drop on inventory background to unequip } } @@ -1004,7 +1004,7 @@ namespace MWGui } else { - mItemView->onControllerButtonEvent(arg.button); + mItemView->onControllerButton(arg.button); } return true; diff --git a/apps/openmw/mwgui/itemselection.cpp b/apps/openmw/mwgui/itemselection.cpp index 86d584f24d..a00c754c3d 100644 --- a/apps/openmw/mwgui/itemselection.cpp +++ b/apps/openmw/mwgui/itemselection.cpp @@ -77,7 +77,7 @@ namespace MWGui if (arg.button == SDL_CONTROLLER_BUTTON_B) onCancelButtonClicked(nullptr); else - mItemView->onControllerButtonEvent(arg.button); + mItemView->onControllerButton(arg.button); return true; } diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index 9cde52f0c2..08e5236fc6 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -202,7 +202,7 @@ namespace MWGui updateControllerFocus(mControllerFocus, -1); } - void ItemView::onControllerButtonEvent(const unsigned char button) + void ItemView::onControllerButton(const unsigned char button) { if (!mItemCount) return; diff --git a/apps/openmw/mwgui/itemview.hpp b/apps/openmw/mwgui/itemview.hpp index 091436ab05..29d44c6b09 100644 --- a/apps/openmw/mwgui/itemview.hpp +++ b/apps/openmw/mwgui/itemview.hpp @@ -35,7 +35,7 @@ namespace MWGui void setActiveControllerWindow(bool active); int getControllerFocus() { return mControllerFocus; } int getItemCount() { return mItemCount; } - void onControllerButtonEvent(const unsigned char button); + void onControllerButton(const unsigned char button); private: void initialiseOverride() override; diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 3e4b8732bb..69b16dfc93 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -726,7 +726,7 @@ namespace MWGui arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT || arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) { - mItemView->onControllerButtonEvent(arg.button); + mItemView->onControllerButton(arg.button); } return true; From cbe74cdab46661a39ee3c9ca0abc55eb30082348 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sat, 31 May 2025 18:58:30 -0700 Subject: [PATCH 069/330] Add controller support to repair and recharge menus --- apps/openmw/mwgui/itemchargeview.cpp | 62 ++++++++++++++++++++++++++ apps/openmw/mwgui/itemchargeview.hpp | 5 +++ apps/openmw/mwgui/itemselection.cpp | 1 + apps/openmw/mwgui/messagebox.cpp | 4 +- apps/openmw/mwgui/recharge.cpp | 16 +++++++ apps/openmw/mwgui/recharge.hpp | 2 + apps/openmw/mwgui/repair.cpp | 16 +++++++ apps/openmw/mwgui/repair.hpp | 2 + apps/openmw/mwgui/windowmanagerimp.cpp | 3 ++ files/data/mygui/openmw_resources.xml | 4 ++ 10 files changed, 113 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/itemchargeview.cpp b/apps/openmw/mwgui/itemchargeview.cpp index 02c3cc182c..abbf328a8c 100644 --- a/apps/openmw/mwgui/itemchargeview.cpp +++ b/apps/openmw/mwgui/itemchargeview.cpp @@ -1,5 +1,6 @@ #include "itemchargeview.hpp" +#include #include #include @@ -9,8 +10,11 @@ #include #include +#include #include "../mwbase/environment.hpp" +#include "../mwbase/inputmanager.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwmechanics/spellutil.hpp" @@ -19,6 +23,7 @@ #include "itemmodel.hpp" #include "itemwidget.hpp" +#include "textcolours.hpp" namespace MWGui { @@ -156,11 +161,20 @@ namespace MWGui mScrollView->setCanvasSize( MyGUI::IntSize(mScrollView->getWidth(), std::max(mScrollView->getHeight(), currentY))); mScrollView->setVisibleVScroll(true); + + if (Settings::gui().mControllerMenus) + updateControllerFocus(-1, mControllerFocus); } void ItemChargeView::resetScrollbars() { mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); + + if (Settings::gui().mControllerMenus) + { + updateControllerFocus(mControllerFocus, 0); + mControllerFocus = 0; + } } void ItemChargeView::setSize(const MyGUI::IntSize& value) @@ -224,4 +238,52 @@ namespace MWGui mScrollView->setViewOffset( MyGUI::IntPoint(0, static_cast(mScrollView->getViewOffset().top + rel * 0.3f))); } + + void ItemChargeView::onControllerButton(const unsigned char button) + { + if (mLines.empty()) + return; + + int prevFocus = mControllerFocus; + + if (button == SDL_CONTROLLER_BUTTON_A) + { + // Select the focused item, if any. + if (mControllerFocus >= 0 && mControllerFocus < mLines.size()) + onIconClicked(mLines[mControllerFocus].mIcon); + } + else if (button == SDL_CONTROLLER_BUTTON_DPAD_UP) + mControllerFocus = wrap(mControllerFocus - 1, mLines.size()); + else if (button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + mControllerFocus = wrap(mControllerFocus + 1, mLines.size()); + + if (prevFocus != mControllerFocus) + updateControllerFocus(prevFocus, mControllerFocus); + } + + void ItemChargeView::updateControllerFocus(int prevFocus, int newFocus) + { + if (mLines.empty()) + return; + + const TextColours& textColours{ MWBase::Environment::get().getWindowManager()->getTextColours() }; + + if (prevFocus >= 0 && prevFocus < mLines.size()) + { + mLines[prevFocus].mText->setTextColour(textColours.normal); + mLines[prevFocus].mIcon->setControllerFocus(false); + } + + if (newFocus >= 0 && newFocus < mLines.size()) + { + mLines[newFocus].mText->setTextColour(textColours.link); + mLines[newFocus].mIcon->setControllerFocus(true); + + // Scroll the list to keep the active item in view + if (mControllerFocus <= 3) + mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mScrollView->setViewOffset(MyGUI::IntPoint(-55 * (mControllerFocus - 3), 0)); + } + } } diff --git a/apps/openmw/mwgui/itemchargeview.hpp b/apps/openmw/mwgui/itemchargeview.hpp index f7617d37eb..73bf9c3de2 100644 --- a/apps/openmw/mwgui/itemchargeview.hpp +++ b/apps/openmw/mwgui/itemchargeview.hpp @@ -52,6 +52,8 @@ namespace MWGui MyGUI::delegates::MultiDelegate eventItemClicked; + void onControllerButton(const unsigned char button); + private: struct Line { @@ -72,6 +74,9 @@ namespace MWGui std::unique_ptr mModel; MyGUI::ScrollView* mScrollView; DisplayMode mDisplayMode; + + int mControllerFocus; + void updateControllerFocus(int prevFocus, int newFocus); }; } diff --git a/apps/openmw/mwgui/itemselection.cpp b/apps/openmw/mwgui/itemselection.cpp index a00c754c3d..ec4ecb9d0f 100644 --- a/apps/openmw/mwgui/itemselection.cpp +++ b/apps/openmw/mwgui/itemselection.cpp @@ -31,6 +31,7 @@ namespace MWGui mControllerButtons.a = "#{sSelect}"; mControllerButtons.b = "#{sBack}"; + mControllerButtons.r3 = "#{sInfo}"; } bool ItemSelectionDialog::exit() diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index ec42993f4d..5f074a67c6 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -454,7 +454,7 @@ namespace MWGui if (mButtons.size() == 1) buttonActivated(mButtons[0]); } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP || arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) { if (mButtons.size() <= 1) return true; @@ -465,7 +465,7 @@ namespace MWGui mControllerFocus = wrap(mControllerFocus - 1, mButtons.size()); mButtons[mControllerFocus]->setStateSelected(true); } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN || arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) { if (mButtons.size() <= 1) return true; diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 7d57988d97..605a9a1a94 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -39,6 +39,10 @@ namespace MWGui mBox->setDisplayMode(ItemChargeView::DisplayMode_EnchantmentCharge); mGemIcon->eventMouseButtonClick += MyGUI::newDelegate(this, &Recharge::onSelectItem); + + mControllerButtons.a = "Recharge"; + mControllerButtons.b = "#{sBack}"; + mControllerButtons.y = "#{sSoulGem}"; } void Recharge::onOpen() @@ -136,4 +140,16 @@ namespace MWGui updateView(); } + bool Recharge::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if ((arg.button == SDL_CONTROLLER_BUTTON_A && !mGemBox->getVisible()) + || arg.button == SDL_CONTROLLER_BUTTON_Y) + onSelectItem(mGemIcon); + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + onCancel(mCancelButton); + else + mBox->onControllerButton(arg.button); + + return true; + } } diff --git a/apps/openmw/mwgui/recharge.hpp b/apps/openmw/mwgui/recharge.hpp index f8a037d2db..c10f96e71e 100644 --- a/apps/openmw/mwgui/recharge.hpp +++ b/apps/openmw/mwgui/recharge.hpp @@ -51,6 +51,8 @@ namespace MWGui void onItemClicked(MyGUI::Widget* sender, const MWWorld::Ptr& item); void onCancel(MyGUI::Widget* sender); void onMouseWheel(MyGUI::Widget* _sender, int _rel); + + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; }; } diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index c1602b8407..6f5d256d86 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -39,6 +39,10 @@ namespace MWGui mRepairBox->setDisplayMode(ItemChargeView::DisplayMode_Health); mToolIcon->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onSelectItem); + + mControllerButtons.a = "#{sRepair}"; + mControllerButtons.b = "#{sBack}"; + mControllerButtons.y = "Tool"; } void Repair::onOpen() @@ -150,4 +154,16 @@ namespace MWGui updateRepairView(); } + bool Repair::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if ((arg.button == SDL_CONTROLLER_BUTTON_A && !mToolBox->getVisible()) + || arg.button == SDL_CONTROLLER_BUTTON_Y) + onSelectItem(mToolIcon); + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + onCancel(mCancelButton); + else + mRepairBox->onControllerButton(arg.button); + + return true; + } } diff --git a/apps/openmw/mwgui/repair.hpp b/apps/openmw/mwgui/repair.hpp index 093a10e3fa..986b28b613 100644 --- a/apps/openmw/mwgui/repair.hpp +++ b/apps/openmw/mwgui/repair.hpp @@ -50,6 +50,8 @@ namespace MWGui void onRepairItem(MyGUI::Widget* sender, const MWWorld::Ptr& ptr); void onCancel(MyGUI::Widget* sender); + + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 00a35df774..9350ef4d1a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -952,6 +952,9 @@ namespace MWGui for (int i = 0; i < winCount; i++) mGuiModeStates[mode].mWindows[i]->setActiveControllerWindow(i == activeIndex); + MWBase::Environment::get().getInputManager()->setGamepadGuiCursorEnabled( + mGuiModeStates[mode].mWindows[activeIndex]->isGamepadCursorAllowed()); + updateControllerButtonsOverlay(); setCursorActive(false); diff --git a/files/data/mygui/openmw_resources.xml b/files/data/mygui/openmw_resources.xml index 08586ea75c..d107c094e3 100644 --- a/files/data/mygui/openmw_resources.xml +++ b/files/data/mygui/openmw_resources.xml @@ -172,6 +172,10 @@ + + + + From 2dc1d8fed7f59fccfb19f3ddca068789b5341c78 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sat, 31 May 2025 19:24:27 -0700 Subject: [PATCH 070/330] Add controller support to merchant repair window --- apps/openmw/mwgui/merchantrepair.cpp | 59 ++++++++++++++++++++++++++++ apps/openmw/mwgui/merchantrepair.hpp | 5 +++ 2 files changed, 64 insertions(+) diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index a59f225e9e..e8155ea790 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -28,6 +28,13 @@ namespace MWGui getWidget(mGoldLabel, "PlayerGold"); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MerchantRepair::onOkButtonClick); + + if (Settings::gui().mControllerMenus) + { + mDisableGamepadCursor = true; + mControllerButtons.a = "#{sRepair}"; + mControllerButtons.b = "#{sBack}"; + } } void MerchantRepair::setPtr(const MWWorld::Ptr& actor) @@ -38,6 +45,7 @@ namespace MWGui while (mList->getChildCount()) MyGUI::Gui::getInstance().destroyWidget(mList->getChildAt(0)); + mButtons.clear(); const int lineHeight = Settings::gui().mFontSize + 2; int currentY = 0; @@ -101,6 +109,15 @@ namespace MWGui button->eventMouseWheel += MyGUI::newDelegate(this, &MerchantRepair::onMouseWheel); button->setUserString("ToolTipType", "ItemPtr"); button->eventMouseButtonClick += MyGUI::newDelegate(this, &MerchantRepair::onRepairButtonClick); + if (price <= playerGold) + mButtons.emplace_back(std::make_pair(button, mButtons.size())); + } + + if (Settings::gui().mControllerMenus) + { + mControllerFocus = 0; + if (mButtons.size() > 0) + mButtons[0].first->setStateSelected(true); } // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the @@ -157,4 +174,46 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_MerchantRepair); } + bool MerchantRepair::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + if (mControllerFocus >= 0 && mControllerFocus < mButtons.size()) + onRepairButtonClick(mButtons[mControllerFocus].first); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + { + onOkButtonClick(mOkButton); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) + { + if (mButtons.size() <= 1) + return true; + + mButtons[mControllerFocus].first->setStateSelected(false); + mControllerFocus = wrap(mControllerFocus - 1, mButtons.size()); + mButtons[mControllerFocus].first->setStateSelected(true); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + { + if (mButtons.size() <= 1) + return true; + + mButtons[mControllerFocus].first->setStateSelected(false); + mControllerFocus = wrap(mControllerFocus + 1, mButtons.size()); + mButtons[mControllerFocus].first->setStateSelected(true); + } + + // Scroll the list to keep the active item in view + int line = mButtons[mControllerFocus].second; + if (line <= 5) + mList->setViewOffset(MyGUI::IntPoint(0, 0)); + else + { + const int lineHeight = Settings::gui().mFontSize + 2; + mList->setViewOffset(MyGUI::IntPoint(0, -lineHeight * (line - 5))); + } + + return true; + } } diff --git a/apps/openmw/mwgui/merchantrepair.hpp b/apps/openmw/mwgui/merchantrepair.hpp index ffe5b86bdb..e878d34b7d 100644 --- a/apps/openmw/mwgui/merchantrepair.hpp +++ b/apps/openmw/mwgui/merchantrepair.hpp @@ -22,13 +22,18 @@ namespace MWGui MyGUI::ScrollView* mList; MyGUI::Button* mOkButton; MyGUI::TextBox* mGoldLabel; + /// List of enabled/repairable items and their index in the full list. + std::vector> mButtons; MWWorld::Ptr mActor; + int mControllerFocus; + protected: void onMouseWheel(MyGUI::Widget* _sender, int _rel); void onRepairButtonClick(MyGUI::Widget* sender); void onOkButtonClick(MyGUI::Widget* sender); + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; }; } From e3a9b71bb9b5b2872c14018c43d7136e414a8026 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sat, 31 May 2025 19:43:28 -0700 Subject: [PATCH 071/330] Add helper function for toggling controller focus on lists --- apps/openmw/mwgui/class.cpp | 16 ++++++++-------- apps/openmw/mwgui/dialogue.cpp | 8 ++++---- apps/openmw/mwgui/messagebox.cpp | 8 ++++---- apps/openmw/mwgui/review.cpp | 20 +++++++------------- apps/openmw/mwgui/trainingwindow.cpp | 8 ++++---- apps/openmw/mwgui/travelwindow.cpp | 8 ++++---- apps/openmw/mwgui/windowbase.cpp | 6 ++++++ apps/openmw/mwgui/windowbase.hpp | 1 + 8 files changed, 38 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index c0660b5f02..700c431246 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -488,9 +488,9 @@ namespace MWGui if (mButtons.size() == 2 && mControllerFocus == 0) return true; - mButtons[mControllerFocus]->setStateSelected(false); + setControllerFocus(mButtons, mControllerFocus, false); mControllerFocus = wrap(mControllerFocus - 1, mButtons.size()); - mButtons[mControllerFocus]->setStateSelected(true); + setControllerFocus(mButtons, mControllerFocus, true); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) { @@ -499,9 +499,9 @@ namespace MWGui if (mButtons.size() == 2 && mControllerFocus == mButtons.size() - 1) return true; - mButtons[mControllerFocus]->setStateSelected(false); + setControllerFocus(mButtons, mControllerFocus, false); mControllerFocus = wrap(mControllerFocus + 1, mButtons.size()); - mButtons[mControllerFocus]->setStateSelected(true); + setControllerFocus(mButtons, mControllerFocus, true); } return true; @@ -709,15 +709,15 @@ namespace MWGui } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) { - mButtons[mControllerFocus]->setStateSelected(false); + setControllerFocus(mButtons, mControllerFocus, false); mControllerFocus = wrap(mControllerFocus - 1, mButtons.size()); - mButtons[mControllerFocus]->setStateSelected(true); + setControllerFocus(mButtons, mControllerFocus, true); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) { - mButtons[mControllerFocus]->setStateSelected(false); + setControllerFocus(mButtons, mControllerFocus, false); mControllerFocus = wrap(mControllerFocus + 1, mButtons.size()); - mButtons[mControllerFocus]->setStateSelected(true); + setControllerFocus(mButtons, mControllerFocus, true); } return true; } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 1dd3f051ef..1a8808c8dc 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -182,15 +182,15 @@ namespace MWGui onCancel(mCancelButton); else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) { - mButtons[mControllerFocus]->setStateSelected(false); + setControllerFocus(mButtons, mControllerFocus, false); mControllerFocus = wrap(mControllerFocus - 1, mButtons.size()); - mButtons[mControllerFocus]->setStateSelected(true); + setControllerFocus(mButtons, mControllerFocus, true); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) { - mButtons[mControllerFocus]->setStateSelected(false); + setControllerFocus(mButtons, mControllerFocus, false); mControllerFocus = wrap(mControllerFocus + 1, mButtons.size()); - mButtons[mControllerFocus]->setStateSelected(true); + setControllerFocus(mButtons, mControllerFocus, true); } return true; diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 5f074a67c6..492ac30052 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -461,9 +461,9 @@ namespace MWGui if (mButtons.size() == 2 && mControllerFocus == 0) return true; - mButtons[mControllerFocus]->setStateSelected(false); + setControllerFocus(mButtons, mControllerFocus, false); mControllerFocus = wrap(mControllerFocus - 1, mButtons.size()); - mButtons[mControllerFocus]->setStateSelected(true); + setControllerFocus(mButtons, mControllerFocus, true); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN || arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) { @@ -472,9 +472,9 @@ namespace MWGui if (mButtons.size() == 2 && mControllerFocus == mButtons.size() - 1) return true; - mButtons[mControllerFocus]->setStateSelected(false); + setControllerFocus(mButtons, mControllerFocus, false); mControllerFocus = wrap(mControllerFocus + 1, mButtons.size()); - mButtons[mControllerFocus]->setStateSelected(true); + setControllerFocus(mButtons, mControllerFocus, true); } return true; diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 19dcda90e4..dda00bd33a 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -121,7 +121,7 @@ namespace MWGui if (Settings::gui().mControllerMenus) { - mButtons[mControllerFocus]->setStateSelected(true); + setControllerFocus(mButtons, mControllerFocus, true); mControllerButtons.a = "#{sSelect}"; mControllerButtons.b = "#{sBack}"; mControllerButtons.x = "#{sDone}"; @@ -574,22 +574,16 @@ namespace MWGui else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP || arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) { - mButtons[mControllerFocus]->setStateSelected(false); - if (mControllerFocus == 0) - mControllerFocus = mButtons.size() - 1; - else - mControllerFocus--; - mButtons[mControllerFocus]->setStateSelected(true); + setControllerFocus(mButtons, mControllerFocus, false); + mControllerFocus = wrap(mControllerFocus - 1, mButtons.size()); + setControllerFocus(mButtons, mControllerFocus, true); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN || arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) { - mButtons[mControllerFocus]->setStateSelected(false); - if (mControllerFocus == mButtons.size() - 1) - mControllerFocus = 0; - else - mControllerFocus++; - mButtons[mControllerFocus]->setStateSelected(true); + setControllerFocus(mButtons, mControllerFocus, false); + mControllerFocus = wrap(mControllerFocus + 1, mButtons.size()); + setControllerFocus(mButtons, mControllerFocus, true); } return true; diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index fcead9d543..65e468ebd4 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -263,18 +263,18 @@ namespace MWGui if (mTrainingButtons.size() <= 1) return true; - mTrainingButtons[mControllerFocus]->setStateSelected(false); + setControllerFocus(mTrainingButtons, mControllerFocus, false); mControllerFocus = wrap(mControllerFocus - 1, mTrainingButtons.size()); - mTrainingButtons[mControllerFocus]->setStateSelected(true); + setControllerFocus(mTrainingButtons, mControllerFocus, true); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) { if (mTrainingButtons.size() <= 1) return true; - mTrainingButtons[mControllerFocus]->setStateSelected(false); + setControllerFocus(mTrainingButtons, mControllerFocus, false); mControllerFocus = wrap(mControllerFocus + 1, mTrainingButtons.size()); - mTrainingButtons[mControllerFocus]->setStateSelected(true); + setControllerFocus(mTrainingButtons, mControllerFocus, true); } return true; diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 083bba391b..eeb2df868f 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -270,18 +270,18 @@ namespace MWGui if (mDestinationButtons.size() <= 1) return true; - mDestinationButtons[mControllerFocus]->setStateSelected(false); + setControllerFocus(mDestinationButtons, mControllerFocus, false); mControllerFocus = wrap(mControllerFocus - 1, mDestinationButtons.size()); - mDestinationButtons[mControllerFocus]->setStateSelected(true); + setControllerFocus(mDestinationButtons, mControllerFocus, true); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) { if (mDestinationButtons.size() <= 1) return true; - mDestinationButtons[mControllerFocus]->setStateSelected(false); + setControllerFocus(mDestinationButtons, mControllerFocus, false); mControllerFocus = wrap(mControllerFocus + 1, mDestinationButtons.size()); - mDestinationButtons[mControllerFocus]->setStateSelected(true); + setControllerFocus(mDestinationButtons, mControllerFocus, true); } // Scroll the list to keep the active item in view diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 995731a775..4ecc26449f 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -25,6 +25,12 @@ int MWGui::wrap(int index, int max) return index; } +void MWGui::setControllerFocus(std::vector buttons, int index, bool focused) +{ + if (index >= 0 && index < buttons.size()) + buttons[index]->setStateSelected(focused); +} + WindowBase::WindowBase(std::string_view parLayout) : Layout(parLayout) { diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index 8fb499ec7e..87bea55e38 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -15,6 +15,7 @@ namespace MWGui class DragAndDrop; int wrap(int index, int max); + void setControllerFocus(std::vector buttons, int index, bool selected); struct ControllerButtonStr { From 63a533cd51c4dfc188049864f022536713bcbf40 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sat, 31 May 2025 20:23:29 -0700 Subject: [PATCH 072/330] Add controller support to the level up dialog --- apps/openmw/mwgui/levelupdialog.cpp | 59 +++++++++++++++++++++++++++++ apps/openmw/mwgui/levelupdialog.hpp | 4 ++ 2 files changed, 63 insertions(+) diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index 87f2db55a5..3b14415206 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include "../mwbase/environment.hpp" @@ -72,6 +73,7 @@ namespace MWGui widgets.mButton->setCaption(attribute.mName); widgets.mValue = hbox->createWidget("SandText", {}, MyGUI::Align::Default); mAttributeWidgets.emplace(attribute.mId, widgets); + mAttributeButtons.emplace_back(widgets.mButton); ++i; } @@ -90,6 +92,13 @@ namespace MWGui mCoins.push_back(image); } + if (Settings::gui().mControllerMenus) + { + mDisableGamepadCursor = true; + mControllerButtons.a = "#{sSelect}"; + mControllerButtons.x = "#{sDone}"; + } + center(); } @@ -217,6 +226,13 @@ namespace MWGui center(); + if (Settings::gui().mControllerMenus) + { + mControllerFocus = 0; + for (int i = 0; i < mAttributeButtons.size(); i++) + setControllerFocus(mAttributeButtons, i, i == 0); + } + // Play LevelUp Music MWBase::Environment::get().getSoundManager()->streamMusic(MWSound::triumphMusic, MWSound::MusicType::Normal); } @@ -363,4 +379,47 @@ namespace MWGui return ret; } + + bool LevelupDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + if (mControllerFocus >= 0 && mControllerFocus < mAttributeButtons.size()) + onAttributeClicked(mAttributeButtons[mControllerFocus]); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_X) + { + onOkButtonClicked(mOkButton); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) + { + setControllerFocus(mAttributeButtons, mControllerFocus, false); + if (mControllerFocus == 0) + mControllerFocus = 3; + else if (mControllerFocus == 4) + mControllerFocus = 7; + else + mControllerFocus--; + setControllerFocus(mAttributeButtons, mControllerFocus, true); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + { + setControllerFocus(mAttributeButtons, mControllerFocus, false); + if (mControllerFocus == 3) + mControllerFocus = 0; + else if (mControllerFocus == 7) + mControllerFocus = 4; + else + mControllerFocus++; + setControllerFocus(mAttributeButtons, mControllerFocus, true); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT || arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + { + setControllerFocus(mAttributeButtons, mControllerFocus, false); + mControllerFocus = (mControllerFocus + 4) % mAttributeButtons.size(); + setControllerFocus(mAttributeButtons, mControllerFocus, true); + } + + return true; + } } diff --git a/apps/openmw/mwgui/levelupdialog.hpp b/apps/openmw/mwgui/levelupdialog.hpp index 486390679b..8a34a94c8b 100644 --- a/apps/openmw/mwgui/levelupdialog.hpp +++ b/apps/openmw/mwgui/levelupdialog.hpp @@ -49,6 +49,10 @@ namespace MWGui std::string_view getLevelupClassImage( const int combatIncreases, const int magicIncreases, const int stealthIncreases); + + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + std::vector mAttributeButtons; + int mControllerFocus; }; } From 95ed6b51da6699e4832631a794485e4e017e567d Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 1 Jun 2025 01:49:57 -0700 Subject: [PATCH 073/330] Allow navigating journal indices with a controller --- apps/openmw/mwgui/bookpage.cpp | 12 +++ apps/openmw/mwgui/bookpage.hpp | 3 + apps/openmw/mwgui/journalbooks.cpp | 8 +- apps/openmw/mwgui/journalbooks.hpp | 2 + apps/openmw/mwgui/journalwindow.cpp | 141 +++++++++++++++++++++++++++- apps/openmw/mwgui/journalwindow.hpp | 2 + 6 files changed, 159 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index cb0717edf3..113ac7d104 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -105,6 +105,18 @@ namespace MWGui Styles mStyles; MyGUI::IntRect mRect; + void setColour(int section, int line, int run, MyGUI::Colour colour) const override + { + if (section < 0 || section >= mSections.size()) + return; + if (line < 0 || line >= mSections[section].mLines.size()) + return; + if (run < 0 || run >= mSections[section].mLines[line].mRuns.size()) + return; + + mSections[section].mLines[line].mRuns[run].mStyle->mNormalColour = colour; + } + virtual ~TypesetBookImpl() {} Range addContent(const BookTypesetter::Utf8Span& text) diff --git a/apps/openmw/mwgui/bookpage.hpp b/apps/openmw/mwgui/bookpage.hpp index 43de2c09ac..34dae0cc0e 100644 --- a/apps/openmw/mwgui/bookpage.hpp +++ b/apps/openmw/mwgui/bookpage.hpp @@ -31,6 +31,9 @@ namespace MWGui /// text combined prior to pagination. virtual std::pair getSize() const = 0; + /// Used to highlight journal indices + virtual void setColour(int section, int line, int run, MyGUI::Colour colour) const = 0; + virtual ~TypesetBook() = default; }; diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 86b45b4863..c127508062 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -169,7 +169,7 @@ namespace MWGui { BookTypesetter::Ptr typesetter = createTypesetter(); - BookTypesetter::Style* header = typesetter->createStyle({}, MyGUI::Colour(0.60f, 0.00f, 0.00f)); + BookTypesetter::Style* header = typesetter->createStyle({}, journalHeaderColour); BookTypesetter::Style* body = typesetter->createStyle({}, MyGUI::Colour::Black); typesetter->write(header, to_utf8_span("You have no journal entries!")); @@ -184,7 +184,7 @@ namespace MWGui { BookTypesetter::Ptr typesetter = createTypesetter(); - BookTypesetter::Style* header = typesetter->createStyle({}, MyGUI::Colour(0.60f, 0.00f, 0.00f)); + BookTypesetter::Style* header = typesetter->createStyle({}, journalHeaderColour); BookTypesetter::Style* body = typesetter->createStyle({}, MyGUI::Colour::Black); mModel->visitJournalEntries({}, AddJournalEntry(typesetter, body, header, true)); @@ -196,7 +196,7 @@ namespace MWGui { BookTypesetter::Ptr typesetter = createTypesetter(); - BookTypesetter::Style* header = typesetter->createStyle({}, MyGUI::Colour(0.60f, 0.00f, 0.00f)); + BookTypesetter::Style* header = typesetter->createStyle({}, journalHeaderColour); BookTypesetter::Style* body = typesetter->createStyle({}, MyGUI::Colour::Black); mModel->visitTopicName(topicId, AddTopicName(typesetter, header)); @@ -212,7 +212,7 @@ namespace MWGui { BookTypesetter::Ptr typesetter = createTypesetter(); - BookTypesetter::Style* header = typesetter->createStyle({}, MyGUI::Colour(0.60f, 0.00f, 0.00f)); + BookTypesetter::Style* header = typesetter->createStyle({}, journalHeaderColour); BookTypesetter::Style* body = typesetter->createStyle({}, MyGUI::Colour::Black); AddQuestName addName(typesetter, header); diff --git a/apps/openmw/mwgui/journalbooks.hpp b/apps/openmw/mwgui/journalbooks.hpp index 1970830eab..dd6cb402c5 100644 --- a/apps/openmw/mwgui/journalbooks.hpp +++ b/apps/openmw/mwgui/journalbooks.hpp @@ -10,6 +10,8 @@ namespace MWGui { MWGui::BookTypesetter::Utf8Span to_utf8_span(std::string_view text); + const MyGUI::Colour journalHeaderColour = MyGUI::Colour(0.60f, 0.00f, 0.00f); + struct JournalBooks { typedef TypesetBook::Ptr Book; diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 8fbeb161ec..bff4b66c72 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -474,6 +474,9 @@ namespace getPage(LeftTopicIndex)->showPage(mTopicIndexBook, 0); getPage(RightTopicIndex)->showPage(mTopicIndexBook, 1); } + + if (Settings::gui().mControllerMenus) + setIndexControllerFocus(mSelectedIndex, true); } void notifyJournal(MyGUI::Widget* _sender) @@ -493,7 +496,7 @@ namespace MyGUI::Button* listItem = _list->getItemWidget(_list->getItemNameAt(i)); if (listItem) { - listItem->setStateSelected(mButtons.size() == _selectedIndex); + listItem->setTextColour(mButtons.size() == _selectedIndex ? MWGui::journalHeaderColour : MyGUI::Colour::Black); mButtons.push_back(listItem); } } @@ -518,7 +521,10 @@ namespace list->adjustSize(); if (Settings::gui().mControllerMenus) + { + mSelectedQuest = 0; addControllerButtons(list, mSelectedQuest); + } MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("book page")); MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay(); @@ -688,8 +694,30 @@ namespace return &mControllerButtons; } + void setIndexControllerFocus(int index, bool focused) + { + int col, row; + bool isRussian = (mEncoding == ToUTF8::WINDOWS_1251); + if (isRussian) + { + // Cyrillic = 30 (10 + 10 + 10) + col = index / 10; + row = index % 10; + } + else + { + // Latin = 26 (13 + 13) + col = index / 13; + row = index % 13; + } + + mTopicIndexBook->setColour(col, row, 0, focused ? MWGui::journalHeaderColour : MyGUI::Colour::Black); + } + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override { + bool isRussian = (mEncoding == ToUTF8::WINDOWS_1251); + if (arg.button == SDL_CONTROLLER_BUTTON_A) // A: Mouse click or Select { if (mOptionsMode && mQuestMode) @@ -704,6 +732,15 @@ namespace Gui::MWList* list = getWidget(TopicsList); notifyTopicSelected(list->getItemNameAt(mSelectedQuest), 0); } + else if (mOptionsMode) + { + // Choose an index. Cyrillic capital A is a 0xd090 in UTF-8. + // Words can not be started with characters 26 or 28. + int russianOffset = 0xd090; + if (mSelectedIndex >= 26) russianOffset++; + if (mSelectedIndex >= 27) russianOffset++; // 27, not 28, because of skipping char 26 + notifyIndexLinkClicked(isRussian ? mSelectedIndex + russianOffset : mSelectedIndex + 'A'); + } return true; } else if (arg.button == SDL_CONTROLLER_BUTTON_B) // B: Back @@ -776,10 +813,41 @@ namespace { if (mOptionsMode && (mQuestMode || mTopicsMode)) { + if (mButtons.size() <= 1) + return true; + // Scroll through the list of quests or topics - mButtons[mSelectedQuest]->setStateSelected(false); + mButtons[mSelectedQuest]->setTextColour(MyGUI::Colour::Black); mSelectedQuest = MWGui::wrap(mSelectedQuest - 1, mButtons.size()); - mButtons[mSelectedQuest]->setStateSelected(true); + mButtons[mSelectedQuest]->setTextColour(MWGui::journalHeaderColour); + } + else if (mOptionsMode) + { + setIndexControllerFocus(mSelectedIndex, false); + if (isRussian) + { + // Cyrillic = 30 (10 + 10 + 10) + if (mSelectedIndex == 0) + mSelectedIndex = 9; + else if (mSelectedIndex == 10) + mSelectedIndex = 19; + else if (mSelectedIndex == 20) + mSelectedIndex = 29; + else + mSelectedIndex--; + } + else + { + // Latin = 26 (13 + 13) + if (mSelectedIndex == 0) + mSelectedIndex = 12; + else if (mSelectedIndex == 13) + mSelectedIndex = 25; + else + mSelectedIndex--; + } + setIndexControllerFocus(mSelectedIndex, true); + setText(PageOneNum, 1); // Redraw the list } return true; } @@ -787,10 +855,41 @@ namespace { if (mOptionsMode && (mQuestMode || mTopicsMode)) { + if (mButtons.size() <= 1) + return true; + // Scroll through the list of quests or topics - mButtons[mSelectedQuest]->setStateSelected(false); + mButtons[mSelectedQuest]->setTextColour(MyGUI::Colour::Black); mSelectedQuest = MWGui::wrap(mSelectedQuest + 1, mButtons.size()); - mButtons[mSelectedQuest]->setStateSelected(true); + mButtons[mSelectedQuest]->setTextColour(MWGui::journalHeaderColour); + } + else if (mOptionsMode) + { + setIndexControllerFocus(mSelectedIndex, false); + if (isRussian) + { + // Cyrillic = 30 (10 + 10 + 10) + if (mSelectedIndex == 9) + mSelectedIndex = 0; + else if (mSelectedIndex == 19) + mSelectedIndex = 10; + else if (mSelectedIndex == 29) + mSelectedIndex = 20; + else + mSelectedIndex++; + } + else + { + // Latin = 26 (13 + 13) + if (mSelectedIndex == 12) + mSelectedIndex = 0; + else if (mSelectedIndex == 25) + mSelectedIndex = 13; + else + mSelectedIndex++; + } + setIndexControllerFocus(mSelectedIndex, true); + setText(PageOneNum, 1); // Redraw the list } return true; } @@ -798,12 +897,44 @@ namespace { if (!mOptionsMode) notifyPrevPage(getWidget(PrevPageBTN)); + else if (mOptionsMode && !mQuestMode && !mTopicsMode) + { + setIndexControllerFocus(mSelectedIndex, false); + if (isRussian) + { + // Cyrillic = 30 (10 + 10 + 10) + mSelectedIndex = (mSelectedIndex + 20) % 30; + } + else + { + // Latin = 26 (13 + 13) + mSelectedIndex = (mSelectedIndex + 13) % 26; + } + setIndexControllerFocus(mSelectedIndex, true); + setText(PageOneNum, 1); // Redraw the list + } return true; } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) { if (!mOptionsMode) notifyNextPage(getWidget(NextPageBTN)); + else if (mOptionsMode && !mQuestMode && !mTopicsMode) + { + setIndexControllerFocus(mSelectedIndex, false); + if (isRussian) + { + // Cyrillic = 30 (10 + 10 + 10) + mSelectedIndex = (mSelectedIndex + 10) % 30; + } + else + { + // Latin = 26 (13 + 13) + mSelectedIndex = (mSelectedIndex + 13) % 26; + } + setIndexControllerFocus(mSelectedIndex, true); + setText(PageOneNum, 1); // Redraw the list + } return true; } else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) // LB: Previous Page diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index 45c4100563..3c66421906 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -34,6 +34,8 @@ namespace MWGui std::vector mButtons; int mSelectedQuest = 0; + int mSelectedIndex = 0; + void setIndexControllerFocus(int index, bool focused); }; } From 263863f3f292635947ed151c37b3073ec6528252 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 1 Jun 2025 16:22:22 -0700 Subject: [PATCH 074/330] Fix modals opening above inventory causing it to change size --- apps/openmw/mwgui/inventorywindow.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index da071cb753..008e96356c 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -213,6 +213,9 @@ namespace MWGui void InventoryWindow::setGuiMode(GuiMode mode) { + if (Settings::gui().mControllerMenus && mGuiMode == mode && isVisible()) + return; + mGuiMode = mode; const WindowSettingValues settings = getModeSettings(mGuiMode); setPinButtonVisible(mode == GM_Inventory && !Settings::gui().mControllerMenus); From 2aa9847b248c868326438f6ca1c262503f0085f8 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 1 Jun 2025 16:27:49 -0700 Subject: [PATCH 075/330] Update controller buttons for character creation and level up --- apps/openmw/mwgui/birth.cpp | 28 ++++++++------------ apps/openmw/mwgui/birth.hpp | 1 - apps/openmw/mwgui/class.cpp | 41 ++++++++++++++++------------- apps/openmw/mwgui/class.hpp | 1 - apps/openmw/mwgui/levelupdialog.cpp | 2 ++ apps/openmw/mwgui/race.cpp | 28 ++++++++------------ apps/openmw/mwgui/race.hpp | 1 - apps/openmw/mwgui/review.cpp | 2 ++ 8 files changed, 49 insertions(+), 55 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index b047f6dc5f..5a5605aa6e 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -60,10 +60,9 @@ namespace MWGui if (Settings::gui().mControllerMenus) { - mOkButton->setStateSelected(true); + mControllerButtons.lStick = "#{sMouse}"; mControllerButtons.a = "#{sSelect}"; mControllerButtons.b = "#{sBack}"; - mControllerButtons.x = "#{sDone}"; } updateBirths(); @@ -76,8 +75,17 @@ namespace MWGui getWidget(okButton, "OKButton"); if (shown) + { okButton->setCaption( MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", {}))); + mControllerButtons.x = "#{sNext}"; + } + else if (Settings::gui().mControllerMenus) + { + okButton->setCaption( + MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sDone", {}))); + mControllerButtons.x = "#{sDone}"; + } else okButton->setCaption( MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", {}))); @@ -280,14 +288,7 @@ namespace MWGui bool BirthDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - if (mOkButtonFocus) - onOkClicked(mOkButton); - else - onBackClicked(mBackButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) + if (arg.button == SDL_CONTROLLER_BUTTON_B) { onBackClicked(mBackButton); } @@ -307,13 +308,6 @@ namespace MWGui winMgr->setKeyFocusWidget(mBirthList); winMgr->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); } - else if ((arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && mOkButtonFocus) || - (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && !mOkButtonFocus)) - { - mOkButtonFocus = !mOkButtonFocus; - mOkButton->setStateSelected(mOkButtonFocus); - mBackButton->setStateSelected(!mOkButtonFocus); - } return true; } diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index 09a0b7b1b5..b41b1fbb9a 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -59,7 +59,6 @@ namespace MWGui ESM::RefId mCurrentBirthId; bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - bool mOkButtonFocus = true; }; } #endif diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 700c431246..f0fe5537da 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -149,10 +149,9 @@ namespace MWGui if (Settings::gui().mControllerMenus) { - mOkButton->setStateSelected(true); + mControllerButtons.lStick = "#{sMouse}"; mControllerButtons.a = "#{sSelect}"; mControllerButtons.b = "#{sBack}"; - mControllerButtons.x = "#{sDone}"; } updateClasses(); @@ -165,8 +164,17 @@ namespace MWGui getWidget(okButton, "OKButton"); if (shown) + { okButton->setCaption( MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", {}))); + mControllerButtons.x = "#{sNext}"; + } + else if (Settings::gui().mControllerMenus) + { + okButton->setCaption( + MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sDone", {}))); + mControllerButtons.x = "#{sDone}"; + } else okButton->setCaption( MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", {}))); @@ -317,14 +325,7 @@ namespace MWGui bool PickClassDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - if (mOkButtonFocus) - onOkClicked(mOkButton); - else - onBackClicked(mBackButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) + if (arg.button == SDL_CONTROLLER_BUTTON_B) { onBackClicked(mBackButton); } @@ -344,13 +345,6 @@ namespace MWGui winMgr->setKeyFocusWidget(mClassList); winMgr->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); } - else if ((arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && mOkButtonFocus) || - (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && !mOkButtonFocus)) - { - mOkButtonFocus = !mOkButtonFocus; - mOkButton->setStateSelected(mOkButtonFocus); - mBackButton->setStateSelected(!mOkButtonFocus); - } return true; } @@ -590,9 +584,9 @@ namespace MWGui if (Settings::gui().mControllerMenus) { okButton->setStateSelected(true); + mControllerButtons.lStick = "#{sMouse}"; mControllerButtons.a = "#{sSelect}"; mControllerButtons.b = "#{sBack}"; - mControllerButtons.x = "#{sDone}"; } // Set default skills, attributes @@ -681,8 +675,17 @@ namespace MWGui getWidget(okButton, "OKButton"); if (shown) + { okButton->setCaption( MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", {}))); + mControllerButtons.x = "#{sNext}"; + } + else if (Settings::gui().mControllerMenus) + { + okButton->setCaption( + MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sDone", {}))); + mControllerButtons.x = "#{sDone}"; + } else okButton->setCaption( MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", {}))); @@ -1150,6 +1153,8 @@ namespace MWGui // Make sure the edit box has focus MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit); + + mControllerButtons.a = "#{sOk}"; } DescriptionDialog::~DescriptionDialog() {} diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index 9f04fa9e13..a4db03d4ab 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -155,7 +155,6 @@ namespace MWGui ESM::RefId mCurrentClassId; bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - bool mOkButtonFocus = true; }; class SelectSpecializationDialog : public WindowModal diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index 3b14415206..3ed3e3b6fc 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -97,6 +97,8 @@ namespace MWGui mDisableGamepadCursor = true; mControllerButtons.a = "#{sSelect}"; mControllerButtons.x = "#{sDone}"; + mOkButton->setCaption( + MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sDone", {}))); } center(); diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 172812bf47..fdc8725fa0 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -108,10 +108,9 @@ namespace MWGui if (Settings::gui().mControllerMenus) { - mOkButton->setStateSelected(true); + mControllerButtons.lStick = "#{sMouse}"; mControllerButtons.a = "#{sSelect}"; mControllerButtons.b = "#{sBack}"; - mControllerButtons.x = "#{sDone}"; mControllerButtons.y = "#{sSex}"; mControllerButtons.l1 = "#{sHair}"; mControllerButtons.r1 = "#{sFace}"; @@ -128,8 +127,17 @@ namespace MWGui getWidget(okButton, "OKButton"); if (shown) + { okButton->setCaption( MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", {}))); + mControllerButtons.x = "#{sNext}"; + } + else if (Settings::gui().mControllerMenus) + { + okButton->setCaption( + MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sDone", {}))); + mControllerButtons.x = "#{sDone}"; + } else okButton->setCaption( MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", {}))); @@ -463,14 +471,7 @@ namespace MWGui bool RaceDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - if (mOkButtonFocus) - onOkClicked(mOkButton); - else - onBackClicked(mBackButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) + if (arg.button == SDL_CONTROLLER_BUTTON_B) { onBackClicked(mBackButton); } @@ -502,13 +503,6 @@ namespace MWGui winMgr->setKeyFocusWidget(mRaceList); winMgr->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); } - else if ((arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && mOkButtonFocus) || - (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && !mOkButtonFocus)) - { - mOkButtonFocus = !mOkButtonFocus; - mOkButton->setStateSelected(mOkButtonFocus); - mBackButton->setStateSelected(!mOkButtonFocus); - } return true; } diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index 3652343308..ead058214c 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -124,7 +124,6 @@ namespace MWGui bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) override; - bool mOkButtonFocus = true; }; } #endif diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index dda00bd33a..003cdb49cb 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -125,6 +125,8 @@ namespace MWGui mControllerButtons.a = "#{sSelect}"; mControllerButtons.b = "#{sBack}"; mControllerButtons.x = "#{sDone}"; + okButton->setCaption( + MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sDone", {}))); } } From df237b5f9b45db444df0084bded4b9f7e1f33714 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 1 Jun 2025 21:34:20 -0700 Subject: [PATCH 076/330] Add controller support to quick key menu --- apps/openmw/mwgui/quickkeysmenu.cpp | 98 +++++++++++++++++++++++++++ apps/openmw/mwgui/quickkeysmenu.hpp | 9 +++ apps/openmw/mwgui/spellview.cpp | 18 ++--- apps/openmw/mwgui/spellview.hpp | 2 +- apps/openmw/mwgui/spellwindow.cpp | 2 +- files/data/mygui/openmw_resources.xml | 5 +- 6 files changed, 122 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 93b0ef071f..daf49e1101 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -58,6 +58,12 @@ namespace MWGui unassign(&mKey[i]); } + + if (Settings::gui().mControllerMenus) + { + mControllerButtons.a = "#{sSelect}"; + mControllerButtons.b = "#{sOK}"; + } } void QuickKeysMenu::clear() @@ -109,6 +115,13 @@ namespace MWGui { validate(index); } + + if (Settings::gui().mControllerMenus) + { + mControllerFocus = 0; + for (int i = 0; i < mKey.size(); i++) + mKey[i].button->setControllerFocus(i == mControllerFocus); + } } void QuickKeysMenu::onClose() @@ -450,6 +463,40 @@ namespace MWGui } } + bool QuickKeysMenu::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + onQuickKeyButtonClicked(mKey[mControllerFocus].button); + if (arg.button == SDL_CONTROLLER_BUTTON_B) + onOkButtonClicked(mOkButton); + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP || + arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + mControllerFocus = (mControllerFocus + 5) % 10; + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) + { + if (mControllerFocus == 0) + mControllerFocus = 4; + else if (mControllerFocus == 5) + mControllerFocus = 9; + else + mControllerFocus--; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + { + if (mControllerFocus == 4) + mControllerFocus = 0; + else if (mControllerFocus == 9) + mControllerFocus = 5; + else + mControllerFocus++; + } + + for (int i = 0; i < mKey.size(); i++) + mKey[i].button->setControllerFocus(i == mControllerFocus); + + return true; + } + // --------------------------------------------------------------------------------------------------------- QuickKeysMenuAssign::QuickKeysMenuAssign(QuickKeysMenu* parent) @@ -485,9 +532,45 @@ namespace MWGui mCancelButton->setCoord((maxWidth - mCancelButton->getTextSize().width - 24) / 2 + 8, mCancelButton->getTop(), mCancelButton->getTextSize().width + 24, mCancelButton->getHeight()); + if (Settings::gui().mControllerMenus) + { + mDisableGamepadCursor = true; + mItemButton->setStateSelected(true); + mControllerButtons.a = "#{sSelect}"; + mControllerButtons.b = "#{sCancel}"; + } + center(); } + bool QuickKeysMenuAssign::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + if (mControllerFocus == 0) + mParent->onItemButtonClicked(mItemButton); + else if (mControllerFocus == 1) + mParent->onMagicButtonClicked(mMagicButton); + else if (mControllerFocus == 2) + mParent->onUnassignButtonClicked(mUnassignButton); + else if (mControllerFocus == 3) + mParent->onCancelButtonClicked(mCancelButton); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + mParent->onCancelButtonClicked(mCancelButton); + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) + mControllerFocus = wrap(mControllerFocus - 1, 4); + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + mControllerFocus = wrap(mControllerFocus + 1, 4); + + mItemButton->setStateSelected(mControllerFocus == 0); + mMagicButton->setStateSelected(mControllerFocus == 1); + mUnassignButton->setStateSelected(mControllerFocus == 2); + mCancelButton->setStateSelected(mControllerFocus == 3); + + return true; + } + void QuickKeysMenu::write(ESM::ESMWriter& writer) { writer.startRecord(ESM::REC_KEYS); @@ -597,6 +680,12 @@ namespace MWGui mMagicList->setHighlightSelected(false); mMagicList->eventSpellClicked += MyGUI::newDelegate(this, &MagicSelectionDialog::onModelIndexSelected); + if (Settings::gui().mControllerMenus) + { + mControllerButtons.a = "#{sSelect}"; + mControllerButtons.b = "#{sCancel}"; + } + center(); } @@ -628,4 +717,13 @@ namespace MWGui mParent->onAssignMagic(spell.mId); } + bool MagicSelectionDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_B) + onCancelButtonClicked(mCancelButton); + else + mMagicList->onControllerButton(arg.button); + + return true; + } } diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index 904029b9a0..228eb926b4 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -72,6 +72,9 @@ namespace MWGui // Check if quick key is still valid inline void validate(int index); void unassign(keyData* key); + + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + int mControllerFocus; }; class QuickKeysMenuAssign : public WindowModal @@ -87,6 +90,9 @@ namespace MWGui MyGUI::Button* mCancelButton; QuickKeysMenu* mParent; + + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + int mControllerFocus; }; class MagicSelectionDialog : public WindowModal @@ -105,6 +111,9 @@ namespace MWGui void onCancelButtonClicked(MyGUI::Widget* sender); void onModelIndexSelected(SpellModel::ModelIndex index); + + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + int mControllerFocus; }; } diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index 6ef73c7794..e36a862730 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -327,14 +327,14 @@ namespace MWGui mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); } - void SpellView::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + void SpellView::onControllerButton(const unsigned char button) { if (mButtons.empty()) return; int prevFocus = mControllerFocus; - if (arg.button == SDL_CONTROLLER_BUTTON_A) + if (button == SDL_CONTROLLER_BUTTON_A) { // Select the focused item, if any. if (mControllerFocus >= 0 && mControllerFocus < mButtons.size()) @@ -343,22 +343,22 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); } } - else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK) + else if (button == SDL_CONTROLLER_BUTTON_RIGHTSTICK) { // Toggle info tooltip mControllerTooltip = !mControllerTooltip; if (mControllerTooltip && mControllerFocus >= 0 && mControllerFocus < mButtons.size()) MWBase::Environment::get().getInputManager()->warpMouseToWidget(mButtons[mControllerFocus].first); } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) + else if (button == SDL_CONTROLLER_BUTTON_DPAD_UP) mControllerFocus--; - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + else if (button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) mControllerFocus++; - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) + else if (button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) mControllerFocus = std::max(0, mControllerFocus - 10); - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + else if (button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) mControllerFocus = std::min(mControllerFocus + 10, (int)mButtons.size() - 1); - else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) + else if (button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) { // Jump to first item in previous group int prevGroupIndex = 0; @@ -371,7 +371,7 @@ namespace MWGui } mControllerFocus = prevGroupIndex; } - else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) + else if (button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) { // Jump to first item in next group for (int groupIndex : mGroupIndices) diff --git a/apps/openmw/mwgui/spellview.hpp b/apps/openmw/mwgui/spellview.hpp index 222d5f1ba3..5a22dcb4d9 100644 --- a/apps/openmw/mwgui/spellview.hpp +++ b/apps/openmw/mwgui/spellview.hpp @@ -57,7 +57,7 @@ namespace MWGui void resetScrollbars(); - void onControllerButtonEvent(const SDL_ControllerButtonEvent& arg); + void onControllerButton(const unsigned char button); private: MyGUI::ScrollView* mScrollView; diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 3eb041f6ab..b4c970c9bd 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -275,7 +275,7 @@ namespace MWGui if (arg.button == SDL_CONTROLLER_BUTTON_B) MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); else - mSpellView->onControllerButtonEvent(arg); + mSpellView->onControllerButton(arg.button); return true; } diff --git a/files/data/mygui/openmw_resources.xml b/files/data/mygui/openmw_resources.xml index d107c094e3..47fa71e984 100644 --- a/files/data/mygui/openmw_resources.xml +++ b/files/data/mygui/openmw_resources.xml @@ -192,7 +192,10 @@ - + + + + From ea71a0bb4f0519bc3bcaa0de2538de8cc4da158a Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 1 Jun 2025 22:13:58 -0700 Subject: [PATCH 077/330] Make controller selection wrap in inventory or containers --- apps/openmw/mwgui/itemview.cpp | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index 08e5236fc6..3d01073694 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -224,19 +224,29 @@ namespace MWGui mControllerTooltip = !mControllerTooltip; updateControllerFocus(-1, mControllerFocus); } - else if (button == SDL_CONTROLLER_BUTTON_DPAD_UP && mControllerFocus % mRows != 0) - mControllerFocus--; - else if (button == SDL_CONTROLLER_BUTTON_DPAD_DOWN && mControllerFocus % mRows != mRows - 1) - mControllerFocus++; + else if (button == SDL_CONTROLLER_BUTTON_DPAD_UP) + { + if (mControllerFocus % mRows == 0) + mControllerFocus = std::min(mControllerFocus + mRows - 1, mItemCount - 1); + else + mControllerFocus--; + } + else if (button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + { + if (mControllerFocus % mRows == mRows - 1 || mControllerFocus == mItemCount - 1) + mControllerFocus -= mControllerFocus % mRows; + else + mControllerFocus++; + } else if (button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && mControllerFocus >= mRows) mControllerFocus -= mRows; - else if (button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && mControllerFocus + mRows < mItemCount) - mControllerFocus += mRows; - - if (mControllerFocus < 0) - mControllerFocus = 0; - else if (mControllerFocus >= mItemCount - 1) - mControllerFocus = mItemCount - 1; + else if (button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + { + if (mControllerFocus + mRows < mItemCount) + mControllerFocus += mRows; + else if (mControllerFocus / mRows != (mItemCount - 1) / mRows) + mControllerFocus = mItemCount - 1; + } if (prevFocus != mControllerFocus) updateControllerFocus(prevFocus, mControllerFocus); From 6bb92c0589bbfa29dad55dcbf5c0240091e22737 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 1 Jun 2025 22:55:21 -0700 Subject: [PATCH 078/330] Clean up logs --- apps/openmw/mwgui/windowmanagerimp.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 9350ef4d1a..9066cbfdd9 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -898,8 +898,7 @@ namespace MWGui int activeIndex = std::clamp(mActiveControllerWindows[mode], 0, (int)state.mWindows.size() - 1); - // REMOVEME - Log(Debug::Error) << "getActiveControllerWindow: " << state.mWindows.size() << " windows in state, mActiveControllerWindows[mode] = " << mActiveControllerWindows[mode] << ", activeIndex=" << activeIndex; + Log(Debug::Debug) << "Getting active controller window: mode=" << mode << ", " << state.mWindows.size() << " window(s), activeIndex=" << activeIndex; // If the active window is no longer visible, find the next visible window. if (!state.mWindows[activeIndex]->isVisible()) @@ -934,8 +933,7 @@ namespace MWGui } } - // REMOVEME - Log(Debug::Error) << "cycleActiveControllerWindow: mode=" << mode << ", activeIndex=" << activeIndex; + Log(Debug::Debug) << "Cycling active controller window: mode=" << mode << ", activeIndex=" << activeIndex; if (mActiveControllerWindows[mode] != activeIndex) setActiveControllerWindow(mode, activeIndex); From 21286aa3762b9dabd9459866fc2c77d1ea35ec44 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 1 Jun 2025 23:27:49 -0700 Subject: [PATCH 079/330] Change 'Back' to 'Cancel' in button prompts to match windows --- apps/openmw/mwgui/alchemywindow.cpp | 2 +- apps/openmw/mwgui/container.cpp | 2 +- apps/openmw/mwgui/dialogue.cpp | 2 +- apps/openmw/mwgui/enchantingdialog.cpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 4 ++- apps/openmw/mwgui/itemselection.cpp | 2 +- apps/openmw/mwgui/merchantrepair.cpp | 2 +- apps/openmw/mwgui/recharge.cpp | 2 +- apps/openmw/mwgui/repair.cpp | 2 +- apps/openmw/mwgui/savegamedialog.cpp | 2 +- apps/openmw/mwgui/spellbuyingwindow.cpp | 2 +- apps/openmw/mwgui/spellcreationdialog.cpp | 4 +-- apps/openmw/mwgui/tradewindow.cpp | 2 +- apps/openmw/mwgui/trainingwindow.cpp | 2 +- apps/openmw/mwgui/travelwindow.cpp | 2 +- .../mygui/openmw_controllerbuttons.layout | 26 +++++++++---------- 16 files changed, 31 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 32334962fb..270b0f1cfe 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -95,7 +95,7 @@ namespace MWGui if (Settings::gui().mControllerMenus) { mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sBack}"; + mControllerButtons.b = "#{sCancel}"; mControllerButtons.x = "#{sCreate}"; mControllerButtons.y = "#{sMagicEffects}"; mControllerButtons.r3 = "#{sInfo}"; diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index c6c810c80e..9fe098f6d5 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -58,7 +58,7 @@ namespace MWGui setCoord(200, 0, 600, 300); mControllerButtons.a = "#{sTake}"; - mControllerButtons.b = "#{sBack}"; + mControllerButtons.b = "#{sClose}"; mControllerButtons.x = "#{sTakeAll}"; mControllerButtons.r3 = "#{sInfo}"; mControllerButtons.l2 = "#{sInventory}"; diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 1a8808c8dc..ff04d5237b 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -91,7 +91,7 @@ namespace MWGui mDisableGamepadCursor = Settings::gui().mControllerMenus; mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sBack}"; + mControllerButtons.b = "#{sCancel}"; } void PersuasionDialog::adjustAction(MyGUI::Widget* action, int& totalHeight) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index d0d9fb7401..b5e0444f25 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -61,7 +61,7 @@ namespace MWGui mName->eventEditSelectAccept += MyGUI::newDelegate(this, &EnchantingDialog::onAccept); mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sBack}"; + mControllerButtons.b = "#{sCancel}"; mControllerButtons.y = "Cast Type"; mControllerButtons.l1 = "#{sItem}"; mControllerButtons.r1 = "#{sSoulGem}"; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 008e96356c..d9061ebc9e 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -132,7 +132,6 @@ namespace MWGui if (Settings::gui().mControllerMenus) { - mControllerButtons.b = "#{sBack}"; mControllerButtons.r3 = "#{sInfo}"; } @@ -888,12 +887,14 @@ namespace MWGui case MWGui::GM_Companion: case MWGui::GM_Container: mControllerButtons.a = "Put"; + mControllerButtons.b = "#{sClose}"; mControllerButtons.x = "#{sTakeAll}"; mControllerButtons.y = ""; mControllerButtons.r2 = "#{sContainer}"; break; case MWGui::GM_Barter: mControllerButtons.a = "#{sSell}"; + mControllerButtons.b = "#{sCancel}"; mControllerButtons.x = "#{sOffer}"; mControllerButtons.y = ""; mControllerButtons.r2 = "#{sBarter}"; @@ -901,6 +902,7 @@ namespace MWGui case MWGui::GM_Inventory: default: mControllerButtons.a = "#{sEquip}"; + mControllerButtons.b = "#{sBack}"; mControllerButtons.x = "#{sDrop}"; mControllerButtons.y = "#{sUnequip}"; mControllerButtons.r2 = ""; diff --git a/apps/openmw/mwgui/itemselection.cpp b/apps/openmw/mwgui/itemselection.cpp index ec4ecb9d0f..ad2b141d8d 100644 --- a/apps/openmw/mwgui/itemselection.cpp +++ b/apps/openmw/mwgui/itemselection.cpp @@ -30,7 +30,7 @@ namespace MWGui center(); mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sBack}"; + mControllerButtons.b = "#{sCancel}"; mControllerButtons.r3 = "#{sInfo}"; } diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index e8155ea790..c720971c5b 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -33,7 +33,7 @@ namespace MWGui { mDisableGamepadCursor = true; mControllerButtons.a = "#{sRepair}"; - mControllerButtons.b = "#{sBack}"; + mControllerButtons.b = "#{sCancel}"; } } diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 605a9a1a94..7fe1be9266 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -41,7 +41,7 @@ namespace MWGui mGemIcon->eventMouseButtonClick += MyGUI::newDelegate(this, &Recharge::onSelectItem); mControllerButtons.a = "Recharge"; - mControllerButtons.b = "#{sBack}"; + mControllerButtons.b = "#{sCancel}"; mControllerButtons.y = "#{sSoulGem}"; } diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 6f5d256d86..32ddf58702 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -41,7 +41,7 @@ namespace MWGui mToolIcon->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onSelectItem); mControllerButtons.a = "#{sRepair}"; - mControllerButtons.b = "#{sBack}"; + mControllerButtons.b = "#{sCancel}"; mControllerButtons.y = "Tool"; } diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index af75152e4b..0f6bfefb54 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -67,7 +67,7 @@ namespace MWGui mDeleteButton->setNeedKeyFocus(false); mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sClose}"; + mControllerButtons.b = "#{sCancel}"; } void SaveGameDialog::onSlotActivated(MyGUI::ListBox* sender, size_t pos) diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 1c986180a8..48d7134b8a 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -36,7 +36,7 @@ namespace MWGui { mDisableGamepadCursor = true; mControllerButtons.a = "#{sBuy}"; - mControllerButtons.b = "#{sBack}"; + mControllerButtons.b = "#{sCancel}"; } } diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index f096beddcb..cc54fb0ceb 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -100,7 +100,7 @@ namespace MWGui if (Settings::gui().mControllerMenus) { mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sBack}"; + mControllerButtons.b = "#{sCancel}"; mControllerButtons.x = "#{sOk}"; } } @@ -598,7 +598,7 @@ namespace MWGui if (Settings::gui().mControllerMenus) { mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sBack}"; + mControllerButtons.b = "#{sCancel}"; mControllerButtons.x = "#{sBuy}"; } } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 69b16dfc93..379c18f59d 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -170,7 +170,7 @@ namespace MWGui setCoord(400, 0, 400, 300); mControllerButtons.a = "#{sBuy}"; - mControllerButtons.b = "#{sBack}"; + mControllerButtons.b = "#{sCancel}"; mControllerButtons.x = "#{sOffer}"; mControllerButtons.r3 = "#{sInfo}"; mControllerButtons.l2 = "#{sInventory}"; diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 65e468ebd4..d5c4f7efbc 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -42,7 +42,7 @@ namespace MWGui { mDisableGamepadCursor = true; mControllerButtons.a = "#{sBuy}"; - mControllerButtons.b = "#{sBack}"; + mControllerButtons.b = "#{sCancel}"; } } diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index eeb2df868f..d205fcba31 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -47,7 +47,7 @@ namespace MWGui { mDisableGamepadCursor = true; mControllerButtons.a = "#{sTravel}"; - mControllerButtons.b = "#{sBack}"; + mControllerButtons.b = "#{sCancel}"; } } diff --git a/files/data/mygui/openmw_controllerbuttons.layout b/files/data/mygui/openmw_controllerbuttons.layout index 42c89e10b4..ffcfeaee16 100644 --- a/files/data/mygui/openmw_controllerbuttons.layout +++ b/files/data/mygui/openmw_controllerbuttons.layout @@ -101,19 +101,6 @@ - - - - - - - - - - - - - @@ -179,6 +166,19 @@ + + + + + + + + + + + + + From 8ae193abe8fa3ceaaf5f5a0956ac82740cd4991e Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Mon, 2 Jun 2025 00:11:01 -0700 Subject: [PATCH 080/330] Fix issue when selecting an inventory item with the tooltip visible --- apps/openmw/mwgui/inventorywindow.cpp | 5 +++++ apps/openmw/mwgui/inventorywindow.hpp | 1 + apps/openmw/mwgui/itemview.hpp | 1 + apps/openmw/mwinput/controllermanager.cpp | 9 +++++++++ 4 files changed, 16 insertions(+) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index d9061ebc9e..99af4d63a3 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -880,6 +880,11 @@ namespace MWGui return osg::Vec2f(normalisedX * float(viewport.width - 1), (1.0 - normalisedY) * float(viewport.height - 1)); } + bool InventoryWindow::isControllerTooltipVisible() + { + return mItemView->isControllerTooltipVisible(); + } + ControllerButtonStr* InventoryWindow::getControllerButtons() { switch (mGuiMode) diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 5b4d61f272..86f31191f9 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -68,6 +68,7 @@ namespace MWGui std::string_view getWindowIdForLua() const override { return "Inventory"; } ControllerButtonStr* getControllerButtons() override; + bool isControllerTooltipVisible(); protected: void onTitleDoubleClicked() override; diff --git a/apps/openmw/mwgui/itemview.hpp b/apps/openmw/mwgui/itemview.hpp index 29d44c6b09..2f5cb99846 100644 --- a/apps/openmw/mwgui/itemview.hpp +++ b/apps/openmw/mwgui/itemview.hpp @@ -35,6 +35,7 @@ namespace MWGui void setActiveControllerWindow(bool active); int getControllerFocus() { return mControllerFocus; } int getItemCount() { return mItemCount; } + bool isControllerTooltipVisible() { return mControllerTooltip; } void onControllerButton(const unsigned char button); private: diff --git a/apps/openmw/mwinput/controllermanager.cpp b/apps/openmw/mwinput/controllermanager.cpp index 48034cae01..1647a5bab2 100644 --- a/apps/openmw/mwinput/controllermanager.cpp +++ b/apps/openmw/mwinput/controllermanager.cpp @@ -16,6 +16,7 @@ #include "../mwbase/luamanager.hpp" #include "../mwbase/statemanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwgui/inventorywindow.hpp" #include "actions.hpp" #include "bindingsmanager.hpp" @@ -252,6 +253,14 @@ namespace MWInput MWGui::WindowBase* topWin = winMgr->getActiveControllerWindow(); if (topWin) { + // When the inventory tooltip is visible, we don't actually want the A button to + // act like a mouse button; it should act normally. + if (treatAsMouse + && arg.button == SDL_CONTROLLER_BUTTON_A + && (MWGui::InventoryWindow *)topWin == winMgr->getInventoryWindow() + && ((MWGui::InventoryWindow *)topWin)->isControllerTooltipVisible()) + treatAsMouse = false; + mGamepadGuiCursorEnabled = topWin->isGamepadCursorAllowed(); // Fall through to mouse click From 6da6b9b98f9ea64035cf0f3ac6456d2bd721c6ea Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Mon, 2 Jun 2025 00:17:10 -0700 Subject: [PATCH 081/330] Update controller support for scroll window to use the keybaord for smoother scrolling --- apps/openmw/mwgui/scrollwindow.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index d032963417..4be1461d0c 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -143,10 +143,8 @@ namespace MWGui } else if (arg.button == SDL_CONTROLLER_BUTTON_B) onCloseButtonClicked(mCloseButton); - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) - onKeyButtonPressed(nullptr, MyGUI::KeyCode::ArrowUp, 0); - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - onKeyButtonPressed(nullptr, MyGUI::KeyCode::ArrowDown, 0); + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP || arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + return false; // Fall through to keyboard return true; } From e50822d1d279c6f26cf1a83745c928934b3226e4 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Mon, 2 Jun 2025 00:41:09 -0700 Subject: [PATCH 082/330] Remember the selected dialog topic when new topics are added to the list --- apps/openmw/mwgui/dialogue.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index ff04d5237b..c928e6a7cf 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -600,6 +600,11 @@ namespace MWGui void DialogueWindow::updateTopicsPane() { + const std::string focusedTopic = + Settings::gui().mControllerMenus && mControllerFocus < mTopicsList->getItemCount() + ? mTopicsList->getItemNameAt(mControllerFocus) + : ""; + mTopicsList->clear(); for (auto& linkPair : mTopicLinks) mDeleteLater.push_back(std::move(linkPair.second)); @@ -654,6 +659,9 @@ namespace MWGui mKeywordSearch.seed(topicId, intptr_t(t.get())); t->eventTopicActivated += MyGUI::newDelegate(this, &DialogueWindow::onTopicActivated); mTopicLinks[topicId] = std::move(t); + + if (keyword == focusedTopic) + mControllerFocus = mTopicsList->getItemCount() - 1; } redrawTopicsList(); From a6d03717cb47a63889e91141ea2dfb408dd0e9e6 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Tue, 3 Jun 2025 00:44:45 -0700 Subject: [PATCH 083/330] Hide cursor icon when showing controller tooltips --- apps/openmw/mwbase/windowmanager.hpp | 2 ++ apps/openmw/mwgui/inventorywindow.cpp | 5 ----- apps/openmw/mwgui/inventorywindow.hpp | 1 - apps/openmw/mwgui/itemview.cpp | 22 +++++++++++++++------- apps/openmw/mwgui/itemview.hpp | 2 -- apps/openmw/mwgui/tooltips.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 11 +++++++++++ apps/openmw/mwgui/windowmanagerimp.hpp | 3 +++ apps/openmw/mwinput/controllermanager.cpp | 8 ++++++-- apps/openmw/mwinput/mousemanager.cpp | 4 ++-- 10 files changed, 40 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 180c9bfee3..ee1990878a 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -390,6 +390,8 @@ namespace MWBase /// Cycle to the next window to receive controller events virtual void cycleActiveControllerWindow(bool next) = 0; virtual void setActiveControllerWindow(MWGui::GuiMode mode, int activeIndex) = 0; + virtual const bool getControllerTooltip() const = 0; + virtual void setControllerTooltip(bool enabled) = 0; virtual void updateControllerButtonsOverlay() = 0; // Used in Lua bindings diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 99af4d63a3..d9061ebc9e 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -880,11 +880,6 @@ namespace MWGui return osg::Vec2f(normalisedX * float(viewport.width - 1), (1.0 - normalisedY) * float(viewport.height - 1)); } - bool InventoryWindow::isControllerTooltipVisible() - { - return mItemView->isControllerTooltipVisible(); - } - ControllerButtonStr* InventoryWindow::getControllerButtons() { switch (mGuiMode) diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 86f31191f9..5b4d61f272 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -68,7 +68,6 @@ namespace MWGui std::string_view getWindowIdForLua() const override { return "Inventory"; } ControllerButtonStr* getControllerButtons() override; - bool isControllerTooltipVisible(); protected: void onTitleDoubleClicked() override; diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index 3d01073694..3d8cf91f8a 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -81,7 +81,7 @@ namespace MWGui if (Settings::gui().mControllerMenus) { - mControllerTooltip = false; + MWBase::Environment::get().getWindowManager()->setControllerTooltip(false); mControllerFocus = std::clamp(mControllerFocus, 0, mItemCount - 1); updateControllerFocus(-1, mControllerFocus); } @@ -190,10 +190,11 @@ namespace MWGui { mControllerActiveWindow = active; - if (mControllerTooltip) + MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); + if (winMgr->getControllerTooltip()) { - MWBase::Environment::get().getWindowManager()->setCursorActive(false); - mControllerTooltip = false; + winMgr->setCursorActive(false); + winMgr->setControllerTooltip(false); } if (active) @@ -221,7 +222,8 @@ namespace MWGui else if (button == SDL_CONTROLLER_BUTTON_RIGHTSTICK) { // Toggle info tooltip - mControllerTooltip = !mControllerTooltip; + MWBase::Environment::get().getWindowManager()->setControllerTooltip( + !MWBase::Environment::get().getWindowManager()->getControllerTooltip()); updateControllerFocus(-1, mControllerFocus); } else if (button == SDL_CONTROLLER_BUTTON_DPAD_UP) @@ -250,10 +252,15 @@ namespace MWGui if (prevFocus != mControllerFocus) updateControllerFocus(prevFocus, mControllerFocus); + else + updateControllerFocus(-1, mControllerFocus); } void ItemView::updateControllerFocus(int prevFocus, int newFocus) { + MWBase::Environment::get().getWindowManager()->setCursorVisible( + !MWBase::Environment::get().getWindowManager()->getControllerTooltip()); + if (!mItemCount) return; @@ -272,8 +279,6 @@ namespace MWGui if (focused) { focused->setControllerFocus(true); - if (mControllerTooltip) - MWBase::Environment::get().getInputManager()->warpMouseToWidget(focused); // Scroll the list to keep the active item in view int column = newFocus / mRows; @@ -281,6 +286,9 @@ namespace MWGui mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); else mScrollView->setViewOffset(MyGUI::IntPoint(-42 * (column - 3), 0)); + + if (MWBase::Environment::get().getWindowManager()->getControllerTooltip()) + MWBase::Environment::get().getInputManager()->warpMouseToWidget(focused); } } } diff --git a/apps/openmw/mwgui/itemview.hpp b/apps/openmw/mwgui/itemview.hpp index 2f5cb99846..7915a4dcf1 100644 --- a/apps/openmw/mwgui/itemview.hpp +++ b/apps/openmw/mwgui/itemview.hpp @@ -35,7 +35,6 @@ namespace MWGui void setActiveControllerWindow(bool active); int getControllerFocus() { return mControllerFocus; } int getItemCount() { return mItemCount; } - bool isControllerTooltipVisible() { return mControllerTooltip; } void onControllerButton(const unsigned char button); private: @@ -56,7 +55,6 @@ namespace MWGui int mItemCount = 0; int mRows; int mControllerFocus = 0; - bool mControllerTooltip; bool mControllerActiveWindow; void updateControllerFocus(int prevFocus, int newFocus); }; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 28f0b80010..67c10b980f 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -94,7 +94,7 @@ namespace MWGui if (guiMode) { - if (!winMgr->getCursorVisible()) + if (!winMgr->getCursorVisible() && !winMgr->getControllerTooltip()) return; const MyGUI::IntPoint& mousePos = MyGUI::InputManager::getInstance().getMousePosition(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 9066cbfdd9..5b32cb8709 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -941,6 +941,9 @@ namespace MWGui void WindowManager::setActiveControllerWindow(GuiMode mode, int activeIndex) { + if (!Settings::gui().mControllerMenus) + return; + int winCount = mGuiModeStates[mode].mWindows.size(); if (winCount == 0) return; @@ -2590,6 +2593,14 @@ namespace MWGui return res; } + void WindowManager::setControllerTooltip(bool enabled) + { + if (!Settings::gui().mControllerMenus) + return; + + mControllerTooltip = enabled; + } + void WindowManager::updateControllerButtonsOverlay() { if (!Settings::gui().mControllerMenus || !mControllerButtonsOverlay) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index d5e36a0971..97847551b1 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -396,6 +396,8 @@ namespace MWGui WindowBase* getActiveControllerWindow() override; void cycleActiveControllerWindow(bool next) override; void setActiveControllerWindow(GuiMode mode, int activeIndex) override; + const bool getControllerTooltip() const override { return mControllerTooltip; } + void setControllerTooltip(bool enabled) override; void updateControllerButtonsOverlay() override; // Used in Lua bindings @@ -508,6 +510,7 @@ namespace MWGui std::vector mGuiModes; // The active window for controller mode for each GUI mode. std::map mActiveControllerWindows; + bool mControllerTooltip; std::unique_ptr mCursorManager; diff --git a/apps/openmw/mwinput/controllermanager.cpp b/apps/openmw/mwinput/controllermanager.cpp index 1647a5bab2..ac2e07e0cc 100644 --- a/apps/openmw/mwinput/controllermanager.cpp +++ b/apps/openmw/mwinput/controllermanager.cpp @@ -257,8 +257,7 @@ namespace MWInput // act like a mouse button; it should act normally. if (treatAsMouse && arg.button == SDL_CONTROLLER_BUTTON_A - && (MWGui::InventoryWindow *)topWin == winMgr->getInventoryWindow() - && ((MWGui::InventoryWindow *)topWin)->isControllerTooltipVisible()) + && winMgr->getControllerTooltip()) treatAsMouse = false; mGamepadGuiCursorEnabled = topWin->isGamepadCursorAllowed(); @@ -363,6 +362,11 @@ namespace MWInput && (arg.axis == SDL_CONTROLLER_AXIS_LEFTX || arg.axis == SDL_CONTROLLER_AXIS_LEFTY)) { // Treat the left stick like a cursor, which is the default behavior. + if (winMgr->getControllerTooltip()) + { + winMgr->setControllerTooltip(false); + winMgr->setCursorVisible(true); + } return false; } diff --git a/apps/openmw/mwinput/mousemanager.cpp b/apps/openmw/mwinput/mousemanager.cpp index 2c6798406b..1367084872 100644 --- a/apps/openmw/mwinput/mousemanager.cpp +++ b/apps/openmw/mwinput/mousemanager.cpp @@ -266,8 +266,8 @@ namespace MWInput void MouseManager::warpMouseToWidget(MyGUI::Widget* widget) { - float widgetX = widget->getAbsoluteCoord().left + 4; - float widgetY = widget->getAbsoluteCoord().top + 4; + float widgetX = widget->getAbsoluteCoord().left + widget->getWidth() / 2; + float widgetY = widget->getAbsoluteCoord().top + widget->getHeight() - 30; if (std::abs(mGuiCursorX - widgetX) > 1 || std::abs(mGuiCursorY - widgetY) > 1) { mGuiCursorX = widgetX; From a824993a605e86a0487cc70c300cab47f43bb247 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Tue, 3 Jun 2025 08:56:39 -0700 Subject: [PATCH 084/330] Fix controller tooltips in magic menu appearing for wrong spell --- apps/openmw/mwinput/mousemanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwinput/mousemanager.cpp b/apps/openmw/mwinput/mousemanager.cpp index 1367084872..540c334b1e 100644 --- a/apps/openmw/mwinput/mousemanager.cpp +++ b/apps/openmw/mwinput/mousemanager.cpp @@ -267,7 +267,7 @@ namespace MWInput void MouseManager::warpMouseToWidget(MyGUI::Widget* widget) { float widgetX = widget->getAbsoluteCoord().left + widget->getWidth() / 2; - float widgetY = widget->getAbsoluteCoord().top + widget->getHeight() - 30; + float widgetY = widget->getAbsoluteCoord().top + widget->getHeight() / 4; if (std::abs(mGuiCursorX - widgetX) > 1 || std::abs(mGuiCursorY - widgetY) > 1) { mGuiCursorX = widgetX; From ae676e1d702352faf1c8d08dfde4d51367b3da03 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Tue, 3 Jun 2025 20:17:53 -0700 Subject: [PATCH 085/330] Fix not checking bounds in some controller menus --- apps/openmw/mwgui/itemchargeview.cpp | 4 ++-- apps/openmw/mwgui/merchantrepair.cpp | 15 +++++++++------ apps/openmw/mwgui/spellbuyingwindow.cpp | 17 ++++++++++------- apps/openmw/mwgui/spellview.cpp | 5 +++-- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwgui/itemchargeview.cpp b/apps/openmw/mwgui/itemchargeview.cpp index abbf328a8c..4ac59642ea 100644 --- a/apps/openmw/mwgui/itemchargeview.cpp +++ b/apps/openmw/mwgui/itemchargeview.cpp @@ -280,10 +280,10 @@ namespace MWGui mLines[newFocus].mIcon->setControllerFocus(true); // Scroll the list to keep the active item in view - if (mControllerFocus <= 3) + if (newFocus <= 3) mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mScrollView->setViewOffset(MyGUI::IntPoint(-55 * (mControllerFocus - 3), 0)); + mScrollView->setViewOffset(MyGUI::IntPoint(-55 * (newFocus - 3), 0)); } } } diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index c720971c5b..c659cac139 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -205,13 +205,16 @@ namespace MWGui } // Scroll the list to keep the active item in view - int line = mButtons[mControllerFocus].second; - if (line <= 5) - mList->setViewOffset(MyGUI::IntPoint(0, 0)); - else + if (mControllerFocus >= 0 && mControllerFocus < mButtons.size()) { - const int lineHeight = Settings::gui().mFontSize + 2; - mList->setViewOffset(MyGUI::IntPoint(0, -lineHeight * (line - 5))); + int line = mButtons[mControllerFocus].second; + if (line <= 5) + mList->setViewOffset(MyGUI::IntPoint(0, 0)); + else + { + const int lineHeight = Settings::gui().mFontSize + 2; + mList->setViewOffset(MyGUI::IntPoint(0, -lineHeight * (line - 5))); + } } return true; diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 48d7134b8a..27065bc2c3 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -247,14 +247,17 @@ namespace MWGui mSpellButtons[mControllerFocus].first->setStateSelected(true); } - // Scroll the list to keep the active item in view - int line = mSpellButtons[mControllerFocus].second; - if (line <= 5) - mSpellsView->setViewOffset(MyGUI::IntPoint(0, 0)); - else + if (mControllerFocus >= 0 && mControllerFocus < mSpellButtons.size()) { - const int lineHeight = Settings::gui().mFontSize + 2; - mSpellsView->setViewOffset(MyGUI::IntPoint(0, -lineHeight * (line - 5))); + // Scroll the list to keep the active item in view + int line = mSpellButtons[mControllerFocus].second; + if (line <= 5) + mSpellsView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + { + const int lineHeight = Settings::gui().mFontSize + 2; + mSpellsView->setViewOffset(MyGUI::IntPoint(0, -lineHeight * (line - 5))); + } } return true; diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index e36a862730..8a18eb440f 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -408,8 +408,6 @@ namespace MWGui if (focused) { focused->onMouseSetFocus(nullptr); - if (mControllerTooltip) - MWBase::Environment::get().getInputManager()->warpMouseToWidget(focused); // Scroll the list to keep the active item in view int line = mButtons[newFocus].second; @@ -420,6 +418,9 @@ namespace MWGui const int lineHeight = focused->getHeight(); mScrollView->setViewOffset(MyGUI::IntPoint(0, -lineHeight * (line - 5))); } + + if (mControllerTooltip) + MWBase::Environment::get().getInputManager()->warpMouseToWidget(focused); } } } From 2dfe1ef7b1ad520173cfa98061777f31fc5a3c59 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Tue, 3 Jun 2025 21:23:21 -0700 Subject: [PATCH 086/330] Show L1 and R1 buttons next to tabs --- apps/openmw/mwgui/inventorywindow.cpp | 16 ++++++++++ apps/openmw/mwgui/tradewindow.cpp | 29 +++++++++++++++---- .../data/mygui/openmw_inventory_window.layout | 12 ++++++++ files/data/mygui/openmw_trade_window.layout | 12 ++++++++ 4 files changed, 64 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index d9061ebc9e..c68fd0fbc7 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -132,6 +132,14 @@ namespace MWGui if (Settings::gui().mControllerMenus) { + // Show L1 and R1 buttons next to tabs + MyGUI::Widget* image; + getWidget(image, "BtnL1Image"); + image->setUserString("Hidden", "false"); + + getWidget(image, "BtnR1Image"); + image->setUserString("Hidden", "false"); + mControllerButtons.r3 = "#{sInfo}"; } @@ -1036,6 +1044,14 @@ namespace MWGui updatePreviewSize(); } + // Show L1 and R1 buttons next to tabs + MyGUI::Widget* image; + getWidget(image, "BtnL1Image"); + image->setVisible(active); + + getWidget(image, "BtnR1Image"); + image->setVisible(active); + mItemView->setActiveControllerWindow(active); WindowBase::setActiveControllerWindow(active); } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 379c18f59d..ca0924396e 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -169,11 +169,22 @@ namespace MWGui setCoord(400, 0, 400, 300); - mControllerButtons.a = "#{sBuy}"; - mControllerButtons.b = "#{sCancel}"; - mControllerButtons.x = "#{sOffer}"; - mControllerButtons.r3 = "#{sInfo}"; - mControllerButtons.l2 = "#{sInventory}"; + if (Settings::gui().mControllerMenus) + { + // Show L1 and R1 buttons next to tabs + MyGUI::Widget* image; + getWidget(image, "BtnL1Image"); + image->setUserString("Hidden", "false"); + + getWidget(image, "BtnR1Image"); + image->setUserString("Hidden", "false"); + + mControllerButtons.a = "#{sBuy}"; + mControllerButtons.b = "#{sCancel}"; + mControllerButtons.x = "#{sOffer}"; + mControllerButtons.r3 = "#{sInfo}"; + mControllerButtons.l2 = "#{sInventory}"; + } } void TradeWindow::setPtr(const MWWorld::Ptr& actor) @@ -734,6 +745,14 @@ namespace MWGui void TradeWindow::setActiveControllerWindow(bool active) { + // Show L1 and R1 buttons next to tabs + MyGUI::Widget* image; + getWidget(image, "BtnL1Image"); + image->setVisible(active); + + getWidget(image, "BtnR1Image"); + image->setVisible(active); + mItemView->setActiveControllerWindow(active); WindowBase::setActiveControllerWindow(active); } diff --git a/files/data/mygui/openmw_inventory_window.layout b/files/data/mygui/openmw_inventory_window.layout index a555c94031..c8b3a6857b 100644 --- a/files/data/mygui/openmw_inventory_window.layout +++ b/files/data/mygui/openmw_inventory_window.layout @@ -30,6 +30,12 @@ + + + + + + @@ -50,6 +56,12 @@ + + + + + + diff --git a/files/data/mygui/openmw_trade_window.layout b/files/data/mygui/openmw_trade_window.layout index 49ccf25ba2..c514155981 100644 --- a/files/data/mygui/openmw_trade_window.layout +++ b/files/data/mygui/openmw_trade_window.layout @@ -7,6 +7,12 @@ + + + + + + @@ -27,6 +33,12 @@ + + + + + + From c35e0d733629f90c4018562ba06d257fb15eae66 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Tue, 3 Jun 2025 21:57:43 -0700 Subject: [PATCH 087/330] Add menu click sounds to some menus when activated by the controller --- apps/openmw/mwgui/alchemywindow.cpp | 6 ++++-- apps/openmw/mwgui/dialogue.cpp | 4 ++++ apps/openmw/mwgui/inventorywindow.cpp | 2 ++ apps/openmw/mwgui/levelupdialog.cpp | 1 + apps/openmw/mwgui/recharge.cpp | 3 +++ apps/openmw/mwgui/repair.cpp | 3 +++ apps/openmw/mwgui/savegamedialog.cpp | 2 ++ apps/openmw/mwgui/settingswindow.cpp | 4 ++-- apps/openmw/mwgui/spellcreationdialog.cpp | 6 ++++++ apps/openmw/mwgui/textinput.cpp | 1 + apps/openmw/mwgui/tradewindow.cpp | 2 ++ apps/openmw/mwgui/travelwindow.cpp | 3 +++ apps/openmw/mwgui/waitdialog.cpp | 6 ++++++ 13 files changed, 39 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 270b0f1cfe..f79abf11c5 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -557,15 +557,16 @@ namespace MWGui if (isFilterListOpen) { // When the filter list combo box is open, send all inputs to it. - if (arg.button == SDL_CONTROLLER_BUTTON_A) + if (arg.button == SDL_CONTROLLER_BUTTON_A || arg.button == SDL_CONTROLLER_BUTTON_Y) { // Select the highlighted entry in the combo box and close it. int index = mFilterValue->getIndexSelected(); mFilterValue->setIndexSelected(index); onFilterChanged(mFilterValue, index); MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mNameEdit); // Close list + MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); } - else if (arg.button == SDL_CONTROLLER_BUTTON_B || arg.button == SDL_CONTROLLER_BUTTON_Y) + else if (arg.button == SDL_CONTROLLER_BUTTON_B) { // Close the list without selecting anything mFilterValue->clearIndexSelected(); @@ -610,6 +611,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mFilterValue); MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); } + MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); } else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) onDecreaseButtonTriggered(); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index c928e6a7cf..d409cd8856 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -177,7 +177,10 @@ namespace MWGui bool PersuasionDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) + { onPersuade(mButtons[mControllerFocus]); + MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); + } else if (arg.button == SDL_CONTROLLER_BUTTON_B) onCancel(mCancelButton); else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) @@ -960,6 +963,7 @@ namespace MWGui onGoodbyeActivated(); else onSelectListItem(mTopicsList->getItemNameAt(mControllerFocus), mControllerFocus); + MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); } else if (arg.button == SDL_CONTROLLER_BUTTON_B) { diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index c68fd0fbc7..c943611820 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -1001,6 +1001,7 @@ namespace MWGui onFilterChanged(mFilterApparel); else if (mFilterMisc->getStateSelected()) onFilterChanged(mFilterMagic); + MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); } else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) { @@ -1014,6 +1015,7 @@ namespace MWGui onFilterChanged(mFilterMisc); else if (mFilterMisc->getStateSelected()) onFilterChanged(mFilterAll); + MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); } else { diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index 3ed3e3b6fc..de79e2a8b3 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -388,6 +388,7 @@ namespace MWGui { if (mControllerFocus >= 0 && mControllerFocus < mAttributeButtons.size()) onAttributeClicked(mAttributeButtons[mControllerFocus]); + MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Item Gold Up")); } else if (arg.button == SDL_CONTROLLER_BUTTON_X) { diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 7fe1be9266..bf71972d0d 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -144,7 +144,10 @@ namespace MWGui { if ((arg.button == SDL_CONTROLLER_BUTTON_A && !mGemBox->getVisible()) || arg.button == SDL_CONTROLLER_BUTTON_Y) + { onSelectItem(mGemIcon); + MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); + } else if (arg.button == SDL_CONTROLLER_BUTTON_B) onCancel(mCancelButton); else diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 32ddf58702..c1241f53f5 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -158,7 +158,10 @@ namespace MWGui { if ((arg.button == SDL_CONTROLLER_BUTTON_A && !mToolBox->getVisible()) || arg.button == SDL_CONTROLLER_BUTTON_Y) + { onSelectItem(mToolIcon); + MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); + } else if (arg.button == SDL_CONTROLLER_BUTTON_B) onCancel(mCancelButton); else diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 0f6bfefb54..7e9067b81a 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -535,6 +535,7 @@ namespace MWGui onOkButtonClicked(mOkButton); else onCancelButtonClicked(mCancelButton); + MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); } else if (arg.button == SDL_CONTROLLER_BUTTON_B) { @@ -546,6 +547,7 @@ namespace MWGui index = wrap(index + 1, mCharacterSelection->getItemCount()); mCharacterSelection->setIndexSelected(index); onCharacterSelected(mCharacterSelection, index); + MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) { diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 70f2ab8ff3..89cdb6694a 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -1146,7 +1146,7 @@ namespace MWGui uint32_t index = mSettingsTab->getIndexSelected(); index = wrap(index - 1, mSettingsTab->getItemCount()); mSettingsTab->setIndexSelected(index); - + MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); return true; } else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) @@ -1154,7 +1154,7 @@ namespace MWGui uint32_t index = mSettingsTab->getIndexSelected(); index = wrap(index + 1, mSettingsTab->getItemCount()); mSettingsTab->setIndexSelected(index); - + MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); return true; } diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index cc54fb0ceb..103fa3df1d 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -401,11 +401,15 @@ namespace MWGui onOkButtonClicked(mOkButton); else if (button == mDeleteButton) onDeleteButtonClicked(mDeleteButton); + MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); } else if (arg.button == SDL_CONTROLLER_BUTTON_B) onCancelButtonClicked(mCancelButton); else if (arg.button == SDL_CONTROLLER_BUTTON_X) + { onOkButtonClicked(mOkButton); + MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); + } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) { if (mControllerFocus == 0) @@ -1036,10 +1040,12 @@ namespace MWGui if (!mRightColumn && mAvailableFocus >= 0 && mAvailableFocus < mAvailableButtons.size()) { onAvailableEffectClicked(mAvailableButtons[mAvailableFocus]); + MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); } else if (mRightColumn && mEffectFocus >= 0 && mEffectFocus < mEffectButtons.size()) { onEditEffect(mEffectButtons[mEffectFocus].second); + MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); } } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) diff --git a/apps/openmw/mwgui/textinput.cpp b/apps/openmw/mwgui/textinput.cpp index 6ef8f1ef8e..7612cf4c67 100644 --- a/apps/openmw/mwgui/textinput.cpp +++ b/apps/openmw/mwgui/textinput.cpp @@ -90,6 +90,7 @@ namespace MWGui if (arg.button == SDL_CONTROLLER_BUTTON_A) { onOkClicked(nullptr); + MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); return true; } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index ca0924396e..fbbd98cc31 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -717,6 +717,7 @@ namespace MWGui onFilterChanged(mFilterApparel); else if (mFilterMisc->getStateSelected()) onFilterChanged(mFilterMagic); + MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); } else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) { @@ -730,6 +731,7 @@ namespace MWGui onFilterChanged(mFilterMisc); else if (mFilterMisc->getStateSelected()) onFilterChanged(mFilterAll); + MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); } else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK || arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP || diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index d205fcba31..48717b0825 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -259,7 +259,10 @@ namespace MWGui if (arg.button == SDL_CONTROLLER_BUTTON_A) { if (mControllerFocus >= 0 && mControllerFocus < mDestinationButtons.size()) + { onTravelButtonClick(mDestinationButtons[mControllerFocus]); + MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); + } } else if (arg.button == SDL_CONTROLLER_BUTTON_B) { diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 8df47e7d58..e2932caf46 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -339,11 +339,17 @@ namespace MWGui bool WaitDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_A) + { onWaitButtonClicked(mWaitButton); + MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); + } else if (arg.button == SDL_CONTROLLER_BUTTON_B) onCancelButtonClicked(mCancelButton); else if (arg.button == SDL_CONTROLLER_BUTTON_X && mUntilHealedButton->getVisible()) + { onUntilHealedButtonClicked(mUntilHealedButton); + MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); + } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) From dc68f28a40580078a892e9a5e35951d2a4fc0481 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Fri, 6 Jun 2025 00:34:01 -0700 Subject: [PATCH 088/330] Disable right stick from panning map if zooming maps is enabled --- apps/openmw/mwgui/mapwindow.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index f90180fb44..1c1920f0b2 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -839,7 +839,7 @@ namespace MWGui mControllerButtons.b = "#{sBack}"; mControllerButtons.x = global ? "#{sLocal}" : "#{sWorld}"; mControllerButtons.y = "#{sCenter}"; - mControllerButtons.rStick = "#{sMove}"; + mControllerButtons.rStick = Settings::map().mAllowZooming ? "" : "#{sMove}"; } } @@ -1420,11 +1420,15 @@ namespace MWGui bool MapWindow::onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) { - int dx = arg.axis == SDL_CONTROLLER_AXIS_RIGHTX ? -30.0f * arg.value / 32767 : 0; - int dy = arg.axis == SDL_CONTROLLER_AXIS_RIGHTY ? -30.0f * arg.value / 32767 : 0; - shiftMap(dx, dy); + if (!Settings::map().mAllowZooming) + { + int dx = arg.axis == SDL_CONTROLLER_AXIS_RIGHTX ? -30.0f * arg.value / 32767 : 0; + int dy = arg.axis == SDL_CONTROLLER_AXIS_RIGHTY ? -30.0f * arg.value / 32767 : 0; + shiftMap(dx, dy); - return true; + return true; + } + return false; } void MapWindow::shiftMap(int dx, int dy) From b2a5ded9294b3bf26438710526ca168221f111a2 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Fri, 6 Jun 2025 00:34:23 -0700 Subject: [PATCH 089/330] Fix scrolling list of items to repair or recharge --- apps/openmw/mwgui/itemchargeview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/itemchargeview.cpp b/apps/openmw/mwgui/itemchargeview.cpp index 4ac59642ea..0b9ea842d9 100644 --- a/apps/openmw/mwgui/itemchargeview.cpp +++ b/apps/openmw/mwgui/itemchargeview.cpp @@ -283,7 +283,7 @@ namespace MWGui if (newFocus <= 3) mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mScrollView->setViewOffset(MyGUI::IntPoint(-55 * (newFocus - 3), 0)); + mScrollView->setViewOffset(MyGUI::IntPoint(0, -55 * (newFocus - 3))); } } } From b1989ffdf7e1d63b6d28f042352ccf8b56ea1e84 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Fri, 6 Jun 2025 00:34:42 -0700 Subject: [PATCH 090/330] Limit size of inventory menu in controller mode --- apps/openmw/mwgui/inventorywindow.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index c943611820..b735d89cf8 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -1032,10 +1032,11 @@ namespace MWGui if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Inventory) { - // Fill the screen, or limit to a certain size on large screens. + // Fill the screen, or limit to a certain size on large screens. Size chosen to + // match the size of the stats window. MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - int width = std::min(viewSize.width, 2200); - int height = std::min(viewSize.height - 48 - 48, 1200); + int width = std::min(viewSize.width, 1600); + int height = std::min(viewSize.height - 48 - 48, 750); int x = (viewSize.width - width) / 2; int y = (viewSize.height - height) / 2; From ea70f2b5c22033858be178d0c9f09dedaea4218d Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sat, 7 Jun 2025 00:35:46 -0700 Subject: [PATCH 091/330] Show tooltips in controller mode on spell menus --- apps/openmw/mwgui/spellbuyingwindow.cpp | 19 +++++++++++++++++++ apps/openmw/mwgui/spellcreationdialog.cpp | 22 ++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 27065bc2c3..3bc38b2e44 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -9,6 +9,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/inputmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" @@ -37,6 +38,7 @@ namespace MWGui mDisableGamepadCursor = true; mControllerButtons.a = "#{sBuy}"; mControllerButtons.b = "#{sCancel}"; + mControllerButtons.r3 = "#{sInfo}"; } } @@ -144,6 +146,13 @@ namespace MWGui mControllerFocus = 0; if (mSpellButtons.size() > 0) mSpellButtons[0].first->setStateSelected(true); + + MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); + if (winMgr->getControllerTooltip()) + { + winMgr->setCursorActive(false); + winMgr->setControllerTooltip(false); + } } // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the @@ -228,6 +237,12 @@ namespace MWGui { onCancelButtonClicked(mCancelButton); } + else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK) + { + // Toggle info tooltip + MWBase::Environment::get().getWindowManager()->setControllerTooltip( + !MWBase::Environment::get().getWindowManager()->getControllerTooltip()); + } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) { if (mSpellButtons.size() <= 1) @@ -258,6 +273,10 @@ namespace MWGui const int lineHeight = Settings::gui().mFontSize + 2; mSpellsView->setViewOffset(MyGUI::IntPoint(0, -lineHeight * (line - 5))); } + + // Warp the mouse to the selected spell to show the tooltip + if (MWBase::Environment::get().getWindowManager()->getControllerTooltip()) + MWBase::Environment::get().getInputManager()->warpMouseToWidget(mSpellButtons[mControllerFocus].first); } return true; diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 103fa3df1d..119a32ffea 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -14,6 +14,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/inputmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwworld/class.hpp" @@ -102,6 +103,7 @@ namespace MWGui mControllerButtons.a = "#{sSelect}"; mControllerButtons.b = "#{sCancel}"; mControllerButtons.x = "#{sOk}"; + mControllerButtons.r3 = "#{sInfo}"; } } @@ -615,6 +617,13 @@ namespace MWGui mPtr = actor; mNameEdit->setCaption({}); + MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); + if (Settings::gui().mControllerMenus && winMgr->getControllerTooltip()) + { + winMgr->setCursorActive(false); + winMgr->setControllerTooltip(false); + } + startEditing(); } @@ -1048,6 +1057,12 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); } } + else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK) + { + // Toggle info tooltip + MWBase::Environment::get().getWindowManager()->setControllerTooltip( + !MWBase::Environment::get().getWindowManager()->getControllerTooltip()); + } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) { if (mRightColumn && mEffectButtons.size() > 0) @@ -1108,6 +1123,13 @@ namespace MWGui mAvailableEffectsList->setViewOffset(-lineHeight * (mAvailableFocus - 5)); } + if (!mRightColumn && mAvailableFocus >= 0 && mAvailableFocus < mAvailableButtons.size()) + { + // Warp the mouse to the selected spell to show the tooltip + if (MWBase::Environment::get().getWindowManager()->getControllerTooltip()) + MWBase::Environment::get().getInputManager()->warpMouseToWidget(mAvailableButtons[mAvailableFocus]); + } + return true; } } From be32cbb4139ed7e10bf174c95ffec18c6db62103 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sat, 7 Jun 2025 22:51:29 -0700 Subject: [PATCH 092/330] Fix clang format issues --- apps/openmw/mwgui/alchemywindow.cpp | 3 ++- apps/openmw/mwgui/class.cpp | 4 ++-- apps/openmw/mwgui/confirmationdialog.cpp | 4 ++-- apps/openmw/mwgui/container.cpp | 11 ++++----- .../openmw/mwgui/controllerbuttonsoverlay.cpp | 3 ++- apps/openmw/mwgui/dialogue.cpp | 11 +++++---- apps/openmw/mwgui/inventorywindow.cpp | 24 ++++++++++++------- apps/openmw/mwgui/itemview.cpp | 4 ++-- apps/openmw/mwgui/journalwindow.cpp | 15 ++++++++---- apps/openmw/mwgui/levelupdialog.cpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 6 ++--- apps/openmw/mwgui/quickkeysmenu.cpp | 3 +-- apps/openmw/mwgui/recharge.cpp | 3 +-- apps/openmw/mwgui/repair.cpp | 3 +-- apps/openmw/mwgui/review.cpp | 8 +++---- apps/openmw/mwgui/savegamedialog.cpp | 11 +++++---- apps/openmw/mwgui/spellcreationdialog.cpp | 18 +++++--------- apps/openmw/mwgui/spellcreationdialog.hpp | 2 +- apps/openmw/mwgui/spellview.cpp | 2 +- apps/openmw/mwgui/spellview.hpp | 2 +- apps/openmw/mwgui/tradewindow.cpp | 8 +++---- apps/openmw/mwgui/windowmanagerimp.cpp | 9 ++++--- apps/openmw/mwinput/controllermanager.cpp | 4 +--- 23 files changed, 80 insertions(+), 80 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index f79abf11c5..074250985c 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -552,7 +552,8 @@ namespace MWGui bool AlchemyWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); - bool isFilterListOpen = focus != nullptr && focus->getParent() != nullptr && focus->getParent()->getParent() == mFilterValue; + bool isFilterListOpen + = focus != nullptr && focus->getParent() != nullptr && focus->getParent()->getParent() == mFilterValue; if (isFilterListOpen) { diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index f0fe5537da..730ade1615 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -91,8 +91,8 @@ namespace MWGui { onBackClicked(mBackButton); } - else if ((arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && mOkButtonFocus) || - (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && !mOkButtonFocus)) + else if ((arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && mOkButtonFocus) + || (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && !mOkButtonFocus)) { mOkButtonFocus = !mOkButtonFocus; mOkButton->setStateSelected(mOkButtonFocus); diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index 36b01112e5..f858b9628a 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -86,8 +86,8 @@ namespace MWGui { onCancelButtonClicked(mCancelButton); } - else if ((arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && !mOkButtonFocus) || - (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && mOkButtonFocus)) + else if ((arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && !mOkButtonFocus) + || (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && mOkButtonFocus)) { mOkButtonFocus = !mOkButtonFocus; mOkButton->setStateSelected(mOkButtonFocus); diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 9fe098f6d5..0be99d38a0 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -127,8 +127,7 @@ namespace MWGui if (!onTakeItem(item, count)) return; - MWGui::InventoryWindow* inventoryWindow - = MWBase::Environment::get().getWindowManager()->getInventoryWindow(); + MWGui::InventoryWindow* inventoryWindow = MWBase::Environment::get().getWindowManager()->getInventoryWindow(); ItemModel* playerModel = inventoryWindow->getModel(); mModel->moveItem(item, count, playerModel); @@ -385,11 +384,9 @@ namespace MWGui if (mDisposeCorpseButton->getVisible()) onDisposeCorpseButtonClicked(mDisposeCorpseButton); } - else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK || - arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP || - arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN || - arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT || - arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK || arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP + || arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN || arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT + || arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) { mItemView->onControllerButton(arg.button); } diff --git a/apps/openmw/mwgui/controllerbuttonsoverlay.cpp b/apps/openmw/mwgui/controllerbuttonsoverlay.cpp index f4b35ac4de..96438fa583 100644 --- a/apps/openmw/mwgui/controllerbuttonsoverlay.cpp +++ b/apps/openmw/mwgui/controllerbuttonsoverlay.cpp @@ -75,7 +75,8 @@ namespace MWGui setVisible(buttonCount > 0); } - int ControllerButtonsOverlay::updateButton(MyGUI::TextBox* text, MyGUI::ImageBox* image, const std::string& buttonStr) + int ControllerButtonsOverlay::updateButton( + MyGUI::TextBox* text, MyGUI::ImageBox* image, const std::string& buttonStr) { if (buttonStr.length() > 0) { diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index d409cd8856..5c325a52d3 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -603,10 +603,10 @@ namespace MWGui void DialogueWindow::updateTopicsPane() { - const std::string focusedTopic = - Settings::gui().mControllerMenus && mControllerFocus < mTopicsList->getItemCount() - ? mTopicsList->getItemNameAt(mControllerFocus) - : ""; + const std::string focusedTopic + = Settings::gui().mControllerMenus && mControllerFocus < mTopicsList->getItemCount() + ? mTopicsList->getItemNameAt(mControllerFocus) + : ""; mTopicsList->clear(); for (auto& linkPair : mTopicLinks) @@ -931,7 +931,8 @@ namespace MWGui { mGoodbyeButton->setStateSelected(focused); } - else { + else + { std::string keyword = mTopicsList->getItemNameAt(mControllerFocus); if (keyword.length() == 0) return; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index b735d89cf8..fd06286a6c 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -941,15 +941,19 @@ namespace MWGui else if (mGuiMode == MWGui::GM_Companion && mDragAndDrop->mIsOnDragAndDrop) { // Drag and drop the item on the companion's window. - MWGui::CompanionWindow* companionWindow = - (MWGui::CompanionWindow *)MWBase::Environment::get().getWindowManager()->getGuiModeWindows(mGuiMode).at(0); + MWGui::CompanionWindow* companionWindow = (MWGui::CompanionWindow*)MWBase::Environment::get() + .getWindowManager() + ->getGuiModeWindows(mGuiMode) + .at(0); mDragAndDrop->drop(companionWindow->getModel(), companionWindow->getItemView()); } else if (mGuiMode == MWGui::GM_Container && mDragAndDrop->mIsOnDragAndDrop) { // Drag and drop the item on the container window. - MWGui::ContainerWindow* containerWindow = - (MWGui::ContainerWindow *)MWBase::Environment::get().getWindowManager()->getGuiModeWindows(mGuiMode).at(0); + MWGui::ContainerWindow* containerWindow = (MWGui::ContainerWindow*)MWBase::Environment::get() + .getWindowManager() + ->getGuiModeWindows(mGuiMode) + .at(0); mDragAndDrop->drop(containerWindow->getModel(), containerWindow->getItemView()); } // GM_Barter is handled by onControllerButtonEvent. No other steps are necessary. @@ -967,16 +971,20 @@ namespace MWGui { // Take all. Pass the button press to the container window and let it do the // logic of taking all. - MWGui::ContainerWindow* containerWindow = - (MWGui::ContainerWindow *)MWBase::Environment::get().getWindowManager()->getGuiModeWindows(mGuiMode).at(0); + MWGui::ContainerWindow* containerWindow = (MWGui::ContainerWindow*)MWBase::Environment::get() + .getWindowManager() + ->getGuiModeWindows(mGuiMode) + .at(0); containerWindow->onControllerButtonEvent(arg); } else if (mGuiMode == MWGui::GM_Barter) { // Offer. Pass the button press to the barter window and let it do the logic // of making an offer. - MWGui::TradeWindow* tradeWindow = - (MWGui::TradeWindow*)MWBase::Environment::get().getWindowManager()->getGuiModeWindows(mGuiMode).at(1); + MWGui::TradeWindow* tradeWindow = (MWGui::TradeWindow*)MWBase::Environment::get() + .getWindowManager() + ->getGuiModeWindows(mGuiMode) + .at(1); tradeWindow->onControllerButtonEvent(arg); } } diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index 3d8cf91f8a..464cec5800 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -268,14 +268,14 @@ namespace MWGui if (prevFocus >= 0 && prevFocus < mItemCount) { - ItemWidget* prev = (ItemWidget *)dragArea->getChildAt(prevFocus); + ItemWidget* prev = (ItemWidget*)dragArea->getChildAt(prevFocus); if (prev) prev->setControllerFocus(false); } if (mControllerActiveWindow && newFocus >= 0 && newFocus < mItemCount) { - ItemWidget* focused = (ItemWidget *)dragArea->getChildAt(newFocus); + ItemWidget* focused = (ItemWidget*)dragArea->getChildAt(newFocus); if (focused) { focused->setControllerFocus(true); diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index bff4b66c72..77918f2a89 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -496,7 +496,8 @@ namespace MyGUI::Button* listItem = _list->getItemWidget(_list->getItemNameAt(i)); if (listItem) { - listItem->setTextColour(mButtons.size() == _selectedIndex ? MWGui::journalHeaderColour : MyGUI::Colour::Black); + listItem->setTextColour( + mButtons.size() == _selectedIndex ? MWGui::journalHeaderColour : MyGUI::Colour::Black); mButtons.push_back(listItem); } } @@ -737,8 +738,10 @@ namespace // Choose an index. Cyrillic capital A is a 0xd090 in UTF-8. // Words can not be started with characters 26 or 28. int russianOffset = 0xd090; - if (mSelectedIndex >= 26) russianOffset++; - if (mSelectedIndex >= 27) russianOffset++; // 27, not 28, because of skipping char 26 + if (mSelectedIndex >= 26) + russianOffset++; + if (mSelectedIndex >= 27) + russianOffset++; // 27, not 28, because of skipping char 26 notifyIndexLinkClicked(isRussian ? mSelectedIndex + russianOffset : mSelectedIndex + 'A'); } return true; @@ -776,7 +779,8 @@ namespace notifyCancel(getWidget(CancelBTN)); mQuestMode = false; } - else { + else + { // Show the quest overlay if viewing a journal entry or the topics if (!mOptionsMode) notifyOptions(getWidget(OptionsBTN)); @@ -793,7 +797,8 @@ namespace notifyCancel(getWidget(CancelBTN)); mQuestMode = false; } - else { + else + { // Show the topics overlay if viewing a journal entry or the quest list if (!mOptionsMode) notifyOptions(getWidget(OptionsBTN)); diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index de79e2a8b3..8b022258cf 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -387,7 +387,7 @@ namespace MWGui if (arg.button == SDL_CONTROLLER_BUTTON_A) { if (mControllerFocus >= 0 && mControllerFocus < mAttributeButtons.size()) - onAttributeClicked(mAttributeButtons[mControllerFocus]); + onAttributeClicked(mAttributeButtons[mControllerFocus]); MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Item Gold Up")); } else if (arg.button == SDL_CONTROLLER_BUTTON_X) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 1c1920f0b2..fb2074570f 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -1440,14 +1440,12 @@ namespace MWGui { mNeedDoorMarkersUpdate = true; mLocalMap->setViewOffset( - MyGUI::IntPoint( - mLocalMap->getViewOffset().left + dx, mLocalMap->getViewOffset().top + dy)); + MyGUI::IntPoint(mLocalMap->getViewOffset().left + dx, mLocalMap->getViewOffset().top + dy)); } else { mGlobalMap->setViewOffset( - MyGUI::IntPoint( - mGlobalMap->getViewOffset().left + dx, mGlobalMap->getViewOffset().top + dy)); + MyGUI::IntPoint(mGlobalMap->getViewOffset().left + dx, mGlobalMap->getViewOffset().top + dy)); } } diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index daf49e1101..b834df83e2 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -469,8 +469,7 @@ namespace MWGui onQuickKeyButtonClicked(mKey[mControllerFocus].button); if (arg.button == SDL_CONTROLLER_BUTTON_B) onOkButtonClicked(mOkButton); - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP || - arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP || arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) mControllerFocus = (mControllerFocus + 5) % 10; else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) { diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index bf71972d0d..cfe7fedc60 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -142,8 +142,7 @@ namespace MWGui bool Recharge::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { - if ((arg.button == SDL_CONTROLLER_BUTTON_A && !mGemBox->getVisible()) - || arg.button == SDL_CONTROLLER_BUTTON_Y) + if ((arg.button == SDL_CONTROLLER_BUTTON_A && !mGemBox->getVisible()) || arg.button == SDL_CONTROLLER_BUTTON_Y) { onSelectItem(mGemIcon); MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index c1241f53f5..8dbac7ef48 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -156,8 +156,7 @@ namespace MWGui bool Repair::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { - if ((arg.button == SDL_CONTROLLER_BUTTON_A && !mToolBox->getVisible()) - || arg.button == SDL_CONTROLLER_BUTTON_Y) + if ((arg.button == SDL_CONTROLLER_BUTTON_A && !mToolBox->getVisible()) || arg.button == SDL_CONTROLLER_BUTTON_Y) { onSelectItem(mToolIcon); MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 003cdb49cb..dcaa49b1e2 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -542,7 +542,7 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - switch(mControllerFocus) + switch (mControllerFocus) { case 0: onNameClicked(mButtons[0]); @@ -573,15 +573,13 @@ namespace MWGui { onOkClicked(mButtons[5]); } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP || - arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP || arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) { setControllerFocus(mButtons, mControllerFocus, false); mControllerFocus = wrap(mControllerFocus - 1, mButtons.size()); setControllerFocus(mButtons, mControllerFocus, true); } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN || - arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN || arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) { setControllerFocus(mButtons, mControllerFocus, false); mControllerFocus = wrap(mControllerFocus + 1, mButtons.size()); diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 7e9067b81a..61cbae81f0 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -163,10 +163,11 @@ namespace MWGui hour = 12; ESM::EpochTimeStamp currentDate = timeManager.getEpochTimeStamp(); - std::string daysPassed = Misc::StringUtils::format("#{Calendar:day} %i", timeManager.getTimeStamp().getDay()); + std::string daysPassed + = Misc::StringUtils::format("#{Calendar:day} %i", timeManager.getTimeStamp().getDay()); std::string_view formattedHour(pm ? "#{Calendar:pm}" : "#{Calendar:am}"); - std::string autoFilename - = Misc::StringUtils::format("%s - %i %s %i %s", daysPassed, currentDate.mDay, month, hour, formattedHour); + std::string autoFilename = Misc::StringUtils::format( + "%s - %i %s %i %s", daysPassed, currentDate.mDay, month, hour, formattedHour); mSaveNameEdit->setCaptionWithReplacing(autoFilename); } @@ -561,8 +562,8 @@ namespace MWGui winMgr->setKeyFocusWidget(mSaveList); winMgr->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); } - else if ((arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && !mOkButtonFocus) || - (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && mOkButtonFocus)) + else if ((arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && !mOkButtonFocus) + || (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && mOkButtonFocus)) { mOkButtonFocus = !mOkButtonFocus; mOkButton->setStateSelected(mOkButtonFocus); diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 119a32ffea..5085464fdb 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -13,8 +13,8 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/inputmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwworld/class.hpp" @@ -550,10 +550,8 @@ namespace MWGui if (prevFocus >= 0 && prevFocus < mButtons.size()) { MyGUI::TextBox* button = mButtons[prevFocus]; - if (button == mMagnitudeMinValue || - button == mMagnitudeMaxValue || - button == mDurationValue || - button == mAreaValue) + if (button == mMagnitudeMinValue || button == mMagnitudeMaxValue || button == mDurationValue + || button == mAreaValue) { button->setTextColour(textColours.normal); } @@ -566,10 +564,8 @@ namespace MWGui if (newFocus >= 0 && newFocus < mButtons.size()) { MyGUI::TextBox* button = mButtons[newFocus]; - if (button == mMagnitudeMinValue || - button == mMagnitudeMaxValue || - button == mDurationValue || - button == mAreaValue) + if (button == mMagnitudeMinValue || button == mMagnitudeMaxValue || button == mDurationValue + || button == mAreaValue) { button->setTextColour(textColours.link); } @@ -744,7 +740,6 @@ namespace MWGui mSuccessChance->setCaption(MyGUI::utility::toString(intChance)); } - bool SpellCreationDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { if (arg.button == SDL_CONTROLLER_BUTTON_B) @@ -761,7 +756,6 @@ namespace MWGui return EffectEditorBase::onControllerButtonEvent(arg); } - // ------------------------------------------------------------------------------------------------ EffectEditorBase::EffectEditorBase(Type type) @@ -856,7 +850,7 @@ namespace MWGui mEffectFocus = 0; mRightColumn = false; if (mAvailableButtons.size() > 0) - mAvailableButtons[0]->setStateSelected(true); + mAvailableButtons[0]->setStateSelected(true); } } diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index cbd57014ce..2a4f5dcbb3 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -1,8 +1,8 @@ #ifndef MWGUI_SPELLCREATION_H #define MWGUI_SPELLCREATION_H -#include #include +#include #include #include diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index 8a18eb440f..b05d0c0435 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -393,7 +393,7 @@ namespace MWGui void SpellView::updateControllerFocus(int prevFocus, int newFocus) { if (mButtons.empty()) - return; + return; if (prevFocus >= 0 && prevFocus < mButtons.size()) { diff --git a/apps/openmw/mwgui/spellview.hpp b/apps/openmw/mwgui/spellview.hpp index 5a22dcb4d9..234ce08626 100644 --- a/apps/openmw/mwgui/spellview.hpp +++ b/apps/openmw/mwgui/spellview.hpp @@ -95,7 +95,7 @@ namespace MWGui void adjustSpellWidget(const Spell& spell, SpellModel::ModelIndex index, MyGUI::Widget* widget); /// Keep a list of buttons for controller navigation and their index in the full list. - std::vector> mButtons; + std::vector> mButtons; /// Keep a list of group offsets for controller navigation std::vector mGroupIndices; diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index fbbd98cc31..f4f88dda04 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -733,11 +733,9 @@ namespace MWGui onFilterChanged(mFilterAll); MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); } - else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK || - arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP || - arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN || - arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT || - arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK || arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP + || arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN || arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT + || arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) { mItemView->onControllerButton(arg.button); } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 5b32cb8709..7ab909983e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -898,7 +898,8 @@ namespace MWGui int activeIndex = std::clamp(mActiveControllerWindows[mode], 0, (int)state.mWindows.size() - 1); - Log(Debug::Debug) << "Getting active controller window: mode=" << mode << ", " << state.mWindows.size() << " window(s), activeIndex=" << activeIndex; + Log(Debug::Debug) << "Getting active controller window: mode=" << mode << ", " << state.mWindows.size() + << " window(s), activeIndex=" << activeIndex; // If the active window is no longer visible, find the next visible window. if (!state.mWindows[activeIndex]->isVisible()) @@ -1903,7 +1904,8 @@ namespace MWGui { // If using controller menus, don't persist changes to size of the stats or magic // windows. - if (Settings::gui().mControllerMenus && (window == (MyGUI::Window*)mStatsWindow || window == (MyGUI::Window*)mSpellWindow)) + if (Settings::gui().mControllerMenus + && (window == (MyGUI::Window*)mStatsWindow || window == (MyGUI::Window*)mSpellWindow)) return; const auto it = mTrackedWindows.find(window); @@ -2616,7 +2618,8 @@ namespace MWGui // setButtons will handle setting visibility based on if any buttons are defined. mControllerButtonsOverlay->setButtons(topWin->getControllerButtons()); - if (getMode() == GM_Inventory) { + if (getMode() == GM_Inventory) + { mInventoryTabsOverlay->setVisible(true); mInventoryTabsOverlay->setTab(mActiveControllerWindows[GM_Inventory]); } diff --git a/apps/openmw/mwinput/controllermanager.cpp b/apps/openmw/mwinput/controllermanager.cpp index ac2e07e0cc..b6994cc3d6 100644 --- a/apps/openmw/mwinput/controllermanager.cpp +++ b/apps/openmw/mwinput/controllermanager.cpp @@ -255,9 +255,7 @@ namespace MWInput { // When the inventory tooltip is visible, we don't actually want the A button to // act like a mouse button; it should act normally. - if (treatAsMouse - && arg.button == SDL_CONTROLLER_BUTTON_A - && winMgr->getControllerTooltip()) + if (treatAsMouse && arg.button == SDL_CONTROLLER_BUTTON_A && winMgr->getControllerTooltip()) treatAsMouse = false; mGamepadGuiCursorEnabled = topWin->isGamepadCursorAllowed(); From ba9d85dc30de351985e06fe3bf529458858f5ba7 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sat, 7 Jun 2025 23:18:48 -0700 Subject: [PATCH 093/330] Run lupdate and add translations --- files/lang/launcher_de.ts | 8 ++++++++ files/lang/launcher_en.ts | 8 ++++++++ files/lang/launcher_fr.ts | 8 ++++++++ files/lang/launcher_ru.ts | 8 ++++++++ files/lang/launcher_sv.ts | 8 ++++++++ 5 files changed, 40 insertions(+) diff --git a/files/lang/launcher_de.ts b/files/lang/launcher_de.ts index 86773e5a54..c4af468e8c 100644 --- a/files/lang/launcher_de.ts +++ b/files/lang/launcher_de.ts @@ -1447,5 +1447,13 @@ to default Morrowind fonts. Check this box if you still prefer original fonts ov Run Script After Startup: + + <html><head/><body><p>Make it easier to use game menus with a controller.</p></body></html> + + + + Enable Controller Menus + + diff --git a/files/lang/launcher_en.ts b/files/lang/launcher_en.ts index a0319318e8..5c24c3fa7d 100644 --- a/files/lang/launcher_en.ts +++ b/files/lang/launcher_en.ts @@ -1447,5 +1447,13 @@ to default Morrowind fonts. Check this box if you still prefer original fonts ov <html><head/><body><p>If enabled - makes transitions between different animations/poses much smoother. Also allows to load animation blending config YAML files that can be bundled with animations in order to customise blending styles.</p></body></html> + + <html><head/><body><p>Make it easier to use game menus with a controller.</p></body></html> + + + + Enable Controller Menus + + diff --git a/files/lang/launcher_fr.ts b/files/lang/launcher_fr.ts index 569a460cd0..413a207abe 100644 --- a/files/lang/launcher_fr.ts +++ b/files/lang/launcher_fr.ts @@ -1450,5 +1450,13 @@ to default Morrowind fonts. Check this box if you still prefer original fonts ov Run Script After Startup: Script à lancer après démarrage : + + Enable Controller Menus + Activer les menus du contrôleur + + + <html><head/><body><p>Make it easier to use game menus with a controller.</p></body></html> + <html><head/><body><p>Faciliter l'utilisation des menus de jeu avec une manette.</p></body></html> + diff --git a/files/lang/launcher_ru.ts b/files/lang/launcher_ru.ts index 879f24dc76..189f8fdaee 100644 --- a/files/lang/launcher_ru.ts +++ b/files/lang/launcher_ru.ts @@ -1462,5 +1462,13 @@ to default Morrowind fonts. Check this box if you still prefer original fonts ov Use the Camera as the Sound Listener Использовать камеру как слушателя + + <html><head/><body><p>Make it easier to use game menus with a controller.</p></body></html> + + + + Enable Controller Menus + + diff --git a/files/lang/launcher_sv.ts b/files/lang/launcher_sv.ts index f2cca2346c..f86e15532f 100644 --- a/files/lang/launcher_sv.ts +++ b/files/lang/launcher_sv.ts @@ -1466,5 +1466,13 @@ de ordinarie fonterna i Morrowind. Bocka denna ruta om du ändå föredrar ordin <html><head/><body><p>If enabled - makes transitions between different animations/poses much smoother. Also allows to load animation blending config YAML files that can be bundled with animations in order to customise blending styles.</p></body></html> <html><head/><body><p>Vid aktivering gör denna funktion att övergångarna mellan olika animationer och poser blir mycket mjukare. Funktionen gör det också möjligt att konfigurera animationsövergångarna i YAML-filer. Dessa filer kan buntas ihop tillsammans med nya animationsfiler.</p></body></html> + + <html><head/><body><p>Make it easier to use game menus with a controller.</p></body></html> + <html><head/><body><p>Gör det enklare att använda spelmenyer med en handkontroll.</p></body></html> + + + Enable Controller Menus + Aktivera kontrollmenyer + From 81720892f9a5ec0307df2c6243d9133b259f1a02 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 8 Jun 2025 00:10:47 -0700 Subject: [PATCH 094/330] Fix compiler warnings --- apps/openmw/mwbase/windowmanager.hpp | 2 +- apps/openmw/mwgui/windowbase.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index ee1990878a..83a714cf05 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -390,7 +390,7 @@ namespace MWBase /// Cycle to the next window to receive controller events virtual void cycleActiveControllerWindow(bool next) = 0; virtual void setActiveControllerWindow(MWGui::GuiMode mode, int activeIndex) = 0; - virtual const bool getControllerTooltip() const = 0; + virtual bool getControllerTooltip() const = 0; virtual void setControllerTooltip(bool enabled) = 0; virtual void updateControllerButtonsOverlay() = 0; diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index 87bea55e38..0be84f12eb 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -80,8 +80,8 @@ namespace MWGui virtual ControllerButtonStr* getControllerButtons() { return &mControllerButtons; } MyGUI::Widget* getControllerScrollWidget() { return mControllerScrollWidget; } bool isGamepadCursorAllowed() { return !mDisableGamepadCursor; } - virtual bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { return true; }; - virtual bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) { return true; }; + virtual bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { return true; } + virtual bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) { return true; } virtual void setActiveControllerWindow(bool active) { mActiveControllerWindow = active; } protected: From 8094761c3e42a13b6b1d61a6e49614f4d594cfa5 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 8 Jun 2025 02:28:42 -0700 Subject: [PATCH 095/330] Fix sign-compare warnings --- apps/openmw/mwgui/bookpage.cpp | 6 ++--- apps/openmw/mwgui/class.cpp | 8 +++--- apps/openmw/mwgui/dialogue.cpp | 20 +++++++-------- apps/openmw/mwgui/inventorytabsoverlay.cpp | 4 +-- apps/openmw/mwgui/itemchargeview.cpp | 6 ++--- apps/openmw/mwgui/itemview.cpp | 2 +- apps/openmw/mwgui/journalwindow.cpp | 4 +-- apps/openmw/mwgui/levelupdialog.cpp | 4 +-- apps/openmw/mwgui/merchantrepair.cpp | 4 +-- apps/openmw/mwgui/messagebox.cpp | 4 +-- apps/openmw/mwgui/quickkeysmenu.cpp | 4 +-- apps/openmw/mwgui/spellbuyingwindow.cpp | 4 +-- apps/openmw/mwgui/spellcreationdialog.cpp | 30 +++++++++++----------- apps/openmw/mwgui/spellview.cpp | 10 ++++---- apps/openmw/mwgui/trainingwindow.cpp | 2 +- apps/openmw/mwgui/travelwindow.cpp | 2 +- apps/openmw/mwgui/windowbase.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- 18 files changed, 59 insertions(+), 59 deletions(-) diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 113ac7d104..d014910c74 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -107,11 +107,11 @@ namespace MWGui void setColour(int section, int line, int run, MyGUI::Colour colour) const override { - if (section < 0 || section >= mSections.size()) + if (section < 0 || section >= static_cast(mSections.size())) return; - if (line < 0 || line >= mSections[section].mLines.size()) + if (line < 0 || line >= static_cast(mSections[section].mLines.size())) return; - if (run < 0 || run >= mSections[section].mLines[line].mRuns.size()) + if (run < 0 || run >= static_cast(mSections[section].mLines[line].mRuns.size())) return; mSections[section].mLines[line].mRuns[run].mStyle->mNormalColour = colour; diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 730ade1615..450a61b4f8 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -467,7 +467,7 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - if (mControllerFocus >= 0 && mControllerFocus < mButtons.size()) + if (mControllerFocus >= 0 && mControllerFocus < static_cast(mButtons.size())) onButtonClicked(mButtons[mControllerFocus]); } else if (arg.button == SDL_CONTROLLER_BUTTON_B) @@ -490,7 +490,7 @@ namespace MWGui { if (mButtons.size() <= 1) return true; - if (mButtons.size() == 2 && mControllerFocus == mButtons.size() - 1) + if (mButtons.size() == 2 && mControllerFocus == static_cast(mButtons.size()) - 1) return true; setControllerFocus(mButtons, mControllerFocus, false); @@ -992,7 +992,7 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - if (mControllerFocus >= 0 && mControllerFocus < mAttributeButtons.size()) + if (mControllerFocus >= 0 && mControllerFocus < static_cast(mAttributeButtons.size())) onAttributeClicked(mAttributeButtons[mControllerFocus]); } else if (arg.button == SDL_CONTROLLER_BUTTON_B) @@ -1094,7 +1094,7 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - if (mControllerFocus >= 0 && mControllerFocus < mSkillButtons.size()) + if (mControllerFocus >= 0 && mControllerFocus < static_cast(mSkillButtons.size())) onSkillClicked(mSkillButtons[mControllerFocus]); } else if (arg.button == SDL_CONTROLLER_BUTTON_B) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 5c325a52d3..fe3675f6fb 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -162,7 +162,7 @@ namespace MWGui if (mBribe1000Button->getEnabled()) mButtons.push_back(mBribe1000Button); - for (int i = 0; i < mButtons.size(); i++) + for (size_t i = 0; i < mButtons.size(); i++) mButtons[i]->setStateSelected(i == 0); } @@ -604,7 +604,7 @@ namespace MWGui void DialogueWindow::updateTopicsPane() { const std::string focusedTopic - = Settings::gui().mControllerMenus && mControllerFocus < mTopicsList->getItemCount() + = Settings::gui().mControllerMenus && mControllerFocus < static_cast(mTopicsList->getItemCount()) ? mTopicsList->getItemNameAt(mControllerFocus) : ""; @@ -924,10 +924,10 @@ namespace MWGui void DialogueWindow::setControllerFocus(int index, bool focused) { // List is mTopicsList + "Goodbye" button below the list. - if (index < 0 || index > mTopicsList->getItemCount()) + if (index < 0 || index > static_cast(mTopicsList->getItemCount())) return; - if (index == mTopicsList->getItemCount()) + if (index == static_cast(mTopicsList->getItemCount())) { mGoodbyeButton->setStateSelected(focused); } @@ -957,10 +957,10 @@ namespace MWGui { if (mChoices.size() > 0) { - if (mControllerChoice >= 0 && mControllerChoice < mChoices.size()) + if (mControllerChoice >= 0 && mControllerChoice < static_cast(mChoices.size())) onChoiceActivated(mControllerChoice + 1); // +1 because choices are indexed starting at 1 } - else if (mControllerFocus == mTopicsList->getItemCount()) + else if (mControllerFocus == static_cast(mTopicsList->getItemCount())) onGoodbyeActivated(); else onSelectListItem(mTopicsList->getItemNameAt(mControllerFocus), mControllerFocus); @@ -975,7 +975,7 @@ namespace MWGui if (mChoices.size() > 0) { // In-dialogue choice (red text) - mControllerChoice = std::clamp(mControllerChoice - 1, 0, (int)mChoices.size() - 1); + mControllerChoice = std::clamp(mControllerChoice - 1, 0, static_cast(mChoices.size()) - 1); mHistory->setFocusItem(mChoiceStyles.at(mControllerChoice)); } else @@ -996,16 +996,16 @@ namespace MWGui if (mChoices.size() > 0) { // In-dialogue choice (red text) - mControllerChoice = std::clamp(mControllerChoice + 1, 0, (int)mChoices.size() - 1); + mControllerChoice = std::clamp(mControllerChoice + 1, 0, static_cast(mChoices.size()) - 1); mHistory->setFocusItem(mChoiceStyles.at(mControllerChoice)); } else { // Number of items is mTopicsList.length+1 because of "Goodbye" button. setControllerFocus(mControllerFocus, false); - if (mControllerFocus >= mTopicsList->getItemCount()) + if (mControllerFocus >= static_cast(mTopicsList->getItemCount())) mControllerFocus = 0; - else if (mControllerFocus == mTopicsList->getItemCount() - 1) + else if (mControllerFocus == static_cast(mTopicsList->getItemCount()) - 1) mControllerFocus = mTopicsList->getItemCount(); // "Goodbye" button else if (mTopicsList->getItemNameAt(mControllerFocus + 1).length() == 0) mControllerFocus += 2; // Skip separator diff --git a/apps/openmw/mwgui/inventorytabsoverlay.cpp b/apps/openmw/mwgui/inventorytabsoverlay.cpp index 14fd110830..35b4d1d87f 100644 --- a/apps/openmw/mwgui/inventorytabsoverlay.cpp +++ b/apps/openmw/mwgui/inventorytabsoverlay.cpp @@ -32,7 +32,7 @@ namespace MWGui if (!MWBase::Environment::get().getWindowManager()->getJournalAllowed()) return; - for (int i = 0; i < mTabs.size(); i++) + for (int i = 0; i < static_cast(mTabs.size()); i++) { if (mTabs[i] == sender) { @@ -45,7 +45,7 @@ namespace MWGui void InventoryTabsOverlay::setTab(int index) { - for (int i = 0; i < mTabs.size(); i++) + for (int i = 0; i < static_cast(mTabs.size()); i++) mTabs[i]->setStateSelected(i == index); } } diff --git a/apps/openmw/mwgui/itemchargeview.cpp b/apps/openmw/mwgui/itemchargeview.cpp index 0b9ea842d9..31b29122f3 100644 --- a/apps/openmw/mwgui/itemchargeview.cpp +++ b/apps/openmw/mwgui/itemchargeview.cpp @@ -249,7 +249,7 @@ namespace MWGui if (button == SDL_CONTROLLER_BUTTON_A) { // Select the focused item, if any. - if (mControllerFocus >= 0 && mControllerFocus < mLines.size()) + if (mControllerFocus >= 0 && mControllerFocus < static_cast(mLines.size())) onIconClicked(mLines[mControllerFocus].mIcon); } else if (button == SDL_CONTROLLER_BUTTON_DPAD_UP) @@ -268,13 +268,13 @@ namespace MWGui const TextColours& textColours{ MWBase::Environment::get().getWindowManager()->getTextColours() }; - if (prevFocus >= 0 && prevFocus < mLines.size()) + if (prevFocus >= 0 && prevFocus < static_cast(mLines.size())) { mLines[prevFocus].mText->setTextColour(textColours.normal); mLines[prevFocus].mIcon->setControllerFocus(false); } - if (newFocus >= 0 && newFocus < mLines.size()) + if (newFocus >= 0 && newFocus < static_cast(mLines.size())) { mLines[newFocus].mText->setTextColour(textColours.link); mLines[newFocus].mIcon->setControllerFocus(true); diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index 464cec5800..c114db5e35 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -61,7 +61,7 @@ namespace MWGui mRows = std::max(maxHeight / 42, 1); } - for (unsigned int i = 0; i < mItemCount; ++i) + for (int i = 0; i < mItemCount; ++i) { MyGUI::Widget* w = dragArea->getChildAt(i); diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 77918f2a89..23adfc5a58 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -491,13 +491,13 @@ namespace void addControllerButtons(Gui::MWList* _list, int _selectedIndex) { mButtons.clear(); - for (int i = 0; i < _list->getItemCount(); i++) + for (size_t i = 0; i < _list->getItemCount(); i++) { MyGUI::Button* listItem = _list->getItemWidget(_list->getItemNameAt(i)); if (listItem) { listItem->setTextColour( - mButtons.size() == _selectedIndex ? MWGui::journalHeaderColour : MyGUI::Colour::Black); + static_cast(mButtons.size()) == _selectedIndex ? MWGui::journalHeaderColour : MyGUI::Colour::Black); mButtons.push_back(listItem); } } diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index 8b022258cf..b9c90e51e2 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -231,7 +231,7 @@ namespace MWGui if (Settings::gui().mControllerMenus) { mControllerFocus = 0; - for (int i = 0; i < mAttributeButtons.size(); i++) + for (size_t i = 0; i < mAttributeButtons.size(); i++) setControllerFocus(mAttributeButtons, i, i == 0); } @@ -386,7 +386,7 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - if (mControllerFocus >= 0 && mControllerFocus < mAttributeButtons.size()) + if (mControllerFocus >= 0 && mControllerFocus < static_cast(mAttributeButtons.size())) onAttributeClicked(mAttributeButtons[mControllerFocus]); MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Item Gold Up")); } diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index c659cac139..7eb10def39 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -178,7 +178,7 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - if (mControllerFocus >= 0 && mControllerFocus < mButtons.size()) + if (mControllerFocus >= 0 && mControllerFocus < static_cast(mButtons.size())) onRepairButtonClick(mButtons[mControllerFocus].first); } else if (arg.button == SDL_CONTROLLER_BUTTON_B) @@ -205,7 +205,7 @@ namespace MWGui } // Scroll the list to keep the active item in view - if (mControllerFocus >= 0 && mControllerFocus < mButtons.size()) + if (mControllerFocus >= 0 && mControllerFocus < static_cast(mButtons.size())) { int line = mButtons[mControllerFocus].second; if (line <= 5) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 492ac30052..c7e997a565 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -446,7 +446,7 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - mControllerFocus = std::clamp(mControllerFocus, 0, (int)mButtons.size() - 1); + mControllerFocus = std::clamp(mControllerFocus, 0, static_cast(mButtons.size()) - 1); buttonActivated(mButtons[mControllerFocus]); } else if (arg.button == SDL_CONTROLLER_BUTTON_B) @@ -469,7 +469,7 @@ namespace MWGui { if (mButtons.size() <= 1) return true; - if (mButtons.size() == 2 && mControllerFocus == mButtons.size() - 1) + if (mButtons.size() == 2 && mControllerFocus == static_cast(mButtons.size()) - 1) return true; setControllerFocus(mButtons, mControllerFocus, false); diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index b834df83e2..ecbf3e6dfc 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -119,7 +119,7 @@ namespace MWGui if (Settings::gui().mControllerMenus) { mControllerFocus = 0; - for (int i = 0; i < mKey.size(); i++) + for (int i = 0; i < static_cast(mKey.size()); i++) mKey[i].button->setControllerFocus(i == mControllerFocus); } } @@ -490,7 +490,7 @@ namespace MWGui mControllerFocus++; } - for (int i = 0; i < mKey.size(); i++) + for (int i = 0; i < static_cast(mKey.size()); i++) mKey[i].button->setControllerFocus(i == mControllerFocus); return true; diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 3bc38b2e44..754055aee5 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -230,7 +230,7 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - if (mControllerFocus >= 0 && mControllerFocus < mSpellButtons.size()) + if (mControllerFocus >= 0 && mControllerFocus < static_cast(mSpellButtons.size())) onSpellButtonClick(mSpellButtons[mControllerFocus].first); } else if (arg.button == SDL_CONTROLLER_BUTTON_B) @@ -262,7 +262,7 @@ namespace MWGui mSpellButtons[mControllerFocus].first->setStateSelected(true); } - if (mControllerFocus >= 0 && mControllerFocus < mSpellButtons.size()) + if (mControllerFocus >= 0 && mControllerFocus < static_cast(mSpellButtons.size())) { // Scroll the list to keep the active item in view int line = mSpellButtons[mControllerFocus].second; diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 5085464fdb..7ea5118883 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -390,7 +390,7 @@ namespace MWGui bool EditEffectDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { int prevFocus = mControllerFocus; - mControllerFocus = std::clamp(mControllerFocus, 0, (int)mButtons.size() - 1); + mControllerFocus = std::clamp(mControllerFocus, 0, static_cast(mButtons.size()) - 1); MyGUI::TextBox* button = mButtons[mControllerFocus]; if (arg.button == SDL_CONTROLLER_BUTTON_A) @@ -415,7 +415,7 @@ namespace MWGui else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) { if (mControllerFocus == 0) - mControllerFocus = (int)mButtons.size() - 2; + mControllerFocus = static_cast(mButtons.size()) - 2; else if (button == mCancelButton && mDeleteButton->getVisible()) mControllerFocus -= 3; else if (button == mCancelButton || (button == mOkButton && mDeleteButton->getVisible())) @@ -547,7 +547,7 @@ namespace MWGui { const TextColours& textColours{ MWBase::Environment::get().getWindowManager()->getTextColours() }; - if (prevFocus >= 0 && prevFocus < mButtons.size()) + if (prevFocus >= 0 && prevFocus < static_cast(mButtons.size())) { MyGUI::TextBox* button = mButtons[prevFocus]; if (button == mMagnitudeMinValue || button == mMagnitudeMaxValue || button == mDurationValue @@ -561,7 +561,7 @@ namespace MWGui } } - if (newFocus >= 0 && newFocus < mButtons.size()) + if (newFocus >= 0 && newFocus < static_cast(mButtons.size())) { MyGUI::TextBox* button = mButtons[newFocus]; if (button == mMagnitudeMinValue || button == mMagnitudeMaxValue || button == mDurationValue @@ -1040,12 +1040,12 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - if (!mRightColumn && mAvailableFocus >= 0 && mAvailableFocus < mAvailableButtons.size()) + if (!mRightColumn && mAvailableFocus >= 0 && mAvailableFocus < static_cast(mAvailableButtons.size())) { onAvailableEffectClicked(mAvailableButtons[mAvailableFocus]); MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); } - else if (mRightColumn && mEffectFocus >= 0 && mEffectFocus < mEffectButtons.size()) + else if (mRightColumn && mEffectFocus >= 0 && mEffectFocus < static_cast(mEffectButtons.size())) { onEditEffect(mEffectButtons[mEffectFocus].second); MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); @@ -1061,14 +1061,14 @@ namespace MWGui { if (mRightColumn && mEffectButtons.size() > 0) { - if (mEffectFocus >= 0 && mEffectFocus < mEffectButtons.size()) + if (mEffectFocus >= 0 && mEffectFocus < static_cast(mEffectButtons.size())) mEffectButtons[mEffectFocus].first->setStateSelected(false); mEffectFocus = wrap(mEffectFocus - 1, mEffectButtons.size()); mEffectButtons[mEffectFocus].first->setStateSelected(true); } else if (!mRightColumn && mAvailableButtons.size() > 0) { - if (mAvailableFocus >= 0 && mAvailableFocus < mAvailableButtons.size()) + if (mAvailableFocus >= 0 && mAvailableFocus < static_cast(mAvailableButtons.size())) mAvailableButtons[mAvailableFocus]->setStateSelected(false); mAvailableFocus = wrap(mAvailableFocus - 1, mAvailableButtons.size()); mAvailableButtons[mAvailableFocus]->setStateSelected(true); @@ -1078,14 +1078,14 @@ namespace MWGui { if (mRightColumn && mEffectButtons.size() > 0) { - if (mEffectFocus >= 0 && mEffectFocus < mEffectButtons.size()) + if (mEffectFocus >= 0 && mEffectFocus < static_cast(mEffectButtons.size())) mEffectButtons[mEffectFocus].first->setStateSelected(false); mEffectFocus = wrap(mEffectFocus + 1, mEffectButtons.size()); mEffectButtons[mEffectFocus].first->setStateSelected(true); } else if (!mRightColumn && mAvailableButtons.size() > 0) { - if (mAvailableFocus >= 0 && mAvailableFocus < mAvailableButtons.size()) + if (mAvailableFocus >= 0 && mAvailableFocus < static_cast(mAvailableButtons.size())) mAvailableButtons[mAvailableFocus]->setStateSelected(false); mAvailableFocus = wrap(mAvailableFocus + 1, mAvailableButtons.size()); mAvailableButtons[mAvailableFocus]->setStateSelected(true); @@ -1094,17 +1094,17 @@ namespace MWGui else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && mRightColumn) { mRightColumn = false; - if (mEffectFocus >= 0 && mEffectFocus < mEffectButtons.size()) + if (mEffectFocus >= 0 && mEffectFocus < static_cast(mEffectButtons.size())) mEffectButtons[mEffectFocus].first->setStateSelected(false); - if (mAvailableFocus >= 0 && mAvailableFocus < mAvailableButtons.size()) + if (mAvailableFocus >= 0 && mAvailableFocus < static_cast(mAvailableButtons.size())) mAvailableButtons[mAvailableFocus]->setStateSelected(true); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && !mRightColumn && mEffectButtons.size() > 0) { mRightColumn = true; - if (mAvailableFocus >= 0 && mAvailableFocus < mAvailableButtons.size()) + if (mAvailableFocus >= 0 && mAvailableFocus < static_cast(mAvailableButtons.size())) mAvailableButtons[mAvailableFocus]->setStateSelected(false); - if (mEffectFocus >= 0 && mEffectFocus < mEffectButtons.size()) + if (mEffectFocus >= 0 && mEffectFocus < static_cast(mEffectButtons.size())) mEffectButtons[mEffectFocus].first->setStateSelected(true); } @@ -1117,7 +1117,7 @@ namespace MWGui mAvailableEffectsList->setViewOffset(-lineHeight * (mAvailableFocus - 5)); } - if (!mRightColumn && mAvailableFocus >= 0 && mAvailableFocus < mAvailableButtons.size()) + if (!mRightColumn && mAvailableFocus >= 0 && mAvailableFocus < static_cast(mAvailableButtons.size())) { // Warp the mouse to the selected spell to show the tooltip if (MWBase::Environment::get().getWindowManager()->getControllerTooltip()) diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index b05d0c0435..fffd492fb7 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -337,7 +337,7 @@ namespace MWGui if (button == SDL_CONTROLLER_BUTTON_A) { // Select the focused item, if any. - if (mControllerFocus >= 0 && mControllerFocus < mButtons.size()) + if (mControllerFocus >= 0 && mControllerFocus < static_cast(mButtons.size())) { onSpellSelected(mButtons[mControllerFocus].first); MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); @@ -347,7 +347,7 @@ namespace MWGui { // Toggle info tooltip mControllerTooltip = !mControllerTooltip; - if (mControllerTooltip && mControllerFocus >= 0 && mControllerFocus < mButtons.size()) + if (mControllerTooltip && mControllerFocus >= 0 && mControllerFocus < static_cast(mButtons.size())) MWBase::Environment::get().getInputManager()->warpMouseToWidget(mButtons[mControllerFocus].first); } else if (button == SDL_CONTROLLER_BUTTON_DPAD_UP) @@ -357,7 +357,7 @@ namespace MWGui else if (button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) mControllerFocus = std::max(0, mControllerFocus - 10); else if (button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) - mControllerFocus = std::min(mControllerFocus + 10, (int)mButtons.size() - 1); + mControllerFocus = std::min(mControllerFocus + 10, static_cast(mButtons.size()) - 1); else if (button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) { // Jump to first item in previous group @@ -395,14 +395,14 @@ namespace MWGui if (mButtons.empty()) return; - if (prevFocus >= 0 && prevFocus < mButtons.size()) + if (prevFocus >= 0 && prevFocus < static_cast(mButtons.size())) { Gui::SharedStateButton* prev = mButtons[prevFocus].first; if (prev) prev->onMouseLostFocus(nullptr); } - if (newFocus >= 0 && newFocus < mButtons.size()) + if (newFocus >= 0 && newFocus < static_cast(mButtons.size())) { Gui::SharedStateButton* focused = mButtons[newFocus].first; if (focused) diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index d5c4f7efbc..5b4d355e61 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -251,7 +251,7 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - if (mControllerFocus >= 0 && mControllerFocus < mTrainingButtons.size()) + if (mControllerFocus >= 0 && mControllerFocus < static_cast(mTrainingButtons.size())) onTrainingSelected(mTrainingButtons[mControllerFocus]); } else if (arg.button == SDL_CONTROLLER_BUTTON_B) diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 48717b0825..a667d3905f 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -258,7 +258,7 @@ namespace MWGui { if (arg.button == SDL_CONTROLLER_BUTTON_A) { - if (mControllerFocus >= 0 && mControllerFocus < mDestinationButtons.size()) + if (mControllerFocus >= 0 && mControllerFocus < static_cast(mDestinationButtons.size())) { onTravelButtonClick(mDestinationButtons[mControllerFocus]); MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 4ecc26449f..b607ec50b2 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -27,7 +27,7 @@ int MWGui::wrap(int index, int max) void MWGui::setControllerFocus(std::vector buttons, int index, bool focused) { - if (index >= 0 && index < buttons.size()) + if (index >= 0 && index < static_cast(buttons.size())) buttons[index]->setStateSelected(focused); } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 97847551b1..6cc61fb279 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -396,7 +396,7 @@ namespace MWGui WindowBase* getActiveControllerWindow() override; void cycleActiveControllerWindow(bool next) override; void setActiveControllerWindow(GuiMode mode, int activeIndex) override; - const bool getControllerTooltip() const override { return mControllerTooltip; } + bool getControllerTooltip() const override { return mControllerTooltip; } void setControllerTooltip(bool enabled) override; void updateControllerButtonsOverlay() override; From f6b06057fa34518d40e0db82af0a2c05a344934f Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 8 Jun 2025 13:51:09 -0700 Subject: [PATCH 096/330] Fix clang warning --- apps/openmw/mwgui/journalwindow.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 23adfc5a58..2a1ee32739 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -496,8 +496,9 @@ namespace MyGUI::Button* listItem = _list->getItemWidget(_list->getItemNameAt(i)); if (listItem) { - listItem->setTextColour( - static_cast(mButtons.size()) == _selectedIndex ? MWGui::journalHeaderColour : MyGUI::Colour::Black); + listItem->setTextColour(static_cast(mButtons.size()) == _selectedIndex + ? MWGui::journalHeaderColour + : MyGUI::Colour::Black); mButtons.push_back(listItem); } } From 4e2e8d1a81c6cf1f087e07f9be59e24de220f26d Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Tue, 10 Jun 2025 01:08:04 +0000 Subject: [PATCH 097/330] Apply 1 suggestion(s) to 1 file(s) Co-authored-by: Joakim Berg --- files/lang/launcher_sv.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/lang/launcher_sv.ts b/files/lang/launcher_sv.ts index f86e15532f..11623ceb5a 100644 --- a/files/lang/launcher_sv.ts +++ b/files/lang/launcher_sv.ts @@ -1472,7 +1472,7 @@ de ordinarie fonterna i Morrowind. Bocka denna ruta om du ändå föredrar ordin Enable Controller Menus - Aktivera kontrollmenyer + Aktivera handkontrollmenyer From 57ae0972574247db72f7c3aa2e485e7b404ebe64 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Mon, 9 Jun 2025 19:23:49 -0700 Subject: [PATCH 098/330] Add controller support to the companion window; also fix giving stacks --- apps/openmw/mwgui/companionwindow.cpp | 65 ++++++++++++++++++++++++++- apps/openmw/mwgui/companionwindow.hpp | 4 ++ apps/openmw/mwgui/inventorywindow.cpp | 33 +++++++++++++- apps/openmw/mwgui/inventorywindow.hpp | 1 + 4 files changed, 100 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 240198eddc..4a7863b856 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -6,6 +6,8 @@ #include #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" @@ -14,6 +16,7 @@ #include "companionitemmodel.hpp" #include "countdialog.hpp" #include "draganddrop.hpp" +#include "inventorywindow.hpp" #include "itemview.hpp" #include "messagebox.hpp" #include "sortfilteritemmodel.hpp" @@ -58,6 +61,11 @@ namespace MWGui mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CompanionWindow::onCloseButtonClicked); setCoord(200, 0, 600, 300); + + mControllerButtons.a = "#{sTake}"; + mControllerButtons.b = "#{sClose}"; + mControllerButtons.r3 = "#{sInfo}"; + mControllerButtons.l2 = "#{sInventory}"; } void CompanionWindow::onItemSelected(int index) @@ -93,8 +101,13 @@ namespace MWGui name += MWGui::ToolTips::getSoulString(object.getCellRef()); dialog->openCountDialog(name, "#{sTake}", count); dialog->eventOkClicked.clear(); - dialog->eventOkClicked += MyGUI::newDelegate(this, &CompanionWindow::dragItem); + if (Settings::gui().mControllerMenus) + dialog->eventOkClicked += MyGUI::newDelegate(this, &CompanionWindow::takeItem); + else + dialog->eventOkClicked += MyGUI::newDelegate(this, &CompanionWindow::dragItem); } + else if (Settings::gui().mControllerMenus) + takeItem(nullptr, count); else dragItem(nullptr, count); } @@ -110,6 +123,29 @@ namespace MWGui mDragAndDrop->startDrag(mSelectedItem, mSortModel, mModel, mItemView, count); } + void CompanionWindow::takeItem(MyGUI::Widget* sender, int count) + { + if (!mModel) + return; + + const ItemStack& item = mModel->getItem(mSelectedItem); + if (!mModel->onTakeItem(item.mBase, count)) + return; + + MWGui::InventoryWindow* inventoryWindow = MWBase::Environment::get().getWindowManager()->getInventoryWindow(); + ItemModel* playerModel = inventoryWindow->getModel(); + + mModel->moveItem(item, count, playerModel); + + inventoryWindow->updateItemView(); + mItemView->update(); + + // play the item's sound + MWWorld::Ptr itemBase = item.mBase; + const ESM::RefId& sound = itemBase.getClass().getUpSoundId(itemBase); + MWBase::Environment::get().getWindowManager()->playSound(sound); + } + void CompanionWindow::onBackgroundSelected() { if (mDragAndDrop->mIsOnDragAndDrop) @@ -202,4 +238,31 @@ namespace MWGui mSortModel = nullptr; } + bool CompanionWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) + { + if (arg.button == SDL_CONTROLLER_BUTTON_A) + { + int index = mItemView->getControllerFocus(); + if (index >= 0 && index < mItemView->getItemCount()) + onItemSelected(index); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_B) + { + onCloseButtonClicked(mCloseButton); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK || arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP + || arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN || arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT + || arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + { + mItemView->onControllerButton(arg.button); + } + + return true; + } + + void CompanionWindow::setActiveControllerWindow(bool active) + { + mItemView->setActiveControllerWindow(active); + WindowBase::setActiveControllerWindow(active); + } } diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index 21869c58f5..c0cd87c9d5 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -34,6 +34,9 @@ namespace MWGui std::string_view getWindowIdForLua() const override { return "Companion"; } + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + void setActiveControllerWindow(bool active) override; + MWGui::ItemView* getItemView() { return mItemView; } ItemModel* getModel() { return mModel; } @@ -55,6 +58,7 @@ namespace MWGui void onNameFilterChanged(MyGUI::EditBox* _sender); void onBackgroundSelected(); void dragItem(MyGUI::Widget* sender, int count); + void takeItem(MyGUI::Widget* sender, int count); void onMessageBoxButtonClicked(int button); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index fd06286a6c..1f06ced300 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -331,7 +331,10 @@ namespace MWGui name += MWGui::ToolTips::getSoulString(object.getCellRef()); dialog->openCountDialog(name, message, count); dialog->eventOkClicked.clear(); - if (mTrading) + if (Settings::gui().mControllerMenus + && (mGuiMode == MWGui::GM_Companion || mGuiMode == MWGui::GM_Container)) + dialog->eventOkClicked += MyGUI::newDelegate(this, &InventoryWindow::giveItem); + else if (mTrading) dialog->eventOkClicked += MyGUI::newDelegate(this, &InventoryWindow::sellItem); else dialog->eventOkClicked += MyGUI::newDelegate(this, &InventoryWindow::dragItem); @@ -411,6 +414,32 @@ namespace MWGui notifyContentChanged(); } + void InventoryWindow::giveItem(MyGUI::Widget* sender, int count) + { + ensureSelectedItemUnequipped(count); + mDragAndDrop->startDrag(mSelectedItem, mSortModel, mTradeModel, mItemView, count); + notifyContentChanged(); + + if (mGuiMode == MWGui::GM_Companion && mDragAndDrop->mIsOnDragAndDrop) + { + // Drag and drop the item on the companion's window. + MWGui::CompanionWindow* companionWindow = (MWGui::CompanionWindow*)MWBase::Environment::get() + .getWindowManager() + ->getGuiModeWindows(mGuiMode) + .at(1); + mDragAndDrop->drop(companionWindow->getModel(), companionWindow->getItemView()); + } + else if (mGuiMode == MWGui::GM_Container && mDragAndDrop->mIsOnDragAndDrop) + { + // Drag and drop the item on the container window. + MWGui::ContainerWindow* containerWindow = (MWGui::ContainerWindow*)MWBase::Environment::get() + .getWindowManager() + ->getGuiModeWindows(mGuiMode) + .at(0); + mDragAndDrop->drop(containerWindow->getModel(), containerWindow->getItemView()); + } + } + void InventoryWindow::updateItemView() { MWBase::Environment::get().getWindowManager()->updateSpellWindow(); @@ -944,7 +973,7 @@ namespace MWGui MWGui::CompanionWindow* companionWindow = (MWGui::CompanionWindow*)MWBase::Environment::get() .getWindowManager() ->getGuiModeWindows(mGuiMode) - .at(0); + .at(1); mDragAndDrop->drop(companionWindow->getModel(), companionWindow->getItemView()); } else if (mGuiMode == MWGui::GM_Container && mDragAndDrop->mIsOnDragAndDrop) diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 5b4d61f272..a14e0f9477 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -122,6 +122,7 @@ namespace MWGui void sellItem(MyGUI::Widget* sender, int count); void dragItem(MyGUI::Widget* sender, int count); + void giveItem(MyGUI::Widget* sender, int count); void onWindowResize(MyGUI::Window* _sender); void onFilterChanged(MyGUI::Widget* _sender); From 47b3674bac55d9efb02d3f172cad1407740e71c0 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Mon, 9 Jun 2025 22:03:12 -0700 Subject: [PATCH 099/330] Update controller focus to use a message box's default focus if available --- apps/openmw/mwgui/messagebox.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index c7e997a565..80b2a34a5b 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -288,7 +288,13 @@ namespace MWGui // If we have more than one button, we need to set the focus to the first one. if (mButtons.size() > 1) - mButtons[0]->setStateSelected(true); + { + mControllerFocus = 0; + if (mDefaultFocus >= 0 && mDefaultFocus < static_cast(mButtons.size())) + mControllerFocus = mDefaultFocus; + for (int i = 0; i < static_cast(mButtons.size()); ++i) + mButtons[i]->setStateSelected(i == mControllerFocus); + } } MyGUI::IntSize mainWidgetSize; From 0df8869f596a3a4a28129cbfbc499890df78c376 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sun, 1 Jun 2025 22:16:21 +0300 Subject: [PATCH 100/330] Cache computed supported directions Invalidated when animation sources are cleared or added --- apps/openmw/mwrender/animation.cpp | 37 +++++++++++++++++++----------- apps/openmw/mwrender/animation.hpp | 1 + 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index f07a325f7c..98a2246cb5 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -722,6 +722,7 @@ namespace MWRender mAnimSources.push_back(animsrc); + mSupportedDirections.clear(); for (const std::string& group : mAnimSources.back()->getTextKeys().getGroups()) mSupportedAnimations.insert(group); @@ -795,6 +796,7 @@ namespace MWRender mAccumCtrl = nullptr; mSupportedAnimations.clear(); + mSupportedDirections.clear(); mAnimSources.clear(); mAnimVelocities.clear(); @@ -2012,20 +2014,29 @@ namespace MWRender std::span prefixes) const { MWWorld::MovementDirectionFlags result = 0; - for (const std::string_view animation : mSupportedAnimations) + for (const std::string_view prefix : prefixes) { - if (std::find_if( - prefixes.begin(), prefixes.end(), [&](std::string_view v) { return animation.starts_with(v); }) - == prefixes.end()) - continue; - if (animation.ends_with("forward")) - result |= MWWorld::MovementDirectionFlag_Forward; - else if (animation.ends_with("back")) - result |= MWWorld::MovementDirectionFlag_Back; - else if (animation.ends_with("left")) - result |= MWWorld::MovementDirectionFlag_Left; - else if (animation.ends_with("right")) - result |= MWWorld::MovementDirectionFlag_Right; + auto it = std::find_if(mSupportedDirections.begin(), mSupportedDirections.end(), + [prefix](const auto& direction) { return direction.first == prefix; }); + if (it == mSupportedDirections.end()) + { + mSupportedDirections.emplace_back(prefix, 0); + it = mSupportedDirections.end() - 1; + for (const std::string_view animation : mSupportedAnimations) + { + if (!animation.starts_with(prefix)) + continue; + if (animation.ends_with("forward")) + it->second |= MWWorld::MovementDirectionFlag_Forward; + else if (animation.ends_with("back")) + it->second |= MWWorld::MovementDirectionFlag_Back; + else if (animation.ends_with("left")) + it->second |= MWWorld::MovementDirectionFlag_Left; + else if (animation.ends_with("right")) + it->second |= MWWorld::MovementDirectionFlag_Right; + } + } + result |= it->second; } return result; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index b6cb6f333c..8f7637804d 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -181,6 +181,7 @@ namespace MWRender AnimSourceList mAnimSources; std::unordered_set mSupportedAnimations; + mutable std::vector> mSupportedDirections; osg::ref_ptr mInsert; From 1e3ddee291b04ced03152034fbb3954a6d7a8bf9 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Tue, 10 Jun 2025 21:42:51 -0700 Subject: [PATCH 101/330] Remove default string when creating a potion that won't work --- apps/openmw/mwgui/alchemywindow.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 074250985c..6cf34702d7 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -119,8 +119,6 @@ namespace MWGui void AlchemyWindow::onCreateButtonClicked(MyGUI::Widget* _sender) { - if (Settings::gui().mControllerMenus && mNameEdit->getCaption().length() == 0) - mNameEdit->setCaption("Unknown potion"); mAlchemy->setPotionName(mNameEdit->getCaption()); int count = mAlchemy->countPotionsToBrew(); count = std::min(count, mBrewCountEdit->getValue()); From e01b8d372c69440e734f86d48fe49fc4dad45cda Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Wed, 11 Jun 2025 23:16:08 -0700 Subject: [PATCH 102/330] In controller mode, make focused spell blue to match other menus --- apps/openmw/mwgui/spellview.cpp | 4 +++- files/data/mygui/openmw_text.skin.xml | 32 +++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index fffd492fb7..0265eea4cb 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -113,7 +113,9 @@ namespace MWGui curType = spell.mType; } - const std::string skin = spell.mActive ? "SandTextButton" : "SpellTextUnequipped"; + std::string skin = spell.mActive ? "SandTextButton" : "SpellTextUnequipped"; + if (Settings::gui().mControllerMenus) + skin = spell.mActive ? "SpellTextEquippedController" : "SpellTextUnequippedController"; const std::string captionSuffix = MWGui::ToolTips::getCountString(spell.mCount); Gui::SharedStateButton* t = mScrollView->createWidget( diff --git a/files/data/mygui/openmw_text.skin.xml b/files/data/mygui/openmw_text.skin.xml index 5f96d0a57c..1724458522 100644 --- a/files/data/mygui/openmw_text.skin.xml +++ b/files/data/mygui/openmw_text.skin.xml @@ -120,6 +120,38 @@ color_misc=0,205,205 # ???? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From b4ede02cce12c935883c26b12b24d3b686e70db0 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Thu, 12 Jun 2025 21:43:01 -0700 Subject: [PATCH 103/330] Move hardcoded strings to i10n --- apps/openmw/mwgui/enchantingdialog.cpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwgui/journalwindow.cpp | 4 ++-- apps/openmw/mwgui/recharge.cpp | 2 +- apps/openmw/mwgui/repair.cpp | 2 +- apps/openmw/mwgui/savegamedialog.cpp | 4 ++-- apps/openmw/mwgui/settingswindow.cpp | 3 +-- files/data/l10n/OMWEngine/de.yaml | 12 +++++++++++- files/data/l10n/OMWEngine/en.yaml | 12 +++++++++++- files/data/l10n/OMWEngine/fr.yaml | 12 +++++++++++- files/data/l10n/OMWEngine/ru.yaml | 12 +++++++++++- files/data/l10n/OMWEngine/sv.yaml | 12 +++++++++++- files/data/mygui/openmw_savegame_dialog.layout | 2 +- 13 files changed, 65 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index b5e0444f25..7a1c1532f6 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -62,7 +62,7 @@ namespace MWGui mControllerButtons.a = "#{sSelect}"; mControllerButtons.b = "#{sCancel}"; - mControllerButtons.y = "Cast Type"; + mControllerButtons.y = "#{OMWEngine:EnchantType}"; mControllerButtons.l1 = "#{sItem}"; mControllerButtons.r1 = "#{sSoulGem}"; } diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 1f06ced300..1f39ccc0ce 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -923,7 +923,7 @@ namespace MWGui { case MWGui::GM_Companion: case MWGui::GM_Container: - mControllerButtons.a = "Put"; + mControllerButtons.a = "#{OMWEngine:InventorySelect}"; mControllerButtons.b = "#{sClose}"; mControllerButtons.x = "#{sTakeAll}"; mControllerButtons.y = ""; diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 2a1ee32739..ddfa16255c 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -219,7 +219,7 @@ namespace } mControllerButtons.a = "#{sSelect}"; - mControllerButtons.x = "Quests"; + mControllerButtons.x = "#{OMWEngine:JournalQuests}"; mControllerButtons.y = "#{sTopics}"; mQuestMode = false; @@ -692,7 +692,7 @@ namespace mControllerButtons.b = mOptionsMode || mStates.size() > 1 ? "#{sBack}" : "#{sClose}"; mControllerButtons.l1 = mOptionsMode ? "" : "#{sPrev}"; mControllerButtons.r1 = mOptionsMode ? "" : "#{sNext}"; - mControllerButtons.r3 = mOptionsMode && mQuestMode ? "Show All" : ""; + mControllerButtons.r3 = mOptionsMode && mQuestMode ? "#{OMWEngine:JournalShowAll}" : ""; return &mControllerButtons; } diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index cfe7fedc60..2dfb47fa23 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -40,7 +40,7 @@ namespace MWGui mGemIcon->eventMouseButtonClick += MyGUI::newDelegate(this, &Recharge::onSelectItem); - mControllerButtons.a = "Recharge"; + mControllerButtons.a = "#{OMWEngine:RechargeSelect}"; mControllerButtons.b = "#{sCancel}"; mControllerButtons.y = "#{sSoulGem}"; } diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 8dbac7ef48..8962ae2abd 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -42,7 +42,7 @@ namespace MWGui mControllerButtons.a = "#{sRepair}"; mControllerButtons.b = "#{sCancel}"; - mControllerButtons.y = "Tool"; + mControllerButtons.y = "#{OMWEngine:RepairTool}"; } void Repair::onOpen() diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 61cbae81f0..2dfcd4cee7 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -245,7 +245,7 @@ namespace MWGui mCharacterSelection->setIndexSelected(selectedIndex); if (selectedIndex == MyGUI::ITEM_NONE) - mCharacterSelection->setCaptionWithReplacing("#{OMWEngine:SelectCharacter}"); + mCharacterSelection->setCaptionWithReplacing("#{OMWEngine:SelectCharacter}..."); fillSaveList(); } @@ -524,7 +524,7 @@ namespace MWGui ControllerButtonStr* SaveGameDialog::getControllerButtons() { - mControllerButtons.y = mSaving ? "" : "Select Character"; + mControllerButtons.y = mSaving ? "" : "#{OMWEngine:SelectCharacter}"; return &mControllerButtons; } diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 89cdb6694a..726809c583 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -462,8 +462,7 @@ namespace MWGui mControllerButtons.a = "#{sSelect}"; mControllerButtons.b = "#{sOk}"; - mControllerButtons.l1 = "#{sPrev} Tab"; - mControllerButtons.r1 = "#{sNext} Tab"; + mControllerButtons.lStick = "#{sMouse}"; } void SettingsWindow::onTabChanged(MyGUI::TabControl* /*_sender*/, size_t /*index*/) diff --git a/files/data/l10n/OMWEngine/de.yaml b/files/data/l10n/OMWEngine/de.yaml index a23dbebdae..25bc145159 100644 --- a/files/data/l10n/OMWEngine/de.yaml +++ b/files/data/l10n/OMWEngine/de.yaml @@ -58,7 +58,7 @@ MissingContentFilesListCopy: |- other{\n\nDrücken Sie „Kopieren“, um alle Namen in die Zwischenablage zu kopieren.} } OverwriteGameConfirmation: "Sind Sie sicher, dass Sie den Spielstand überschreiben wollen?" -SelectCharacter: "Charakter auswählen..." +SelectCharacter: "Charakter auswählen" TimePlayed: "Spielzeit" @@ -213,3 +213,13 @@ WindowModeWindowed: "Fenster" WindowModeWindowedFullscreen: "Fenster in Vollbildgröße" # More fitting translations of "wobbly" are welcome WobblyShores: "Wabbelige Uferlinien" + + +# Controller button names + +EnchantType: "Zaubertyp" +InventorySelect: "Geben" +JournalQuests: "Quests" +JournalShowAll: "Alle Anzeigen" +RechargeSelect: "Aufladen" +RepairTool: "Werkzeug" diff --git a/files/data/l10n/OMWEngine/en.yaml b/files/data/l10n/OMWEngine/en.yaml index 8a3217a03c..176e604f8e 100644 --- a/files/data/l10n/OMWEngine/en.yaml +++ b/files/data/l10n/OMWEngine/en.yaml @@ -58,7 +58,7 @@ MissingContentFilesListCopy: |- other{\n\nPress Copy to place their names to the clipboard.} } OverwriteGameConfirmation: "Are you sure you want to overwrite this saved game?" -SelectCharacter: "Select Character..." +SelectCharacter: "Select Character" TimePlayed: "Time Played" @@ -212,3 +212,13 @@ WindowModeHint: "Hint: Windowed Fullscreen mode\nalways uses the native display WindowModeWindowed: "Windowed" WindowModeWindowedFullscreen: "Windowed Fullscreen" WobblyShores: "Wobbly Shores" + + +# Controller button names + +EnchantType: "Cast Type" +InventorySelect: "Put" +JournalQuests: "Quests" +JournalShowAll: "Show All" +RechargeSelect: "Recharge" +RepairTool: "Tool" diff --git a/files/data/l10n/OMWEngine/fr.yaml b/files/data/l10n/OMWEngine/fr.yaml index fc584d8293..bd96ae0d80 100644 --- a/files/data/l10n/OMWEngine/fr.yaml +++ b/files/data/l10n/OMWEngine/fr.yaml @@ -58,7 +58,7 @@ MissingContentFilesListCopy: |- other{\n\nCliquez sur Copier pour placer ces noms dans le presse-papier.} } OverwriteGameConfirmation: "Écraser la sauvegarde précédente ?" -SelectCharacter: "Sélection du personnage..." +SelectCharacter: "Sélection du personnage" TimePlayed: "Temps de jeu" @@ -212,3 +212,13 @@ WindowModeHint: "Info : Le mode \"Fenêtré plein écran\" utilise toujours la r WindowModeWindowed: "Fenêtré" WindowModeWindowedFullscreen: "Fenêtré plein écran" WobblyShores: "Rivages vacillants" + + +# Controller button names + +EnchantType: "Type de lancement" +InventorySelect: "Placer" +JournalQuests: "Quêtes" +JournalShowAll: "Tout Afficher" +RechargeSelect: "Recharge" +RepairTool: "Outil" diff --git a/files/data/l10n/OMWEngine/ru.yaml b/files/data/l10n/OMWEngine/ru.yaml index c50fbac38e..6bee247c9d 100644 --- a/files/data/l10n/OMWEngine/ru.yaml +++ b/files/data/l10n/OMWEngine/ru.yaml @@ -58,7 +58,7 @@ MissingContentFilesListCopy: |- other{\n\nНажмите Скопировать, чтобы поместить их названия в буфер обмена.} } OverwriteGameConfirmation: "Вы уверены, что хотите перезаписать это сохранение?" -SelectCharacter: "Выберите персонажа..." +SelectCharacter: "Выберите персонажа" TimePlayed: "Время в игре" @@ -212,3 +212,13 @@ WindowModeHint: "Подсказка: режим Оконный без полей WindowModeWindowed: "Оконный" WindowModeWindowedFullscreen: "Оконный без полей" WobblyShores: "Колеблющиеся берега" + + +# Controller button names + +EnchantType: "Тип заклинания" +InventorySelect: "Поместить" +JournalQuests: "Квесты" +JournalShowAll: "Показать все" +RechargeSelect: "Перезарядить" +RepairTool: "Инструмент" diff --git a/files/data/l10n/OMWEngine/sv.yaml b/files/data/l10n/OMWEngine/sv.yaml index b3bb6788ed..9b2afed84f 100644 --- a/files/data/l10n/OMWEngine/sv.yaml +++ b/files/data/l10n/OMWEngine/sv.yaml @@ -59,7 +59,7 @@ MissingContentFilesListCopy: |- other{\n\nKlicka på kopiera för att placera deras namn i urklipp.} } OverwriteGameConfirmation: "Är du säker på att du vill skriva över det här sparade spelet?" -SelectCharacter: "Välj spelfigur..." +SelectCharacter: "Välj spelfigur" # Settings menu @@ -213,3 +213,13 @@ WindowModeHint: "Notera: Helskärm i fönsterläge\nanvänder alltid skärmens n WindowModeWindowed: "Fönster" WindowModeWindowedFullscreen: "Helskärm i fönsterläge" WobblyShores: "Vaggande stränder" + + +# Controller button names + +EnchantType: "Typ" +InventorySelect: "Sätta" +JournalQuests: "Uppdrag" +JournalShowAll: "Visa Alla" +RechargeSelect: "Ladda" +RepairTool: "Verktyg" diff --git a/files/data/mygui/openmw_savegame_dialog.layout b/files/data/mygui/openmw_savegame_dialog.layout index 1e40b5dd34..1683326065 100644 --- a/files/data/mygui/openmw_savegame_dialog.layout +++ b/files/data/mygui/openmw_savegame_dialog.layout @@ -6,7 +6,7 @@ - + From ef651ee1875c74ff9acfd622ec82bd124face4bd Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sat, 14 Jun 2025 13:13:36 -0700 Subject: [PATCH 104/330] Update swedish translation for putting an item in a container --- files/data/l10n/OMWEngine/sv.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/data/l10n/OMWEngine/sv.yaml b/files/data/l10n/OMWEngine/sv.yaml index 9b2afed84f..50a33582f3 100644 --- a/files/data/l10n/OMWEngine/sv.yaml +++ b/files/data/l10n/OMWEngine/sv.yaml @@ -218,7 +218,7 @@ WobblyShores: "Vaggande stränder" # Controller button names EnchantType: "Typ" -InventorySelect: "Sätta" +InventorySelect: "Placera" JournalQuests: "Uppdrag" JournalShowAll: "Visa Alla" RechargeSelect: "Ladda" From 8d545a43d51cb2f5a9686489e968de5221551478 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sat, 14 Jun 2025 13:14:32 -0700 Subject: [PATCH 105/330] Scrolll the list of quests in controller mode --- apps/openmw/mwgui/journalwindow.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index ddfa16255c..4c2e885e4e 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -826,6 +826,18 @@ namespace mButtons[mSelectedQuest]->setTextColour(MyGUI::Colour::Black); mSelectedQuest = MWGui::wrap(mSelectedQuest - 1, mButtons.size()); mButtons[mSelectedQuest]->setTextColour(MWGui::journalHeaderColour); + + // Scroll the list to keep the active item in view + Gui::MWList* list = getWidget(QuestsList); + if (mSelectedQuest <= 3) + list->setViewOffset(0); + else + { + int offset = 0; + for (int i = 0; i < mSelectedQuest - 3; i++) + offset += mButtons[i]->getHeight() + 3; + list->setViewOffset(-offset); + } } else if (mOptionsMode) { @@ -868,6 +880,18 @@ namespace mButtons[mSelectedQuest]->setTextColour(MyGUI::Colour::Black); mSelectedQuest = MWGui::wrap(mSelectedQuest + 1, mButtons.size()); mButtons[mSelectedQuest]->setTextColour(MWGui::journalHeaderColour); + + // Scroll the list to keep the active item in view + Gui::MWList* list = getWidget(QuestsList); + if (mSelectedQuest <= 3) + list->setViewOffset(0); + else + { + int offset = 0; + for (int i = 0; i < mSelectedQuest - 3; i++) + offset += mButtons[i]->getHeight() + 3; + list->setViewOffset(-offset); + } } else if (mOptionsMode) { From 0a0340327794b69f57a39930946098e5a03f5c82 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sat, 14 Jun 2025 13:42:51 -0700 Subject: [PATCH 106/330] Fix closing dialogue when a choice is active; improve scrolling --- apps/openmw/mwgui/dialogue.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index fe3675f6fb..d89c7753ce 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -944,10 +944,21 @@ namespace MWGui if (focused) { // Scroll the side bar to keep the active item in view - if (index <= 5) + if (index <= 8) mTopicsList->setViewOffset(0); else - mTopicsList->setViewOffset(-20 * (index - 5)); + { + int offset = 0; + for (int i = 0; i < index - 8; i++) + { + std::string keyword = mTopicsList->getItemNameAt(i); + if (keyword.length() == 0) + offset += 21; + else + offset += mTopicsList->getItemWidget(keyword)->getHeight() + 3; + } + mTopicsList->setViewOffset(-offset); + } } } @@ -966,7 +977,7 @@ namespace MWGui onSelectListItem(mTopicsList->getItemNameAt(mControllerFocus), mControllerFocus); MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) + else if (arg.button == SDL_CONTROLLER_BUTTON_B && mChoices.size() < 2) { onGoodbyeActivated(); } From 50e58637490cb2bbe4a5ab8533ae2ae3f52295dc Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Wed, 18 Jun 2025 19:46:22 -0700 Subject: [PATCH 107/330] Use shoulder buttons on wait menu, similar to other slider menus --- apps/openmw/mwgui/waitdialog.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index e2932caf46..7edd69f6f4 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -354,6 +354,16 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::ArrowUp, 0, false); + else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) + { + mHourSlider->setScrollPosition(0); + onHourSliderChangedPosition(mHourSlider, mHourSlider->getScrollPosition()); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) + { + mHourSlider->setScrollPosition(mHourSlider->getScrollRange() - 1); + onHourSliderChangedPosition(mHourSlider, mHourSlider->getScrollPosition()); + } return true; } From 2905ed5fb111f1f67fffeb3a4c4f1625b7c082d7 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Fri, 20 Jun 2025 22:41:39 -0700 Subject: [PATCH 108/330] Fix controller selection of nested dialog choices --- apps/openmw/mwgui/dialogue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index d89c7753ce..b96bf85f6f 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -969,7 +969,7 @@ namespace MWGui if (mChoices.size() > 0) { if (mControllerChoice >= 0 && mControllerChoice < static_cast(mChoices.size())) - onChoiceActivated(mControllerChoice + 1); // +1 because choices are indexed starting at 1 + onChoiceActivated(mChoices[mControllerChoice].second); } else if (mControllerFocus == static_cast(mTopicsList->getItemCount())) onGoodbyeActivated(); From 190680a3a902f327c3e29488da58158d7bf40bf1 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Fri, 20 Jun 2025 23:37:53 -0700 Subject: [PATCH 109/330] Replace semi-janky rstick controller bindings with dpad --- apps/openmw/mwgui/controllerbuttonsoverlay.cpp | 4 ++++ apps/openmw/mwgui/controllerbuttonsoverlay.hpp | 3 +++ apps/openmw/mwgui/mapwindow.cpp | 15 +-------------- apps/openmw/mwgui/mapwindow.hpp | 1 - apps/openmw/mwgui/scrollwindow.cpp | 15 +-------------- apps/openmw/mwgui/scrollwindow.hpp | 1 - apps/openmw/mwgui/windowbase.hpp | 1 + files/data/CMakeLists.txt | 1 + .../data/mygui/openmw_controllerbuttons.layout | 13 +++++++++++++ files/data/textures/omw_steam_button_dpad.dds | Bin 0 -> 22000 bytes 10 files changed, 24 insertions(+), 30 deletions(-) create mode 100644 files/data/textures/omw_steam_button_dpad.dds diff --git a/apps/openmw/mwgui/controllerbuttonsoverlay.cpp b/apps/openmw/mwgui/controllerbuttonsoverlay.cpp index 96438fa583..9466f40105 100644 --- a/apps/openmw/mwgui/controllerbuttonsoverlay.cpp +++ b/apps/openmw/mwgui/controllerbuttonsoverlay.cpp @@ -14,6 +14,9 @@ namespace MWGui getWidget(mImageB, "BtnBImage"); getWidget(mTextB, "BtnBText"); + getWidget(mImageDpad, "BtnDpadImage"); + getWidget(mTextDpad, "BtnDpadText"); + getWidget(mImageL1, "BtnL1Image"); getWidget(mTextL1, "BtnL1Text"); @@ -58,6 +61,7 @@ namespace MWGui int buttonCount = 0; buttonCount += updateButton(mTextA, mImageA, buttons->a); buttonCount += updateButton(mTextB, mImageB, buttons->b); + buttonCount += updateButton(mTextDpad, mImageDpad, buttons->dpad); buttonCount += updateButton(mTextL1, mImageL1, buttons->l1); buttonCount += updateButton(mTextL2, mImageL2, buttons->l2); buttonCount += updateButton(mTextL3, mImageL3, buttons->l3); diff --git a/apps/openmw/mwgui/controllerbuttonsoverlay.hpp b/apps/openmw/mwgui/controllerbuttonsoverlay.hpp index 7663bbed44..7008384bee 100644 --- a/apps/openmw/mwgui/controllerbuttonsoverlay.hpp +++ b/apps/openmw/mwgui/controllerbuttonsoverlay.hpp @@ -24,6 +24,9 @@ namespace MWGui MyGUI::ImageBox* mImageB; MyGUI::TextBox* mTextB; + MyGUI::ImageBox* mImageDpad; + MyGUI::TextBox* mTextDpad; + MyGUI::ImageBox* mImageL1; MyGUI::TextBox* mTextL1; diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index fb2074570f..38cfbc1e58 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -839,7 +839,7 @@ namespace MWGui mControllerButtons.b = "#{sBack}"; mControllerButtons.x = global ? "#{sLocal}" : "#{sWorld}"; mControllerButtons.y = "#{sCenter}"; - mControllerButtons.rStick = Settings::map().mAllowZooming ? "" : "#{sMove}"; + mControllerButtons.dpad = Settings::map().mAllowZooming ? "" : "#{sMove}"; } } @@ -1418,19 +1418,6 @@ namespace MWGui return true; } - bool MapWindow::onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) - { - if (!Settings::map().mAllowZooming) - { - int dx = arg.axis == SDL_CONTROLLER_AXIS_RIGHTX ? -30.0f * arg.value / 32767 : 0; - int dy = arg.axis == SDL_CONTROLLER_AXIS_RIGHTY ? -30.0f * arg.value / 32767 : 0; - shiftMap(dx, dy); - - return true; - } - return false; - } - void MapWindow::shiftMap(int dx, int dy) { if (dx == 0 && dy == 0) diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 240c30adc0..8730964094 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -272,7 +272,6 @@ namespace MWGui protected: bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) override; void setActiveControllerWindow(bool active) override; private: diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 4be1461d0c..59fb1f2d20 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -41,7 +41,7 @@ namespace MWGui mControllerScrollWidget = mTextView; mControllerButtons.b = "#{sClose}"; - mControllerButtons.rStick = "#{sScrolldown}"; + mControllerButtons.dpad = "#{sScrolldown}"; center(); } @@ -148,17 +148,4 @@ namespace MWGui return true; } - - bool ScrollWindow::onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) - { - if (arg.axis == SDL_CONTROLLER_AXIS_RIGHTY) - { - MWBase::Environment::get().getInputManager()->setGamepadGuiCursorEnabled(false); - - int scroll = -30.0f * arg.value / 32767; - mTextView->setViewOffset(mTextView->getViewOffset() + MyGUI::IntPoint(0, scroll)); - return true; - } - return false; - } } diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index f1047fdeba..314925c7a7 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -33,7 +33,6 @@ namespace MWGui void setTakeButtonShow(bool show); void onKeyButtonPressed(MyGUI::Widget* sender, MyGUI::KeyCode key, MyGUI::Char character); bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) override; private: Gui::ImageButton* mCloseButton; diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index 0be84f12eb..b4d17a1ba3 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -21,6 +21,7 @@ namespace MWGui { std::string a; std::string b; + std::string dpad; std::string l1; std::string l2; std::string l3; diff --git a/files/data/CMakeLists.txt b/files/data/CMakeLists.txt index 2b8ea7a568..b1da9f6756 100644 --- a/files/data/CMakeLists.txt +++ b/files/data/CMakeLists.txt @@ -12,6 +12,7 @@ set(BUILTIN_DATA_FILES textures/omw_menu_icon_active.dds textures/omw_steam_button_a.dds textures/omw_steam_button_b.dds + textures/omw_steam_button_dpad.dds textures/omw_steam_button_l1.dds textures/omw_steam_button_l2.dds textures/omw_steam_button_l3.dds diff --git a/files/data/mygui/openmw_controllerbuttons.layout b/files/data/mygui/openmw_controllerbuttons.layout index ffcfeaee16..e0e68bf2ed 100644 --- a/files/data/mygui/openmw_controllerbuttons.layout +++ b/files/data/mygui/openmw_controllerbuttons.layout @@ -36,6 +36,19 @@ + + + + + + + + + + + + + diff --git a/files/data/textures/omw_steam_button_dpad.dds b/files/data/textures/omw_steam_button_dpad.dds new file mode 100644 index 0000000000000000000000000000000000000000..d730db44a84fb05bdd4fb87961ca61bdd2d9c8e5 GIT binary patch literal 22000 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 literal 0 HcmV?d00001 From c41f034a23fd0f1c94a19a183e800970813d0e21 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sat, 21 Jun 2025 21:34:11 -0700 Subject: [PATCH 110/330] Scroll the list of topics in controller mode --- apps/openmw/mwgui/journalwindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 4c2e885e4e..a661acb847 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -828,7 +828,7 @@ namespace mButtons[mSelectedQuest]->setTextColour(MWGui::journalHeaderColour); // Scroll the list to keep the active item in view - Gui::MWList* list = getWidget(QuestsList); + Gui::MWList* list = getWidget(mQuestMode ? QuestsList : TopicsList); if (mSelectedQuest <= 3) list->setViewOffset(0); else @@ -882,7 +882,7 @@ namespace mButtons[mSelectedQuest]->setTextColour(MWGui::journalHeaderColour); // Scroll the list to keep the active item in view - Gui::MWList* list = getWidget(QuestsList); + Gui::MWList* list = getWidget(mQuestMode ? QuestsList : TopicsList); if (mSelectedQuest <= 3) list->setViewOffset(0); else From fb5fa6ce1849812ca18fc731d663627433491f7a Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sat, 21 Jun 2025 22:04:35 -0700 Subject: [PATCH 111/330] Fix controller tooltip disappearing because of spurious controller input --- apps/openmw/mwgui/itemview.cpp | 2 +- apps/openmw/mwinput/controllermanager.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index c114db5e35..8b003b267d 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -81,7 +81,6 @@ namespace MWGui if (Settings::gui().mControllerMenus) { - MWBase::Environment::get().getWindowManager()->setControllerTooltip(false); mControllerFocus = std::clamp(mControllerFocus, 0, mItemCount - 1); updateControllerFocus(-1, mControllerFocus); } @@ -215,6 +214,7 @@ namespace MWGui // Select the focused item, if any. if (mControllerFocus >= 0 && mControllerFocus < mItemCount) { + MWBase::Environment::get().getWindowManager()->setControllerTooltip(false); MyGUI::Widget* dragArea = mScrollView->getChildAt(0); onSelectedItem(dragArea->getChildAt(mControllerFocus)); } diff --git a/apps/openmw/mwinput/controllermanager.cpp b/apps/openmw/mwinput/controllermanager.cpp index b6994cc3d6..8a60ff0673 100644 --- a/apps/openmw/mwinput/controllermanager.cpp +++ b/apps/openmw/mwinput/controllermanager.cpp @@ -360,7 +360,7 @@ namespace MWInput && (arg.axis == SDL_CONTROLLER_AXIS_LEFTX || arg.axis == SDL_CONTROLLER_AXIS_LEFTY)) { // Treat the left stick like a cursor, which is the default behavior. - if (winMgr->getControllerTooltip()) + if (winMgr->getControllerTooltip() && std::abs(arg.value) > 2000) { winMgr->setControllerTooltip(false); winMgr->setCursorVisible(true); From 5777a3cc3fad21bff38c9513d1edf07351813a72 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 22 Jun 2025 14:44:32 -0700 Subject: [PATCH 112/330] Update controller buttons shown for companion window --- apps/openmw/mwgui/inventorywindow.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 1f39ccc0ce..52d4eae732 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -922,6 +922,12 @@ namespace MWGui switch (mGuiMode) { case MWGui::GM_Companion: + mControllerButtons.a = "#{OMWEngine:InventorySelect}"; + mControllerButtons.b = "#{sClose}"; + mControllerButtons.x = ""; + mControllerButtons.y = ""; + mControllerButtons.r2 = "#{sCompanionShare}"; + break; case MWGui::GM_Container: mControllerButtons.a = "#{OMWEngine:InventorySelect}"; mControllerButtons.b = "#{sClose}"; From 88b43cabecff18c5f6b032e531925db4e879f8d3 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Sun, 22 Jun 2025 14:47:54 -0700 Subject: [PATCH 113/330] Reset controller focus when reopening container and quest menus --- apps/openmw/mwgui/journalwindow.cpp | 62 +++++++++++++------------- apps/openmw/mwgui/journalwindow.hpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 2 + 3 files changed, 33 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index a661acb847..e68c7299d9 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -252,7 +252,8 @@ namespace } updateShowingPages(); - mSelectedQuest = 0; + if (Settings::gui().mControllerMenus) + setControllerFocusedQuest(0); MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(getWidget(CloseBTN)); } @@ -524,7 +525,7 @@ namespace if (Settings::gui().mControllerMenus) { - mSelectedQuest = 0; + setControllerFocusedQuest(0); addControllerButtons(list, mSelectedQuest); } @@ -823,21 +824,7 @@ namespace return true; // Scroll through the list of quests or topics - mButtons[mSelectedQuest]->setTextColour(MyGUI::Colour::Black); - mSelectedQuest = MWGui::wrap(mSelectedQuest - 1, mButtons.size()); - mButtons[mSelectedQuest]->setTextColour(MWGui::journalHeaderColour); - - // Scroll the list to keep the active item in view - Gui::MWList* list = getWidget(mQuestMode ? QuestsList : TopicsList); - if (mSelectedQuest <= 3) - list->setViewOffset(0); - else - { - int offset = 0; - for (int i = 0; i < mSelectedQuest - 3; i++) - offset += mButtons[i]->getHeight() + 3; - list->setViewOffset(-offset); - } + setControllerFocusedQuest(MWGui::wrap(mSelectedQuest - 1, mButtons.size())); } else if (mOptionsMode) { @@ -877,21 +864,7 @@ namespace return true; // Scroll through the list of quests or topics - mButtons[mSelectedQuest]->setTextColour(MyGUI::Colour::Black); - mSelectedQuest = MWGui::wrap(mSelectedQuest + 1, mButtons.size()); - mButtons[mSelectedQuest]->setTextColour(MWGui::journalHeaderColour); - - // Scroll the list to keep the active item in view - Gui::MWList* list = getWidget(mQuestMode ? QuestsList : TopicsList); - if (mSelectedQuest <= 3) - list->setViewOffset(0); - else - { - int offset = 0; - for (int i = 0; i < mSelectedQuest - 3; i++) - offset += mButtons[i]->getHeight() + 3; - list->setViewOffset(-offset); - } + setControllerFocusedQuest(MWGui::wrap(mSelectedQuest + 1, mButtons.size())); } else if (mOptionsMode) { @@ -982,6 +955,31 @@ namespace return false; } + + void setControllerFocusedQuest(int index) + { + int listSize = static_cast(mButtons.size()); + if (mSelectedQuest >= 0 && mSelectedQuest < listSize) + mButtons[mSelectedQuest]->setTextColour(MyGUI::Colour::Black); + + mSelectedQuest = index; + if (mSelectedQuest >= 0 && mSelectedQuest < listSize) + { + mButtons[mSelectedQuest]->setTextColour(MWGui::journalHeaderColour); + + // Scroll the list to keep the active item in view + Gui::MWList* list = getWidget(mQuestMode ? QuestsList : TopicsList); + if (mSelectedQuest <= 3) + list->setViewOffset(0); + else + { + int offset = 0; + for (int i = 0; i < mSelectedQuest - 3; i++) + offset += mButtons[i]->getHeight() + 3; + list->setViewOffset(-offset); + } + } + } }; } diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index 3c66421906..31efa695bb 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -36,6 +36,7 @@ namespace MWGui int mSelectedQuest = 0; int mSelectedIndex = 0; void setIndexControllerFocus(int index, bool focused); + void setControllerFocusedQuest(int index); }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 7ab909983e..5447861ace 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1407,6 +1407,8 @@ namespace MWGui if (Settings::gui().mControllerMenus) { + if (mode == GM_Container) + mActiveControllerWindows[mode] = 0; // Ensure controller focus is on container // Activate first visible window. This needs to be called after updateVisible. mActiveControllerWindows[mode] = std::max(mActiveControllerWindows[mode] - 1, -1); cycleActiveControllerWindow(true); From fdc878d766c33b889d1cc74b413fb7830bf04df7 Mon Sep 17 00:00:00 2001 From: epochwon Date: Wed, 25 Jun 2025 17:04:21 -0400 Subject: [PATCH 114/330] elongate specular highlight --- files/shaders/compatibility/water.frag | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/files/shaders/compatibility/water.frag b/files/shaders/compatibility/water.frag index 749dcf27cd..6e447daad5 100644 --- a/files/shaders/compatibility/water.frag +++ b/files/shaders/compatibility/water.frag @@ -40,6 +40,8 @@ const vec3 SUN_EXT = vec3(0.45, 0.55, 0.68); // sunlight extinction const float SUN_SPEC_FADING_THRESHOLD = 0.15; // visibility at which sun specularity starts to fade const float SPEC_HARDNESS = 256.0; // specular highlights hardness +const float SPEC_BUMPINESS = 5.0; // surface bumpiness boost for specular +const float SPEC_BRIGHTNESS = 1.5; // boosts the brightness of the specular highlights const float BUMP_SUPPRESS_DEPTH = 300.0; // at what water depth bumpmap will be suppressed for reflections and refractions (prevents artifacts at shores) const float REFR_FOG_DISTORT_DISTANCE = 3000.0; // at what distance refraction fog will be calculated using real water depth instead of distorted depth (prevents splotchy shores) @@ -161,7 +163,8 @@ void main(void) sunSpec.a = min(1.0, sunSpec.a / SUN_SPEC_FADING_THRESHOLD); // specular - float specular = pow(max(dot(reflect(viewDir, normal), sunWorldDir), 0.0), SPEC_HARDNESS) * shadow * sunSpec.a; + vec3 R = reflect(viewDir, normalize(vec3(normal.x * SPEC_BUMPINESS, normal.y * SPEC_BUMPINESS, normal.z))); + float specular = clamp(pow(atan(max(dot(R, sunWorldDir), 0.0) * 1.55), SPEC_HARDNESS) * SPEC_BRIGHTNESS, 0.0, 1.0) * shadow * sunSpec.a; // artificial specularity to make rain ripples more noticeable vec3 skyColorEstimate = vec3(max(0.0, mix(-0.3, 1.0, sunFade))); From 13f1b76a25b0c56aa919a544e88566cc1e5c9287 Mon Sep 17 00:00:00 2001 From: epochwon Date: Wed, 25 Jun 2025 17:23:04 -0400 Subject: [PATCH 115/330] tabs to spaces --- files/shaders/compatibility/water.frag | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/files/shaders/compatibility/water.frag b/files/shaders/compatibility/water.frag index 6e447daad5..33b6fe1163 100644 --- a/files/shaders/compatibility/water.frag +++ b/files/shaders/compatibility/water.frag @@ -40,8 +40,8 @@ const vec3 SUN_EXT = vec3(0.45, 0.55, 0.68); // sunlight extinction const float SUN_SPEC_FADING_THRESHOLD = 0.15; // visibility at which sun specularity starts to fade const float SPEC_HARDNESS = 256.0; // specular highlights hardness -const float SPEC_BUMPINESS = 5.0; // surface bumpiness boost for specular -const float SPEC_BRIGHTNESS = 1.5; // boosts the brightness of the specular highlights +const float SPEC_BUMPINESS = 5.0; // surface bumpiness boost for specular +const float SPEC_BRIGHTNESS = 1.5; // boosts the brightness of the specular highlights const float BUMP_SUPPRESS_DEPTH = 300.0; // at what water depth bumpmap will be suppressed for reflections and refractions (prevents artifacts at shores) const float REFR_FOG_DISTORT_DISTANCE = 3000.0; // at what distance refraction fog will be calculated using real water depth instead of distorted depth (prevents splotchy shores) From c89b2b0c600a4715a08f457daefb8bc350bb25e1 Mon Sep 17 00:00:00 2001 From: epochwon Date: Tue, 1 Jul 2025 10:42:42 -0400 Subject: [PATCH 116/330] fix indenting --- files/shaders/compatibility/water.frag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/shaders/compatibility/water.frag b/files/shaders/compatibility/water.frag index 33b6fe1163..81abdc094f 100644 --- a/files/shaders/compatibility/water.frag +++ b/files/shaders/compatibility/water.frag @@ -164,7 +164,7 @@ void main(void) // specular vec3 R = reflect(viewDir, normalize(vec3(normal.x * SPEC_BUMPINESS, normal.y * SPEC_BUMPINESS, normal.z))); - float specular = clamp(pow(atan(max(dot(R, sunWorldDir), 0.0) * 1.55), SPEC_HARDNESS) * SPEC_BRIGHTNESS, 0.0, 1.0) * shadow * sunSpec.a; + float specular = clamp(pow(atan(max(dot(R, sunWorldDir), 0.0) * 1.55), SPEC_HARDNESS) * SPEC_BRIGHTNESS, 0.0, 1.0) * shadow * sunSpec.a; // artificial specularity to make rain ripples more noticeable vec3 skyColorEstimate = vec3(max(0.0, mix(-0.3, 1.0, sunFade))); From 0027a5bcab250cc785fa77fdc1e69edbfc1d6d16 Mon Sep 17 00:00:00 2001 From: epochwon Date: Wed, 2 Jul 2025 10:49:27 -0400 Subject: [PATCH 117/330] make the specular terms easier to read, turn the magic number into a const --- files/shaders/compatibility/water.frag | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/files/shaders/compatibility/water.frag b/files/shaders/compatibility/water.frag index 81abdc094f..dbf36560b3 100644 --- a/files/shaders/compatibility/water.frag +++ b/files/shaders/compatibility/water.frag @@ -163,8 +163,13 @@ void main(void) sunSpec.a = min(1.0, sunSpec.a / SUN_SPEC_FADING_THRESHOLD); // specular - vec3 R = reflect(viewDir, normalize(vec3(normal.x * SPEC_BUMPINESS, normal.y * SPEC_BUMPINESS, normal.z))); - float specular = clamp(pow(atan(max(dot(R, sunWorldDir), 0.0) * 1.55), SPEC_HARDNESS) * SPEC_BRIGHTNESS, 0.0, 1.0) * shadow * sunSpec.a; + const float SPEC_MAGIC = 1.55; // from the original blender shader, changing it makes the spec vanish or become too bright + + vec3 specNormal = normalize(vec3(normal.x * SPEC_BUMPINESS, normal.y * SPEC_BUMPINESS, normal.z)); + vec3 viewReflectDir = reflect(viewDir, specNormal); + float phongTerm = max(dot(viewReflectDir, sunWorldDir), 0.0); + float specular = pow(atan(phongTerm * SPEC_MAGIC), SPEC_HARDNESS) * SPEC_BRIGHTNESS; + specular = clamp(specular, 0.0, 1.0) * shadow * sunSpec.a; // artificial specularity to make rain ripples more noticeable vec3 skyColorEstimate = vec3(max(0.0, mix(-0.3, 1.0, sunFade))); From 3767b60512da226faf6cffb1f18bfa5bb2322740 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Wed, 2 Jul 2025 21:35:26 -0700 Subject: [PATCH 118/330] Fix L1 and R1 buttons not disappearing --- apps/openmw/mwgui/inventorywindow.cpp | 2 ++ apps/openmw/mwgui/tradewindow.cpp | 2 ++ files/data/mygui/openmw_inventory_window.layout | 2 ++ files/data/mygui/openmw_trade_window.layout | 2 ++ 4 files changed, 8 insertions(+) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 52d4eae732..38dbff914a 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -135,9 +135,11 @@ namespace MWGui // Show L1 and R1 buttons next to tabs MyGUI::Widget* image; getWidget(image, "BtnL1Image"); + image->setVisible(true); image->setUserString("Hidden", "false"); getWidget(image, "BtnR1Image"); + image->setVisible(true); image->setUserString("Hidden", "false"); mControllerButtons.r3 = "#{sInfo}"; diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index f4f88dda04..c26a7f030a 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -174,9 +174,11 @@ namespace MWGui // Show L1 and R1 buttons next to tabs MyGUI::Widget* image; getWidget(image, "BtnL1Image"); + image->setVisible(true); image->setUserString("Hidden", "false"); getWidget(image, "BtnR1Image"); + image->setVisible(true); image->setUserString("Hidden", "false"); mControllerButtons.a = "#{sBuy}"; diff --git a/files/data/mygui/openmw_inventory_window.layout b/files/data/mygui/openmw_inventory_window.layout index c8b3a6857b..2f2af06021 100644 --- a/files/data/mygui/openmw_inventory_window.layout +++ b/files/data/mygui/openmw_inventory_window.layout @@ -34,6 +34,7 @@ + @@ -60,6 +61,7 @@ + diff --git a/files/data/mygui/openmw_trade_window.layout b/files/data/mygui/openmw_trade_window.layout index c514155981..e5cf8a0ba0 100644 --- a/files/data/mygui/openmw_trade_window.layout +++ b/files/data/mygui/openmw_trade_window.layout @@ -11,6 +11,7 @@ + @@ -37,6 +38,7 @@ + From 7cc25d8916518068be48241d89217fcd349404b5 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Wed, 2 Jul 2025 22:00:40 -0700 Subject: [PATCH 119/330] Dialog window improvements: use LB/RB to move up/down by 5; if only one dialog choice, autoselect it. --- apps/openmw/mwgui/dialogue.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index b96bf85f6f..4a30532f5e 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -968,7 +968,9 @@ namespace MWGui { if (mChoices.size() > 0) { - if (mControllerChoice >= 0 && mControllerChoice < static_cast(mChoices.size())) + if (mChoices.size() == 1) + onChoiceActivated(mChoices[0].second); + else if (mControllerChoice >= 0 && mControllerChoice < static_cast(mChoices.size())) onChoiceActivated(mChoices[mControllerChoice].second); } else if (mControllerFocus == static_cast(mTopicsList->getItemCount())) @@ -1025,6 +1027,18 @@ namespace MWGui setControllerFocus(mControllerFocus, true); } } + else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER && mChoices.size() == 0) + { + setControllerFocus(mControllerFocus, false); + mControllerFocus = std::max(mControllerFocus - 5, 0); + setControllerFocus(mControllerFocus, true); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER && mChoices.size() == 0) + { + setControllerFocus(mControllerFocus, false); + mControllerFocus = std::min(mControllerFocus + 5, static_cast(mTopicsList->getItemCount())); + setControllerFocus(mControllerFocus, true); + } return true; } From 29177bccb8dac4458330f7c0294cc4eb2e9f076f Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Fri, 21 Feb 2025 00:56:09 +0300 Subject: [PATCH 120/330] Play the item's down sound when an item quick key is assigned --- apps/openmw/mwgui/quickkeysmenu.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index c8932c97b6..7e501071e4 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -246,6 +246,8 @@ namespace MWGui if (mItemSelectionDialog) mItemSelectionDialog->setVisible(false); + + MWBase::Environment::get().getWindowManager()->playSound(item.getClass().getDownSoundId(item)); } void QuickKeysMenu::onAssignItemCancel() From 982962c6086b553d6746dfd971e0318a6cbab941 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Fri, 21 Feb 2025 00:56:37 +0300 Subject: [PATCH 121/330] Don't center quick keys menu instructions --- files/data/mygui/openmw_quickkeys_menu.layout | 1 - 1 file changed, 1 deletion(-) diff --git a/files/data/mygui/openmw_quickkeys_menu.layout b/files/data/mygui/openmw_quickkeys_menu.layout index ba6832cf95..892d4e748b 100644 --- a/files/data/mygui/openmw_quickkeys_menu.layout +++ b/files/data/mygui/openmw_quickkeys_menu.layout @@ -12,7 +12,6 @@ - From 733dfbb89d938ebb1c9539205a5713227374fdc1 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Fri, 21 Feb 2025 01:00:17 +0300 Subject: [PATCH 122/330] Don't assume any scripted item is usable --- apps/openmw/mwgui/sortfilteritemmodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index fe85ea4bd0..8c6277db4d 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.cpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.cpp @@ -279,7 +279,7 @@ namespace MWGui && !base.get()->mBase->mData.mIsScroll) return false; - if ((mFilter & Filter_OnlyUsableItems) && base.getClass().getScript(base).empty()) + if ((mFilter & Filter_OnlyUsableItems)) { std::unique_ptr actionOnUse = base.getClass().use(base); if (!actionOnUse || actionOnUse->isNullAction()) From a0e0b3c65b8610365602988372430f21b3abd0d7 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Thu, 3 Jul 2025 08:30:50 +0300 Subject: [PATCH 123/330] Some quick key menu layout fixes --- files/data/mygui/openmw_quickkeys_menu.layout | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/files/data/mygui/openmw_quickkeys_menu.layout b/files/data/mygui/openmw_quickkeys_menu.layout index 892d4e748b..697f186411 100644 --- a/files/data/mygui/openmw_quickkeys_menu.layout +++ b/files/data/mygui/openmw_quickkeys_menu.layout @@ -1,35 +1,35 @@ - + - + - + - + - - - - - + + + + + - + From 206d38f3d7b71ecd78f31d627e52d1d4ca9de8c1 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Wed, 2 Jul 2025 16:58:31 +0200 Subject: [PATCH 124/330] Fix path handling for files in BSAs --- apps/bulletobjecttool/main.cpp | 2 +- apps/components_tests/fx/technique.cpp | 3 +- apps/navmeshtool/main.cpp | 2 +- apps/niftest/niftest.cpp | 4 +- apps/opencs/model/world/data.cpp | 4 +- apps/openmw/engine.cpp | 2 +- apps/openmw/mwgui/postprocessorhud.cpp | 38 ++++++++------ apps/openmw/mwgui/postprocessorhud.hpp | 3 +- apps/openmw/mwrender/postprocessor.cpp | 40 ++++++++------ apps/openmw/mwrender/postprocessor.hpp | 6 +-- components/bsa/ba2dx10file.hpp | 1 + components/bsa/ba2gnrlfile.hpp | 1 + components/bsa/bsafile.hpp | 16 +++--- components/bsa/compressedbsafile.hpp | 1 + components/fx/technique.cpp | 22 ++++---- components/fx/technique.hpp | 10 ++-- components/testing/util.hpp | 4 +- components/vfs/bsaarchive.hpp | 72 ++++++++++++++++++++------ components/vfs/file.hpp | 5 +- components/vfs/filesystemarchive.cpp | 10 ++++ components/vfs/filesystemarchive.hpp | 4 +- components/vfs/manager.cpp | 19 ++++--- components/vfs/manager.hpp | 7 ++- components/vfs/pathutil.hpp | 14 +++++ components/vfs/registerarchives.cpp | 4 +- components/vfs/registerarchives.hpp | 7 ++- 26 files changed, 201 insertions(+), 100 deletions(-) diff --git a/apps/bulletobjecttool/main.cpp b/apps/bulletobjecttool/main.cpp index 5cacedd07e..659d97b7f1 100644 --- a/apps/bulletobjecttool/main.cpp +++ b/apps/bulletobjecttool/main.cpp @@ -155,7 +155,7 @@ namespace VFS::Manager vfs; - VFS::registerArchives(&vfs, fileCollections, archives, true); + VFS::registerArchives(&vfs, fileCollections, archives, true, &encoder.getStatelessEncoder()); Settings::Manager::load(config); diff --git a/apps/components_tests/fx/technique.cpp b/apps/components_tests/fx/technique.cpp index ad57074b18..2becf4da5b 100644 --- a/apps/components_tests/fx/technique.cpp +++ b/apps/components_tests/fx/technique.cpp @@ -113,7 +113,8 @@ namespace void compile(const std::string& name) { - mTechnique = std::make_unique(*mVFS.get(), mImageManager, name, 1, 1, true, true); + mTechnique = std::make_unique( + *mVFS.get(), mImageManager, Technique::makeFileName(name), name, 1, 1, true, true); mTechnique->compile(); } }; diff --git a/apps/navmeshtool/main.cpp b/apps/navmeshtool/main.cpp index 08ed10c3b3..6cfa7fc61d 100644 --- a/apps/navmeshtool/main.cpp +++ b/apps/navmeshtool/main.cpp @@ -189,7 +189,7 @@ namespace NavMeshTool VFS::Manager vfs; - VFS::registerArchives(&vfs, fileCollections, archives, true); + VFS::registerArchives(&vfs, fileCollections, archives, true, &encoder.getStatelessEncoder()); Settings::Manager::load(config); diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp index 8634134665..7f19008bd1 100644 --- a/apps/niftest/niftest.cpp +++ b/apps/niftest/niftest.cpp @@ -113,7 +113,7 @@ bool isBSA(const std::filesystem::path& path) std::unique_ptr makeArchive(const std::filesystem::path& path) { if (isBSA(path)) - return VFS::makeBsaArchive(path); + return VFS::makeBsaArchive(path, nullptr); if (std::filesystem::is_directory(path)) return std::make_unique(path); return nullptr; @@ -198,7 +198,7 @@ void readVFS(std::unique_ptr&& archive, const std::filesystem::pat { try { - readVFS(VFS::makeBsaArchive(file.second), file.second, quiet); + readVFS(VFS::makeBsaArchive(file.second, nullptr), file.second, quiet); } catch (const std::exception& e) { diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 00e5fec7b0..fa9251b949 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -143,7 +143,7 @@ CSMWorld::Data::Data(ToUTF8::FromType encoding, const Files::PathContainer& data , mArchives(archives) , mVFS(std::make_unique()) { - VFS::registerArchives(mVFS.get(), Files::Collections(mDataPaths), mArchives, true); + VFS::registerArchives(mVFS.get(), Files::Collections(mDataPaths), mArchives, true, &mEncoder.getStatelessEncoder()); mResourcesManager.setVFS(mVFS.get()); @@ -1465,7 +1465,7 @@ std::vector CSMWorld::Data::getIds(bool listDeleted) const void CSMWorld::Data::assetsChanged() { mVFS.get()->reset(); - VFS::registerArchives(mVFS.get(), Files::Collections(mDataPaths), mArchives, true); + VFS::registerArchives(mVFS.get(), Files::Collections(mDataPaths), mArchives, true, &mEncoder.getStatelessEncoder()); const UniversalId assetTableIds[] = { UniversalId::Type_Meshes, UniversalId::Type_Icons, UniversalId::Type_Musics, UniversalId::Type_SoundsRes, UniversalId::Type_Textures, UniversalId::Type_Videos }; diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 0f82e953c1..29cfb41071 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -729,7 +729,7 @@ void OMW::Engine::prepareEngine() mVFS = std::make_unique(); - VFS::registerArchives(mVFS.get(), mFileCollections, mArchives, true); + VFS::registerArchives(mVFS.get(), mFileCollections, mArchives, true, &mEncoder.get()->getStatelessEncoder()); mResourceSystem = std::make_unique( mVFS.get(), Settings::cells().mCacheExpiryDelay, &mEncoder.get()->getStatelessEncoder()); diff --git a/apps/openmw/mwgui/postprocessorhud.cpp b/apps/openmw/mwgui/postprocessorhud.cpp index 7712594c54..cc95203a0f 100644 --- a/apps/openmw/mwgui/postprocessorhud.cpp +++ b/apps/openmw/mwgui/postprocessorhud.cpp @@ -33,6 +33,14 @@ namespace MWGui { + namespace + { + std::shared_ptr& getTechnique(const MyGUI::ListBox& list, size_t selected) + { + return *list.getItemDataAt>(selected); + } + } + void PostProcessorHud::ListWrapper::onKeyButtonPressed(MyGUI::KeyCode key, MyGUI::Char ch) { if (MyGUI::InputManager::getInstance().isShiftPressed() @@ -117,7 +125,7 @@ namespace MWGui if (index >= sender->getItemCount()) return; - updateConfigView(sender->getItemNameAt(index)); + updateConfigView(getTechnique(*sender, index)->getFileName()); } void PostProcessorHud::toggleTechnique(bool enabled) @@ -131,7 +139,7 @@ namespace MWGui auto* processor = MWBase::Environment::get().getWorld()->getPostProcessor(); mOverrideHint = list->getItemNameAt(selected); - auto technique = *list->getItemDataAt>(selected); + auto technique = getTechnique(*list, selected); if (technique->getDynamic()) return; @@ -167,7 +175,7 @@ namespace MWGui if (static_cast(index) != selected) { - auto technique = *mActiveList->getItemDataAt>(selected); + auto technique = getTechnique(*mActiveList, selected); if (technique->getDynamic() || technique->getInternal()) return; @@ -290,16 +298,16 @@ namespace MWGui return; if (mInactiveList->getIndexSelected() != MyGUI::ITEM_NONE) - updateConfigView(mInactiveList->getItemNameAt(mInactiveList->getIndexSelected())); + updateConfigView(getTechnique(*mInactiveList, mInactiveList->getIndexSelected())->getFileName()); else if (mActiveList->getIndexSelected() != MyGUI::ITEM_NONE) - updateConfigView(mActiveList->getItemNameAt(mActiveList->getIndexSelected())); + updateConfigView(getTechnique(*mActiveList, mActiveList->getIndexSelected())->getFileName()); } - void PostProcessorHud::updateConfigView(const std::string& name) + void PostProcessorHud::updateConfigView(VFS::Path::NormalizedView path) { auto* processor = MWBase::Environment::get().getWorld()->getPostProcessor(); - auto technique = processor->loadTechnique(name); + auto technique = processor->loadTechnique(path); if (technique->getStatus() == fx::Technique::Status::File_Not_exists) return; @@ -423,22 +431,22 @@ namespace MWGui auto* processor = MWBase::Environment::get().getWorld()->getPostProcessor(); - std::vector techniques; - for (const auto& [name, _] : processor->getTechniqueMap()) - techniques.push_back(name); - std::sort(techniques.begin(), techniques.end(), Misc::StringUtils::ciLess); + std::vector techniques; + for (const auto& vfsPath : processor->getTechniqueFiles()) + techniques.emplace_back(vfsPath); + std::sort(techniques.begin(), techniques.end()); - for (const std::string& name : techniques) + for (VFS::Path::NormalizedView path : techniques) { - auto technique = processor->loadTechnique(name); + auto technique = processor->loadTechnique(path); if (!technique->getHidden() && !processor->isTechniqueEnabled(technique)) { - std::string lowerName = Utf8Stream::lowerCaseUtf8(name); + std::string lowerName = Utf8Stream::lowerCaseUtf8(technique->getName()); std::string lowerCaption = mFilter->getCaption(); lowerCaption = Utf8Stream::lowerCaseUtf8(lowerCaption); if (lowerName.find(lowerCaption) != std::string::npos) - mInactiveList->addItem(name, technique); + mInactiveList->addItem(technique->getName(), technique); } } diff --git a/apps/openmw/mwgui/postprocessorhud.hpp b/apps/openmw/mwgui/postprocessorhud.hpp index 20e27bac3a..0028999966 100644 --- a/apps/openmw/mwgui/postprocessorhud.hpp +++ b/apps/openmw/mwgui/postprocessorhud.hpp @@ -6,6 +6,7 @@ #include #include +#include namespace MyGUI { @@ -48,7 +49,7 @@ namespace MWGui void notifyFilterChanged(MyGUI::EditBox* sender); - void updateConfigView(const std::string& name); + void updateConfigView(VFS::Path::NormalizedView path); void notifyResetButtonClicked(MyGUI::Widget* sender); diff --git a/apps/openmw/mwrender/postprocessor.cpp b/apps/openmw/mwrender/postprocessor.cpp index 1f1b7258b3..3a2d5218d5 100644 --- a/apps/openmw/mwrender/postprocessor.cpp +++ b/apps/openmw/mwrender/postprocessor.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -250,14 +251,12 @@ namespace MWRender void PostProcessor::populateTechniqueFiles() { - for (const auto& name : mVFS->getRecursiveDirectoryIterator(fx::Technique::sSubdir)) + for (const auto& path : mVFS->getRecursiveDirectoryIterator(fx::Technique::sSubdir)) { - std::filesystem::path path = Files::pathFromUnicodeString(name); - std::string fileExt = Misc::StringUtils::lowerCase(Files::pathToUnicodeString(path.extension())); - if (!path.parent_path().has_parent_path() && fileExt == fx::Technique::sExt) + std::string_view fileExt = Misc::getFileExtension(path); + if (path.parent().parent().empty() && fileExt == fx::Technique::sExt) { - const auto absolutePath = mVFS->getAbsoluteFileName(path); - mTechniqueFileMap[Files::pathToUnicodeString(absolutePath.stem())] = absolutePath; + mTechniqueFiles.emplace(path); } } } @@ -351,7 +350,7 @@ namespace MWRender if (technique->getStatus() == fx::Technique::Status::File_Not_exists) continue; - const auto lastWriteTime = std::filesystem::last_write_time(mTechniqueFileMap[technique->getName()]); + const auto lastWriteTime = mVFS->getLastModified(technique->getFileName()); const bool isDirty = technique->setLastModificationTime(lastWriteTime); if (!isDirty) @@ -363,7 +362,7 @@ namespace MWRender std::this_thread::sleep_for(std::chrono::milliseconds(5)); if (technique->compile()) - Log(Debug::Info) << "Reloaded technique : " << mTechniqueFileMap[technique->getName()]; + Log(Debug::Info) << "Reloaded technique : " << technique->getFileName(); mReload = technique->isValid(); } @@ -750,27 +749,31 @@ namespace MWRender } std::shared_ptr PostProcessor::loadTechnique(const std::string& name, bool loadNextFrame) + { + VFS::Path::Normalized path = fx::Technique::makeFileName(name); + return loadTechnique(VFS::Path::NormalizedView(path), loadNextFrame); + } + + std::shared_ptr PostProcessor::loadTechnique(VFS::Path::NormalizedView path, bool loadNextFrame) { for (const auto& technique : mTemplates) - if (Misc::StringUtils::ciEqual(technique->getName(), name)) + if (technique->getFileName() == path) return technique; for (const auto& technique : mQueuedTemplates) - if (Misc::StringUtils::ciEqual(technique->getName(), name)) + if (technique->getFileName() == path) return technique; - std::string realName = name; - auto fileIter = mTechniqueFileMap.find(name); - if (fileIter != mTechniqueFileMap.end()) - realName = fileIter->first; + if (!mTechniqueFiles.contains(path)) + return {}; auto technique = std::make_shared(*mVFS, *mRendering.getResourceSystem()->getImageManager(), - std::move(realName), renderWidth(), renderHeight(), mUBO, mNormalsSupported); + path, mVFS->getStem(path), renderWidth(), renderHeight(), mUBO, mNormalsSupported); technique->compile(); if (technique->getStatus() != fx::Technique::Status::File_Not_exists) - technique->setLastModificationTime(std::filesystem::last_write_time(fileIter->second)); + technique->setLastModificationTime(mVFS->getLastModified(path)); if (loadNextFrame) { @@ -802,7 +805,10 @@ namespace MWRender if (techniqueName.empty()) continue; - mTechniques.push_back(loadTechnique(techniqueName)); + auto technique = loadTechnique(techniqueName); + if (!technique) + continue; + mTechniques.push_back(std::move(technique)); } dirtyTechniques(); diff --git a/apps/openmw/mwrender/postprocessor.hpp b/apps/openmw/mwrender/postprocessor.hpp index 6b1f4612f1..4b854cbc9c 100644 --- a/apps/openmw/mwrender/postprocessor.hpp +++ b/apps/openmw/mwrender/postprocessor.hpp @@ -128,7 +128,7 @@ namespace MWRender const TechniqueList& getTemplates() const { return mTemplates; } - const auto& getTechniqueMap() const { return mTechniqueFileMap; } + const auto& getTechniqueFiles() const { return mTechniqueFiles; } void resize(); @@ -176,6 +176,7 @@ namespace MWRender void toggleMode(); + std::shared_ptr loadTechnique(VFS::Path::NormalizedView path, bool loadNextFrame = false); std::shared_ptr loadTechnique(const std::string& name, bool loadNextFrame = false); TechniqueList getChain(); @@ -232,8 +233,7 @@ namespace MWRender TechniqueList mQueuedTemplates; TechniqueList mInternalTechniques; - std::unordered_map - mTechniqueFileMap; + std::unordered_set> mTechniqueFiles; RenderingManager& mRendering; osgViewer::Viewer* mViewer; diff --git a/components/bsa/ba2dx10file.hpp b/components/bsa/ba2dx10file.hpp index cd1f822179..c902a4ccb0 100644 --- a/components/bsa/ba2dx10file.hpp +++ b/components/bsa/ba2dx10file.hpp @@ -50,6 +50,7 @@ namespace Bsa public: using BSAFile::getFilename; using BSAFile::getList; + using BSAFile::getPath; using BSAFile::open; BA2DX10File(); diff --git a/components/bsa/ba2gnrlfile.hpp b/components/bsa/ba2gnrlfile.hpp index 0bc94eae0e..080ba3a8df 100644 --- a/components/bsa/ba2gnrlfile.hpp +++ b/components/bsa/ba2gnrlfile.hpp @@ -38,6 +38,7 @@ namespace Bsa public: using BSAFile::getFilename; using BSAFile::getList; + using BSAFile::getPath; using BSAFile::open; BA2GNRLFile(); diff --git a/components/bsa/bsafile.hpp b/components/bsa/bsafile.hpp index ad7acdad17..7b910208d8 100644 --- a/components/bsa/bsafile.hpp +++ b/components/bsa/bsafile.hpp @@ -84,15 +84,15 @@ namespace Bsa protected: bool mHasChanged = false; + /// True when an archive has been loaded + bool mIsLoaded = false; + /// Table of files in this archive FileList mFiles; /// Filename string buffer std::vector mStringBuf; - /// True when an archive has been loaded - bool mIsLoaded; - /// Used for error messages std::filesystem::path mFilepath; @@ -109,11 +109,6 @@ namespace Bsa * ----------------------------------- */ - BSAFile() - : mIsLoaded(false) - { - } - virtual ~BSAFile() { close(); @@ -148,6 +143,11 @@ namespace Bsa return Files::pathToUnicodeString(mFilepath); } + const std::filesystem::path& getPath() const + { + return mFilepath; + } + // checks version of BSA from file header static BsaVersion detectVersion(const std::filesystem::path& filePath); }; diff --git a/components/bsa/compressedbsafile.hpp b/components/bsa/compressedbsafile.hpp index 83620f11bc..1e359ea3fe 100644 --- a/components/bsa/compressedbsafile.hpp +++ b/components/bsa/compressedbsafile.hpp @@ -117,6 +117,7 @@ namespace Bsa public: using BSAFile::getFilename; using BSAFile::getList; + using BSAFile::getPath; using BSAFile::open; CompressedBSAFile() = default; diff --git a/components/fx/technique.cpp b/components/fx/technique.cpp index a8cd455dea..58ea55b2f6 100644 --- a/components/fx/technique.cpp +++ b/components/fx/technique.cpp @@ -37,22 +37,20 @@ namespace namespace fx { - namespace + VFS::Path::Normalized Technique::makeFileName(std::string_view name) { - VFS::Path::Normalized makeFilePath(std::string_view name) - { - std::string fileName(name); - fileName += Technique::sExt; - VFS::Path::Normalized result(Technique::sSubdir); - result /= fileName; - return result; - } + std::string fileName(name); + fileName += '.'; + fileName += Technique::sExt; + VFS::Path::Normalized result(Technique::sSubdir); + result /= fileName; + return result; } - Technique::Technique(const VFS::Manager& vfs, Resource::ImageManager& imageManager, std::string name, int width, - int height, bool ubo, bool supportsNormals) + Technique::Technique(const VFS::Manager& vfs, Resource::ImageManager& imageManager, + VFS::Path::NormalizedView fileName, std::string name, int width, int height, bool ubo, bool supportsNormals) : mName(std::move(name)) - , mFilePath(makeFilePath(mName)) + , mFilePath(fileName) , mLastModificationTime(std::filesystem::file_time_type::clock::now()) , mWidth(width) , mHeight(height) diff --git a/components/fx/technique.hpp b/components/fx/technique.hpp index ad5e876faa..00b87a86e2 100644 --- a/components/fx/technique.hpp +++ b/components/fx/technique.hpp @@ -105,8 +105,8 @@ namespace fx using UniformMap = std::vector>; using RenderTargetMap = std::unordered_map; - static constexpr std::string_view sExt = ".omwfx"; - static constexpr std::string_view sSubdir = "shaders"; + static constexpr std::string_view sExt = "omwfx"; + static constexpr VFS::Path::NormalizedView sSubdir{ "shaders" }; enum class Status { @@ -123,8 +123,10 @@ namespace fx static constexpr FlagsType Flag_Disable_SunGlare = (1 << 4); static constexpr FlagsType Flag_Hidden = (1 << 5); - Technique(const VFS::Manager& vfs, Resource::ImageManager& imageManager, std::string name, int width, - int height, bool ubo, bool supportsNormals); + static VFS::Path::Normalized makeFileName(std::string_view name); + + Technique(const VFS::Manager& vfs, Resource::ImageManager& imageManager, VFS::Path::NormalizedView fileName, + std::string name, int width, int height, bool ubo, bool supportsNormals); bool compile(); diff --git a/components/testing/util.hpp b/components/testing/util.hpp index 53331d6d37..e2183d5403 100644 --- a/components/testing/util.hpp +++ b/components/testing/util.hpp @@ -56,7 +56,9 @@ namespace TestingOpenMW Files::IStreamPtr open() override { return std::make_unique(mContent, std::ios_base::in); } - std::filesystem::path getPath() override { return "TestFile"; } + std::filesystem::file_time_type getLastModified() const override { return {}; } + + std::string getStem() const override { return "TestFile"; } private: const std::string mContent; diff --git a/components/vfs/bsaarchive.hpp b/components/vfs/bsaarchive.hpp index 2e6fac6558..f89e47d971 100644 --- a/components/vfs/bsaarchive.hpp +++ b/components/vfs/bsaarchive.hpp @@ -10,45 +10,72 @@ #include #include +#include + #include #include #include namespace VFS { + template + class BsaArchive; + template class BsaArchiveFile : public File { public: - BsaArchiveFile(const Bsa::BSAFile::FileStruct* info, FileType* bsa) + BsaArchiveFile(const Bsa::BSAFile::FileStruct* info, const BsaArchive* bsa) : mInfo(info) , mFile(bsa) { } - Files::IStreamPtr open() override { return mFile->getFile(mInfo); } + Files::IStreamPtr open() override { return mFile->getFile()->getFile(mInfo); } - std::filesystem::path getPath() override { return mInfo->name(); } + std::filesystem::file_time_type getLastModified() const override + { + return std::filesystem::last_write_time(mFile->getFile()->getPath()); + } + + std::string getStem() const override + { + std::string_view name = mInfo->name(); + auto index = name.find_last_of("\\/"); + if (index != std::string_view::npos) + name = name.substr(index + 1); + index = name.find_last_of('.'); + if (index != std::string_view::npos && index != 0) + name = name.substr(0, index); + std::string out; + std::string_view utf8 = mFile->getUtf8(name, out); + if (out.data() == utf8.data()) + out.resize(utf8.size()); + else + out = utf8; + return out; + } const Bsa::BSAFile::FileStruct* mInfo; - FileType* mFile; + const BsaArchive* mFile; }; template class BsaArchive : public Archive { public: - BsaArchive(const std::filesystem::path& filename) + BsaArchive(const std::filesystem::path& filename, const ToUTF8::StatelessUtf8Encoder* encoder) : Archive() + , mEncoder(encoder) { mFile = std::make_unique(); mFile->open(filename); - const Bsa::BSAFile::FileList& filelist = mFile->getList(); - for (Bsa::BSAFile::FileList::const_iterator it = filelist.begin(); it != filelist.end(); ++it) + std::string buffer; + for (const Bsa::BSAFile::FileStruct& file : mFile->getList()) { - mResources.emplace_back(&*it, mFile.get()); - mFiles.emplace_back(it->name()); + mResources.emplace_back(&file, this); + mFiles.emplace_back(getUtf8(file.name(), buffer)); } std::sort(mFiles.begin(), mFiles.end()); @@ -56,8 +83,12 @@ namespace VFS void listResources(FileMap& out) override { + std::string buffer; for (auto& resource : mResources) - out[VFS::Path::Normalized(resource.mInfo->name())] = &resource; + { + std::string_view path = getUtf8(resource.mInfo->name(), buffer); + out[VFS::Path::Normalized(path)] = &resource; + } } bool contains(Path::NormalizedView file) const override @@ -67,26 +98,37 @@ namespace VFS std::string getDescription() const override { return std::string{ "BSA: " } + mFile->getFilename(); } + BSAFileType* getFile() const { return mFile.get(); } + + std::string_view getUtf8(std::string_view input, std::string& buffer) const + { + if (mEncoder == nullptr) + return input; + return mEncoder->getUtf8(input, ToUTF8::BufferAllocationPolicy::UseGrowFactor, buffer); + } + private: std::unique_ptr mFile; std::vector> mResources; std::vector mFiles; + const ToUTF8::StatelessUtf8Encoder* mEncoder; }; - inline std::unique_ptr makeBsaArchive(const std::filesystem::path& path) + inline std::unique_ptr makeBsaArchive( + const std::filesystem::path& path, const ToUTF8::StatelessUtf8Encoder* encoder) { switch (Bsa::BSAFile::detectVersion(path)) { case Bsa::BsaVersion::Unknown: break; case Bsa::BsaVersion::Uncompressed: - return std::make_unique>(path); + return std::make_unique>(path, encoder); case Bsa::BsaVersion::Compressed: - return std::make_unique>(path); + return std::make_unique>(path, encoder); case Bsa::BsaVersion::BA2GNRL: - return std::make_unique>(path); + return std::make_unique>(path, encoder); case Bsa::BsaVersion::BA2DX10: - return std::make_unique>(path); + return std::make_unique>(path, encoder); } throw std::runtime_error("Unknown archive type '" + Files::pathToUnicodeString(path) + "'"); diff --git a/components/vfs/file.hpp b/components/vfs/file.hpp index f2dadb1162..7c65e3a1ba 100644 --- a/components/vfs/file.hpp +++ b/components/vfs/file.hpp @@ -2,6 +2,7 @@ #define OPENMW_COMPONENTS_VFS_FILE_H #include +#include #include @@ -14,7 +15,9 @@ namespace VFS virtual Files::IStreamPtr open() = 0; - virtual std::filesystem::path getPath() = 0; + virtual std::filesystem::file_time_type getLastModified() const = 0; + + virtual std::string getStem() const = 0; }; } diff --git a/components/vfs/filesystemarchive.cpp b/components/vfs/filesystemarchive.cpp index 3303c6656c..0b67df45bc 100644 --- a/components/vfs/filesystemarchive.cpp +++ b/components/vfs/filesystemarchive.cpp @@ -81,4 +81,14 @@ namespace VFS return Files::openConstrainedFileStream(mPath); } + std::filesystem::file_time_type FileSystemArchiveFile::getLastModified() const + { + return std::filesystem::last_write_time(mPath); + } + + std::string FileSystemArchiveFile::getStem() const + { + return Files::pathToUnicodeString(mPath.stem()); + } + } diff --git a/components/vfs/filesystemarchive.hpp b/components/vfs/filesystemarchive.hpp index 215c443b58..f6b1a2ec5e 100644 --- a/components/vfs/filesystemarchive.hpp +++ b/components/vfs/filesystemarchive.hpp @@ -17,7 +17,9 @@ namespace VFS Files::IStreamPtr open() override; - std::filesystem::path getPath() override { return mPath; } + std::filesystem::file_time_type getLastModified() const override; + + std::string getStem() const override; private: std::filesystem::path mPath; diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp index 12ef378017..ff25150f67 100644 --- a/components/vfs/manager.cpp +++ b/components/vfs/manager.cpp @@ -81,15 +81,20 @@ namespace VFS return {}; } - std::filesystem::path Manager::getAbsoluteFileName(const std::filesystem::path& name) const + std::filesystem::file_time_type Manager::getLastModified(VFS::Path::NormalizedView name) const { - std::string normalized = Files::pathToUnicodeString(name); - Path::normalizeFilenameInPlace(normalized); - - const auto found = mIndex.find(normalized); + const auto found = mIndex.find(name); if (found == mIndex.end()) - throw std::runtime_error("Resource '" + normalized + "' is not found"); - return found->second->getPath(); + throw std::runtime_error("Resource '" + std::string(name.value()) + "' not found"); + return found->second->getLastModified(); + } + + std::string Manager::getStem(VFS::Path::NormalizedView name) const + { + const auto found = mIndex.find(name); + if (found == mIndex.end()) + throw std::runtime_error("Resource '" + std::string(name.value()) + "' not found"); + return found->second->getStem(); } RecursiveDirectoryRange Manager::getRecursiveDirectoryIterator(std::string_view path) const diff --git a/components/vfs/manager.hpp b/components/vfs/manager.hpp index b6a9d796cc..3d10b3f355 100644 --- a/components/vfs/manager.hpp +++ b/components/vfs/manager.hpp @@ -72,10 +72,9 @@ namespace VFS RecursiveDirectoryRange getRecursiveDirectoryIterator() const; - /// Retrieve the absolute path to the file - /// @note Throws an exception if the file can not be found. - /// @note May be called from any thread once the index has been built. - std::filesystem::path getAbsoluteFileName(const std::filesystem::path& name) const; + std::filesystem::file_time_type getLastModified(VFS::Path::NormalizedView name) const; + // Equivalent to std::filesystem::path::stem. The result isn't normalized. + std::string getStem(VFS::Path::NormalizedView name) const; private: std::vector> mArchives; diff --git a/components/vfs/pathutil.hpp b/components/vfs/pathutil.hpp index f5393617d7..b4b4f6e278 100644 --- a/components/vfs/pathutil.hpp +++ b/components/vfs/pathutil.hpp @@ -127,6 +127,15 @@ namespace VFS::Path return stream << value.mValue; } + NormalizedView parent() const + { + NormalizedView p; + const std::size_t pos = mValue.find_last_of(separator); + if (pos != std::string_view::npos) + p.mValue = mValue.substr(0, pos); + return p; + } + private: std::string_view mValue; }; @@ -259,6 +268,11 @@ namespace VFS::Path return stream << value.mValue; } + NormalizedView parent() const + { + return NormalizedView(*this).parent(); + } + private: std::string mValue; }; diff --git a/components/vfs/registerarchives.cpp b/components/vfs/registerarchives.cpp index f017b5f73c..1d03766220 100644 --- a/components/vfs/registerarchives.cpp +++ b/components/vfs/registerarchives.cpp @@ -14,7 +14,7 @@ namespace VFS { void registerArchives(VFS::Manager* vfs, const Files::Collections& collections, - const std::vector& archives, bool useLooseFiles) + const std::vector& archives, bool useLooseFiles, const ToUTF8::StatelessUtf8Encoder* encoder) { const Files::PathContainer& dataDirs = collections.getPaths(); @@ -25,7 +25,7 @@ namespace VFS // Last BSA has the highest priority const auto archivePath = collections.getPath(*archive); Log(Debug::Info) << "Adding BSA archive " << archivePath; - vfs->addArchive(makeBsaArchive(archivePath)); + vfs->addArchive(makeBsaArchive(archivePath, encoder)); } else { diff --git a/components/vfs/registerarchives.hpp b/components/vfs/registerarchives.hpp index dac29f87a3..03247b74d3 100644 --- a/components/vfs/registerarchives.hpp +++ b/components/vfs/registerarchives.hpp @@ -3,13 +3,18 @@ #include +namespace ToUTF8 +{ + class StatelessUtf8Encoder; +} + namespace VFS { class Manager; /// @brief Register BSA and file system archives based on the given OpenMW configuration. void registerArchives(VFS::Manager* vfs, const Files::Collections& collections, - const std::vector& archives, bool useLooseFiles); + const std::vector& archives, bool useLooseFiles, const ToUTF8::StatelessUtf8Encoder* encoder); } #endif From a6cf35982005eea1cdc1c6b2c0bac364cedda95a Mon Sep 17 00:00:00 2001 From: Kuyondo <2538602-Kuyondo@users.noreply.gitlab.com> Date: Mon, 28 Apr 2025 17:02:17 +0800 Subject: [PATCH 125/330] update offer player side, next frame update view --- apps/openmw/mwgui/companionwindow.cpp | 17 +++++++++-- apps/openmw/mwgui/companionwindow.hpp | 7 ++--- apps/openmw/mwgui/container.cpp | 21 +++++++++++-- apps/openmw/mwgui/container.hpp | 9 +++--- apps/openmw/mwgui/draganddrop.cpp | 13 +++++--- apps/openmw/mwgui/inventorywindow.cpp | 44 ++++++++++++--------------- apps/openmw/mwgui/inventorywindow.hpp | 4 +-- apps/openmw/mwgui/tradewindow.cpp | 24 ++++++++++----- apps/openmw/mwgui/tradewindow.hpp | 18 ++++++----- 9 files changed, 96 insertions(+), 61 deletions(-) diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 731403f3a3..bdcb8abc9b 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -43,6 +43,7 @@ namespace MWGui , mSortModel(nullptr) , mModel(nullptr) , mSelectedItem(-1) + , mUpdateNextFrame(false) , mDragAndDrop(dragAndDrop) , mMessageBoxManager(manager) { @@ -141,7 +142,13 @@ namespace MWGui void CompanionWindow::onFrame(float dt) { checkReferenceAvailable(); - updateEncumbranceBar(); + + if (mUpdateNextFrame) + { + updateEncumbranceBar(); + mItemView->update(); + mUpdateNextFrame = false; + } } void CompanionWindow::updateEncumbranceBar() @@ -204,9 +211,13 @@ namespace MWGui mSortModel = nullptr; } - void CompanionWindow::updateItemView() + void CompanionWindow::itemAdded(const MWWorld::ConstPtr& item, int count) { - mItemView->update(); + mUpdateNextFrame = true; } + void CompanionWindow::itemRemoved(const MWWorld::ConstPtr& item, int count) + { + mUpdateNextFrame = true; + } } diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index 6f8452997f..5a4b5880ff 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -32,10 +32,8 @@ namespace MWGui void onFrame(float dt) override; void clear() override { resetReference(); } - void updateItemView(); - - void itemAdded(const MWWorld::ConstPtr& item, int count) override { updateItemView(); } - void itemRemoved(const MWWorld::ConstPtr& item, int count) override { updateItemView(); } + void itemAdded(const MWWorld::ConstPtr& item, int count) override; + void itemRemoved(const MWWorld::ConstPtr& item, int count) override; std::string_view getWindowIdForLua() const override { return "Companion"; } @@ -44,6 +42,7 @@ namespace MWGui SortFilterItemModel* mSortModel; CompanionItemModel* mModel; int mSelectedItem; + bool mUpdateNextFrame; DragAndDrop* mDragAndDrop; diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index bb0f90ddc9..6e768f6e1e 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -38,6 +38,7 @@ namespace MWGui , mSortModel(nullptr) , mModel(nullptr) , mSelectedItem(-1) + , mUpdateNextFrame(false) , mTreatNextOpenAsLoot(false) { getWidget(mDisposeCorpseButton, "DisposeCorpseButton"); @@ -323,8 +324,24 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); } - void ContainerWindow::updateItemView() + void ContainerWindow::onFrame(float dt) { - mItemView->update(); + checkReferenceAvailable(); + + if (mUpdateNextFrame) + { + mItemView->update(); + mUpdateNextFrame = false; + } + } + + void ContainerWindow::itemAdded(const MWWorld::ConstPtr& item, int count) + { + mUpdateNextFrame = true; + } + + void ContainerWindow::itemRemoved(const MWWorld::ConstPtr& item, int count) + { + mUpdateNextFrame = true; } } diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 4898a0eb1c..a7702ebbfe 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -32,7 +32,7 @@ namespace MWGui void onClose() override; void clear() override { resetReference(); } - void onFrame(float dt) override { checkReferenceAvailable(); } + void onFrame(float dt) override; void resetReference() override; @@ -40,10 +40,8 @@ namespace MWGui void treatNextOpenAsLoot() { mTreatNextOpenAsLoot = true; } - void updateItemView(); - - void itemAdded(const MWWorld::ConstPtr& item, int count) override { updateItemView(); } - void itemRemoved(const MWWorld::ConstPtr& item, int count) override { updateItemView(); } + void itemAdded(const MWWorld::ConstPtr& item, int count) override; + void itemRemoved(const MWWorld::ConstPtr& item, int count) override; std::string_view getWindowIdForLua() const override { return "Container"; } @@ -54,6 +52,7 @@ namespace MWGui SortFilterItemModel* mSortModel; ItemModel* mModel; int mSelectedItem; + bool mUpdateNextFrame; bool mTreatNextOpenAsLoot; MyGUI::Button* mDisposeCorpseButton; MyGUI::Button* mTakeButton; diff --git a/apps/openmw/mwgui/draganddrop.cpp b/apps/openmw/mwgui/draganddrop.cpp index 17ce5360c0..52b0939238 100644 --- a/apps/openmw/mwgui/draganddrop.cpp +++ b/apps/openmw/mwgui/draganddrop.cpp @@ -84,13 +84,12 @@ namespace MWGui mDraggedWidget->setNeedMouseFocus(false); mDraggedWidget->setCount(count); - sourceView->update(); - MWBase::Environment::get().getWindowManager()->setDragDrop(true); mIsOnDragAndDrop = true; - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView(); + // Update item view after completing drag-and-drop setup + mSourceView->update(); } void DragAndDrop::drop(ItemModel* targetModel, ItemView* targetView) @@ -153,8 +152,12 @@ namespace MWGui // since mSourceView doesn't get updated in drag() MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView(); - MyGUI::Gui::getInstance().destroyWidget(mDraggedWidget); - mDraggedWidget = nullptr; + if (mDraggedWidget) + { + MyGUI::Gui::getInstance().destroyWidget(mDraggedWidget); + mDraggedWidget = nullptr; + } + MWBase::Environment::get().getWindowManager()->setDragDrop(false); } diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 656f1a3db4..43163e175d 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -86,7 +86,7 @@ namespace MWGui , mLastYSize(0) , mPreview(std::make_unique(parent, resourceSystem, MWMechanics::getPlayer())) , mTrading(false) - , mUpdateTimer(0.f) + , mUpdateNextFrame(false) { mPreviewTexture = std::make_unique(mPreview->getTexture(), mPreview->getTextureStateSet()); @@ -683,22 +683,21 @@ namespace MWGui void InventoryWindow::onFrame(float dt) { - updateEncumbranceBar(); - - if (mPinned) + if (mUpdateNextFrame) { - mUpdateTimer += dt; - if (0.1f < mUpdateTimer) + if (mTrading) { - mUpdateTimer = 0; - - // Update pinned inventory in-game - if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) - { - mItemView->update(); - notifyContentChanged(); - } + mTradeModel->updateBorrowed(); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->mTradeModel->updateBorrowed(); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->updateItemView(); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->updateOffer(); } + + updateEncumbranceBar(); + mDragAndDrop->update(); + mItemView->update(); + notifyContentChanged(); + mUpdateNextFrame = false; } } @@ -850,19 +849,14 @@ namespace MWGui mPreview->rebuild(); } + void InventoryWindow::itemAdded(const MWWorld::ConstPtr& item, int count) + { + mUpdateNextFrame = true; + } + void InventoryWindow::itemRemoved(const MWWorld::ConstPtr& item, int count) { - if (mDragAndDrop->mIsOnDragAndDrop && mDragAndDrop->mItem.mBase == item) - mDragAndDrop->update(); - - if (mTrading) - { - mTradeModel->updateBorrowed(); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->getTradeModel()->updateBorrowed(); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->updateItemView(); - } - - updateItemView(); + mUpdateNextFrame = true; } MyGUI::IntSize InventoryWindow::getPreviewViewportSize() const diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 079e629673..7f0d64dce0 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -63,7 +63,7 @@ namespace MWGui void setGuiMode(GuiMode mode); - void itemAdded(const MWWorld::ConstPtr& item, int count) override { updateItemView(); } + void itemAdded(const MWWorld::ConstPtr& item, int count) override; void itemRemoved(const MWWorld::ConstPtr& item, int count) override; /// Cycle to previous/next weapon @@ -111,7 +111,7 @@ namespace MWGui std::unique_ptr mPreview; bool mTrading; - float mUpdateTimer; + bool mUpdateNextFrame; void toggleMaximized(); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index cf882d96cf..ea124f0a97 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -123,6 +123,7 @@ namespace MWGui , mItemToSell(-1) , mCurrentBalance(0) , mCurrentMerchantOffer(0) + , mUpdateNextFrame(false) { getWidget(mFilterAll, "AllButton"); getWidget(mFilterWeapon, "WeaponButton"); @@ -209,6 +210,16 @@ namespace MWGui void TradeWindow::onFrame(float dt) { checkReferenceAvailable(); + + if (isVisible() && mUpdateNextFrame) + { + mTradeModel->updateBorrowed(); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getTradeModel()->updateBorrowed(); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView(); + mItemView->update(); + updateOffer(); + mUpdateNextFrame = false; + } } void TradeWindow::onNameFilterChanged(MyGUI::EditBox* _sender) @@ -652,14 +663,13 @@ namespace MWGui mItemView->update(); } + void TradeWindow::itemAdded(const MWWorld::ConstPtr& item, int count) + { + mUpdateNextFrame = true; + } + void TradeWindow::itemRemoved(const MWWorld::ConstPtr& item, int count) { - mTradeModel->updateBorrowed(); - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getTradeModel()->updateBorrowed(); - - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView(); - updateItemView(); - - updateOffer(); + mUpdateNextFrame = true; } } diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 748d7ce7d5..b0581d0d38 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -33,22 +33,15 @@ namespace MWGui void onFrame(float dt) override; void clear() override { resetReference(); } - void borrowItem(int index, size_t count); - void returnItem(int index, size_t count); - - int getMerchantServices(); - bool exit() override; void resetReference() override; void onDeleteCustomData(const MWWorld::Ptr& ptr) override; - TradeItemModel* getTradeModel() { return mTradeModel; } - void updateItemView(); - void itemAdded(const MWWorld::ConstPtr& item, int count) override { updateItemView(); } + void itemAdded(const MWWorld::ConstPtr& item, int count) override; void itemRemoved(const MWWorld::ConstPtr& item, int count) override; typedef MyGUI::delegates::MultiDelegate<> EventHandle_TradeDone; @@ -57,6 +50,8 @@ namespace MWGui std::string_view getWindowIdForLua() const override { return "Trade"; } private: + friend class InventoryWindow; + ItemView* mItemView; SortFilterItemModel* mSortModel; TradeItemModel* mTradeModel; @@ -90,6 +85,8 @@ namespace MWGui int mCurrentBalance; int mCurrentMerchantOffer; + bool mUpdateNextFrame; + void sellToNpc( const MWWorld::Ptr& item, int count, bool boughtItem); ///< only used for adjusting the gold balance void buyFromNpc( @@ -100,6 +97,11 @@ namespace MWGui void onItemSelected(int index); void sellItem(MyGUI::Widget* sender, int count); + void borrowItem(int index, size_t count); + void returnItem(int index, size_t count); + + int getMerchantServices(); + void onFilterChanged(MyGUI::Widget* _sender); void onNameFilterChanged(MyGUI::EditBox* _sender); void onOfferButtonClicked(MyGUI::Widget* _sender); From 32f59c16aa422608fb95cb576f3142100109e2e5 Mon Sep 17 00:00:00 2001 From: Kuyondo Date: Mon, 2 Jun 2025 01:10:55 +0800 Subject: [PATCH 126/330] move some util to lua --- components/CMakeLists.txt | 1 + components/lua/util.lua | 21 +++++++++++++++++++++ components/lua/utilpackage.cpp | 12 +++++------- 3 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 components/lua/util.lua diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index aa6c8763bb..69c7ba462e 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -61,6 +61,7 @@ add_component_dir (lua luastate scriptscontainer asyncpackage utilpackage serialization configuration l10n storage utf8 shapes/box inputactions yamlloader scripttracker luastateptr ) +copy_resource_file("lua/util.lua" "${OPENMW_RESOURCES_ROOT}" "resources/lua_libs/util.lua") add_component_dir (l10n messagebundles manager diff --git a/components/lua/util.lua b/components/lua/util.lua new file mode 100644 index 0000000000..10b2a46418 --- /dev/null +++ b/components/lua/util.lua @@ -0,0 +1,21 @@ + +local M = {} + +function M.remap(value, min, max, newMin, newMax) + return newMin + (value - min) * (newMax - newMin) / (max - min) +end + +function M.round(value) + return value >= 0 and math.floor(value + 0.5) or math.ceil(value - 0.5) +end + +function M.clamp(value, low, high) + return value < low and low or (value > high and high or value) +end + +function M.normalizeAngle(angle) + local fullTurns = angle / (2 * math.pi) + 0.5 + return (fullTurns - math.floor(fullTurns) - 0.5) * (2 * math.pi) +end + +return M \ No newline at end of file diff --git a/components/lua/utilpackage.cpp b/components/lua/utilpackage.cpp index 85492ccf06..2b706e1cb8 100644 --- a/components/lua/utilpackage.cpp +++ b/components/lua/utilpackage.cpp @@ -352,16 +352,14 @@ namespace LuaUtil return std::make_tuple(angles.z(), angles.y(), angles.x()); }; + sol::function luaUtilLoader = lua["loadInternalLib"]("util"); + sol::table utils = luaUtilLoader(); + for (const auto& [key, value] : utils) + util[key.as()] = value; + // Utility functions - util["clamp"] = [](double value, double from, double to) { return std::clamp(value, from, to); }; - // NOTE: `util["clamp"] = std::clamp` causes error 'AddressSanitizer: stack-use-after-scope' - util["normalizeAngle"] = &Misc::normalizeAngle; util["makeReadOnly"] = [](const sol::table& tbl) { return makeReadOnly(tbl, /*strictIndex=*/false); }; util["makeStrictReadOnly"] = [](const sol::table& tbl) { return makeReadOnly(tbl, /*strictIndex=*/true); }; - util["remap"] = [](double value, double min, double max, double newMin, double newMax) { - return newMin + (value - min) * (newMax - newMin) / (max - min); - }; - util["round"] = [](double value) { return round(value); }; if (lua["bit32"] != sol::nil) { From dbc732231f5eb19377f2bc7a43a99b0543b295fe Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Thu, 3 Jul 2025 17:21:50 +0200 Subject: [PATCH 127/330] Allow non-existent techniques to exist --- apps/openmw/mwrender/postprocessor.cpp | 20 ++++++++++++-------- apps/openmw/mwrender/postprocessor.hpp | 2 +- components/vfs/pathutil.hpp | 17 +++++++++++++++++ 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/postprocessor.cpp b/apps/openmw/mwrender/postprocessor.cpp index 3a2d5218d5..379b71bc66 100644 --- a/apps/openmw/mwrender/postprocessor.cpp +++ b/apps/openmw/mwrender/postprocessor.cpp @@ -748,7 +748,7 @@ namespace MWRender return technique->isValid(); } - std::shared_ptr PostProcessor::loadTechnique(const std::string& name, bool loadNextFrame) + std::shared_ptr PostProcessor::loadTechnique(std::string_view name, bool loadNextFrame) { VFS::Path::Normalized path = fx::Technique::makeFileName(name); return loadTechnique(VFS::Path::NormalizedView(path), loadNextFrame); @@ -764,11 +764,14 @@ namespace MWRender if (technique->getFileName() == path) return technique; - if (!mTechniqueFiles.contains(path)) - return {}; + std::string name; + if (mTechniqueFiles.contains(path)) + name = mVFS->getStem(path); + else + name = path.stem(); auto technique = std::make_shared(*mVFS, *mRendering.getResourceSystem()->getImageManager(), - path, mVFS->getStem(path), renderWidth(), renderHeight(), mUBO, mNormalsSupported); + path, std::move(name), renderWidth(), renderHeight(), mUBO, mNormalsSupported); technique->compile(); @@ -805,10 +808,7 @@ namespace MWRender if (techniqueName.empty()) continue; - auto technique = loadTechnique(techniqueName); - if (!technique) - continue; - mTechniques.push_back(std::move(technique)); + mTechniques.push_back(loadTechnique(techniqueName)); } dirtyTechniques(); @@ -831,7 +831,11 @@ namespace MWRender void PostProcessor::toggleMode() { for (auto& technique : mTemplates) + { + if (technique->getStatus() == fx::Technique::Status::File_Not_exists) + continue; technique->compile(); + } dirtyTechniques(true); } diff --git a/apps/openmw/mwrender/postprocessor.hpp b/apps/openmw/mwrender/postprocessor.hpp index 4b854cbc9c..eb9bc6347c 100644 --- a/apps/openmw/mwrender/postprocessor.hpp +++ b/apps/openmw/mwrender/postprocessor.hpp @@ -177,7 +177,7 @@ namespace MWRender void toggleMode(); std::shared_ptr loadTechnique(VFS::Path::NormalizedView path, bool loadNextFrame = false); - std::shared_ptr loadTechnique(const std::string& name, bool loadNextFrame = false); + std::shared_ptr loadTechnique(std::string_view name, bool loadNextFrame = false); TechniqueList getChain(); diff --git a/components/vfs/pathutil.hpp b/components/vfs/pathutil.hpp index b4b4f6e278..a890be8a54 100644 --- a/components/vfs/pathutil.hpp +++ b/components/vfs/pathutil.hpp @@ -136,6 +136,18 @@ namespace VFS::Path return p; } + std::string_view stem() const + { + std::string_view stem = mValue; + std::size_t pos = stem.find_last_of(separator); + if (pos != std::string_view::npos) + stem = stem.substr(pos + 1); + pos = stem.find_first_of(extensionSeparator); + if (pos != std::string_view::npos) + stem = stem.substr(0, pos); + return stem; + } + private: std::string_view mValue; }; @@ -273,6 +285,11 @@ namespace VFS::Path return NormalizedView(*this).parent(); } + std::string_view stem() const + { + return NormalizedView(*this).stem(); + } + private: std::string mValue; }; From 44fb923d7bfe4b47cc712a72604f75f91cb2fe29 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Thu, 3 Jul 2025 11:58:58 -0700 Subject: [PATCH 128/330] Keep active quest focused in same journal session --- apps/openmw/mwgui/journalwindow.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index e68c7299d9..e9c927cda4 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -599,7 +599,10 @@ namespace list->adjustSize(); if (Settings::gui().mControllerMenus) + { addControllerButtons(list, mSelectedQuest); + setControllerFocusedQuest(MWGui::wrap(mSelectedQuest, mButtons.size())); + } if (mAllQuests) { From 5d8c349899f66f4a2db362c0c465fadfa52fb5bb Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Thu, 3 Jul 2025 11:44:36 -0700 Subject: [PATCH 129/330] Fix issues with setControllerFocus --- apps/openmw/mwgui/dialogue.cpp | 20 ++++++++++---------- apps/openmw/mwgui/dialogue.hpp | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 4a30532f5e..6508622bba 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -921,20 +921,20 @@ namespace MWGui && actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion"); } - void DialogueWindow::setControllerFocus(int index, bool focused) + void DialogueWindow::setControllerFocus(size_t index, bool focused) { // List is mTopicsList + "Goodbye" button below the list. - if (index < 0 || index > static_cast(mTopicsList->getItemCount())) + if (index < 0 || index > mTopicsList->getItemCount()) return; - if (index == static_cast(mTopicsList->getItemCount())) + if (index == mTopicsList->getItemCount()) { mGoodbyeButton->setStateSelected(focused); } else { - std::string keyword = mTopicsList->getItemNameAt(mControllerFocus); - if (keyword.length() == 0) + const std::string& keyword = mTopicsList->getItemNameAt(mControllerFocus); + if (keyword.empty()) return; MyGUI::Button* button = mTopicsList->getItemWidget(keyword); @@ -949,10 +949,10 @@ namespace MWGui else { int offset = 0; - for (int i = 0; i < index - 8; i++) + for (size_t i = 0; i < index - 8; i++) { - std::string keyword = mTopicsList->getItemNameAt(i); - if (keyword.length() == 0) + const std::string& keyword = mTopicsList->getItemNameAt(i); + if (keyword.empty()) offset += 21; else offset += mTopicsList->getItemWidget(keyword)->getHeight() + 3; @@ -997,7 +997,7 @@ namespace MWGui setControllerFocus(mControllerFocus, false); if (mControllerFocus <= 0) mControllerFocus = mTopicsList->getItemCount(); // "Goodbye" button - else if (mTopicsList->getItemNameAt(mControllerFocus - 1).length() == 0) + else if (mTopicsList->getItemNameAt(mControllerFocus - 1).empty()) mControllerFocus -= 2; // Skip separator else mControllerFocus--; @@ -1020,7 +1020,7 @@ namespace MWGui mControllerFocus = 0; else if (mControllerFocus == static_cast(mTopicsList->getItemCount()) - 1) mControllerFocus = mTopicsList->getItemCount(); // "Goodbye" button - else if (mTopicsList->getItemNameAt(mControllerFocus + 1).length() == 0) + else if (mTopicsList->getItemNameAt(mControllerFocus + 1).empty()) mControllerFocus += 2; // Skip separator else mControllerFocus++; diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 9a19617425..6f03076e92 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -229,7 +229,7 @@ namespace MWGui std::unique_ptr mCallback; std::unique_ptr mGreetingCallback; - void setControllerFocus(int index, bool focused); + void setControllerFocus(size_t index, bool focused); int mControllerFocus = 0; int mControllerChoice = -1; From 7f34e52a11b5da4942e0b30a5b4b90552e24d9be Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Tue, 18 Feb 2025 19:33:29 +0100 Subject: [PATCH 130/330] lua interface for window visibility --- apps/openmw/mwbase/windowmanager.hpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 5 +++++ apps/openmw/mwgui/windowmanagerimp.hpp | 1 + apps/openmw/mwlua/uibindings.cpp | 2 ++ files/data/scripts/omw/ui.lua | 7 +++++++ 5 files changed, 16 insertions(+) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 8164501b4b..037f719e6d 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -384,6 +384,7 @@ namespace MWBase // Used in Lua bindings virtual const std::vector& getGuiModeStack() const = 0; virtual void setDisabledByLua(std::string_view windowId, bool disabled) = 0; + virtual bool isWindowVisible(std::string_view windowId) const = 0; virtual std::vector getAllWindowIds() const = 0; virtual std::vector getAllowedWindowIds(MWGui::GuiMode mode) const = 0; }; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 565fb43127..2c1741977c 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -2406,6 +2406,11 @@ namespace MWGui updateVisible(); } + bool WindowManager::isWindowVisible(std::string_view windowId) const + { + return mLuaIdToWindow.at(windowId)->isVisible(); + } + std::vector WindowManager::getAllWindowIds() const { std::vector res; diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 650e2bab78..1a96092b60 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -390,6 +390,7 @@ namespace MWGui // Used in Lua bindings const std::vector& getGuiModeStack() const override { return mGuiModes; } void setDisabledByLua(std::string_view windowId, bool disabled) override; + bool isWindowVisible(std::string_view windowId) const override; std::vector getAllWindowIds() const override; std::vector getAllowedWindowIds(GuiMode mode) const override; diff --git a/apps/openmw/mwlua/uibindings.cpp b/apps/openmw/mwlua/uibindings.cpp index bc5581eb74..826338ca7d 100644 --- a/apps/openmw/mwlua/uibindings.cpp +++ b/apps/openmw/mwlua/uibindings.cpp @@ -296,6 +296,8 @@ namespace MWLua luaManager->addAction( [=, window = std::move(window)]() { windowManager->setDisabledByLua(window, disabled); }); }; + api["_isWindowVisible"] + = [windowManager](std::string_view window) { return windowManager->isWindowVisible(window); }; // TODO // api["_showMouseCursor"] = [](bool) {}; diff --git a/files/data/scripts/omw/ui.lua b/files/data/scripts/omw/ui.lua index e29bbe254e..379396bd35 100644 --- a/files/data/scripts/omw/ui.lua +++ b/files/data/scripts/omw/ui.lua @@ -240,6 +240,13 @@ return { -- @return #boolean isHudVisible = function() return ui._isHudVisible() end, + --- + -- Returns if the given window is visible or not + -- @function [parent=#UI] isWindowVisible + -- @param #string windowName + -- @return #boolean + isWindowVisible = ui._isWindowVisible, + -- TODO -- registerHudElement = function(name, showFn, hideFn) end, -- showHudElement = function(name, bool) end, From 593988e82b8b30be57b209f2ca597f8a3cc7f7c4 Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Tue, 18 Feb 2025 20:43:03 +0100 Subject: [PATCH 131/330] bump lua revision --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7301496172..123462b8fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,7 +82,7 @@ message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) set(OPENMW_VERSION_MINOR 50) set(OPENMW_VERSION_RELEASE 0) -set(OPENMW_LUA_API_REVISION 78) +set(OPENMW_LUA_API_REVISION 79) set(OPENMW_POSTPROCESSING_API_REVISION 2) set(OPENMW_VERSION_COMMITHASH "") From 9fe420e562d3b5ee02bfa8aedd33ca34c0db88e0 Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Tue, 18 Feb 2025 20:59:46 +0100 Subject: [PATCH 132/330] improve error report when windowId is invalid. --- apps/openmw/mwgui/windowmanagerimp.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 2c1741977c..4ff297dd94 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -2408,7 +2408,10 @@ namespace MWGui bool WindowManager::isWindowVisible(std::string_view windowId) const { - return mLuaIdToWindow.at(windowId)->isVisible(); + auto it = mLuaIdToWindow.find(windowId); + if (it == mLuaIdToWindow.end()) + throw std::logic_error("Invalid window name: " + std::string(windowId)); + return it->second->isVisible(); } std::vector WindowManager::getAllWindowIds() const From b1f32c8cee871cee60339a20b5c1cc683bd8a858 Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Wed, 19 Feb 2025 14:59:05 +0100 Subject: [PATCH 133/330] isWindowVisible must handle replaced windows' visibility --- files/data/scripts/omw/ui.lua | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/files/data/scripts/omw/ui.lua b/files/data/scripts/omw/ui.lua index 379396bd35..9d5133b3d0 100644 --- a/files/data/scripts/omw/ui.lua +++ b/files/data/scripts/omw/ui.lua @@ -155,6 +155,13 @@ local function onUiModeChangedEvent(data) end end +local function isWindowVisible(windowName) + if replacedWindows[windowName] then + return replacedWindows[windowName].visible + end + return ui._isWindowVisible(windowName) +end + return { interfaceName = 'UI', --- @@ -245,7 +252,7 @@ return { -- @function [parent=#UI] isWindowVisible -- @param #string windowName -- @return #boolean - isWindowVisible = ui._isWindowVisible, + isWindowVisible = isWindowVisible, -- TODO -- registerHudElement = function(name, showFn, hideFn) end, From ffac1cdf3c67196862be28aaba21f7aa2b28bf94 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Thu, 3 Jul 2025 14:20:24 -0700 Subject: [PATCH 134/330] Remove int casts by using size_t in a few places --- apps/openmw/mwgui/bookpage.cpp | 8 ++--- apps/openmw/mwgui/bookpage.hpp | 2 +- apps/openmw/mwgui/journalwindow.cpp | 45 ++++++++++++++--------------- apps/openmw/mwgui/journalwindow.hpp | 8 ++--- 4 files changed, 31 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index d014910c74..2c58ca3b72 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -105,13 +105,13 @@ namespace MWGui Styles mStyles; MyGUI::IntRect mRect; - void setColour(int section, int line, int run, MyGUI::Colour colour) const override + void setColour(size_t section, size_t line, size_t run, const MyGUI::Colour& colour) const override { - if (section < 0 || section >= static_cast(mSections.size())) + if (section >= mSections.size()) return; - if (line < 0 || line >= static_cast(mSections[section].mLines.size())) + if (line >= mSections[section].mLines.size()) return; - if (run < 0 || run >= static_cast(mSections[section].mLines[line].mRuns.size())) + if (run >= mSections[section].mLines[line].mRuns.size()) return; mSections[section].mLines[line].mRuns[run].mStyle->mNormalColour = colour; diff --git a/apps/openmw/mwgui/bookpage.hpp b/apps/openmw/mwgui/bookpage.hpp index 34dae0cc0e..bb85130b7f 100644 --- a/apps/openmw/mwgui/bookpage.hpp +++ b/apps/openmw/mwgui/bookpage.hpp @@ -32,7 +32,7 @@ namespace MWGui virtual std::pair getSize() const = 0; /// Used to highlight journal indices - virtual void setColour(int section, int line, int run, MyGUI::Colour colour) const = 0; + virtual void setColour(size_t section, size_t line, size_t run, const MyGUI::Colour& colour) const = 0; virtual ~TypesetBook() = default; }; diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index e9c927cda4..8302f4faea 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -477,7 +477,7 @@ namespace } if (Settings::gui().mControllerMenus) - setIndexControllerFocus(mSelectedIndex, true); + setIndexControllerFocus(true); } void notifyJournal(MyGUI::Widget* _sender) @@ -489,7 +489,7 @@ namespace MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay(); } - void addControllerButtons(Gui::MWList* _list, int _selectedIndex) + void addControllerButtons(Gui::MWList* _list, size_t _selectedIndex) { mButtons.clear(); for (size_t i = 0; i < _list->getItemCount(); i++) @@ -497,9 +497,8 @@ namespace MyGUI::Button* listItem = _list->getItemWidget(_list->getItemNameAt(i)); if (listItem) { - listItem->setTextColour(static_cast(mButtons.size()) == _selectedIndex - ? MWGui::journalHeaderColour - : MyGUI::Colour::Black); + listItem->setTextColour( + mButtons.size() == _selectedIndex ? MWGui::journalHeaderColour : MyGUI::Colour::Black); mButtons.push_back(listItem); } } @@ -700,21 +699,21 @@ namespace return &mControllerButtons; } - void setIndexControllerFocus(int index, bool focused) + void setIndexControllerFocus(bool focused) { int col, row; bool isRussian = (mEncoding == ToUTF8::WINDOWS_1251); if (isRussian) { // Cyrillic = 30 (10 + 10 + 10) - col = index / 10; - row = index % 10; + col = mSelectedIndex / 10; + row = mSelectedIndex % 10; } else { // Latin = 26 (13 + 13) - col = index / 13; - row = index % 13; + col = mSelectedIndex / 13; + row = mSelectedIndex % 13; } mTopicIndexBook->setColour(col, row, 0, focused ? MWGui::journalHeaderColour : MyGUI::Colour::Black); @@ -831,7 +830,7 @@ namespace } else if (mOptionsMode) { - setIndexControllerFocus(mSelectedIndex, false); + setIndexControllerFocus(false); if (isRussian) { // Cyrillic = 30 (10 + 10 + 10) @@ -854,7 +853,7 @@ namespace else mSelectedIndex--; } - setIndexControllerFocus(mSelectedIndex, true); + setIndexControllerFocus(true); setText(PageOneNum, 1); // Redraw the list } return true; @@ -871,7 +870,7 @@ namespace } else if (mOptionsMode) { - setIndexControllerFocus(mSelectedIndex, false); + setIndexControllerFocus(false); if (isRussian) { // Cyrillic = 30 (10 + 10 + 10) @@ -894,7 +893,7 @@ namespace else mSelectedIndex++; } - setIndexControllerFocus(mSelectedIndex, true); + setIndexControllerFocus(true); setText(PageOneNum, 1); // Redraw the list } return true; @@ -905,7 +904,7 @@ namespace notifyPrevPage(getWidget(PrevPageBTN)); else if (mOptionsMode && !mQuestMode && !mTopicsMode) { - setIndexControllerFocus(mSelectedIndex, false); + setIndexControllerFocus(false); if (isRussian) { // Cyrillic = 30 (10 + 10 + 10) @@ -916,7 +915,7 @@ namespace // Latin = 26 (13 + 13) mSelectedIndex = (mSelectedIndex + 13) % 26; } - setIndexControllerFocus(mSelectedIndex, true); + setIndexControllerFocus(true); setText(PageOneNum, 1); // Redraw the list } return true; @@ -927,7 +926,7 @@ namespace notifyNextPage(getWidget(NextPageBTN)); else if (mOptionsMode && !mQuestMode && !mTopicsMode) { - setIndexControllerFocus(mSelectedIndex, false); + setIndexControllerFocus(false); if (isRussian) { // Cyrillic = 30 (10 + 10 + 10) @@ -938,7 +937,7 @@ namespace // Latin = 26 (13 + 13) mSelectedIndex = (mSelectedIndex + 13) % 26; } - setIndexControllerFocus(mSelectedIndex, true); + setIndexControllerFocus(true); setText(PageOneNum, 1); // Redraw the list } return true; @@ -959,14 +958,14 @@ namespace return false; } - void setControllerFocusedQuest(int index) + void setControllerFocusedQuest(size_t index) { - int listSize = static_cast(mButtons.size()); - if (mSelectedQuest >= 0 && mSelectedQuest < listSize) + size_t listSize = mButtons.size(); + if (mSelectedQuest < listSize) mButtons[mSelectedQuest]->setTextColour(MyGUI::Colour::Black); mSelectedQuest = index; - if (mSelectedQuest >= 0 && mSelectedQuest < listSize) + if (mSelectedQuest < listSize) { mButtons[mSelectedQuest]->setTextColour(MWGui::journalHeaderColour); @@ -977,7 +976,7 @@ namespace else { int offset = 0; - for (int i = 0; i < mSelectedQuest - 3; i++) + for (int i = 0; i < static_cast(mSelectedQuest) - 3; i++) offset += mButtons[i]->getHeight() + 3; list->setViewOffset(-offset); } diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index e324133b44..4a1f686ff1 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -33,10 +33,10 @@ namespace MWGui std::string_view getWindowIdForLua() const override { return "Journal"; } std::vector mButtons; - int mSelectedQuest = 0; - int mSelectedIndex = 0; - void setIndexControllerFocus(int index, bool focused); - void setControllerFocusedQuest(int index); + size_t mSelectedQuest = 0; + size_t mSelectedIndex = 0; + void setIndexControllerFocus(bool focused); + void setControllerFocusedQuest(size_t index); }; } From ee33424c207352420f358ed6e391e73d0e2135cd Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Thu, 3 Jul 2025 14:32:13 -0700 Subject: [PATCH 135/330] Prevent controller from dismissing dialog window when there is a choice active --- apps/openmw/mwgui/dialogue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 18963ea50a..d0dbe5426c 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -982,7 +982,7 @@ namespace MWGui onSelectListItem(mTopicsList->getItemNameAt(mControllerFocus), mControllerFocus); MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); } - else if (arg.button == SDL_CONTROLLER_BUTTON_B && mChoices.size() < 2) + else if (arg.button == SDL_CONTROLLER_BUTTON_B && mChoices.empty()) { onGoodbyeActivated(); } From 088b2d1bbcfd95730e05d9345a6e0824c2276584 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Thu, 3 Jul 2025 14:47:34 -0700 Subject: [PATCH 136/330] Fix GCC warning --- apps/openmw/mwgui/dialogue.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index d0dbe5426c..b3f83f3771 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -927,7 +927,7 @@ namespace MWGui void DialogueWindow::setControllerFocus(size_t index, bool focused) { // List is mTopicsList + "Goodbye" button below the list. - if (index < 0 || index > mTopicsList->getItemCount()) + if (index > mTopicsList->getItemCount()) return; if (index == mTopicsList->getItemCount()) @@ -952,7 +952,7 @@ namespace MWGui else { int offset = 0; - for (size_t i = 0; i < index - 8; i++) + for (int i = 0; i < static_cast(index) - 8; i++) { const std::string& keyword = mTopicsList->getItemNameAt(i); if (keyword.empty()) From 8379c31f13ed096203bf20aebda17ed397c027f9 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Fri, 4 Jul 2025 02:40:52 -0700 Subject: [PATCH 137/330] Add option to show controller tooltips by default --- apps/launcher/settingspage.cpp | 8 ++++++ apps/launcher/settingspage.hpp | 1 + apps/launcher/ui/settingspage.ui | 13 +++++++++ apps/openmw/mwgui/itemview.cpp | 10 +++---- apps/openmw/mwgui/spellbuyingwindow.cpp | 6 ++--- apps/openmw/mwgui/spellcreationdialog.cpp | 28 +++++++++++--------- apps/openmw/mwgui/spellview.cpp | 27 ++++++++++++++----- apps/openmw/mwgui/spellview.hpp | 3 ++- apps/openmw/mwgui/spellwindow.cpp | 6 +++-- apps/openmw/mwgui/windowmanagerimp.cpp | 32 +++++++++++++++++------ apps/openmw/mwinput/controllermanager.cpp | 5 +++- apps/openmw/mwinput/controllermanager.hpp | 1 + components/settings/categories/gui.hpp | 1 + files/lang/launcher_de.ts | 8 ++++++ files/lang/launcher_en.ts | 8 ++++++ files/lang/launcher_fr.ts | 8 ++++++ files/lang/launcher_ru.ts | 8 ++++++ files/lang/launcher_sv.ts | 8 ++++++ files/settings-default.cfg | 3 +++ 19 files changed, 142 insertions(+), 42 deletions(-) diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index 94a1a0b8a0..294c2c09f3 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -304,7 +304,9 @@ bool Launcher::SettingsPage::loadSettings() loadSettingBool(Settings::gui().mColorTopicEnable, *changeDialogTopicsCheckBox); showOwnedComboBox->setCurrentIndex(Settings::game().mShowOwned); loadSettingBool(Settings::gui().mStretchMenuBackground, *stretchBackgroundCheckBox); + connect(controllerMenusCheckBox, &QCheckBox::toggled, this, &SettingsPage::slotControllerMenusToggled); loadSettingBool(Settings::gui().mControllerMenus, *controllerMenusCheckBox); + loadSettingBool(Settings::gui().mControllerTooltips, *controllerMenuTooltipsCheckBox); loadSettingBool(Settings::map().mAllowZooming, *useZoomOnMapCheckBox); loadSettingBool(Settings::game().mGraphicHerbalism, *graphicHerbalismCheckBox); scalingSpinBox->setValue(Settings::gui().mScalingFactor); @@ -499,6 +501,7 @@ void Launcher::SettingsPage::saveSettings() saveSettingInt(*showOwnedComboBox, Settings::game().mShowOwned); saveSettingBool(*stretchBackgroundCheckBox, Settings::gui().mStretchMenuBackground); saveSettingBool(*controllerMenusCheckBox, Settings::gui().mControllerMenus); + saveSettingBool(*controllerMenuTooltipsCheckBox, Settings::gui().mControllerTooltips); saveSettingBool(*useZoomOnMapCheckBox, Settings::map().mAllowZooming); saveSettingBool(*graphicHerbalismCheckBox, Settings::game().mGraphicHerbalism); Settings::gui().mScalingFactor.set(scalingSpinBox->value()); @@ -557,6 +560,11 @@ void Launcher::SettingsPage::slotAnimSourcesToggled(bool checked) } } +void Launcher::SettingsPage::slotControllerMenusToggled(bool checked) +{ + controllerMenuTooltipsCheckBox->setEnabled(checked); +} + void Launcher::SettingsPage::slotPostProcessToggled(bool checked) { postprocessTransparentPostpassCheckBox->setEnabled(checked); diff --git a/apps/launcher/settingspage.hpp b/apps/launcher/settingspage.hpp index d2bb80d86a..2c6eca477a 100644 --- a/apps/launcher/settingspage.hpp +++ b/apps/launcher/settingspage.hpp @@ -34,6 +34,7 @@ namespace Launcher void slotSkyBlendingToggled(bool checked); void slotShadowDistLimitToggled(bool checked); void slotDistantLandToggled(bool checked); + void slotControllerMenusToggled(bool checked); private: Config::GameSettings& mGameSettings; diff --git a/apps/launcher/ui/settingspage.ui b/apps/launcher/ui/settingspage.ui index e501ed156f..aace4b49c7 100644 --- a/apps/launcher/ui/settingspage.ui +++ b/apps/launcher/ui/settingspage.ui @@ -1408,6 +1408,19 @@ + + + + false + + + <html><head/><body><p>When using controller menus, make tooltips visible by default.</p></body></html> + + + Show Controller Tooltips By Default + + + diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index 8b003b267d..0afb3d3d76 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -21,6 +21,7 @@ namespace MWGui ItemView::ItemView() : mScrollView(nullptr) + , mControllerActiveWindow(false) { } @@ -189,12 +190,8 @@ namespace MWGui { mControllerActiveWindow = active; - MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); - if (winMgr->getControllerTooltip()) - { - winMgr->setCursorActive(false); - winMgr->setControllerTooltip(false); - } + MWBase::Environment::get().getWindowManager()->setControllerTooltip( + active && Settings::gui().mControllerTooltips); if (active) updateControllerFocus(-1, mControllerFocus); @@ -214,7 +211,6 @@ namespace MWGui // Select the focused item, if any. if (mControllerFocus >= 0 && mControllerFocus < mItemCount) { - MWBase::Environment::get().getWindowManager()->setControllerTooltip(false); MyGUI::Widget* dragArea = mScrollView->getChildAt(0); onSelectedItem(dragArea->getChildAt(mControllerFocus)); } diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 5d25dc592c..e43bbfc497 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -149,11 +149,9 @@ namespace MWGui mSpellButtons[0].first->setStateSelected(true); MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); + winMgr->setControllerTooltip(Settings::gui().mControllerTooltips); if (winMgr->getControllerTooltip()) - { - winMgr->setCursorActive(false); - winMgr->setControllerTooltip(false); - } + MWBase::Environment::get().getInputManager()->warpMouseToWidget(mSpellButtons[0].first); } // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 7ea5118883..976c2eebd8 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -103,7 +103,6 @@ namespace MWGui mControllerButtons.a = "#{sSelect}"; mControllerButtons.b = "#{sCancel}"; mControllerButtons.x = "#{sOk}"; - mControllerButtons.r3 = "#{sInfo}"; } } @@ -602,6 +601,7 @@ namespace MWGui mControllerButtons.a = "#{sSelect}"; mControllerButtons.b = "#{sCancel}"; mControllerButtons.x = "#{sBuy}"; + mControllerButtons.r3 = "#{sInfo}"; } } @@ -613,13 +613,6 @@ namespace MWGui mPtr = actor; mNameEdit->setCaption({}); - MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); - if (Settings::gui().mControllerMenus && winMgr->getControllerTooltip()) - { - winMgr->setCursorActive(false); - winMgr->setControllerTooltip(false); - } - startEditing(); } @@ -850,7 +843,11 @@ namespace MWGui mEffectFocus = 0; mRightColumn = false; if (mAvailableButtons.size() > 0) + { mAvailableButtons[0]->setStateSelected(true); + if (MWBase::Environment::get().getWindowManager()->getControllerTooltip()) + MWBase::Environment::get().getInputManager()->warpMouseToWidget(mAvailableButtons[0]); + } } } @@ -1038,24 +1035,25 @@ namespace MWGui bool EffectEditorBase::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { + MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); + if (arg.button == SDL_CONTROLLER_BUTTON_A) { if (!mRightColumn && mAvailableFocus >= 0 && mAvailableFocus < static_cast(mAvailableButtons.size())) { onAvailableEffectClicked(mAvailableButtons[mAvailableFocus]); - MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); + winMgr->playSound(ESM::RefId::stringRefId("Menu Click")); } else if (mRightColumn && mEffectFocus >= 0 && mEffectFocus < static_cast(mEffectButtons.size())) { onEditEffect(mEffectButtons[mEffectFocus].second); - MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); + winMgr->playSound(ESM::RefId::stringRefId("Menu Click")); } } else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK) { // Toggle info tooltip - MWBase::Environment::get().getWindowManager()->setControllerTooltip( - !MWBase::Environment::get().getWindowManager()->getControllerTooltip()); + winMgr->setControllerTooltip(!mRightColumn && !winMgr->getControllerTooltip()); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) { @@ -1098,6 +1096,8 @@ namespace MWGui mEffectButtons[mEffectFocus].first->setStateSelected(false); if (mAvailableFocus >= 0 && mAvailableFocus < static_cast(mAvailableButtons.size())) mAvailableButtons[mAvailableFocus]->setStateSelected(true); + + winMgr->setControllerTooltip(Settings::gui().mControllerTooltips); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && !mRightColumn && mEffectButtons.size() > 0) { @@ -1106,6 +1106,8 @@ namespace MWGui mAvailableButtons[mAvailableFocus]->setStateSelected(false); if (mEffectFocus >= 0 && mEffectFocus < static_cast(mEffectButtons.size())) mEffectButtons[mEffectFocus].first->setStateSelected(true); + + winMgr->setControllerTooltip(false); } // Scroll the list to keep the active item in view @@ -1120,7 +1122,7 @@ namespace MWGui if (!mRightColumn && mAvailableFocus >= 0 && mAvailableFocus < static_cast(mAvailableButtons.size())) { // Warp the mouse to the selected spell to show the tooltip - if (MWBase::Environment::get().getWindowManager()->getControllerTooltip()) + if (winMgr->getControllerTooltip()) MWBase::Environment::get().getInputManager()->warpMouseToWidget(mAvailableButtons[mAvailableFocus]); } diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index 0265eea4cb..a3eef23092 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -32,6 +32,8 @@ namespace MWGui : mScrollView(nullptr) , mShowCostColumn(true) , mHighlightSelected(true) + , mControllerActiveWindow(false) + , mControllerFocus(0) { } @@ -94,7 +96,6 @@ namespace MWGui mLines.clear(); mButtons.clear(); mGroupIndices.clear(); - mControllerTooltip = false; while (mScrollView->getChildCount()) MyGUI::Gui::getInstance().destroyWidget(mScrollView->getChildAt(0)); @@ -231,6 +232,12 @@ namespace MWGui height += lineHeight; } + if (Settings::gui().mControllerMenus) + { + mControllerFocus = wrap(mControllerFocus, mButtons.size()); + updateControllerFocus(-1, mControllerFocus); + } + // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the // scrollbar is hidden mScrollView->setVisibleVScroll(false); @@ -329,6 +336,13 @@ namespace MWGui mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); } + void SpellView::setActiveControllerWindow(bool active) + { + mControllerActiveWindow = active; + if (active) + update(); + } + void SpellView::onControllerButton(const unsigned char button) { if (mButtons.empty()) @@ -348,9 +362,8 @@ namespace MWGui else if (button == SDL_CONTROLLER_BUTTON_RIGHTSTICK) { // Toggle info tooltip - mControllerTooltip = !mControllerTooltip; - if (mControllerTooltip && mControllerFocus >= 0 && mControllerFocus < static_cast(mButtons.size())) - MWBase::Environment::get().getInputManager()->warpMouseToWidget(mButtons[mControllerFocus].first); + MWBase::Environment::get().getWindowManager()->setControllerTooltip( + !MWBase::Environment::get().getWindowManager()->getControllerTooltip()); } else if (button == SDL_CONTROLLER_BUTTON_DPAD_UP) mControllerFocus--; @@ -390,6 +403,8 @@ namespace MWGui if (prevFocus != mControllerFocus) updateControllerFocus(prevFocus, mControllerFocus); + else + updateControllerFocus(-1, mControllerFocus); } void SpellView::updateControllerFocus(int prevFocus, int newFocus) @@ -404,7 +419,7 @@ namespace MWGui prev->onMouseLostFocus(nullptr); } - if (newFocus >= 0 && newFocus < static_cast(mButtons.size())) + if (mControllerActiveWindow && newFocus >= 0 && newFocus < static_cast(mButtons.size())) { Gui::SharedStateButton* focused = mButtons[newFocus].first; if (focused) @@ -421,7 +436,7 @@ namespace MWGui mScrollView->setViewOffset(MyGUI::IntPoint(0, -lineHeight * (line - 5))); } - if (mControllerTooltip) + if (MWBase::Environment::get().getWindowManager()->getControllerTooltip()) MWBase::Environment::get().getInputManager()->warpMouseToWidget(focused); } } diff --git a/apps/openmw/mwgui/spellview.hpp b/apps/openmw/mwgui/spellview.hpp index 234ce08626..a2571cd822 100644 --- a/apps/openmw/mwgui/spellview.hpp +++ b/apps/openmw/mwgui/spellview.hpp @@ -57,6 +57,7 @@ namespace MWGui void resetScrollbars(); + void setActiveControllerWindow(bool active); void onControllerButton(const unsigned char button); private: @@ -99,8 +100,8 @@ namespace MWGui /// Keep a list of group offsets for controller navigation std::vector mGroupIndices; + bool mControllerActiveWindow; int mControllerFocus; - bool mControllerTooltip; void updateControllerFocus(int prevFocus, int newFocus); void onSpellSelected(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index ea21a67423..c8d9b2acd9 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -323,10 +323,12 @@ namespace MWGui MyGUI::Window* window = mMainWidget->castType(); window->setCoord(x, active ? y : viewSize.height + 1, width, height); + + MWBase::Environment::get().getWindowManager()->setControllerTooltip( + active && Settings::gui().mControllerTooltips); } - if (active) - mSpellView->update(); + mSpellView->setActiveControllerWindow(active); WindowBase::setActiveControllerWindow(active); } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 5447861ace..3d98e28bde 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -949,10 +949,16 @@ namespace MWGui if (winCount == 0) return; - mActiveControllerWindows[mode] = std::clamp(activeIndex, 0, winCount - 1); + activeIndex = std::clamp(activeIndex, 0, winCount - 1); + mActiveControllerWindows[mode] = activeIndex; + // Set active window last so inactive windows don't stomp on changes it makes, e.g. to tooltips. for (int i = 0; i < winCount; i++) - mGuiModeStates[mode].mWindows[i]->setActiveControllerWindow(i == activeIndex); + { + if (i != activeIndex) + mGuiModeStates[mode].mWindows[i]->setActiveControllerWindow(false); + } + mGuiModeStates[mode].mWindows[activeIndex]->setActiveControllerWindow(true); MWBase::Environment::get().getInputManager()->setGamepadGuiCursorEnabled( mGuiModeStates[mode].mWindows[activeIndex]->isGamepadCursorAllowed()); @@ -1468,13 +1474,23 @@ namespace MWGui if (mConsole && mConsole->isVisible()) mConsole->onOpen(); - if (Settings::gui().mControllerMenus && !mGuiModes.empty()) + if (Settings::gui().mControllerMenus) { - // Re-apply any controller-specific window changes. - const GuiMode mode = mGuiModes.back(); - int winCount = mGuiModeStates[mode].mWindows.size(); - for (int i = 0; i < winCount; i++) - mGuiModeStates[mode].mWindows[i]->setActiveControllerWindow(i == mActiveControllerWindows[mode]); + if (mGuiModes.empty()) + setControllerTooltip(false); + else + { + // Re-apply any controller-specific window changes. + const GuiMode mode = mGuiModes.back(); + int winCount = mGuiModeStates[mode].mWindows.size(); + + for (int i = 0; i < winCount; i++) + { + if (i != mActiveControllerWindows[mode]) + mGuiModeStates[mode].mWindows[i]->setActiveControllerWindow(false); + } + mGuiModeStates[mode].mWindows[mActiveControllerWindows[mode]]->setActiveControllerWindow(true); + } } } diff --git a/apps/openmw/mwinput/controllermanager.cpp b/apps/openmw/mwinput/controllermanager.cpp index 8a60ff0673..9962c639ad 100644 --- a/apps/openmw/mwinput/controllermanager.cpp +++ b/apps/openmw/mwinput/controllermanager.cpp @@ -32,6 +32,7 @@ namespace MWInput , mGamepadGuiCursorEnabled(true) , mGuiCursorEnabled(true) , mJoystickLastUsed(false) + , mGamepadMousePressed(false) { if (!controllerBindingsFile.empty()) { @@ -142,6 +143,7 @@ namespace MWInput if (arg.button == SDL_CONTROLLER_BUTTON_A) // We'll pretend that A is left click. { bool mousePressSuccess = mMouseManager->injectMouseButtonPress(SDL_BUTTON_LEFT); + mGamepadMousePressed = true; if (MyGUI::InputManager::getInstance().getMouseFocusWidget()) { MyGUI::Button* b @@ -186,12 +188,13 @@ namespace MWInput mJoystickLastUsed = true; if (MWBase::Environment::get().getWindowManager()->isGuiMode()) { - if (mGamepadGuiCursorEnabled) + if (mGamepadGuiCursorEnabled && (!Settings::gui().mControllerMenus || mGamepadMousePressed)) { // Temporary mouse binding until keyboard controls are available: if (arg.button == SDL_CONTROLLER_BUTTON_A) // We'll pretend that A is left click. { bool mousePressSuccess = mMouseManager->injectMouseButtonRelease(SDL_BUTTON_LEFT); + mGamepadMousePressed = false; if (mBindingsManager->isDetectingBindingState()) // If the player just triggered binding, don't let // button release bind. return; diff --git a/apps/openmw/mwinput/controllermanager.hpp b/apps/openmw/mwinput/controllermanager.hpp index 596a9ef465..670a3c846f 100644 --- a/apps/openmw/mwinput/controllermanager.hpp +++ b/apps/openmw/mwinput/controllermanager.hpp @@ -62,6 +62,7 @@ namespace MWInput bool mGamepadGuiCursorEnabled; bool mGuiCursorEnabled; bool mJoystickLastUsed; + bool mGamepadMousePressed; }; } #endif diff --git a/components/settings/categories/gui.hpp b/components/settings/categories/gui.hpp index 139d55d9c8..aea288ca65 100644 --- a/components/settings/categories/gui.hpp +++ b/components/settings/categories/gui.hpp @@ -26,6 +26,7 @@ namespace Settings SettingValue mTooltipDelay{ mIndex, "GUI", "tooltip delay", makeMaxSanitizerFloat(0) }; SettingValue mStretchMenuBackground{ mIndex, "GUI", "stretch menu background" }; SettingValue mControllerMenus{ mIndex, "GUI", "controller menus" }; + SettingValue mControllerTooltips{ mIndex, "GUI", "controller tooltips" }; SettingValue mSubtitles{ mIndex, "GUI", "subtitles" }; SettingValue mHitFader{ mIndex, "GUI", "hit fader" }; SettingValue mWerewolfOverlay{ mIndex, "GUI", "werewolf overlay" }; diff --git a/files/lang/launcher_de.ts b/files/lang/launcher_de.ts index c4af468e8c..fe36e91646 100644 --- a/files/lang/launcher_de.ts +++ b/files/lang/launcher_de.ts @@ -1455,5 +1455,13 @@ to default Morrowind fonts. Check this box if you still prefer original fonts ov Enable Controller Menus + + <html><head/><body><p>When using controller menus, make tooltips visible by default.</p></body></html> + + + + Show Controller Tooltips By Default + + diff --git a/files/lang/launcher_en.ts b/files/lang/launcher_en.ts index 5c24c3fa7d..4097d29dd2 100644 --- a/files/lang/launcher_en.ts +++ b/files/lang/launcher_en.ts @@ -1455,5 +1455,13 @@ to default Morrowind fonts. Check this box if you still prefer original fonts ov Enable Controller Menus + + <html><head/><body><p>When using controller menus, make tooltips visible by default.</p></body></html> + + + + Show Controller Tooltips By Default + + diff --git a/files/lang/launcher_fr.ts b/files/lang/launcher_fr.ts index 413a207abe..3d2363130e 100644 --- a/files/lang/launcher_fr.ts +++ b/files/lang/launcher_fr.ts @@ -1458,5 +1458,13 @@ to default Morrowind fonts. Check this box if you still prefer original fonts ov <html><head/><body><p>Make it easier to use game menus with a controller.</p></body></html> <html><head/><body><p>Faciliter l'utilisation des menus de jeu avec une manette.</p></body></html> + + <html><head/><body><p>When using controller menus, make tooltips visible by default.</p></body></html> + <html><head/><body><p>Lorsque vous utilisez les menus du contrôleur, rendez les info-bulles visibles par défaut.</p></body></html> + + + Show Controller Tooltips By Default + Afficher les info-bulles du contrôleur par défaut + diff --git a/files/lang/launcher_ru.ts b/files/lang/launcher_ru.ts index 189f8fdaee..cd6768942f 100644 --- a/files/lang/launcher_ru.ts +++ b/files/lang/launcher_ru.ts @@ -1470,5 +1470,13 @@ to default Morrowind fonts. Check this box if you still prefer original fonts ov Enable Controller Menus + + <html><head/><body><p>When using controller menus, make tooltips visible by default.</p></body></html> + + + + Show Controller Tooltips By Default + + diff --git a/files/lang/launcher_sv.ts b/files/lang/launcher_sv.ts index 11623ceb5a..63912de9e1 100644 --- a/files/lang/launcher_sv.ts +++ b/files/lang/launcher_sv.ts @@ -1474,5 +1474,13 @@ de ordinarie fonterna i Morrowind. Bocka denna ruta om du ändå föredrar ordin Enable Controller Menus Aktivera handkontrollmenyer + + <html><head/><body><p>When using controller menus, make tooltips visible by default.</p></body></html> + <html><head/><body><p>När du använder kontrollmenyer, synliggör verktygstips som standard.</p></body></html> + + + Show Controller Tooltips By Default + Visa verktygstips för kontrollenheter som standard + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 6a0701803b..16dc7b78ff 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -204,6 +204,9 @@ stretch menu background = false # Make menus easier to navigate with a controller. controller menus = false +# When true, you do not need to press R3 to show tooltips. +controller tooltips = false + # Subtitles for NPC spoken dialog and some sound effects. subtitles = false From a5b8db70a4ea2d537e1e15672b1bfe28f48b27c7 Mon Sep 17 00:00:00 2001 From: Cody Glassman Date: Fri, 4 Jul 2025 06:59:05 -0700 Subject: [PATCH 138/330] docs - improve styling in headers and code blocks --- docs/source/_ext/omw-lexers.py | 19 +++++ docs/source/_static/theme-override.css | 14 ++++ docs/source/conf.py | 3 +- .../installation/install-game-files.rst | 6 +- .../reference/lua-scripting/overview.rst | 6 +- ...line-blender-collada-animated-creature.rst | 1 - ...pipeline-blender-collada-static-models.rst | 2 +- .../modding/custom-shader-effects.rst | 6 +- docs/source/reference/modding/extended.rst | 21 +++-- docs/source/reference/modding/font.rst | 30 ++++--- .../modding/openmw-game-template.rst | 12 ++- docs/source/reference/modding/paths.rst | 80 +++++++++++++------ .../convert-bump-mapped-mods.rst | 44 +++------- .../texture-modding/texture-basics.rst | 36 +++++---- 14 files changed, 178 insertions(+), 102 deletions(-) create mode 100644 docs/source/_ext/omw-lexers.py diff --git a/docs/source/_ext/omw-lexers.py b/docs/source/_ext/omw-lexers.py new file mode 100644 index 0000000000..02cd526304 --- /dev/null +++ b/docs/source/_ext/omw-lexers.py @@ -0,0 +1,19 @@ +from pygments.lexer import RegexLexer, bygroups +from pygments.token import Comment, Name, Operator, String, Text +from sphinx.highlighting import lexers + +class OMWConfigLexer(RegexLexer): + name = 'openmwcfg' + aliases = ['openmwcfg'] + filenames = ['openmw.cfg'] + + tokens = { + 'root': [ + (r'(\s*)(#.*$)', bygroups(Text.Whitespace, Comment.Single)), + (r'(\s*)([a-zA-Z0-9_.+-]+)(\s*(\+)?=\s*)(.*)', bygroups(Text.Whitespace, Name.Attribute, Operator, Operator, String)), + (r'.+\n', Text), + ], + } + +def setup(_): + lexers["openmwcfg"] = OMWConfigLexer() diff --git a/docs/source/_static/theme-override.css b/docs/source/_static/theme-override.css index e41ab2c2d6..cf9ae168bc 100644 --- a/docs/source/_static/theme-override.css +++ b/docs/source/_static/theme-override.css @@ -138,3 +138,17 @@ tbody tr:hover { #left-sidebar { overflow-y: scroll; } + +#content div[class^=highlight], #content pre.literal-block, p, h4, h5, h6 { + margin-bottom: 1.5rem; +} + +h5 { + font-size: 1.15rem; + font-weight: 600; +} + +h6 { + font-size: 1.08rem; + font-weight: 600; +} \ No newline at end of file diff --git a/docs/source/conf.py b/docs/source/conf.py index aaa42e3678..d6f19c38f1 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -43,7 +43,8 @@ extensions = [ 'sphinx.ext.viewcode', 'sphinx.ext.autosectionlabel', 'sphinx_design', - 'omw-directives' + 'omw-directives', + 'omw-lexers', ] #autosectionlabel_prefix_document = True diff --git a/docs/source/manuals/installation/install-game-files.rst b/docs/source/manuals/installation/install-game-files.rst index cb44f7d1de..0dad7bfa4d 100644 --- a/docs/source/manuals/installation/install-game-files.rst +++ b/docs/source/manuals/installation/install-game-files.rst @@ -81,15 +81,15 @@ For Distributions Using `apt` (e.g., Ubuntu, Debian) .. code:: console - sudo apt update - sudo apt install innoextract + $ sudo apt update + $ sudo apt install innoextract For macOS using Homebrew ++++++++++++++++++++++++ .. code:: console - brew install innoextract + $ brew install innoextract Once innoextract is installed, download the game from GOG. The downloaded file should be called ``setup_tes_morrowind_goty_2.0.0.7.exe`` or something similar. When ``innoextract`` is run on it, it will extract the files directly into the folder the ``setup.exe`` file is located. If you have a specific folder where you want it to be extracted to, for example in ``~/Documents/Games/Morrowind`` You can specify it with the ``-d`` flag. diff --git a/docs/source/reference/lua-scripting/overview.rst b/docs/source/reference/lua-scripting/overview.rst index 852d63ca0a..b838385524 100644 --- a/docs/source/reference/lua-scripting/overview.rst +++ b/docs/source/reference/lua-scripting/overview.rst @@ -126,10 +126,12 @@ The options are: Enable it in ``openmw.cfg`` the same way as any other mod: -:: +.. code-block:: openmwcfg + :caption: openmw.cfg data=path/to/my_lua_mod - content=my_lua_mod.omwscripts # or content=my_lua_mod.omwaddon + # or content=my_lua_mod.omwaddon + content=my_lua_mod.omwscripts Now every time the player presses "X" on a keyboard, a message is shown. diff --git a/docs/source/reference/modding/custom-models/pipeline-blender-collada-animated-creature.rst b/docs/source/reference/modding/custom-models/pipeline-blender-collada-animated-creature.rst index f07ba7651a..21da034a54 100644 --- a/docs/source/reference/modding/custom-models/pipeline-blender-collada-animated-creature.rst +++ b/docs/source/reference/modding/custom-models/pipeline-blender-collada-animated-creature.rst @@ -177,7 +177,6 @@ definitions and events. At a minimum it needs to include at least animation runforward: stop 4.433333 attack1: start 4.466667 attack1: stop 5.433333 - ... The textkeys file is placed in the same folder as the model and matches the model's name. diff --git a/docs/source/reference/modding/custom-models/pipeline-blender-collada-static-models.rst b/docs/source/reference/modding/custom-models/pipeline-blender-collada-static-models.rst index d52c952b3d..5fb109c962 100644 --- a/docs/source/reference/modding/custom-models/pipeline-blender-collada-static-models.rst +++ b/docs/source/reference/modding/custom-models/pipeline-blender-collada-static-models.rst @@ -168,7 +168,7 @@ the file path to the texture is incorrect and OpenMW can't find it. To fix this you can open the exported ``.dae`` file in a text editor and check the texture's filepath. In the example of this barrel model it's found on lines 13-17. -.. code:: +.. code-block:: xml diff --git a/docs/source/reference/modding/custom-shader-effects.rst b/docs/source/reference/modding/custom-shader-effects.rst index 0e7776c7ae..41dd4c7369 100644 --- a/docs/source/reference/modding/custom-shader-effects.rst +++ b/docs/source/reference/modding/custom-shader-effects.rst @@ -23,7 +23,8 @@ dungeons. To use this feature the :ref:`soft particles` setting must be enabled. This setting can either be activated in the OpenMW launcher or changed in `settings.cfg`: -:: +.. code-block:: ini + :caption: settings.cfg [Shaders] soft particles = true @@ -64,7 +65,8 @@ Blue and alpha channels are ignored. To use this feature the :ref:`post processing ` setting must be enabled. This setting can either be activated in the OpenMW launcher, in-game, or changed in `settings.cfg`: -:: +.. code-block:: ini + :caption: settings.cfg [Post Processing] enabled = true diff --git a/docs/source/reference/modding/extended.rst b/docs/source/reference/modding/extended.rst index 001492f254..8b5c30fdd0 100644 --- a/docs/source/reference/modding/extended.rst +++ b/docs/source/reference/modding/extended.rst @@ -91,7 +91,8 @@ The behavior of such a model: The actual state toggling time depends on the sunrise/sunset time settings in `openmw.cfg`: -:: +.. code-block:: openmwcfg + :caption: openmw.cfg fallback=Weather_Sunrise_Time,6 fallback=Weather_Sunset_Time,18 @@ -102,7 +103,8 @@ These settings lead to the "night" starting at 20:00 and ending at 6:00. The engine checks if the weather is bright enough to support the "interior day" mode using the Glare_View setting. If it is >= 0.5, the engine considers the weather bright. -:: +.. code-block:: openmwcfg + :caption: openmw.cfg fallback=Weather_Clear_Glare_View,1 fallback=Weather_Foggy_Glare_View,0.25 @@ -138,7 +140,8 @@ If you want to override walking animations, you should override ``xbase_anim_fem To enable this feature, you should have this line in your settings.cfg: -:: +.. code-block:: ini + :caption: settings.cfg [Game] use additional anim sources = true @@ -157,7 +160,8 @@ This feature conflicts with old mods which use scripted scabbards, arrows with p The minimum you need is the ``xbase_anim_sh.nif`` file from the `Weapon Sheathing`_ mod and this line in your settings.cfg: -:: +.. code-block:: ini + :caption: settings.cfg [Game] weapon sheathing = true @@ -205,7 +209,8 @@ Skeleton extensions It is possible to inject custom bones into actor skeletons: -:: +.. code-block:: ini + :caption: settings.cfg [Game] use additional anim sources = true @@ -323,14 +328,16 @@ General advices to create assets for this feature: Groundcover mods can be registered in the openmw.cfg via "groundcover" entries instead of "content" ones: -:: +.. code-block:: openmwcfg + :caption: openmw.cfg groundcover=my_grass_mod.esp Every static from such mod is treated as a groundcover object. Also groundcover detection should be enabled via settings.cfg: -:: +.. code-block:: ini + :caption: settings.cfg [Groundcover] enabled = true diff --git a/docs/source/reference/modding/font.rst b/docs/source/reference/modding/font.rst index 2c67a940d1..b0bb342168 100644 --- a/docs/source/reference/modding/font.rst +++ b/docs/source/reference/modding/font.rst @@ -3,8 +3,11 @@ Fonts Default UI font and font used in magic scrolls are defined in ``openmw.cfg``: - fallback=Fonts_Font_0,MysticCards - fallback=Fonts_Font_2,DemonicLetters +.. code-block:: openmwcfg + :caption: openmw.cfg + + fallback=Fonts_Font_0,MysticCards + fallback=Fonts_Font_2,DemonicLetters When there are no ``Fonts_Font_*`` lines in user's ``openmw.cfg``, built-in TrueType fonts are used. Font used by console and another debug windows is not configurable (so ``Fonts_Font_1`` is unused). @@ -20,8 +23,11 @@ You can use --export-fonts command line option to write the converted font They can be used instead of TrueType fonts if needed by specifying their ``.fnt`` files names in the ``openmw.cfg``. For example: - fallback=Fonts_Font_0,magic_cards_regular - fallback=Fonts_Font_2,daedric_font +.. code-block:: openmwcfg + :caption: openmw.cfg + + fallback=Fonts_Font_0,magic_cards_regular + fallback=Fonts_Font_2,daedric_font In this example OpenMW will search for ``magic_cards_regular.fnt`` and ``daedric_font.fnt`` in the ``Fonts`` folder in data directories. If they are not found, built-in TrueType fonts will be used as a fallback. @@ -35,16 +41,22 @@ Unlike vanilla Morrowind, OpenMW directly supports TrueType (``.ttf``) fonts. Th OpenMW has build-in TrueType fonts: MysticCards, DemonicLetters and DejaVuLGCSansMono, which are used by default. TrueType fonts are configured via ``openmw.cfg`` too: - fallback=Fonts_Font_0,MysticCards - fallback=Fonts_Font_2,DemonicLetters +.. code-block:: openmwcfg + :caption: openmw.cfg + + fallback=Fonts_Font_0,MysticCards + fallback=Fonts_Font_2,DemonicLetters In this example, OpenMW will scan ``Fonts`` folder in data directories for ``.omwfont`` files. These files are XML files with schema provided by MyGUI. OpenMW uses ``.omwfont`` files which name (without extension) matches ``openmw.cfg`` entries. -It is also possible to adjust the font size via ``settings.cfg`` file:: +It is also possible to adjust the font size via ``settings.cfg`` file - [GUI] - font size = 16 +.. code-block:: ini + :caption: settings.cfg + + [GUI] + font size = 16 The ``font size`` setting accepts clamped values in range from 12 to 18. diff --git a/docs/source/reference/modding/openmw-game-template.rst b/docs/source/reference/modding/openmw-game-template.rst index 68fa667911..51ddaf6efb 100644 --- a/docs/source/reference/modding/openmw-game-template.rst +++ b/docs/source/reference/modding/openmw-game-template.rst @@ -36,7 +36,8 @@ and ``data=`` tells OpenMW what folders to look for meshes, textures, audio, and other assets. The required lines would look like this, but with the paths of course different on your system. -.. code:: +.. code-block:: openmwcfg + :caption: openmw.cfg content=template.omwgame data="/home/someuser/example-suite/data" @@ -51,7 +52,8 @@ you need to remove or comment out the following lines from ``openmw.cfg``. Not doing so will either produce errors or load Morrowind content, which you probably do not want when you are making your own game. -.. code:: +.. code-block:: openmwcfg + :caption: openmw.cfg fallback-archive=Morrowind.bsa fallback-archive=Tribunal.bsa @@ -70,8 +72,10 @@ are instead assigned through ``settings.cfg``. These models are player and NPC animations, and meshes for the sky. In ``settings.cfg`` used by your OpenMW install, add the following lines under the ``[Models]`` section. -.. code:: +.. code-block:: ini + :caption: settings.cfg + [Models] xbaseanim = meshes/BasicPlayer.dae baseanim = meshes/BasicPlayer.dae xbaseanim1st = meshes/BasicPlayer.dae @@ -103,7 +107,7 @@ need to be copied to ``resources/mygui`` folder found in your OpenMW installatio folder. Overwrite any files aready in this folder. These files provide the UI font, its definition, and some minor UI tweaks. -.. code:: +.. code-block:: none openmw_box.skin.xml openmw_button.skin.xml diff --git a/docs/source/reference/modding/paths.rst b/docs/source/reference/modding/paths.rst index 4ea5219e74..0409777dc2 100644 --- a/docs/source/reference/modding/paths.rst +++ b/docs/source/reference/modding/paths.rst @@ -133,8 +133,9 @@ This can't change until computers are able to read minds. Lines with options have an option name, then an equals sign (``=``), then an option value. Option names and values have leading and trailing whitespace trimmed, but whitespace within an option value is preserved - it's only removed if it's at the ends. -This means that these are all equivalent: -:: +This means that these are all equivalent + +.. code-block:: openmwcfg data=some/dir data=some/dir @@ -226,7 +227,10 @@ Navigate to the OpenMW installation directory, and open the ``openmw.cfg`` file By default, this contains a warning at the top telling you that this is the local ``openmw.cfg`` and not to modify it. However, for this kind of install, it's okay to do so, so you can remove this warning. -Change the start of the file from:: +Change the start of the file from + +.. code-block:: openmwcfg + :caption: openmw.cfg # This is the local openmw.cfg file. Do not modify! # Modifications should be done on the user openmw.cfg file instead @@ -243,7 +247,10 @@ Change the start of the file from:: fallback=LightAttenuation_ConstantValue,0.0 fallback=LightAttenuation_UseLinear,1 -to:: +to + +.. code-block:: openmwcfg + :caption: openmw.cfg data-local=userdata/data user-data=userdata @@ -274,7 +281,10 @@ Navigate to the OpenMW installation directory, and open the ``openmw.cfg`` file By default, this contains a warning at the top telling you that this is the local ``openmw.cfg`` and not to modify it. However, you'll need to make a small change to create this kind of install. -Change the start of the file from:: +Change the start of the file from + +.. code-block:: openmwcfg + :caption: openmw.cfg # This is the local openmw.cfg file. Do not modify! # Modifications should be done on the user openmw.cfg file instead @@ -291,7 +301,10 @@ Change the start of the file from:: fallback=LightAttenuation_ConstantValue,0.0 fallback=LightAttenuation_UseLinear,1 -to:: +to + +.. code-block:: openmwcfg + :caption: openmw.cfg # This is the local openmw.cfg file. Do not modify! # Modifications should be done on the user openmw.cfg file instead @@ -330,7 +343,10 @@ From scratch Start by installing OpenMW in the usual way. Don't bother with first-time setup (i.e. telling it the location of an existing *Morrowind* installation). -In the default configuration directory (see `Configuration files and log files`_), create a file called ``openmw.cfg`` containing just:: +In the default configuration directory (see `Configuration files and log files`_), create a file called ``openmw.cfg`` containing just + +.. code-block:: openmwcfg + :caption: openmw.cfg # select the game profile config=Morrowind @@ -340,7 +356,10 @@ This will put the basic setup required to play *Morrowind* into a new ``Morrowin Next, come up with a name for the subprofile you'll create for your mod list. If you're following a modding guide, they've probably already given it a name, e.g. *Total Overhaul*, so that's the example we'll use. -Add a line to the ``Morrowind/openmw.cfg`` with the profile name, e.g.:: +Add a line to the ``Morrowind/openmw.cfg`` with the profile name, e.g. + +.. code-block:: openmwcfg + :caption: Morrowind/openmw.cfg # select the mod list profile config=Total Overhaul @@ -356,7 +375,10 @@ The ones in the ``Morrowind`` directory are used for all profiles for *Morrowind The ones in the ``Morrowind/Total Overhaul`` directory are only used for the *Total Overhaul* profile, so you can set up that mod list and any settings it requires here, and they won't affect any other profiles you set up later. Making changes within the launcher will affect these files and leave all the others alone. -If you want the *Total Overhaul* profile to keep its saved games etc. in a dedicated location instead of mixing them in with ones from another profile, you can add a ``user-data=…`` line to your ``Morrowind/Total Overhaul/openmw.cfg``, e.g.:: +If you want the *Total Overhaul* profile to keep its saved games etc. in a dedicated location instead of mixing them in with ones from another profile, you can add a ``user-data=…`` line to your ``Morrowind/Total Overhaul/openmw.cfg``, e.g. + +.. code-block:: openmwcfg + :caption: Morrowind/Total Overhaul/openmw.cfg # put saved games in a saves directory next to this file user-data=. @@ -377,12 +399,18 @@ You'll now have an empty directory e.g. at ``Documents\My Games\OpenMW\Original` Next, move all the files that were already in the default configuration directory to the profile directory you just made. Afterwards, the default configuration directory should only contain the profile directory you made. -Create a new ``openmw.cfg`` file in the default configuration directory containing:: +Create a new ``openmw.cfg`` file in the default configuration directory containing + +.. code-block:: openmwcfg + :caption: openmw.cfg # select the profile config=Original -In the ``openmw.cfg`` in the profile directory, add these lines:: +In the ``openmw.cfg`` in the profile directory, add these lines + +.. code-block:: openmwcfg + :caption: openmw.cfg data-local=data user-data=. @@ -402,9 +430,11 @@ Passing arguments on the command line lets you avoid this. The basic idea is that you need to pass ``--replace config`` to ignore the configuration directories that the engine would have loaded because they were specified in ``openmw.cfg`` files, and pass each one you want to use instead with ``--config ``. -E.g. if you've got a profile called *Morrowind* in your default configuration directory, and it's got a *Total Overhaul* subprofile, you could load it by running:: +E.g. if you've got a profile called *Morrowind* in your default configuration directory, and it's got a *Total Overhaul* subprofile, you could load it by running - openmw --replace config --config ?userconfig?/Morrowind --config "?userconfig?/Morrowind/Total Overhaul" +.. code-block:: console + + $ openmw --replace config --config ?userconfig?/Morrowind --config "?userconfig?/Morrowind/Total Overhaul" You can put this command into a script or shortcut and use it to easily launch OpenMW with that profile. @@ -422,15 +452,17 @@ On Windows, you can create a desktop shortcut to run this command with these ste * At the end of that field, add the arguments for the profile you want, e.g. ``--replace config --config ?userconfig?/Morrowind --config "?userconfig?/Morrowind/Total Overhaul"``. * Press *Apply* or *OK* to save the changes, and test the shortcut by double-clicking it. -On most Linux distros, you can create a ``.desktop`` file like this:: +On most Linux distros, you can create a ``.desktop`` file like this - [Desktop Entry] - Type=Application - Name=OpenMW - Total Overhaul - GenericName=Role Playing Game - Comment=OpenMW with the Total Overhaul profile - Keywords=Morrowind;Reimplementation Mods;esm;bsa; - TryExec=openmw - Exec=openmw --replace config --config ?userconfig?/Morrowind --config "?userconfig?/Morrowind/Total Overhaul" - Icon=openmw - Categories=Game;RolePlaying; +.. code-block:: desktop + + [Desktop Entry] + Type=Application + Name=OpenMW - Total Overhaul + GenericName=Role Playing Game + Comment=OpenMW with the Total Overhaul profile + Keywords=Morrowind;Reimplementation Mods;esm;bsa; + TryExec=openmw + Exec=openmw --replace config --config ?userconfig?/Morrowind --config "?userconfig?/Morrowind/Total Overhaul" + Icon=openmw + Categories=Game;RolePlaying; diff --git a/docs/source/reference/modding/texture-modding/convert-bump-mapped-mods.rst b/docs/source/reference/modding/texture-modding/convert-bump-mapped-mods.rst index e05177c268..89ea25519d 100644 --- a/docs/source/reference/modding/texture-modding/convert-bump-mapped-mods.rst +++ b/docs/source/reference/modding/texture-modding/convert-bump-mapped-mods.rst @@ -2,24 +2,9 @@ Normal maps from Morrowind to OpenMW ==================================== -- `General introduction to normal map conversion`_ - - `OpenMW normal-mapping`_ - - `Activating normal-mapping shaders in OpenMW`_ - - `Morrowind bump-mapping`_ - - `MGE XE normal-mapping`_ -- `Converting PeterBitt's Scamp Replacer`_ (Mod made for the MGE XE PBR prototype) - - `Tutorial - MGE`_ -- `Converting Lougian's Hlaalu Bump mapped`_ (Morrowind's bump-mapping, part 1: *without* custom models) - - `Tutorial - Morrowind, Part 1`_ -- `Converting Apel's Various Things - Sacks`_ (Morrowind's bump-mapping, part 2: *with* custom models) - - `Tutorial - Morrowind, Part 2`_ - General introduction to normal map conversion --------------------------------------------- -:Authors: Joakim (Lysol) Berg, Alexei (Capo) Dobrohotov -:Updated: 2020-03-03 - This page has general information and tutorials on how normal-mapping works in OpenMW and how you can make mods using the old environment-mapped bump-mapping technique (such as `Netch Bump mapped`_ and `Hlaalu Bump mapped`_, and maybe the most (in)famous one to previously give shiny rocks in OpenMW, the mod `On the Rocks`_!, featured in MGSO and Morrowind Rebirth) work better in OpenMW. @@ -58,14 +43,15 @@ Activating normal-mapping shaders in OpenMW Before normal (and specular and parallax) maps can show up in OpenMW, their auto-detection needs to be turned on in settings.cfg_-file. Add these rows where it would make sense: -:: +.. code-block:: ini + :caption: settings.cfg - [Shaders] - auto use object normal maps = true - auto use terrain normal maps = true + [Shaders] + auto use object normal maps = true + auto use terrain normal maps = true - auto use object specular maps = true - auto use terrain specular maps = true + auto use object specular maps = true + auto use terrain specular maps = true See OpenMW's wiki page about `texture modding`_ to read more about it. @@ -81,10 +67,11 @@ are processed which makes bump-mapped models look a bit better, can make use of the gloss map channel in the bump map and can apply bump-mapping to skinned models. Add this to settings.cfg_-file: -:: +.. code-block:: ini + :caption: settings.cfg - [Shaders] - apply lighting to environment maps = true + [Shaders] + apply lighting to environment maps = true But sometimes you may want them to look a bit better than in vanilla. Technically you aren't supposed to convert bump maps because they shouldn't be normal maps that are supported by OpenMW as well, @@ -117,9 +104,6 @@ Converting PeterBitt's Scamp Replacer ------------------------------------- **Mod made for the MGE XE PBR prototype** -:Authors: Joakim (Lysol) Berg -:Updated: 2016-11-11 - So, let's say you've found out that PeterBitt_ makes awesome models and textures featuring physically based rendering (PBR) and normal maps. Let's say that you tried to run his `PBR Scamp Replacer`_ in OpenMW and that you were greatly disappointed when the normal map didn't seem to work. Lastly, let's say you came here, looking for some answers. @@ -161,9 +145,6 @@ Converting Lougian's Hlaalu Bump mapped --------------------------------------- **Mod made for Morrowind's bump-mapping, without custom models** -:Authors: Joakim (Lysol) Berg, Alexei (Capo) Dobrohotov -:Updated: 2020-03-03 - Converting normal maps made for the Morrowind's bump-mapping can be really easy or a real pain, depending on a few circumstances. In this tutorial, we will look at a very easy, although in some cases a bit time-consuming, example. @@ -192,9 +173,6 @@ Converting Apel's Various Things - Sacks ---------------------------------------- **Mod made for Morrowind bump-mapping, with custom models** -:Authors: Joakim (Lysol) Berg, Alexei (Capostrophic) Dobrohotov -:Updated: 2020-03-03 - In part one of this tutorial, we converted a mod that only included modified Morrowind model (``.nif``) files so that the bump maps could be loaded as normal maps. We ignored those model files since they are not needed with OpenMW. In this tutorial however, diff --git a/docs/source/reference/modding/texture-modding/texture-basics.rst b/docs/source/reference/modding/texture-modding/texture-basics.rst index 96ec48508b..2d85d1ed3b 100644 --- a/docs/source/reference/modding/texture-modding/texture-basics.rst +++ b/docs/source/reference/modding/texture-modding/texture-basics.rst @@ -55,17 +55,20 @@ Simply create the textures with appropriate naming convention the normal map would have to be called foo_n.dds). To enable this automatic use based on filename pattern, you will have to add the following to your -`settings.cfg `_ file:: +`settings.cfg `_ file - [Shaders] - auto use object normal maps = true +.. code-block:: ini + :caption: settings.cfg - auto use object specular maps = true + [Shaders] + auto use object normal maps = true - normal map pattern = _n - normal height map pattern = _nh + auto use object specular maps = true - specular map pattern = _spec + normal map pattern = _n + normal height map pattern = _nh + + specular map pattern = _spec Additionally, a normal map with the `_nh` pattern enables the use of the normal map's alpha channel as height information. @@ -92,18 +95,21 @@ For example, if you wanted to add specular mapping to a terrain layer called roc you would copy this texture to a new file called rock_diffusespec.dds, and then edit its alpha channel to set the specular intensity. -The relevant settings are:: +The relevant settings are - [Shaders] - auto use terrain normal maps = true +.. code-block:: ini + :caption: settings.cfg - auto use terrain specular maps = true + [Shaders] + auto use terrain normal maps = true - terrain specular map pattern = _diffusespec + auto use terrain specular maps = true - # Also used for terrain normal maps - normal map pattern = _n - normal height map pattern = _nh + terrain specular map pattern = _diffusespec + + # Also used for terrain normal maps + normal map pattern = _n + normal height map pattern = _nh OSG native files ################ From bc78aa4198b3f21636a7d8d1ad2fec19a7681e55 Mon Sep 17 00:00:00 2001 From: Cody Glassman Date: Fri, 4 Jul 2025 11:03:29 -0700 Subject: [PATCH 139/330] docs - add semicolons before examples --- docs/source/reference/modding/font.rst | 2 +- docs/source/reference/modding/paths.rst | 22 +++++++++---------- .../texture-modding/texture-basics.rst | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/source/reference/modding/font.rst b/docs/source/reference/modding/font.rst index b0bb342168..c0e91eec04 100644 --- a/docs/source/reference/modding/font.rst +++ b/docs/source/reference/modding/font.rst @@ -50,7 +50,7 @@ TrueType fonts are configured via ``openmw.cfg`` too: In this example, OpenMW will scan ``Fonts`` folder in data directories for ``.omwfont`` files. These files are XML files with schema provided by MyGUI. OpenMW uses ``.omwfont`` files which name (without extension) matches ``openmw.cfg`` entries. -It is also possible to adjust the font size via ``settings.cfg`` file +It is also possible to adjust the font size via ``settings.cfg`` file: .. code-block:: ini :caption: settings.cfg diff --git a/docs/source/reference/modding/paths.rst b/docs/source/reference/modding/paths.rst index 0409777dc2..c0f7d4cea6 100644 --- a/docs/source/reference/modding/paths.rst +++ b/docs/source/reference/modding/paths.rst @@ -133,7 +133,7 @@ This can't change until computers are able to read minds. Lines with options have an option name, then an equals sign (``=``), then an option value. Option names and values have leading and trailing whitespace trimmed, but whitespace within an option value is preserved - it's only removed if it's at the ends. -This means that these are all equivalent +This means that these are all equivalent: .. code-block:: openmwcfg @@ -227,7 +227,7 @@ Navigate to the OpenMW installation directory, and open the ``openmw.cfg`` file By default, this contains a warning at the top telling you that this is the local ``openmw.cfg`` and not to modify it. However, for this kind of install, it's okay to do so, so you can remove this warning. -Change the start of the file from +Change the start of the file from: .. code-block:: openmwcfg :caption: openmw.cfg @@ -247,7 +247,7 @@ Change the start of the file from fallback=LightAttenuation_ConstantValue,0.0 fallback=LightAttenuation_UseLinear,1 -to +to: .. code-block:: openmwcfg :caption: openmw.cfg @@ -281,7 +281,7 @@ Navigate to the OpenMW installation directory, and open the ``openmw.cfg`` file By default, this contains a warning at the top telling you that this is the local ``openmw.cfg`` and not to modify it. However, you'll need to make a small change to create this kind of install. -Change the start of the file from +Change the start of the file from: .. code-block:: openmwcfg :caption: openmw.cfg @@ -301,7 +301,7 @@ Change the start of the file from fallback=LightAttenuation_ConstantValue,0.0 fallback=LightAttenuation_UseLinear,1 -to +to: .. code-block:: openmwcfg :caption: openmw.cfg @@ -356,7 +356,7 @@ This will put the basic setup required to play *Morrowind* into a new ``Morrowin Next, come up with a name for the subprofile you'll create for your mod list. If you're following a modding guide, they've probably already given it a name, e.g. *Total Overhaul*, so that's the example we'll use. -Add a line to the ``Morrowind/openmw.cfg`` with the profile name, e.g. +Add a line to the ``Morrowind/openmw.cfg`` with the profile name like this: .. code-block:: openmwcfg :caption: Morrowind/openmw.cfg @@ -375,7 +375,7 @@ The ones in the ``Morrowind`` directory are used for all profiles for *Morrowind The ones in the ``Morrowind/Total Overhaul`` directory are only used for the *Total Overhaul* profile, so you can set up that mod list and any settings it requires here, and they won't affect any other profiles you set up later. Making changes within the launcher will affect these files and leave all the others alone. -If you want the *Total Overhaul* profile to keep its saved games etc. in a dedicated location instead of mixing them in with ones from another profile, you can add a ``user-data=…`` line to your ``Morrowind/Total Overhaul/openmw.cfg``, e.g. +If you want the *Total Overhaul* profile to keep its saved games etc. in a dedicated location instead of mixing them in with ones from another profile, you can add a ``user-data=…`` line to your ``Morrowind/Total Overhaul/openmw.cfg``, like this: .. code-block:: openmwcfg :caption: Morrowind/Total Overhaul/openmw.cfg @@ -399,7 +399,7 @@ You'll now have an empty directory e.g. at ``Documents\My Games\OpenMW\Original` Next, move all the files that were already in the default configuration directory to the profile directory you just made. Afterwards, the default configuration directory should only contain the profile directory you made. -Create a new ``openmw.cfg`` file in the default configuration directory containing +Create a new ``openmw.cfg`` file in the default configuration directory containing: .. code-block:: openmwcfg :caption: openmw.cfg @@ -407,7 +407,7 @@ Create a new ``openmw.cfg`` file in the default configuration directory containi # select the profile config=Original -In the ``openmw.cfg`` in the profile directory, add these lines +In the ``openmw.cfg`` in the profile directory, add these lines: .. code-block:: openmwcfg :caption: openmw.cfg @@ -430,7 +430,7 @@ Passing arguments on the command line lets you avoid this. The basic idea is that you need to pass ``--replace config`` to ignore the configuration directories that the engine would have loaded because they were specified in ``openmw.cfg`` files, and pass each one you want to use instead with ``--config ``. -E.g. if you've got a profile called *Morrowind* in your default configuration directory, and it's got a *Total Overhaul* subprofile, you could load it by running +E.g. if you've got a profile called *Morrowind* in your default configuration directory, and it's got a *Total Overhaul* subprofile, you could load it by running: .. code-block:: console @@ -452,7 +452,7 @@ On Windows, you can create a desktop shortcut to run this command with these ste * At the end of that field, add the arguments for the profile you want, e.g. ``--replace config --config ?userconfig?/Morrowind --config "?userconfig?/Morrowind/Total Overhaul"``. * Press *Apply* or *OK* to save the changes, and test the shortcut by double-clicking it. -On most Linux distros, you can create a ``.desktop`` file like this +On most Linux distros, you can create a ``.desktop`` file like this: .. code-block:: desktop diff --git a/docs/source/reference/modding/texture-modding/texture-basics.rst b/docs/source/reference/modding/texture-modding/texture-basics.rst index 2d85d1ed3b..26a47f4e0a 100644 --- a/docs/source/reference/modding/texture-modding/texture-basics.rst +++ b/docs/source/reference/modding/texture-modding/texture-basics.rst @@ -55,7 +55,7 @@ Simply create the textures with appropriate naming convention the normal map would have to be called foo_n.dds). To enable this automatic use based on filename pattern, you will have to add the following to your -`settings.cfg `_ file +`settings.cfg `_ file: .. code-block:: ini :caption: settings.cfg From 28de55df6acc5f6af88488cd76562a3e2f8e0e85 Mon Sep 17 00:00:00 2001 From: Cody Glassman Date: Fri, 4 Jul 2025 11:19:04 -0700 Subject: [PATCH 140/330] docs - use default pygment style in light mode --- docs/source/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index d6f19c38f1..0b953a4275 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -139,7 +139,7 @@ exclude_patterns = [] #show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = 'default' pygments_style_dark = 'github-dark' # A list of ignored prefixes for module index sorting. From ec3357ff3f9f233ceff676a9916fd224ca50f373 Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Fri, 4 Jul 2025 20:30:31 +0200 Subject: [PATCH 141/330] Bump UI interface version number --- files/data/scripts/omw/ui.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/data/scripts/omw/ui.lua b/files/data/scripts/omw/ui.lua index 9d5133b3d0..31502fd6ee 100644 --- a/files/data/scripts/omw/ui.lua +++ b/files/data/scripts/omw/ui.lua @@ -171,7 +171,7 @@ return { interface = { --- Interface version -- @field [parent=#UI] #number version - version = 1, + version = 2, --- All available UI modes. -- Use `view(I.UI.MODE)` in `luap` console mode to see the list. From ce0ae47478fc8df4e39c374834409239550b74a0 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Fri, 4 Jul 2025 11:53:36 -0700 Subject: [PATCH 142/330] Expose controller menus setting to Lua --- apps/openmw/mwlua/inputbindings.cpp | 7 ++++--- files/data/scripts/omw/input/gamepadcontrols.lua | 7 +++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwlua/inputbindings.cpp b/apps/openmw/mwlua/inputbindings.cpp index c3b47c5061..9efb38a3fa 100644 --- a/apps/openmw/mwlua/inputbindings.cpp +++ b/apps/openmw/mwlua/inputbindings.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/inputmanager.hpp" @@ -69,9 +70,8 @@ namespace MWLua = sol::readonly_property([](const SDLUtil::TouchEvent& e) -> int { return e.mDevice; }); touchpadEvent["finger"] = sol::readonly_property([](const SDLUtil::TouchEvent& e) -> int { return e.mFinger; }); - touchpadEvent["position"] = sol::readonly_property([](const SDLUtil::TouchEvent& e) -> osg::Vec2f { - return { e.mX, e.mY }; - }); + touchpadEvent["position"] + = sol::readonly_property([](const SDLUtil::TouchEvent& e) -> osg::Vec2f { return { e.mX, e.mY }; }); touchpadEvent["pressure"] = sol::readonly_property([](const SDLUtil::TouchEvent& e) -> float { return e.mPressure; }); return sol::table(lua, sol::create); @@ -239,6 +239,7 @@ namespace MWLua api["isMouseButtonPressed"] = [](int button) -> bool { return SDL_GetMouseState(nullptr, nullptr) & SDL_BUTTON(button); }; api["_isGamepadCursorActive"] = [input]() -> bool { return input->isGamepadGuiCursorEnabled(); }; + api["_isControllerMenusEnabled"] = [input]() -> bool { return Settings::gui().mControllerMenus; }; api["_setGamepadCursorActive"] = [input](bool v) { input->setGamepadGuiCursorEnabled(v); MWBase::Environment::get().getWindowManager()->setCursorActive(v); diff --git a/files/data/scripts/omw/input/gamepadcontrols.lua b/files/data/scripts/omw/input/gamepadcontrols.lua index 9b89d505b5..75ca494a27 100644 --- a/files/data/scripts/omw/input/gamepadcontrols.lua +++ b/files/data/scripts/omw/input/gamepadcontrols.lua @@ -20,6 +20,13 @@ return { return input._isGamepadCursorActive() end, + --- Checks if the controller menu option is enabled. If true, UI is replaced with a more controller appropriate interface. + -- @function [parent=#GamepadControls] isControllerMenusEnabled + -- @return #boolean + isControllerMenusEnabled = function() + return input._isControllerMenusEnabled() + end, + --- Sets if the gamepad cursor is active. If it is active, the left stick can move the cursor, and A will be interpreted as a mouse click. -- @function [parent=#GamepadControls] setGamepadCursorActive -- @param #boolean value From 04d73cf195859b5c628e4e49d9d443e83b430638 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Fri, 4 Jul 2025 12:02:17 -0700 Subject: [PATCH 143/330] Revert clang formatting suggestion because it breaks the pipeline --- apps/openmw/mwlua/inputbindings.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwlua/inputbindings.cpp b/apps/openmw/mwlua/inputbindings.cpp index 9efb38a3fa..1a95ed4007 100644 --- a/apps/openmw/mwlua/inputbindings.cpp +++ b/apps/openmw/mwlua/inputbindings.cpp @@ -70,8 +70,9 @@ namespace MWLua = sol::readonly_property([](const SDLUtil::TouchEvent& e) -> int { return e.mDevice; }); touchpadEvent["finger"] = sol::readonly_property([](const SDLUtil::TouchEvent& e) -> int { return e.mFinger; }); - touchpadEvent["position"] - = sol::readonly_property([](const SDLUtil::TouchEvent& e) -> osg::Vec2f { return { e.mX, e.mY }; }); + touchpadEvent["position"] = sol::readonly_property([](const SDLUtil::TouchEvent& e) -> osg::Vec2f { + return { e.mX, e.mY }; + }); touchpadEvent["pressure"] = sol::readonly_property([](const SDLUtil::TouchEvent& e) -> float { return e.mPressure; }); return sol::table(lua, sol::create); From 28f3b4a530ab7aeb11e62bcaf33ceb26e2788d18 Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Fri, 4 Jul 2025 12:49:54 -0700 Subject: [PATCH 144/330] Remove unused argument from lambda to fix compiler warning --- apps/openmw/mwlua/inputbindings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwlua/inputbindings.cpp b/apps/openmw/mwlua/inputbindings.cpp index 1a95ed4007..7cb727a83e 100644 --- a/apps/openmw/mwlua/inputbindings.cpp +++ b/apps/openmw/mwlua/inputbindings.cpp @@ -240,7 +240,7 @@ namespace MWLua api["isMouseButtonPressed"] = [](int button) -> bool { return SDL_GetMouseState(nullptr, nullptr) & SDL_BUTTON(button); }; api["_isGamepadCursorActive"] = [input]() -> bool { return input->isGamepadGuiCursorEnabled(); }; - api["_isControllerMenusEnabled"] = [input]() -> bool { return Settings::gui().mControllerMenus; }; + api["_isControllerMenusEnabled"] = []() -> bool { return Settings::gui().mControllerMenus; }; api["_setGamepadCursorActive"] = [input](bool v) { input->setGamepadGuiCursorEnabled(v); MWBase::Environment::get().getWindowManager()->setCursorActive(v); From 4bf43665c4aa5268a5a1a5f63d5a14e954078fd2 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Thu, 27 Feb 2025 21:42:49 +0300 Subject: [PATCH 145/330] Revise birthsign tooltip layout (#6792) Make all description bits distinct widgets to allow proper padding Use spaces instead of line breaks to separate spells Enable word-wrapping for description text Make the tooltip wider and increase padding --- apps/openmw/mwgui/tooltips.cpp | 31 +++++++++++-------------- files/data/mygui/openmw_tooltips.layout | 26 +++++++++++++++++---- 2 files changed, 36 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 28f0b80010..7f8de572ed 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -894,7 +894,8 @@ namespace MWGui widget->setUserString("ToolTipLayout", "BirthSignToolTip"); widget->setUserString( "ImageTexture_BirthSignImage", Misc::ResourceHelpers::correctTexturePath(sign->mTexture, vfs)); - std::string text = sign->mName + "\n#{fontcolourhtml=normal}" + sign->mDescription; + widget->setUserString("Caption_BirthSignName", sign->mName); + widget->setUserString("Caption_BirthSignDescription", sign->mDescription); std::vector abilities, powers, spells; @@ -915,26 +916,22 @@ namespace MWGui spells.push_back(spell); } - using Category = std::pair&, std::string_view>; - for (const auto& [category, label] : std::initializer_list{ - { abilities, "sBirthsignmenu1" }, { powers, "sPowers" }, { spells, "sBirthsignmenu2" } }) + using Category = std::tuple&, std::string_view, std::string_view>; + std::initializer_list categories{ { abilities, "#{sBirthsignmenu1}", "Abilities" }, + { powers, "#{sPowers}", "Powers" }, { spells, "#{sBirthsignmenu2}", "Spells" } }; + + for (const auto& [category, label, widgetName] : categories) { - bool addHeader = true; - for (const ESM::Spell* spell : category) + std::string text; + if (!category.empty()) { - if (addHeader) - { - text += "\n\n#{fontcolourhtml=header}#{"; - text += label; - text += '}'; - addHeader = false; - } - - text += "\n#{fontcolourhtml=normal}" + spell->mName; + text = std::string(label) + "\n#{fontcolourhtml=normal}"; + for (const ESM::Spell* spell : category) + text += spell->mName + ' '; + text.pop_back(); } + widget->setUserString("Caption_BirthSign" + std::string(widgetName), text); } - - widget->setUserString("Caption_BirthSignText", text); } void ToolTips::createRaceToolTip(MyGUI::Widget* widget, const ESM::Race* playerRace) diff --git a/files/data/mygui/openmw_tooltips.layout b/files/data/mygui/openmw_tooltips.layout index ce927038c2..39cfbd06e1 100644 --- a/files/data/mygui/openmw_tooltips.layout +++ b/files/data/mygui/openmw_tooltips.layout @@ -272,16 +272,34 @@ - + - + - + - + + + + + + + + + + + + + + + + + + + From 38efdd2fd8035bf4ea249ef6d1df3688f787adec Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sat, 5 Jul 2025 01:00:26 +0300 Subject: [PATCH 146/330] Revert "Merge branch 'master' into 'master'" This reverts merge request !4710 --- apps/launcher/settingspage.cpp | 10 - apps/launcher/settingspage.hpp | 1 - apps/launcher/ui/settingspage.ui | 23 -- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwbase/inputmanager.hpp | 2 - apps/openmw/mwbase/windowmanager.hpp | 13 - apps/openmw/mwgui/alchemywindow.cpp | 96 +---- apps/openmw/mwgui/alchemywindow.hpp | 2 - apps/openmw/mwgui/birth.cpp | 54 +-- apps/openmw/mwgui/birth.hpp | 4 - apps/openmw/mwgui/bookpage.cpp | 18 - apps/openmw/mwgui/bookpage.hpp | 5 - apps/openmw/mwgui/bookwindow.cpp | 26 -- apps/openmw/mwgui/bookwindow.hpp | 2 - apps/openmw/mwgui/class.cpp | 319 +-------------- apps/openmw/mwgui/class.hpp | 22 - apps/openmw/mwgui/companionwindow.cpp | 65 +-- apps/openmw/mwgui/companionwindow.hpp | 9 - apps/openmw/mwgui/confirmationdialog.cpp | 40 -- apps/openmw/mwgui/confirmationdialog.hpp | 3 - apps/openmw/mwgui/container.cpp | 81 +--- apps/openmw/mwgui/container.hpp | 8 - .../openmw/mwgui/controllerbuttonsoverlay.cpp | 106 ----- .../openmw/mwgui/controllerbuttonsoverlay.hpp | 72 ---- apps/openmw/mwgui/countdialog.cpp | 30 +- apps/openmw/mwgui/countdialog.hpp | 6 +- apps/openmw/mwgui/dialogue.cpp | 195 --------- apps/openmw/mwgui/dialogue.hpp | 13 - apps/openmw/mwgui/enchantingdialog.cpp | 26 -- apps/openmw/mwgui/enchantingdialog.hpp | 2 - apps/openmw/mwgui/hud.cpp | 16 +- apps/openmw/mwgui/hud.hpp | 2 - apps/openmw/mwgui/inventorytabsoverlay.cpp | 51 --- apps/openmw/mwgui/inventorytabsoverlay.hpp | 24 -- apps/openmw/mwgui/inventorywindow.cpp | 244 +----------- apps/openmw/mwgui/inventorywindow.hpp | 5 - apps/openmw/mwgui/itemchargeview.cpp | 62 --- apps/openmw/mwgui/itemchargeview.hpp | 5 - apps/openmw/mwgui/itemselection.cpp | 17 - apps/openmw/mwgui/itemselection.hpp | 1 - apps/openmw/mwgui/itemview.cpp | 133 +----- apps/openmw/mwgui/itemview.hpp | 12 - apps/openmw/mwgui/itemwidget.cpp | 13 - apps/openmw/mwgui/itemwidget.hpp | 3 - apps/openmw/mwgui/journalbooks.cpp | 8 +- apps/openmw/mwgui/journalbooks.hpp | 2 - apps/openmw/mwgui/journalwindow.cpp | 343 ---------------- apps/openmw/mwgui/journalwindow.hpp | 6 - apps/openmw/mwgui/levelupdialog.cpp | 62 --- apps/openmw/mwgui/levelupdialog.hpp | 4 - apps/openmw/mwgui/mainmenu.cpp | 30 +- apps/openmw/mwgui/mainmenu.hpp | 1 - apps/openmw/mwgui/mapwindow.cpp | 174 +------- apps/openmw/mwgui/mapwindow.hpp | 10 - apps/openmw/mwgui/merchantrepair.cpp | 62 --- apps/openmw/mwgui/merchantrepair.hpp | 5 - apps/openmw/mwgui/messagebox.cpp | 54 --- apps/openmw/mwgui/messagebox.hpp | 3 - apps/openmw/mwgui/quickkeysmenu.cpp | 97 ----- apps/openmw/mwgui/quickkeysmenu.hpp | 9 - apps/openmw/mwgui/race.cpp | 91 +---- apps/openmw/mwgui/race.hpp | 8 +- apps/openmw/mwgui/recharge.cpp | 18 - apps/openmw/mwgui/recharge.hpp | 2 - apps/openmw/mwgui/repair.cpp | 18 - apps/openmw/mwgui/repair.hpp | 2 - apps/openmw/mwgui/review.cpp | 66 --- apps/openmw/mwgui/review.hpp | 5 - apps/openmw/mwgui/savegamedialog.cpp | 87 +--- apps/openmw/mwgui/savegamedialog.hpp | 5 - apps/openmw/mwgui/scrollwindow.cpp | 33 -- apps/openmw/mwgui/scrollwindow.hpp | 4 - apps/openmw/mwgui/settingswindow.cpp | 34 +- apps/openmw/mwgui/settingswindow.hpp | 2 - apps/openmw/mwgui/spellbuyingwindow.cpp | 80 ---- apps/openmw/mwgui/spellbuyingwindow.hpp | 4 - apps/openmw/mwgui/spellcreationdialog.cpp | 377 +----------------- apps/openmw/mwgui/spellcreationdialog.hpp | 27 +- apps/openmw/mwgui/spellview.cpp | 127 +----- apps/openmw/mwgui/spellview.hpp | 15 - apps/openmw/mwgui/spellwindow.cpp | 44 -- apps/openmw/mwgui/spellwindow.hpp | 2 - apps/openmw/mwgui/statswindow.cpp | 39 -- apps/openmw/mwgui/statswindow.hpp | 4 - apps/openmw/mwgui/textinput.cpp | 13 - apps/openmw/mwgui/textinput.hpp | 1 - apps/openmw/mwgui/tooltips.cpp | 2 +- apps/openmw/mwgui/tradewindow.cpp | 115 ------ apps/openmw/mwgui/tradewindow.hpp | 4 - apps/openmw/mwgui/trainingwindow.cpp | 50 --- apps/openmw/mwgui/trainingwindow.hpp | 4 - apps/openmw/mwgui/travelwindow.cpp | 63 --- apps/openmw/mwgui/travelwindow.hpp | 6 - apps/openmw/mwgui/waitdialog.cpp | 42 -- apps/openmw/mwgui/waitdialog.hpp | 6 +- apps/openmw/mwgui/widgets.cpp | 26 -- apps/openmw/mwgui/widgets.hpp | 8 - apps/openmw/mwgui/windowbase.cpp | 18 - apps/openmw/mwgui/windowbase.hpp | 36 -- apps/openmw/mwgui/windowmanagerimp.cpp | 204 ---------- apps/openmw/mwgui/windowmanagerimp.hpp | 18 - apps/openmw/mwinput/controllermanager.cpp | 97 +---- apps/openmw/mwinput/controllermanager.hpp | 1 - apps/openmw/mwinput/inputmanagerimp.cpp | 7 - apps/openmw/mwinput/inputmanagerimp.hpp | 1 - apps/openmw/mwinput/mousemanager.cpp | 13 - apps/openmw/mwinput/mousemanager.hpp | 1 - apps/openmw/mwlua/inputbindings.cpp | 2 - components/CMakeLists.txt | 2 +- components/settings/categories/gui.hpp | 2 - components/widgets/list.cpp | 5 - components/widgets/list.hpp | 1 - components/widgets/scrollbar.cpp | 17 - components/widgets/scrollbar.hpp | 18 - components/widgets/sharedstatebutton.hpp | 5 +- components/widgets/widgets.cpp | 2 - files/data/CMakeLists.txt | 18 - files/data/l10n/OMWEngine/de.yaml | 12 +- files/data/l10n/OMWEngine/en.yaml | 12 +- files/data/l10n/OMWEngine/fr.yaml | 12 +- files/data/l10n/OMWEngine/ru.yaml | 12 +- files/data/l10n/OMWEngine/sv.yaml | 12 +- .../mygui/openmw_controllerbuttons.layout | 211 ---------- files/data/mygui/openmw_inventory_tabs.layout | 51 --- .../data/mygui/openmw_inventory_window.layout | 14 - files/data/mygui/openmw_layers.xml | 1 - files/data/mygui/openmw_resources.xml | 13 +- .../data/mygui/openmw_savegame_dialog.layout | 2 +- files/data/mygui/openmw_text.skin.xml | 32 -- files/data/mygui/openmw_trade_window.layout | 14 - .../scripts/omw/input/gamepadcontrols.lua | 7 - files/data/textures/omw_menu_icon_active.dds | Bin 5616 -> 0 bytes files/data/textures/omw_steam_button_a.dds | Bin 22000 -> 0 bytes files/data/textures/omw_steam_button_b.dds | Bin 22000 -> 0 bytes files/data/textures/omw_steam_button_dpad.dds | Bin 22000 -> 0 bytes files/data/textures/omw_steam_button_l1.dds | Bin 22000 -> 0 bytes files/data/textures/omw_steam_button_l2.dds | Bin 22000 -> 0 bytes files/data/textures/omw_steam_button_l3.dds | Bin 22000 -> 0 bytes .../data/textures/omw_steam_button_lstick.dds | Bin 22000 -> 0 bytes files/data/textures/omw_steam_button_menu.dds | Bin 22000 -> 0 bytes files/data/textures/omw_steam_button_r1.dds | Bin 22000 -> 0 bytes files/data/textures/omw_steam_button_r2.dds | Bin 22000 -> 0 bytes files/data/textures/omw_steam_button_r3.dds | Bin 22000 -> 0 bytes .../data/textures/omw_steam_button_rstick.dds | Bin 22000 -> 0 bytes files/data/textures/omw_steam_button_view.dds | Bin 22000 -> 0 bytes files/data/textures/omw_steam_button_x.dds | Bin 22000 -> 0 bytes files/data/textures/omw_steam_button_y.dds | Bin 22000 -> 0 bytes files/lang/launcher_de.ts | 16 - files/lang/launcher_en.ts | 16 - files/lang/launcher_fr.ts | 16 - files/lang/launcher_ru.ts | 16 - files/lang/launcher_sv.ts | 16 - files/settings-default.cfg | 6 - 153 files changed, 94 insertions(+), 5012 deletions(-) delete mode 100644 apps/openmw/mwgui/controllerbuttonsoverlay.cpp delete mode 100644 apps/openmw/mwgui/controllerbuttonsoverlay.hpp delete mode 100644 apps/openmw/mwgui/inventorytabsoverlay.cpp delete mode 100644 apps/openmw/mwgui/inventorytabsoverlay.hpp delete mode 100644 components/widgets/scrollbar.cpp delete mode 100644 components/widgets/scrollbar.hpp delete mode 100644 files/data/mygui/openmw_controllerbuttons.layout delete mode 100644 files/data/mygui/openmw_inventory_tabs.layout delete mode 100644 files/data/textures/omw_menu_icon_active.dds delete mode 100644 files/data/textures/omw_steam_button_a.dds delete mode 100644 files/data/textures/omw_steam_button_b.dds delete mode 100644 files/data/textures/omw_steam_button_dpad.dds delete mode 100644 files/data/textures/omw_steam_button_l1.dds delete mode 100644 files/data/textures/omw_steam_button_l2.dds delete mode 100644 files/data/textures/omw_steam_button_l3.dds delete mode 100644 files/data/textures/omw_steam_button_lstick.dds delete mode 100644 files/data/textures/omw_steam_button_menu.dds delete mode 100644 files/data/textures/omw_steam_button_r1.dds delete mode 100644 files/data/textures/omw_steam_button_r2.dds delete mode 100644 files/data/textures/omw_steam_button_r3.dds delete mode 100644 files/data/textures/omw_steam_button_rstick.dds delete mode 100644 files/data/textures/omw_steam_button_view.dds delete mode 100644 files/data/textures/omw_steam_button_x.dds delete mode 100644 files/data/textures/omw_steam_button_y.dds diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index 294c2c09f3..dfddc45bc5 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -304,9 +304,6 @@ bool Launcher::SettingsPage::loadSettings() loadSettingBool(Settings::gui().mColorTopicEnable, *changeDialogTopicsCheckBox); showOwnedComboBox->setCurrentIndex(Settings::game().mShowOwned); loadSettingBool(Settings::gui().mStretchMenuBackground, *stretchBackgroundCheckBox); - connect(controllerMenusCheckBox, &QCheckBox::toggled, this, &SettingsPage::slotControllerMenusToggled); - loadSettingBool(Settings::gui().mControllerMenus, *controllerMenusCheckBox); - loadSettingBool(Settings::gui().mControllerTooltips, *controllerMenuTooltipsCheckBox); loadSettingBool(Settings::map().mAllowZooming, *useZoomOnMapCheckBox); loadSettingBool(Settings::game().mGraphicHerbalism, *graphicHerbalismCheckBox); scalingSpinBox->setValue(Settings::gui().mScalingFactor); @@ -500,8 +497,6 @@ void Launcher::SettingsPage::saveSettings() saveSettingBool(*changeDialogTopicsCheckBox, Settings::gui().mColorTopicEnable); saveSettingInt(*showOwnedComboBox, Settings::game().mShowOwned); saveSettingBool(*stretchBackgroundCheckBox, Settings::gui().mStretchMenuBackground); - saveSettingBool(*controllerMenusCheckBox, Settings::gui().mControllerMenus); - saveSettingBool(*controllerMenuTooltipsCheckBox, Settings::gui().mControllerTooltips); saveSettingBool(*useZoomOnMapCheckBox, Settings::map().mAllowZooming); saveSettingBool(*graphicHerbalismCheckBox, Settings::game().mGraphicHerbalism); Settings::gui().mScalingFactor.set(scalingSpinBox->value()); @@ -560,11 +555,6 @@ void Launcher::SettingsPage::slotAnimSourcesToggled(bool checked) } } -void Launcher::SettingsPage::slotControllerMenusToggled(bool checked) -{ - controllerMenuTooltipsCheckBox->setEnabled(checked); -} - void Launcher::SettingsPage::slotPostProcessToggled(bool checked) { postprocessTransparentPostpassCheckBox->setEnabled(checked); diff --git a/apps/launcher/settingspage.hpp b/apps/launcher/settingspage.hpp index 2c6eca477a..d2bb80d86a 100644 --- a/apps/launcher/settingspage.hpp +++ b/apps/launcher/settingspage.hpp @@ -34,7 +34,6 @@ namespace Launcher void slotSkyBlendingToggled(bool checked); void slotShadowDistLimitToggled(bool checked); void slotDistantLandToggled(bool checked); - void slotControllerMenusToggled(bool checked); private: Config::GameSettings& mGameSettings; diff --git a/apps/launcher/ui/settingspage.ui b/apps/launcher/ui/settingspage.ui index aace4b49c7..e792ac2843 100644 --- a/apps/launcher/ui/settingspage.ui +++ b/apps/launcher/ui/settingspage.ui @@ -1398,29 +1398,6 @@ - - - - <html><head/><body><p>Make it easier to use game menus with a controller.</p></body></html> - - - Enable Controller Menus - - - - - - - false - - - <html><head/><body><p>When using controller menus, make tooltips visible by default.</p></body></html> - - - Show Controller Tooltips By Default - - - diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 39fe9c4f7a..e3629d6f27 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -44,7 +44,7 @@ add_openmw_dir (mwgui tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview draganddrop timeadvancer jailscreen itemchargeview keyboardnavigation textcolours statswatcher - postprocessorhud settings controllerbuttonsoverlay inventorytabsoverlay + postprocessorhud settings ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index f5adc42340..5ee20476b3 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -5,7 +5,6 @@ #include #include -#include #include #include @@ -62,7 +61,6 @@ namespace MWBase virtual float getControllerAxisValue(SDL_GameControllerAxis axis) const = 0; // returns value in range [-1, 1] virtual int getMouseMoveX() const = 0; virtual int getMouseMoveY() const = 0; - virtual void warpMouseToWidget(MyGUI::Widget* widget) = 0; /// Actions available for binding to keyboard buttons virtual const std::initializer_list& getActionKeySorting() = 0; diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 83a714cf05..8164501b4b 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -11,9 +11,7 @@ #include -#include "../mwgui/hud.hpp" #include "../mwgui/mode.hpp" -#include "../mwgui/windowbase.hpp" #include @@ -159,9 +157,7 @@ namespace MWBase virtual MWGui::CountDialog* getCountDialog() = 0; virtual MWGui::ConfirmationDialog* getConfirmationDialog() = 0; virtual MWGui::TradeWindow* getTradeWindow() = 0; - virtual MWGui::HUD* getHud() = 0; virtual MWGui::PostProcessorHud* getPostProcessorHud() = 0; - virtual std::vector getGuiModeWindows(MWGui::GuiMode mode) = 0; /// Make the player use an item, while updating GUI state accordingly virtual void useItem(const MWWorld::Ptr& item, bool force = false) = 0; @@ -385,15 +381,6 @@ namespace MWBase /// Same as viewer->getCamera()->getCullMask(), provided for consistency. virtual uint32_t getCullMask() = 0; - /// Return the window that should receive controller events - virtual MWGui::WindowBase* getActiveControllerWindow() = 0; - /// Cycle to the next window to receive controller events - virtual void cycleActiveControllerWindow(bool next) = 0; - virtual void setActiveControllerWindow(MWGui::GuiMode mode, int activeIndex) = 0; - virtual bool getControllerTooltip() const = 0; - virtual void setControllerTooltip(bool enabled) = 0; - virtual void updateControllerButtonsOverlay() = 0; - // Used in Lua bindings virtual const std::vector& getGuiModeStack() const = 0; virtual void setDisabledByLua(std::string_view windowId, bool disabled) = 0; diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 6cf34702d7..5a6245fca0 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include @@ -92,15 +91,6 @@ namespace MWGui mFilterValue->eventEditTextChange += MyGUI::newDelegate(this, &AlchemyWindow::onFilterEdited); mFilterType->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::switchFilterType); - if (Settings::gui().mControllerMenus) - { - mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sCancel}"; - mControllerButtons.x = "#{sCreate}"; - mControllerButtons.y = "#{sMagicEffects}"; - mControllerButtons.r3 = "#{sInfo}"; - } - center(); } @@ -175,12 +165,7 @@ namespace MWGui std::string_view ingredient = wm->getGameSettingString("sIngredients", "Ingredients"); if (mFilterType->getCaption() == ingredient) - { - if (Settings::gui().mControllerMenus) - switchFilterType(mFilterType); - else - mCurrentFilter = FilterType::ByName; - } + mCurrentFilter = FilterType::ByName; else mCurrentFilter = FilterType::ByEffect; updateFilters(); @@ -306,9 +291,6 @@ namespace MWGui initFilter(); MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mNameEdit); - - if (Settings::gui().mControllerMenus) - mItemView->setActiveControllerWindow(true); } void AlchemyWindow::onIngredientSelected(MyGUI::Widget* _sender) @@ -546,80 +528,4 @@ namespace MWGui if (currentCount > 1) mBrewCountEdit->setValue(currentCount - 1); } - - bool AlchemyWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); - bool isFilterListOpen - = focus != nullptr && focus->getParent() != nullptr && focus->getParent()->getParent() == mFilterValue; - - if (isFilterListOpen) - { - // When the filter list combo box is open, send all inputs to it. - if (arg.button == SDL_CONTROLLER_BUTTON_A || arg.button == SDL_CONTROLLER_BUTTON_Y) - { - // Select the highlighted entry in the combo box and close it. - int index = mFilterValue->getIndexSelected(); - mFilterValue->setIndexSelected(index); - onFilterChanged(mFilterValue, index); - MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mNameEdit); // Close list - MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - { - // Close the list without selecting anything - mFilterValue->clearIndexSelected(); - onFilterEdited(mFilterValue); - MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mNameEdit); // Close list - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) - MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::ArrowUp, 0, false); - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); - } - else - { - if (arg.button == SDL_CONTROLLER_BUTTON_B) - { - // Remove active ingredients or close the window - if (mIngredients[3]->isUserString("ToolTipType")) - onIngredientSelected(mIngredients[3]); - else if (mIngredients[2]->isUserString("ToolTipType")) - onIngredientSelected(mIngredients[2]); - else if (mIngredients[1]->isUserString("ToolTipType")) - onIngredientSelected(mIngredients[1]); - else if (mIngredients[0]->isUserString("ToolTipType")) - onIngredientSelected(mIngredients[0]); - else - onCancelButtonClicked(mCancelButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_X) - onCreateButtonClicked(mCreateButton); - else if (arg.button == SDL_CONTROLLER_BUTTON_Y && mFilterValue->getItemCount() > 0) - { - // Magical effects/ingredients filter - if (mFilterValue->getIndexSelected() != MyGUI::ITEM_NONE) - { - // Clear the active filter - mFilterValue->clearIndexSelected(); - onFilterEdited(mFilterValue); - } - else - { - // Open the combo box to choose the a filter - MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mFilterValue); - MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); - } - MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) - onDecreaseButtonTriggered(); - else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) - onIncreaseButtonTriggered(); - else - mItemView->onControllerButton(arg.button); - } - - return true; - } } diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index e79c41b659..82e5c3f583 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -99,8 +99,6 @@ namespace MWGui std::vector mApparatus; std::vector mIngredients; - - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; }; } diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 5a5605aa6e..3dfdd17627 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -50,20 +50,15 @@ namespace MWGui mBirthList->eventListSelectAccept += MyGUI::newDelegate(this, &BirthDialog::onAccept); mBirthList->eventListChangePosition += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); - getWidget(mBackButton, "BackButton"); - mBackButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onBackClicked); + MyGUI::Button* backButton; + getWidget(backButton, "BackButton"); + backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onBackClicked); - getWidget(mOkButton, "OKButton"); - mOkButton->setCaption( + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + okButton->setCaption( MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", {}))); - mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked); - - if (Settings::gui().mControllerMenus) - { - mControllerButtons.lStick = "#{sMouse}"; - mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sBack}"; - } + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked); updateBirths(); updateSpells(); @@ -75,17 +70,8 @@ namespace MWGui getWidget(okButton, "OKButton"); if (shown) - { okButton->setCaption( MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", {}))); - mControllerButtons.x = "#{sNext}"; - } - else if (Settings::gui().mControllerMenus) - { - okButton->setCaption( - MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sDone", {}))); - mControllerButtons.x = "#{sDone}"; - } else okButton->setCaption( MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", {}))); @@ -285,30 +271,4 @@ namespace MWGui mSpellArea->setVisibleVScroll(true); mSpellArea->setViewOffset(MyGUI::IntPoint(0, 0)); } - - bool BirthDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_B) - { - onBackClicked(mBackButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_X) - { - onOkClicked(mOkButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) - { - MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); - winMgr->setKeyFocusWidget(mBirthList); - winMgr->injectKeyPress(MyGUI::KeyCode::ArrowUp, 0, false); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - { - MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); - winMgr->setKeyFocusWidget(mBirthList); - winMgr->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); - } - - return true; - } } diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index b41b1fbb9a..db9e997b6c 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -53,12 +53,8 @@ namespace MWGui MyGUI::ScrollView* mSpellArea; MyGUI::ImageBox* mBirthImage; std::vector mSpellItems; - MyGUI::Button* mBackButton; - MyGUI::Button* mOkButton; ESM::RefId mCurrentBirthId; - - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; }; } #endif diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 2c58ca3b72..47e85b1f4b 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -105,18 +105,6 @@ namespace MWGui Styles mStyles; MyGUI::IntRect mRect; - void setColour(size_t section, size_t line, size_t run, const MyGUI::Colour& colour) const override - { - if (section >= mSections.size()) - return; - if (line >= mSections[section].mLines.size()) - return; - if (run >= mSections[section].mLines[line].mRuns.size()) - return; - - mSections[section].mLines[line].mRuns[run].mStyle->mNormalColour = colour; - } - virtual ~TypesetBookImpl() {} Range addContent(const BookTypesetter::Utf8Span& text) @@ -1300,12 +1288,6 @@ namespace MWGui void unadviseLinkClicked() override { mPageDisplay->mLinkClicked = std::function(); } - void setFocusItem(BookTypesetter::Style* itemStyle) override - { - mPageDisplay->mFocusItem = (TypesetBookImpl::StyleImpl*)itemStyle; - mPageDisplay->dirtyFocusItem(); - } - protected: void initialiseOverride() override { diff --git a/apps/openmw/mwgui/bookpage.hpp b/apps/openmw/mwgui/bookpage.hpp index bb85130b7f..d42fb4783f 100644 --- a/apps/openmw/mwgui/bookpage.hpp +++ b/apps/openmw/mwgui/bookpage.hpp @@ -31,9 +31,6 @@ namespace MWGui /// text combined prior to pagination. virtual std::pair getSize() const = 0; - /// Used to highlight journal indices - virtual void setColour(size_t section, size_t line, size_t run, const MyGUI::Colour& colour) const = 0; - virtual ~TypesetBook() = default; }; @@ -167,8 +164,6 @@ namespace MWGui /// Register the widget and associated sub-widget with MyGUI. Should be /// called once near the beginning of the program. static void registerMyGUIComponents(); - - virtual void setFocusItem(BookTypesetter::Style* itemStyle) = 0; }; } diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index beba6e5968..ef875a18b9 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -66,10 +66,6 @@ namespace MWGui MyGUI::IntCoord(0, 0, (64 - 7) * scale, mNextPageButton->getSize().height * scale)); } - mControllerButtons.l1 = "#{sPrev}"; - mControllerButtons.r1 = "#{sNext}"; - mControllerButtons.b = "#{sClose}"; - center(); } @@ -222,26 +218,4 @@ namespace MWGui } } - ControllerButtonStr* BookWindow::getControllerButtons() - { - mControllerButtons.a = mTakeButton->getVisible() ? "#{sTake}" : ""; - return &mControllerButtons; - } - - bool BookWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - if (mTakeButton->getVisible()) - onTakeButtonClicked(mTakeButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - onCloseButtonClicked(mCloseButton); - else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) - prevPage(); - else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) - nextPage(); - - return true; - } } diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index 0a1beb7342..5a3dfdf584 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -18,10 +18,8 @@ namespace MWGui void setInventoryAllowed(bool allowed); void onResChange(int, int) override { center(); } - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; std::string_view getWindowIdForLua() const override { return "Book"; } - ControllerButtonStr* getControllerButtons() override; protected: void onNextPageButtonClicked(MyGUI::Widget* sender); diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 450a61b4f8..839f0f5072 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #include "tooltips.hpp" @@ -47,21 +46,15 @@ namespace MWGui getWidget(mClassImage, "ClassImage"); getWidget(mClassName, "ClassName"); - getWidget(mBackButton, "BackButton"); - mBackButton->setCaptionWithReplacing("#{sMessageQuestionAnswer3}"); - mBackButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onBackClicked); + MyGUI::Button* backButton; + getWidget(backButton, "BackButton"); + backButton->setCaptionWithReplacing("#{sMessageQuestionAnswer3}"); + backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onBackClicked); - getWidget(mOkButton, "OKButton"); - mOkButton->setCaptionWithReplacing("#{sMessageQuestionAnswer2}"); - mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked); - - if (Settings::gui().mControllerMenus) - { - mOkButton->setStateSelected(true); - mDisableGamepadCursor = true; - mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sBack}"; - } + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + okButton->setCaptionWithReplacing("#{sMessageQuestionAnswer2}"); + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked); center(); } @@ -78,30 +71,6 @@ namespace MWGui center(); } - bool GenerateClassResultDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - if (mOkButtonFocus) - onOkClicked(mOkButton); - else - onBackClicked(mBackButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - { - onBackClicked(mBackButton); - } - else if ((arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && mOkButtonFocus) - || (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && !mOkButtonFocus)) - { - mOkButtonFocus = !mOkButtonFocus; - mOkButton->setStateSelected(mOkButtonFocus); - mBackButton->setStateSelected(!mOkButtonFocus); - } - - return true; - } - // widget controls void GenerateClassResultDialog::onOkClicked(MyGUI::Widget* _sender) @@ -141,18 +110,13 @@ namespace MWGui getWidget(mClassImage, "ClassImage"); - getWidget(mBackButton, "BackButton"); - mBackButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onBackClicked); + MyGUI::Button* backButton; + getWidget(backButton, "BackButton"); + backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onBackClicked); - getWidget(mOkButton, "OKButton"); - mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onOkClicked); - - if (Settings::gui().mControllerMenus) - { - mControllerButtons.lStick = "#{sMouse}"; - mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sBack}"; - } + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onOkClicked); updateClasses(); updateStats(); @@ -164,17 +128,8 @@ namespace MWGui getWidget(okButton, "OKButton"); if (shown) - { okButton->setCaption( MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", {}))); - mControllerButtons.x = "#{sNext}"; - } - else if (Settings::gui().mControllerMenus) - { - okButton->setCaption( - MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sDone", {}))); - mControllerButtons.x = "#{sDone}"; - } else okButton->setCaption( MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", {}))); @@ -323,32 +278,6 @@ namespace MWGui setClassImage(mClassImage, mCurrentClassId); } - bool PickClassDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_B) - { - onBackClicked(mBackButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_X) - { - onOkClicked(mOkButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) - { - MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); - winMgr->setKeyFocusWidget(mClassList); - winMgr->injectKeyPress(MyGUI::KeyCode::ArrowUp, 0, false); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - { - MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); - winMgr->setKeyFocusWidget(mClassList); - winMgr->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); - } - - return true; - } - /* InfoBoxDialog */ void InfoBoxDialog::fitToText(MyGUI::TextBox* widget) @@ -390,9 +319,6 @@ namespace MWGui getWidget(mButtonBar, "ButtonBar"); center(); - - mDisableGamepadCursor = Settings::gui().mControllerMenus; - mControllerButtons.a = "#{sSelect}"; } void InfoBoxDialog::setText(const std::string& str) @@ -427,13 +353,6 @@ namespace MWGui fitToText(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &InfoBoxDialog::onButtonClicked); coord.top += button->getHeight(); - - if (Settings::gui().mControllerMenus && buttons.size() > 1 && this->mButtons.empty()) - { - // First button is selected by default - button->setStateSelected(true); - } - this->mButtons.push_back(button); } } @@ -463,44 +382,6 @@ namespace MWGui } } - bool InfoBoxDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - if (mControllerFocus >= 0 && mControllerFocus < static_cast(mButtons.size())) - onButtonClicked(mButtons[mControllerFocus]); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - { - if (mButtons.size() == 1) - onButtonClicked(mButtons[0]); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) - { - if (mButtons.size() <= 1) - return true; - if (mButtons.size() == 2 && mControllerFocus == 0) - return true; - - setControllerFocus(mButtons, mControllerFocus, false); - mControllerFocus = wrap(mControllerFocus - 1, mButtons.size()); - setControllerFocus(mButtons, mControllerFocus, true); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - { - if (mButtons.size() <= 1) - return true; - if (mButtons.size() == 2 && mControllerFocus == static_cast(mButtons.size()) - 1) - return true; - - setControllerFocus(mButtons, mControllerFocus, false); - mControllerFocus = wrap(mControllerFocus + 1, mButtons.size()); - setControllerFocus(mButtons, mControllerFocus, true); - } - - return true; - } - /* ClassChoiceDialog */ ClassChoiceDialog::ClassChoiceDialog() @@ -569,25 +450,14 @@ namespace MWGui MyGUI::Button* descriptionButton; getWidget(descriptionButton, "DescriptionButton"); descriptionButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionClicked); - mButtons.push_back(descriptionButton); MyGUI::Button* backButton; getWidget(backButton, "BackButton"); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onBackClicked); - mButtons.push_back(backButton); MyGUI::Button* okButton; getWidget(okButton, "OKButton"); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onOkClicked); - mButtons.push_back(okButton); - - if (Settings::gui().mControllerMenus) - { - okButton->setStateSelected(true); - mControllerButtons.lStick = "#{sMouse}"; - mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sBack}"; - } // Set default skills, attributes @@ -675,56 +545,13 @@ namespace MWGui getWidget(okButton, "OKButton"); if (shown) - { okButton->setCaption( MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", {}))); - mControllerButtons.x = "#{sNext}"; - } - else if (Settings::gui().mControllerMenus) - { - okButton->setCaption( - MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sDone", {}))); - mControllerButtons.x = "#{sDone}"; - } else okButton->setCaption( MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", {}))); } - bool CreateClassDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - if (mControllerFocus == 0) - onDescriptionClicked(mButtons[0]); - else if (mControllerFocus == 1) - onBackClicked(mButtons[1]); - else - onOkClicked(mButtons[2]); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - { - onBackClicked(mButtons[1]); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_X) - { - onOkClicked(mButtons[2]); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) - { - setControllerFocus(mButtons, mControllerFocus, false); - mControllerFocus = wrap(mControllerFocus - 1, mButtons.size()); - setControllerFocus(mButtons, mControllerFocus, true); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) - { - setControllerFocus(mButtons, mControllerFocus, false); - mControllerFocus = wrap(mControllerFocus + 1, mButtons.size()); - setControllerFocus(mButtons, mControllerFocus, true); - } - return true; - } - // widget controls void CreateClassDialog::onDialogCancel() @@ -881,9 +708,6 @@ namespace MWGui MyGUI::Button* cancelButton; getWidget(cancelButton, "CancelButton"); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onCancelClicked); - - mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sCancel}"; } SelectSpecializationDialog::~SelectSpecializationDialog() {} @@ -915,16 +739,6 @@ namespace MWGui return true; } - bool SelectSpecializationDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_B) - { - onCancelClicked(nullptr); - return true; - } - return false; - } - /* SelectAttributeDialog */ SelectAttributeDialog::SelectAttributeDialog() @@ -946,7 +760,6 @@ namespace MWGui widget->setAttributeId(attribute.mId); widget->eventClicked += MyGUI::newDelegate(this, &SelectAttributeDialog::onAttributeClicked); ToolTips::createAttributeToolTip(widget, attribute.mId); - mAttributeButtons.emplace_back(widget); } attributes->setVisibleVScroll(false); @@ -957,16 +770,6 @@ namespace MWGui MyGUI::Button* cancelButton; getWidget(cancelButton, "CancelButton"); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectAttributeDialog::onCancelClicked); - - if (Settings::gui().mControllerMenus) - { - mControllerFocus = 0; - if (mAttributeButtons.size() > 0) - mAttributeButtons[0]->setStateSelected(true); - - mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sCancel}"; - } } // widget controls @@ -988,33 +791,6 @@ namespace MWGui return true; } - bool SelectAttributeDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - if (mControllerFocus >= 0 && mControllerFocus < static_cast(mAttributeButtons.size())) - onAttributeClicked(mAttributeButtons[mControllerFocus]); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - { - onCancelClicked(nullptr); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) - { - mAttributeButtons[mControllerFocus]->setStateSelected(false); - mControllerFocus = wrap(mControllerFocus - 1, mAttributeButtons.size()); - mAttributeButtons[mControllerFocus]->setStateSelected(true); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - { - mAttributeButtons[mControllerFocus]->setStateSelected(false); - mControllerFocus = wrap(mControllerFocus + 1, mAttributeButtons.size()); - mAttributeButtons[mControllerFocus]->setStateSelected(true); - } - - return true; - } - /* SelectSkillDialog */ SelectSkillDialog::SelectSkillDialog() @@ -1044,7 +820,6 @@ namespace MWGui skillWidget->setSkillId(skill.mId); skillWidget->eventClicked += MyGUI::newDelegate(this, &SelectSkillDialog::onSkillClicked); ToolTips::createSkillToolTip(skillWidget, skill.mId); - mSkillButtons.emplace_back(skillWidget); } for (const auto& [widget, coord] : specializations) { @@ -1057,16 +832,6 @@ namespace MWGui MyGUI::Button* cancelButton; getWidget(cancelButton, "CancelButton"); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSkillDialog::onCancelClicked); - - if (Settings::gui().mControllerMenus) - { - mControllerFocus = 0; - if (mSkillButtons.size() > 0) - mSkillButtons[0]->setStateSelected(true); - - mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sCancel}"; - } } SelectSkillDialog::~SelectSkillDialog() {} @@ -1090,51 +855,6 @@ namespace MWGui return true; } - bool SelectSkillDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - if (mControllerFocus >= 0 && mControllerFocus < static_cast(mSkillButtons.size())) - onSkillClicked(mSkillButtons[mControllerFocus]); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - { - onCancelClicked(nullptr); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) - { - mSkillButtons[mControllerFocus]->setStateSelected(false); - mControllerFocus = wrap(mControllerFocus - 1, mSkillButtons.size()); - mSkillButtons[mControllerFocus]->setStateSelected(true); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - { - mSkillButtons[mControllerFocus]->setStateSelected(false); - mControllerFocus = wrap(mControllerFocus + 1, mSkillButtons.size()); - mSkillButtons[mControllerFocus]->setStateSelected(true); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) - { - mSkillButtons[mControllerFocus]->setStateSelected(false); - if (mControllerFocus < 9) - mControllerFocus += 18; - else - mControllerFocus -= 9; - mSkillButtons[mControllerFocus]->setStateSelected(true); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) - { - mSkillButtons[mControllerFocus]->setStateSelected(false); - if (mControllerFocus >= 18) - mControllerFocus -= 18; - else - mControllerFocus += 9; - mSkillButtons[mControllerFocus]->setStateSelected(true); - } - - return true; - } - /* DescriptionDialog */ DescriptionDialog::DescriptionDialog() @@ -1153,8 +873,6 @@ namespace MWGui // Make sure the edit box has focus MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit); - - mControllerButtons.a = "#{sOk}"; } DescriptionDialog::~DescriptionDialog() {} @@ -1186,13 +904,4 @@ namespace MWGui imageBox->setImageTexture(classImage); } - bool DescriptionDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A || arg.button == SDL_CONTROLLER_BUTTON_B) - { - onOkClicked(nullptr); - return true; - } - return false; - } } diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index a4db03d4ab..f89a0c7d88 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -42,7 +42,6 @@ namespace MWGui protected: void onButtonClicked(MyGUI::Widget* _sender); - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; private: void fitToText(MyGUI::TextBox* widget); @@ -51,7 +50,6 @@ namespace MWGui MyGUI::TextBox* mText; MyGUI::Widget* mButtonBar; std::vector mButtons; - int mControllerFocus = 0; }; // Lets the player choose between 3 ways of creating a class @@ -94,14 +92,10 @@ namespace MWGui protected: void onOkClicked(MyGUI::Widget* _sender); void onBackClicked(MyGUI::Widget* _sender); - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - bool mOkButtonFocus = true; private: MyGUI::ImageBox* mClassImage; MyGUI::TextBox* mClassName; - MyGUI::Button* mBackButton; - MyGUI::Button* mOkButton; ESM::RefId mCurrentClassId; }; @@ -146,15 +140,11 @@ namespace MWGui MyGUI::ImageBox* mClassImage; MyGUI::ListBox* mClassList; MyGUI::TextBox* mSpecializationName; - MyGUI::Button* mBackButton; - MyGUI::Button* mOkButton; Widgets::MWAttributePtr mFavoriteAttribute[2]; Widgets::MWSkillPtr mMajorSkill[5]; Widgets::MWSkillPtr mMinorSkill[5]; ESM::RefId mCurrentClassId; - - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; }; class SelectSpecializationDialog : public WindowModal @@ -183,7 +173,6 @@ namespace MWGui protected: void onSpecializationClicked(MyGUI::Widget* _sender); void onCancelClicked(MyGUI::Widget* _sender); - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; private: MyGUI::TextBox *mSpecialization0, *mSpecialization1, *mSpecialization2; @@ -217,9 +206,6 @@ namespace MWGui protected: void onAttributeClicked(Widgets::MWAttributePtr _sender); void onCancelClicked(MyGUI::Widget* _sender); - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - int mControllerFocus; - std::vector mAttributeButtons; private: ESM::RefId mAttributeId; @@ -251,9 +237,6 @@ namespace MWGui protected: void onSkillClicked(Widgets::MWSkillPtr _sender); void onCancelClicked(MyGUI::Widget* _sender); - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - int mControllerFocus; - std::vector mSkillButtons; private: ESM::RefId mSkillId; @@ -275,7 +258,6 @@ namespace MWGui protected: void onOkClicked(MyGUI::Widget* _sender); - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; private: MyGUI::EditBox* mTextEdit; @@ -332,7 +314,6 @@ namespace MWGui private: MyGUI::EditBox* mEditName; MyGUI::TextBox* mSpecializationName; - std::vector mButtons; Widgets::MWAttributePtr mFavoriteAttribute0, mFavoriteAttribute1; std::array mMajorSkill; std::array mMinorSkill; @@ -348,9 +329,6 @@ namespace MWGui Widgets::MWAttributePtr mAffectedAttribute; Widgets::MWSkillPtr mAffectedSkill; - - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - int mControllerFocus = 2; }; } #endif diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 4a7863b856..240198eddc 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -6,8 +6,6 @@ #include #include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" @@ -16,7 +14,6 @@ #include "companionitemmodel.hpp" #include "countdialog.hpp" #include "draganddrop.hpp" -#include "inventorywindow.hpp" #include "itemview.hpp" #include "messagebox.hpp" #include "sortfilteritemmodel.hpp" @@ -61,11 +58,6 @@ namespace MWGui mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CompanionWindow::onCloseButtonClicked); setCoord(200, 0, 600, 300); - - mControllerButtons.a = "#{sTake}"; - mControllerButtons.b = "#{sClose}"; - mControllerButtons.r3 = "#{sInfo}"; - mControllerButtons.l2 = "#{sInventory}"; } void CompanionWindow::onItemSelected(int index) @@ -101,13 +93,8 @@ namespace MWGui name += MWGui::ToolTips::getSoulString(object.getCellRef()); dialog->openCountDialog(name, "#{sTake}", count); dialog->eventOkClicked.clear(); - if (Settings::gui().mControllerMenus) - dialog->eventOkClicked += MyGUI::newDelegate(this, &CompanionWindow::takeItem); - else - dialog->eventOkClicked += MyGUI::newDelegate(this, &CompanionWindow::dragItem); + dialog->eventOkClicked += MyGUI::newDelegate(this, &CompanionWindow::dragItem); } - else if (Settings::gui().mControllerMenus) - takeItem(nullptr, count); else dragItem(nullptr, count); } @@ -123,29 +110,6 @@ namespace MWGui mDragAndDrop->startDrag(mSelectedItem, mSortModel, mModel, mItemView, count); } - void CompanionWindow::takeItem(MyGUI::Widget* sender, int count) - { - if (!mModel) - return; - - const ItemStack& item = mModel->getItem(mSelectedItem); - if (!mModel->onTakeItem(item.mBase, count)) - return; - - MWGui::InventoryWindow* inventoryWindow = MWBase::Environment::get().getWindowManager()->getInventoryWindow(); - ItemModel* playerModel = inventoryWindow->getModel(); - - mModel->moveItem(item, count, playerModel); - - inventoryWindow->updateItemView(); - mItemView->update(); - - // play the item's sound - MWWorld::Ptr itemBase = item.mBase; - const ESM::RefId& sound = itemBase.getClass().getUpSoundId(itemBase); - MWBase::Environment::get().getWindowManager()->playSound(sound); - } - void CompanionWindow::onBackgroundSelected() { if (mDragAndDrop->mIsOnDragAndDrop) @@ -238,31 +202,4 @@ namespace MWGui mSortModel = nullptr; } - bool CompanionWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - int index = mItemView->getControllerFocus(); - if (index >= 0 && index < mItemView->getItemCount()) - onItemSelected(index); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - { - onCloseButtonClicked(mCloseButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK || arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP - || arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN || arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT - || arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) - { - mItemView->onControllerButton(arg.button); - } - - return true; - } - - void CompanionWindow::setActiveControllerWindow(bool active) - { - mItemView->setActiveControllerWindow(active); - WindowBase::setActiveControllerWindow(active); - } } diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index c0cd87c9d5..97f3a0072e 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -1,8 +1,6 @@ #ifndef OPENMW_MWGUI_COMPANIONWINDOW_H #define OPENMW_MWGUI_COMPANIONWINDOW_H -#include "companionitemmodel.hpp" -#include "itemmodel.hpp" #include "referenceinterface.hpp" #include "windowbase.hpp" @@ -34,12 +32,6 @@ namespace MWGui std::string_view getWindowIdForLua() const override { return "Companion"; } - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - void setActiveControllerWindow(bool active) override; - - MWGui::ItemView* getItemView() { return mItemView; } - ItemModel* getModel() { return mModel; } - private: ItemView* mItemView; SortFilterItemModel* mSortModel; @@ -58,7 +50,6 @@ namespace MWGui void onNameFilterChanged(MyGUI::EditBox* _sender); void onBackgroundSelected(); void dragItem(MyGUI::Widget* sender, int count); - void takeItem(MyGUI::Widget* sender, int count); void onMessageBoxButtonClicked(int button); diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index f858b9628a..48b209f17e 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -3,8 +3,6 @@ #include #include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" @@ -19,13 +17,6 @@ namespace MWGui mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ConfirmationDialog::onCancelButtonClicked); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ConfirmationDialog::onOkButtonClicked); - - if (Settings::gui().mControllerMenus) - { - mDisableGamepadCursor = true; - mControllerButtons.a = "#{sOk}"; - mControllerButtons.b = "#{sCancel}"; - } } void ConfirmationDialog::askForConfirmation(const std::string& message) @@ -44,13 +35,6 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mOkButton); - if (Settings::gui().mControllerMenus) - { - mOkButtonFocus = true; - mOkButton->setStateSelected(true); - mCancelButton->setStateSelected(false); - } - center(); } @@ -72,28 +56,4 @@ namespace MWGui eventOkClicked(); } - - bool ConfirmationDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - if (mOkButtonFocus) - onOkButtonClicked(mOkButton); - else - onCancelButtonClicked(mCancelButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - { - onCancelButtonClicked(mCancelButton); - } - else if ((arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && !mOkButtonFocus) - || (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && mOkButtonFocus)) - { - mOkButtonFocus = !mOkButtonFocus; - mOkButton->setStateSelected(mOkButtonFocus); - mCancelButton->setStateSelected(!mOkButtonFocus); - } - - return true; - } } diff --git a/apps/openmw/mwgui/confirmationdialog.hpp b/apps/openmw/mwgui/confirmationdialog.hpp index 9b26e3a3c9..1344f2a501 100644 --- a/apps/openmw/mwgui/confirmationdialog.hpp +++ b/apps/openmw/mwgui/confirmationdialog.hpp @@ -27,9 +27,6 @@ namespace MWGui void onCancelButtonClicked(MyGUI::Widget* _sender); void onOkButtonClicked(MyGUI::Widget* _sender); - - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - bool mOkButtonFocus = true; }; } diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 0be99d38a0..6ab2c862d4 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -3,8 +3,6 @@ #include #include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/scriptmanager.hpp" @@ -56,12 +54,6 @@ namespace MWGui mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onTakeAllButtonClicked); setCoord(200, 0, 600, 300); - - mControllerButtons.a = "#{sTake}"; - mControllerButtons.b = "#{sClose}"; - mControllerButtons.x = "#{sTakeAll}"; - mControllerButtons.r3 = "#{sInfo}"; - mControllerButtons.l2 = "#{sInventory}"; } void ContainerWindow::onItemSelected(int index) @@ -96,13 +88,8 @@ namespace MWGui name += MWGui::ToolTips::getSoulString(object.getCellRef()); dialog->openCountDialog(name, "#{sTake}", count); dialog->eventOkClicked.clear(); - if (Settings::gui().mControllerMenus) - dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerWindow::takeItem); - else - dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerWindow::dragItem); + dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerWindow::dragItem); } - else if (Settings::gui().mControllerMenus) - takeItem(nullptr, count); else dragItem(nullptr, count); } @@ -118,29 +105,6 @@ namespace MWGui mDragAndDrop->startDrag(mSelectedItem, mSortModel, mModel, mItemView, count); } - void ContainerWindow::takeItem(MyGUI::Widget* sender, int count) - { - if (!mModel) - return; - - const ItemStack& item = mModel->getItem(mSelectedItem); - if (!onTakeItem(item, count)) - return; - - MWGui::InventoryWindow* inventoryWindow = MWBase::Environment::get().getWindowManager()->getInventoryWindow(); - ItemModel* playerModel = inventoryWindow->getModel(); - - mModel->moveItem(item, count, playerModel); - - inventoryWindow->updateItemView(); - mItemView->update(); - - // play the item's sound - MWWorld::Ptr itemBase = item.mBase; - const ESM::RefId& sound = itemBase.getClass().getUpSoundId(itemBase); - MWBase::Environment::get().getWindowManager()->playSound(sound); - } - void ContainerWindow::dropItem() { if (!mModel) @@ -356,47 +320,4 @@ namespace MWGui if (mModel && mModel->usesContainer(ptr)) MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); } - - ControllerButtonStr* ContainerWindow::getControllerButtons() - { - mControllerButtons.r1 = mDisposeCorpseButton->getVisible() ? "#{sDisposeofCorpse}" : ""; - return &mControllerButtons; - } - - bool ContainerWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - int index = mItemView->getControllerFocus(); - if (index >= 0 && index < mItemView->getItemCount()) - onItemSelected(index); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - { - onCloseButtonClicked(mCloseButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_X) - { - onTakeAllButtonClicked(mTakeButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) - { - if (mDisposeCorpseButton->getVisible()) - onDisposeCorpseButtonClicked(mDisposeCorpseButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK || arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP - || arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN || arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT - || arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) - { - mItemView->onControllerButton(arg.button); - } - - return true; - } - - void ContainerWindow::setActiveControllerWindow(bool active) - { - mItemView->setActiveControllerWindow(active); - WindowBase::setActiveControllerWindow(active); - } } diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 96ee6a6380..555fa8e1ae 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -40,13 +40,6 @@ namespace MWGui std::string_view getWindowIdForLua() const override { return "Container"; } - ControllerButtonStr* getControllerButtons() override; - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - void setActiveControllerWindow(bool active) override; - - MWGui::ItemView* getItemView() { return mItemView; } - ItemModel* getModel() { return mModel; } - private: DragAndDrop* mDragAndDrop; @@ -62,7 +55,6 @@ namespace MWGui void onItemSelected(int index); void onBackgroundSelected(); void dragItem(MyGUI::Widget* sender, int count); - void takeItem(MyGUI::Widget* sender, int count); void dropItem(); void onCloseButtonClicked(MyGUI::Widget* _sender); void onTakeAllButtonClicked(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/controllerbuttonsoverlay.cpp b/apps/openmw/mwgui/controllerbuttonsoverlay.cpp deleted file mode 100644 index 9466f40105..0000000000 --- a/apps/openmw/mwgui/controllerbuttonsoverlay.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "controllerbuttonsoverlay.hpp" - -#include "../mwbase/environment.hpp" -#include "../mwbase/windowmanager.hpp" - -namespace MWGui -{ - ControllerButtonsOverlay::ControllerButtonsOverlay() - : WindowBase("openmw_controllerbuttons.layout") - { - getWidget(mImageA, "BtnAImage"); - getWidget(mTextA, "BtnAText"); - - getWidget(mImageB, "BtnBImage"); - getWidget(mTextB, "BtnBText"); - - getWidget(mImageDpad, "BtnDpadImage"); - getWidget(mTextDpad, "BtnDpadText"); - - getWidget(mImageL1, "BtnL1Image"); - getWidget(mTextL1, "BtnL1Text"); - - getWidget(mImageL2, "BtnL2Image"); - getWidget(mTextL2, "BtnL2Text"); - - getWidget(mImageL3, "BtnL3Image"); - getWidget(mTextL3, "BtnL3Text"); - - getWidget(mImageLStick, "BtnLStickImage"); - getWidget(mTextLStick, "BtnLStickText"); - - getWidget(mImageMenu, "BtnMenuImage"); - getWidget(mTextMenu, "BtnMenuText"); - - getWidget(mImageR1, "BtnR1Image"); - getWidget(mTextR1, "BtnR1Text"); - - getWidget(mImageR2, "BtnR2Image"); - getWidget(mTextR2, "BtnR2Text"); - - getWidget(mImageR3, "BtnR3Image"); - getWidget(mTextR3, "BtnR3Text"); - - getWidget(mImageRStick, "BtnRStickImage"); - getWidget(mTextRStick, "BtnRStickText"); - - getWidget(mImageView, "BtnViewImage"); - getWidget(mTextView, "BtnViewText"); - - getWidget(mImageX, "BtnXImage"); - getWidget(mTextX, "BtnXText"); - - getWidget(mImageY, "BtnYImage"); - getWidget(mTextY, "BtnYText"); - - getWidget(mHBox, "ButtonBox"); - } - - void ControllerButtonsOverlay::setButtons(ControllerButtonStr* buttons) - { - int buttonCount = 0; - buttonCount += updateButton(mTextA, mImageA, buttons->a); - buttonCount += updateButton(mTextB, mImageB, buttons->b); - buttonCount += updateButton(mTextDpad, mImageDpad, buttons->dpad); - buttonCount += updateButton(mTextL1, mImageL1, buttons->l1); - buttonCount += updateButton(mTextL2, mImageL2, buttons->l2); - buttonCount += updateButton(mTextL3, mImageL3, buttons->l3); - buttonCount += updateButton(mTextLStick, mImageLStick, buttons->lStick); - buttonCount += updateButton(mTextMenu, mImageMenu, buttons->menu); - buttonCount += updateButton(mTextR1, mImageR1, buttons->r1); - buttonCount += updateButton(mTextR2, mImageR2, buttons->r2); - buttonCount += updateButton(mTextR3, mImageR3, buttons->r3); - buttonCount += updateButton(mTextRStick, mImageRStick, buttons->rStick); - buttonCount += updateButton(mTextView, mImageView, buttons->view); - buttonCount += updateButton(mTextX, mImageX, buttons->x); - buttonCount += updateButton(mTextY, mImageY, buttons->y); - mHBox->notifyChildrenSizeChanged(); - - setVisible(buttonCount > 0); - } - - int ControllerButtonsOverlay::updateButton( - MyGUI::TextBox* text, MyGUI::ImageBox* image, const std::string& buttonStr) - { - if (buttonStr.length() > 0) - { - image->setVisible(true); - image->setUserString("Hidden", "false"); - - text->setCaptionWithReplacing(buttonStr); - text->setVisible(true); - text->setUserString("Hidden", "false"); - text->setSize(text->getTextSize().width + 16, 48); - return 1; - } - else - { - image->setVisible(false); - image->setUserString("Hidden", "true"); - - text->setVisible(false); - text->setUserString("Hidden", "true"); - return 0; - } - } -} diff --git a/apps/openmw/mwgui/controllerbuttonsoverlay.hpp b/apps/openmw/mwgui/controllerbuttonsoverlay.hpp deleted file mode 100644 index 7008384bee..0000000000 --- a/apps/openmw/mwgui/controllerbuttonsoverlay.hpp +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef MWGUI_CONTROLLERBUTTONSOVERLAY_H -#define MWGUI_CONTROLLERBUTTONSOVERLAY_H - -#include -#include - -#include - -#include "windowbase.hpp" - -namespace MWGui -{ - class ControllerButtonsOverlay : public WindowBase - { - public: - ControllerButtonsOverlay(); - - void setButtons(ControllerButtonStr* buttons); - - private: - MyGUI::ImageBox* mImageA; - MyGUI::TextBox* mTextA; - - MyGUI::ImageBox* mImageB; - MyGUI::TextBox* mTextB; - - MyGUI::ImageBox* mImageDpad; - MyGUI::TextBox* mTextDpad; - - MyGUI::ImageBox* mImageL1; - MyGUI::TextBox* mTextL1; - - MyGUI::ImageBox* mImageL2; - MyGUI::TextBox* mTextL2; - - MyGUI::ImageBox* mImageL3; - MyGUI::TextBox* mTextL3; - - MyGUI::ImageBox* mImageLStick; - MyGUI::TextBox* mTextLStick; - - MyGUI::ImageBox* mImageMenu; - MyGUI::TextBox* mTextMenu; - - MyGUI::ImageBox* mImageR1; - MyGUI::TextBox* mTextR1; - - MyGUI::ImageBox* mImageR2; - MyGUI::TextBox* mTextR2; - - MyGUI::ImageBox* mImageR3; - MyGUI::TextBox* mTextR3; - - MyGUI::ImageBox* mImageRStick; - MyGUI::TextBox* mTextRStick; - - MyGUI::ImageBox* mImageView; - MyGUI::TextBox* mTextView; - - MyGUI::ImageBox* mImageX; - MyGUI::TextBox* mTextX; - - MyGUI::ImageBox* mImageY; - MyGUI::TextBox* mTextY; - - Gui::HBox* mHBox; - - int updateButton(MyGUI::TextBox* text, MyGUI::ImageBox* image, const std::string& buttonStr); - }; -} - -#endif diff --git a/apps/openmw/mwgui/countdialog.cpp b/apps/openmw/mwgui/countdialog.cpp index 816d67921c..2ca6657a17 100644 --- a/apps/openmw/mwgui/countdialog.cpp +++ b/apps/openmw/mwgui/countdialog.cpp @@ -27,9 +27,6 @@ namespace MWGui mSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &CountDialog::onSliderMoved); // make sure we read the enter key being pressed to accept multiple items mItemEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &CountDialog::onEnterKeyPressed); - - mControllerButtons.a = "#{sOk}"; - mControllerButtons.b = "#{sCancel}"; } void CountDialog::openCountDialog(const std::string& item, const std::string& message, const int maxCount) @@ -41,7 +38,7 @@ namespace MWGui MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); mSlider->setScrollRange(maxCount); - mItemText->setCaptionWithReplacing(item); + mItemText->setCaption(item); int width = std::max(mItemText->getTextSize().width + 160, 320); setCoord(viewSize.width / 2 - width / 2, viewSize.height / 2 - mMainWidget->getHeight() / 2, width, @@ -57,13 +54,6 @@ namespace MWGui mItemEdit->setValue(maxCount); } - void CountDialog::setCount(int count) - { - count = std::clamp(count, 1, (int)mSlider->getScrollRange()); - mSlider->setScrollPosition(count - 1); - mItemEdit->setValue(count); - } - void CountDialog::onCancelButtonClicked(MyGUI::Widget* _sender) { setVisible(false); @@ -96,22 +86,4 @@ namespace MWGui { mItemEdit->setValue(_position + 1); } - - bool CountDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - onOkButtonClicked(mOkButton); - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - onCancelButtonClicked(mCancelButton); - else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) - setCount(1); - else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) - setCount((int)mSlider->getScrollRange()); - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) - MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) - MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::ArrowUp, 0, false); - - return true; - } } diff --git a/apps/openmw/mwgui/countdialog.hpp b/apps/openmw/mwgui/countdialog.hpp index b3a1aab3b3..9cdf231549 100644 --- a/apps/openmw/mwgui/countdialog.hpp +++ b/apps/openmw/mwgui/countdialog.hpp @@ -3,8 +3,6 @@ #include "windowbase.hpp" -#include - namespace Gui { class NumericEditBox; @@ -17,7 +15,6 @@ namespace MWGui public: CountDialog(); void openCountDialog(const std::string& item, const std::string& message, const int maxCount); - void setCount(int count); typedef MyGUI::delegates::MultiDelegate EventHandle_WidgetInt; @@ -27,7 +24,7 @@ namespace MWGui EventHandle_WidgetInt eventOkClicked; private: - Gui::ScrollBar* mSlider; + MyGUI::ScrollBar* mSlider; Gui::NumericEditBox* mItemEdit; MyGUI::TextBox* mItemText; MyGUI::TextBox* mLabelText; @@ -39,7 +36,6 @@ namespace MWGui void onEditValueChanged(int value); void onSliderMoved(MyGUI::ScrollBar* _sender, size_t _position); void onEnterKeyPressed(MyGUI::EditBox* _sender); - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; }; } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index b3f83f3771..6b1e007770 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -88,10 +88,6 @@ namespace MWGui mBribe10Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); mBribe100Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); mBribe1000Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); - - mDisableGamepadCursor = Settings::gui().mControllerMenus; - mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sCancel}"; } void PersuasionDialog::adjustAction(MyGUI::Widget* action, int& totalHeight) @@ -148,24 +144,6 @@ namespace MWGui else mMainWidget->setSize(mInitialMainWidgetWidth, mMainWidget->getSize().height); - if (Settings::gui().mControllerMenus) - { - mControllerFocus = 0; - mButtons.clear(); - mButtons.push_back(mAdmireButton); - mButtons.push_back(mIntimidateButton); - mButtons.push_back(mTauntButton); - if (mBribe10Button->getEnabled()) - mButtons.push_back(mBribe10Button); - if (mBribe100Button->getEnabled()) - mButtons.push_back(mBribe100Button); - if (mBribe1000Button->getEnabled()) - mButtons.push_back(mBribe1000Button); - - for (size_t i = 0; i < mButtons.size(); i++) - mButtons[i]->setStateSelected(i == 0); - } - WindowModal::onOpen(); } @@ -174,31 +152,6 @@ namespace MWGui return mAdmireButton; } - bool PersuasionDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - onPersuade(mButtons[mControllerFocus]); - MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - onCancel(mCancelButton); - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) - { - setControllerFocus(mButtons, mControllerFocus, false); - mControllerFocus = wrap(mControllerFocus - 1, mButtons.size()); - setControllerFocus(mButtons, mControllerFocus, true); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - { - setControllerFocus(mButtons, mControllerFocus, false); - mControllerFocus = wrap(mControllerFocus + 1, mButtons.size()); - setControllerFocus(mButtons, mControllerFocus, true); - } - - return true; - } - // -------------------------------------------------------------------------------------------------- Response::Response(std::string_view text, std::string_view title, bool needMargin) @@ -382,11 +335,6 @@ namespace MWGui mMainWidget->castType()->eventWindowChangeCoord += MyGUI::newDelegate(this, &DialogueWindow::onWindowResize); - - mControllerScrollWidget = mHistory->getParent(); - mControllerButtons.a = "#{sAsk}"; - mControllerButtons.b = "#{sGoodbye}"; - mControllerButtons.rStick = "#{sScrollup}"; } void DialogueWindow::onTradeComplete() @@ -540,14 +488,6 @@ namespace MWGui updateTopics(); updateTopicsPane(); // force update for new services - if (Settings::gui().mControllerMenus && !sameActor) - { - setControllerFocus(mControllerFocus, false); - // Reset focus to very top. Maybe change this to mTopicsList->getItemCount() - mKeywords.size()? - mControllerFocus = 0; - setControllerFocus(mControllerFocus, true); - } - updateDisposition(); restock(); } @@ -603,11 +543,6 @@ namespace MWGui void DialogueWindow::updateTopicsPane() { - const std::string focusedTopic - = Settings::gui().mControllerMenus && mControllerFocus < static_cast(mTopicsList->getItemCount()) - ? mTopicsList->getItemNameAt(mControllerFocus) - : ""; - mTopicsList->clear(); for (auto& linkPair : mTopicLinks) mDeleteLater.push_back(std::move(linkPair.second)); @@ -665,16 +600,10 @@ namespace MWGui mKeywordSearch.seed(topicId, intptr_t(t.get())); t->eventTopicActivated += MyGUI::newDelegate(this, &DialogueWindow::onTopicActivated); mTopicLinks[topicId] = std::move(t); - - if (keyword == focusedTopic) - mControllerFocus = mTopicsList->getItemCount() - 1; } redrawTopicsList(); updateHistory(); - - if (Settings::gui().mControllerMenus) - setControllerFocus(mControllerFocus, true); } void DialogueWindow::updateHistory(bool scrollbar) @@ -701,8 +630,6 @@ namespace MWGui // choices const TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); mChoices = MWBase::Environment::get().getDialogueManager()->getChoices(); - mChoiceStyles.clear(); - mControllerChoice = -1; // -1 so you must make a choice (and can't accidentally pick the first answer) for (std::pair& choice : mChoices) { auto link = std::make_unique(choice.second); @@ -714,7 +641,6 @@ namespace MWGui BookTypesetter::Style* questionStyle = typesetter->createHotStyle( body, textColours.answer, textColours.answerOver, textColours.answerPressed, interactiveId); typesetter->write(questionStyle, to_utf8_span(choice.first)); - mChoiceStyles.push_back(questionStyle); } mGoodbye = MWBase::Environment::get().getDialogueManager()->isGoodbye(); @@ -924,125 +850,4 @@ namespace MWGui && actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion"); } - void DialogueWindow::setControllerFocus(size_t index, bool focused) - { - // List is mTopicsList + "Goodbye" button below the list. - if (index > mTopicsList->getItemCount()) - return; - - if (index == mTopicsList->getItemCount()) - { - mGoodbyeButton->setStateSelected(focused); - } - else - { - const std::string& keyword = mTopicsList->getItemNameAt(mControllerFocus); - if (keyword.empty()) - return; - - MyGUI::Button* button = mTopicsList->getItemWidget(keyword); - button->setStateSelected(focused); - } - - if (focused) - { - // Scroll the side bar to keep the active item in view - if (index <= 8) - mTopicsList->setViewOffset(0); - else - { - int offset = 0; - for (int i = 0; i < static_cast(index) - 8; i++) - { - const std::string& keyword = mTopicsList->getItemNameAt(i); - if (keyword.empty()) - offset += 21; - else - offset += mTopicsList->getItemWidget(keyword)->getHeight() + 3; - } - mTopicsList->setViewOffset(-offset); - } - } - } - - bool DialogueWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - if (mChoices.size() > 0) - { - if (mChoices.size() == 1) - onChoiceActivated(mChoices[0].second); - else if (mControllerChoice >= 0 && mControllerChoice < static_cast(mChoices.size())) - onChoiceActivated(mChoices[mControllerChoice].second); - } - else if (mControllerFocus == static_cast(mTopicsList->getItemCount())) - onGoodbyeActivated(); - else - onSelectListItem(mTopicsList->getItemNameAt(mControllerFocus), mControllerFocus); - MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B && mChoices.empty()) - { - onGoodbyeActivated(); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) - { - if (mChoices.size() > 0) - { - // In-dialogue choice (red text) - mControllerChoice = std::clamp(mControllerChoice - 1, 0, static_cast(mChoices.size()) - 1); - mHistory->setFocusItem(mChoiceStyles.at(mControllerChoice)); - } - else - { - // Number of items is mTopicsList.length+1 because of "Goodbye" button. - setControllerFocus(mControllerFocus, false); - if (mControllerFocus <= 0) - mControllerFocus = mTopicsList->getItemCount(); // "Goodbye" button - else if (mTopicsList->getItemNameAt(mControllerFocus - 1).empty()) - mControllerFocus -= 2; // Skip separator - else - mControllerFocus--; - setControllerFocus(mControllerFocus, true); - } - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - { - if (mChoices.size() > 0) - { - // In-dialogue choice (red text) - mControllerChoice = std::clamp(mControllerChoice + 1, 0, static_cast(mChoices.size()) - 1); - mHistory->setFocusItem(mChoiceStyles.at(mControllerChoice)); - } - else - { - // Number of items is mTopicsList.length+1 because of "Goodbye" button. - setControllerFocus(mControllerFocus, false); - if (mControllerFocus >= static_cast(mTopicsList->getItemCount())) - mControllerFocus = 0; - else if (mControllerFocus == static_cast(mTopicsList->getItemCount()) - 1) - mControllerFocus = mTopicsList->getItemCount(); // "Goodbye" button - else if (mTopicsList->getItemNameAt(mControllerFocus + 1).empty()) - mControllerFocus += 2; // Skip separator - else - mControllerFocus++; - setControllerFocus(mControllerFocus, true); - } - } - else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER && mChoices.size() == 0) - { - setControllerFocus(mControllerFocus, false); - mControllerFocus = std::max(mControllerFocus - 5, 0); - setControllerFocus(mControllerFocus, true); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER && mChoices.size() == 0) - { - setControllerFocus(mControllerFocus, false); - mControllerFocus = std::min(mControllerFocus + 5, static_cast(mTopicsList->getItemCount())); - setControllerFocus(mControllerFocus, true); - } - - return true; - } } diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 6f03076e92..8a8b309401 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -49,9 +49,6 @@ namespace MWGui MyGUI::Widget* getDefaultKeyFocus() override; - protected: - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - private: std::unique_ptr mCallback; @@ -68,9 +65,6 @@ namespace MWGui MyGUI::Widget* mActionsBox; Gui::AutoSizedTextBox* mGoldLabel; - std::vector mButtons; - int mControllerFocus = 0; - void adjustAction(MyGUI::Widget* action, int& totalHeight); void onCancel(MyGUI::Widget* sender); @@ -192,8 +186,6 @@ namespace MWGui void onReferenceUnavailable() override; - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - private: void updateDisposition(); void restock(); @@ -205,7 +197,6 @@ namespace MWGui std::vector> mHistoryContents; std::vector> mChoices; - std::vector mChoiceStyles; bool mGoodbye; std::vector> mLinks; @@ -229,10 +220,6 @@ namespace MWGui std::unique_ptr mCallback; std::unique_ptr mGreetingCallback; - void setControllerFocus(size_t index, bool focused); - int mControllerFocus = 0; - int mControllerChoice = -1; - void updateTopicFormat(); }; } diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 7a1c1532f6..af4a3e8ce3 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -59,12 +59,6 @@ namespace MWGui mBuyButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onBuyButtonClicked); mTypeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onTypeButtonClicked); mName->eventEditSelectAccept += MyGUI::newDelegate(this, &EnchantingDialog::onAccept); - - mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sCancel}"; - mControllerButtons.y = "#{OMWEngine:EnchantType}"; - mControllerButtons.l1 = "#{sItem}"; - mControllerButtons.r1 = "#{sSoulGem}"; } void EnchantingDialog::onOpen() @@ -158,7 +152,6 @@ namespace MWGui mEnchanting.setSelfEnchanting(false); mEnchanting.setEnchanter(ptr); mBuyButton->setCaptionWithReplacing("#{sBuy}"); - mControllerButtons.x = "#{sBuy}"; mChanceLayout->setVisible(false); mPtr = ptr; setSoulGem(MWWorld::Ptr()); @@ -170,7 +163,6 @@ namespace MWGui mEnchanting.setSelfEnchanting(true); mEnchanting.setEnchanter(MWMechanics::getPlayer()); mBuyButton->setCaptionWithReplacing("#{sCreate}"); - mControllerButtons.x = "#{sCreate}"; mChanceLayout->setVisible(Settings::game().mShowEnchantChance); mPtr = MWMechanics::getPlayer(); setSoulGem(ptr); @@ -390,22 +382,4 @@ namespace MWGui } } } - - bool EnchantingDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_B) - onCancelButtonClicked(mCancelButton); - else if (arg.button == SDL_CONTROLLER_BUTTON_X) - onBuyButtonClicked(mBuyButton); - else if (arg.button == SDL_CONTROLLER_BUTTON_Y) - onTypeButtonClicked(mTypeButton); - else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) - onSelectItem(mItemBox); - else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) - onSelectSoul(mSoulBox); - else - return EffectEditorBase::onControllerButtonEvent(arg); - - return true; - } } diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 3cda350152..4c720a11fc 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -73,8 +73,6 @@ namespace MWGui MWMechanics::Enchanting mEnchanting; ESM::EffectList mEffectList; - - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; }; } diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index a62120fc10..0a37c93b4f 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -243,17 +243,6 @@ namespace MWGui mDrowningBar->setVisible(visible); } - void HUD::dropDraggedItem(float mouseX, float mouseY) - { - if (!mDragAndDrop->mIsOnDragAndDrop) - return; - - MWBase::Environment::get().getWorld()->breakInvisibility(MWMechanics::getPlayer()); - - WorldItemModel drop(mouseX, mouseY); - mDragAndDrop->drop(&drop, nullptr); - } - void HUD::onWorldClicked(MyGUI::Widget* _sender) { if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) @@ -263,12 +252,15 @@ namespace MWGui if (mDragAndDrop->mIsOnDragAndDrop) { // drop item into the gameworld + MWBase::Environment::get().getWorld()->breakInvisibility(MWMechanics::getPlayer()); + MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition(); float mouseX = cursorPosition.left / float(viewSize.width); float mouseY = cursorPosition.top / float(viewSize.height); - dropDraggedItem(mouseX, mouseY); + WorldItemModel drop(mouseX, mouseY); + mDragAndDrop->drop(&drop, nullptr); winMgr->changePointer("arrow"); } diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 1a1076ff68..8dd98628c4 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -61,8 +61,6 @@ namespace MWGui void clear() override; - void dropDraggedItem(float mouseX, float mouseY); - private: MyGUI::ProgressBar *mHealth, *mMagicka, *mStamina, *mEnemyHealth, *mDrowning; MyGUI::Widget* mHealthFrame; diff --git a/apps/openmw/mwgui/inventorytabsoverlay.cpp b/apps/openmw/mwgui/inventorytabsoverlay.cpp deleted file mode 100644 index 35b4d1d87f..0000000000 --- a/apps/openmw/mwgui/inventorytabsoverlay.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "inventorytabsoverlay.hpp" - -#include "../mwbase/environment.hpp" -#include "../mwbase/windowmanager.hpp" - -namespace MWGui -{ - InventoryTabsOverlay::InventoryTabsOverlay() - : WindowBase("openmw_inventory_tabs.layout") - { - MyGUI::Button* tab; - - getWidget(tab, "TabMap"); - tab->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryTabsOverlay::onTabClicked); - mTabs.push_back(tab); - - getWidget(tab, "TabInventory"); - tab->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryTabsOverlay::onTabClicked); - mTabs.push_back(tab); - - getWidget(tab, "TabSpells"); - tab->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryTabsOverlay::onTabClicked); - mTabs.push_back(tab); - - getWidget(tab, "TabStats"); - tab->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryTabsOverlay::onTabClicked); - mTabs.push_back(tab); - } - - void InventoryTabsOverlay::onTabClicked(MyGUI::Widget* sender) - { - if (!MWBase::Environment::get().getWindowManager()->getJournalAllowed()) - return; - - for (int i = 0; i < static_cast(mTabs.size()); i++) - { - if (mTabs[i] == sender) - { - MWBase::Environment::get().getWindowManager()->setActiveControllerWindow(GM_Inventory, i); - setTab(i); - break; - } - } - } - - void InventoryTabsOverlay::setTab(int index) - { - for (int i = 0; i < static_cast(mTabs.size()); i++) - mTabs[i]->setStateSelected(i == index); - } -} diff --git a/apps/openmw/mwgui/inventorytabsoverlay.hpp b/apps/openmw/mwgui/inventorytabsoverlay.hpp deleted file mode 100644 index 5368d9710f..0000000000 --- a/apps/openmw/mwgui/inventorytabsoverlay.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef MWGUI_INVENTORYTABSSOVERLAY_H -#define MWGUI_INVENTORYTABSSOVERLAY_H - -#include - -#include "windowbase.hpp" - -namespace MWGui -{ - class InventoryTabsOverlay : public WindowBase - { - public: - InventoryTabsOverlay(); - - void setTab(int index); - - private: - std::vector mTabs; - - void onTabClicked(MyGUI::Widget* sender); - }; -} - -#endif diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index a398139df4..b4a2024052 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -31,11 +31,8 @@ #include "../mwmechanics/actorutil.hpp" #include "../mwmechanics/npcstats.hpp" -#include "companionwindow.hpp" -#include "container.hpp" #include "countdialog.hpp" #include "draganddrop.hpp" -#include "hud.hpp" #include "inventoryitemmodel.hpp" #include "itemview.hpp" #include "settings.hpp" @@ -130,21 +127,6 @@ namespace MWGui setGuiMode(mGuiMode); - if (Settings::gui().mControllerMenus) - { - // Show L1 and R1 buttons next to tabs - MyGUI::Widget* image; - getWidget(image, "BtnL1Image"); - image->setVisible(true); - image->setUserString("Hidden", "false"); - - getWidget(image, "BtnR1Image"); - image->setVisible(true); - image->setUserString("Hidden", "false"); - - mControllerButtons.r3 = "#{sInfo}"; - } - adjustPanes(); } @@ -222,13 +204,9 @@ namespace MWGui void InventoryWindow::setGuiMode(GuiMode mode) { - if (Settings::gui().mControllerMenus && mGuiMode == mode && isVisible()) - return; - mGuiMode = mode; const WindowSettingValues settings = getModeSettings(mGuiMode); - setPinButtonVisible( - mode != GM_Container && mode != GM_Companion && mode != GM_Barter && !Settings::gui().mControllerMenus); + setPinButtonVisible(mode != GM_Container && mode != GM_Companion && mode != GM_Barter); const WindowRectSettingValues& rect = settings.mIsMaximized ? settings.mMaximized : settings.mRegular; @@ -324,9 +302,7 @@ namespace MWGui } } - // Show a dialog to select a count of items, but not when using an item from the inventory - // in controller mode. In that case, we skip the dialog and just use one item immediately. - if (count > 1 && !shift && !(Settings::gui().mControllerMenus && mGuiMode == MWGui::GM_Inventory)) + if (count > 1 && !shift) { CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); std::string message = mTrading ? "#{sQuanityMenuMessage01}" : "#{sTake}"; @@ -334,10 +310,7 @@ namespace MWGui name += MWGui::ToolTips::getSoulString(object.getCellRef()); dialog->openCountDialog(name, message, count); dialog->eventOkClicked.clear(); - if (Settings::gui().mControllerMenus - && (mGuiMode == MWGui::GM_Companion || mGuiMode == MWGui::GM_Container)) - dialog->eventOkClicked += MyGUI::newDelegate(this, &InventoryWindow::giveItem); - else if (mTrading) + if (mTrading) dialog->eventOkClicked += MyGUI::newDelegate(this, &InventoryWindow::sellItem); else dialog->eventOkClicked += MyGUI::newDelegate(this, &InventoryWindow::dragItem); @@ -417,32 +390,6 @@ namespace MWGui notifyContentChanged(); } - void InventoryWindow::giveItem(MyGUI::Widget* sender, int count) - { - ensureSelectedItemUnequipped(count); - mDragAndDrop->startDrag(mSelectedItem, mSortModel, mTradeModel, mItemView, count); - notifyContentChanged(); - - if (mGuiMode == MWGui::GM_Companion && mDragAndDrop->mIsOnDragAndDrop) - { - // Drag and drop the item on the companion's window. - MWGui::CompanionWindow* companionWindow = (MWGui::CompanionWindow*)MWBase::Environment::get() - .getWindowManager() - ->getGuiModeWindows(mGuiMode) - .at(1); - mDragAndDrop->drop(companionWindow->getModel(), companionWindow->getItemView()); - } - else if (mGuiMode == MWGui::GM_Container && mDragAndDrop->mIsOnDragAndDrop) - { - // Drag and drop the item on the container window. - MWGui::ContainerWindow* containerWindow = (MWGui::ContainerWindow*)MWBase::Environment::get() - .getWindowManager() - ->getGuiModeWindows(mGuiMode) - .at(0); - mDragAndDrop->drop(containerWindow->getModel(), containerWindow->getItemView()); - } - } - void InventoryWindow::updateItemView() { MWBase::Environment::get().getWindowManager()->updateSpellWindow(); @@ -919,189 +866,4 @@ namespace MWGui const MyGUI::IntSize viewport = getPreviewViewportSize(); return osg::Vec2f(normalisedX * float(viewport.width - 1), (1.0 - normalisedY) * float(viewport.height - 1)); } - - ControllerButtonStr* InventoryWindow::getControllerButtons() - { - switch (mGuiMode) - { - case MWGui::GM_Companion: - mControllerButtons.a = "#{OMWEngine:InventorySelect}"; - mControllerButtons.b = "#{sClose}"; - mControllerButtons.x = ""; - mControllerButtons.y = ""; - mControllerButtons.r2 = "#{sCompanionShare}"; - break; - case MWGui::GM_Container: - mControllerButtons.a = "#{OMWEngine:InventorySelect}"; - mControllerButtons.b = "#{sClose}"; - mControllerButtons.x = "#{sTakeAll}"; - mControllerButtons.y = ""; - mControllerButtons.r2 = "#{sContainer}"; - break; - case MWGui::GM_Barter: - mControllerButtons.a = "#{sSell}"; - mControllerButtons.b = "#{sCancel}"; - mControllerButtons.x = "#{sOffer}"; - mControllerButtons.y = ""; - mControllerButtons.r2 = "#{sBarter}"; - break; - case MWGui::GM_Inventory: - default: - mControllerButtons.a = "#{sEquip}"; - mControllerButtons.b = "#{sBack}"; - mControllerButtons.x = "#{sDrop}"; - mControllerButtons.y = "#{sUnequip}"; - mControllerButtons.r2 = ""; - break; - } - return &mControllerButtons; - } - - bool InventoryWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_B) - { - MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - mItemView->onControllerButton(SDL_CONTROLLER_BUTTON_A); - // The following actions are done here, not in onItemSelectedFromSourceModel, because we - // want the mouse to work even in controller mode. - if (mGuiMode == MWGui::GM_Inventory && mDragAndDrop->mIsOnDragAndDrop) - { - // Drag and drop the item on the avatar to activate it. - onAvatarClicked(nullptr); // Equip or use - // Drop any remaining items back in inventory. This is needed when clicking on a - // stack of items; we only want to use the first item. - onBackgroundSelected(); - } - else if (mGuiMode == MWGui::GM_Companion && mDragAndDrop->mIsOnDragAndDrop) - { - // Drag and drop the item on the companion's window. - MWGui::CompanionWindow* companionWindow = (MWGui::CompanionWindow*)MWBase::Environment::get() - .getWindowManager() - ->getGuiModeWindows(mGuiMode) - .at(1); - mDragAndDrop->drop(companionWindow->getModel(), companionWindow->getItemView()); - } - else if (mGuiMode == MWGui::GM_Container && mDragAndDrop->mIsOnDragAndDrop) - { - // Drag and drop the item on the container window. - MWGui::ContainerWindow* containerWindow = (MWGui::ContainerWindow*)MWBase::Environment::get() - .getWindowManager() - ->getGuiModeWindows(mGuiMode) - .at(0); - mDragAndDrop->drop(containerWindow->getModel(), containerWindow->getItemView()); - } - // GM_Barter is handled by onControllerButtonEvent. No other steps are necessary. - } - else if (arg.button == SDL_CONTROLLER_BUTTON_X) - { - if (mGuiMode == MWGui::GM_Inventory) - { - // Drop the item into the gameworld - mItemView->onControllerButton(SDL_CONTROLLER_BUTTON_A); - if (mDragAndDrop->mIsOnDragAndDrop) - MWBase::Environment::get().getWindowManager()->getHud()->dropDraggedItem(0.5f, 0.5f); - } - else if (mGuiMode == MWGui::GM_Container) - { - // Take all. Pass the button press to the container window and let it do the - // logic of taking all. - MWGui::ContainerWindow* containerWindow = (MWGui::ContainerWindow*)MWBase::Environment::get() - .getWindowManager() - ->getGuiModeWindows(mGuiMode) - .at(0); - containerWindow->onControllerButtonEvent(arg); - } - else if (mGuiMode == MWGui::GM_Barter) - { - // Offer. Pass the button press to the barter window and let it do the logic - // of making an offer. - MWGui::TradeWindow* tradeWindow = (MWGui::TradeWindow*)MWBase::Environment::get() - .getWindowManager() - ->getGuiModeWindows(mGuiMode) - .at(1); - tradeWindow->onControllerButtonEvent(arg); - } - } - else if (arg.button == SDL_CONTROLLER_BUTTON_Y) - { - if (mGuiMode == MWGui::GM_Inventory) - { - // Unequip an item. - mItemView->onControllerButton(SDL_CONTROLLER_BUTTON_A); - onBackgroundSelected(); // Drop on inventory background to unequip - } - } - else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) - { - if (mFilterAll->getStateSelected()) - onFilterChanged(mFilterMisc); - else if (mFilterWeapon->getStateSelected()) - onFilterChanged(mFilterAll); - else if (mFilterApparel->getStateSelected()) - onFilterChanged(mFilterWeapon); - else if (mFilterMagic->getStateSelected()) - onFilterChanged(mFilterApparel); - else if (mFilterMisc->getStateSelected()) - onFilterChanged(mFilterMagic); - MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) - { - if (mFilterAll->getStateSelected()) - onFilterChanged(mFilterWeapon); - else if (mFilterWeapon->getStateSelected()) - onFilterChanged(mFilterApparel); - else if (mFilterApparel->getStateSelected()) - onFilterChanged(mFilterMagic); - else if (mFilterMagic->getStateSelected()) - onFilterChanged(mFilterMisc); - else if (mFilterMisc->getStateSelected()) - onFilterChanged(mFilterAll); - MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); - } - else - { - mItemView->onControllerButton(arg.button); - } - - return true; - } - - void InventoryWindow::setActiveControllerWindow(bool active) - { - if (!Settings::gui().mControllerMenus) - return; - - if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Inventory) - { - // Fill the screen, or limit to a certain size on large screens. Size chosen to - // match the size of the stats window. - MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - int width = std::min(viewSize.width, 1600); - int height = std::min(viewSize.height - 48 - 48, 750); - int x = (viewSize.width - width) / 2; - int y = (viewSize.height - height) / 2; - - MyGUI::Window* window = mMainWidget->castType(); - window->setCoord(x, active ? y : viewSize.height + 1, width, height); - - adjustPanes(); - updatePreviewSize(); - } - - // Show L1 and R1 buttons next to tabs - MyGUI::Widget* image; - getWidget(image, "BtnL1Image"); - image->setVisible(active); - - getWidget(image, "BtnR1Image"); - image->setVisible(active); - - mItemView->setActiveControllerWindow(active); - WindowBase::setActiveControllerWindow(active); - } } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index a14e0f9477..9fc77ceec5 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -67,12 +67,8 @@ namespace MWGui std::string_view getWindowIdForLua() const override { return "Inventory"; } - ControllerButtonStr* getControllerButtons() override; - protected: void onTitleDoubleClicked() override; - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - void setActiveControllerWindow(bool active) override; private: DragAndDrop* mDragAndDrop; @@ -122,7 +118,6 @@ namespace MWGui void sellItem(MyGUI::Widget* sender, int count); void dragItem(MyGUI::Widget* sender, int count); - void giveItem(MyGUI::Widget* sender, int count); void onWindowResize(MyGUI::Window* _sender); void onFilterChanged(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/itemchargeview.cpp b/apps/openmw/mwgui/itemchargeview.cpp index 31b29122f3..02c3cc182c 100644 --- a/apps/openmw/mwgui/itemchargeview.cpp +++ b/apps/openmw/mwgui/itemchargeview.cpp @@ -1,6 +1,5 @@ #include "itemchargeview.hpp" -#include #include #include @@ -10,11 +9,8 @@ #include #include -#include #include "../mwbase/environment.hpp" -#include "../mwbase/inputmanager.hpp" -#include "../mwbase/windowmanager.hpp" #include "../mwmechanics/spellutil.hpp" @@ -23,7 +19,6 @@ #include "itemmodel.hpp" #include "itemwidget.hpp" -#include "textcolours.hpp" namespace MWGui { @@ -161,20 +156,11 @@ namespace MWGui mScrollView->setCanvasSize( MyGUI::IntSize(mScrollView->getWidth(), std::max(mScrollView->getHeight(), currentY))); mScrollView->setVisibleVScroll(true); - - if (Settings::gui().mControllerMenus) - updateControllerFocus(-1, mControllerFocus); } void ItemChargeView::resetScrollbars() { mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); - - if (Settings::gui().mControllerMenus) - { - updateControllerFocus(mControllerFocus, 0); - mControllerFocus = 0; - } } void ItemChargeView::setSize(const MyGUI::IntSize& value) @@ -238,52 +224,4 @@ namespace MWGui mScrollView->setViewOffset( MyGUI::IntPoint(0, static_cast(mScrollView->getViewOffset().top + rel * 0.3f))); } - - void ItemChargeView::onControllerButton(const unsigned char button) - { - if (mLines.empty()) - return; - - int prevFocus = mControllerFocus; - - if (button == SDL_CONTROLLER_BUTTON_A) - { - // Select the focused item, if any. - if (mControllerFocus >= 0 && mControllerFocus < static_cast(mLines.size())) - onIconClicked(mLines[mControllerFocus].mIcon); - } - else if (button == SDL_CONTROLLER_BUTTON_DPAD_UP) - mControllerFocus = wrap(mControllerFocus - 1, mLines.size()); - else if (button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - mControllerFocus = wrap(mControllerFocus + 1, mLines.size()); - - if (prevFocus != mControllerFocus) - updateControllerFocus(prevFocus, mControllerFocus); - } - - void ItemChargeView::updateControllerFocus(int prevFocus, int newFocus) - { - if (mLines.empty()) - return; - - const TextColours& textColours{ MWBase::Environment::get().getWindowManager()->getTextColours() }; - - if (prevFocus >= 0 && prevFocus < static_cast(mLines.size())) - { - mLines[prevFocus].mText->setTextColour(textColours.normal); - mLines[prevFocus].mIcon->setControllerFocus(false); - } - - if (newFocus >= 0 && newFocus < static_cast(mLines.size())) - { - mLines[newFocus].mText->setTextColour(textColours.link); - mLines[newFocus].mIcon->setControllerFocus(true); - - // Scroll the list to keep the active item in view - if (newFocus <= 3) - mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); - else - mScrollView->setViewOffset(MyGUI::IntPoint(0, -55 * (newFocus - 3))); - } - } } diff --git a/apps/openmw/mwgui/itemchargeview.hpp b/apps/openmw/mwgui/itemchargeview.hpp index 73bf9c3de2..f7617d37eb 100644 --- a/apps/openmw/mwgui/itemchargeview.hpp +++ b/apps/openmw/mwgui/itemchargeview.hpp @@ -52,8 +52,6 @@ namespace MWGui MyGUI::delegates::MultiDelegate eventItemClicked; - void onControllerButton(const unsigned char button); - private: struct Line { @@ -74,9 +72,6 @@ namespace MWGui std::unique_ptr mModel; MyGUI::ScrollView* mScrollView; DisplayMode mDisplayMode; - - int mControllerFocus; - void updateControllerFocus(int prevFocus, int newFocus); }; } diff --git a/apps/openmw/mwgui/itemselection.cpp b/apps/openmw/mwgui/itemselection.cpp index ad2b141d8d..4fe40ce693 100644 --- a/apps/openmw/mwgui/itemselection.cpp +++ b/apps/openmw/mwgui/itemselection.cpp @@ -3,8 +3,6 @@ #include #include -#include - #include "inventoryitemmodel.hpp" #include "itemview.hpp" #include "sortfilteritemmodel.hpp" @@ -28,10 +26,6 @@ namespace MWGui cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ItemSelectionDialog::onCancelButtonClicked); center(); - - mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sCancel}"; - mControllerButtons.r3 = "#{sInfo}"; } bool ItemSelectionDialog::exit() @@ -46,8 +40,6 @@ namespace MWGui mSortModel = sortModel.get(); mItemView->setModel(std::move(sortModel)); mItemView->resetScrollBars(); - if (Settings::gui().mControllerMenus) - mItemView->setActiveControllerWindow(true); } void ItemSelectionDialog::setCategory(int category) @@ -73,13 +65,4 @@ namespace MWGui exit(); } - bool ItemSelectionDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_B) - onCancelButtonClicked(nullptr); - else - mItemView->onControllerButton(arg.button); - - return true; - } } diff --git a/apps/openmw/mwgui/itemselection.hpp b/apps/openmw/mwgui/itemselection.hpp index 83af6d4840..fe87d7e38a 100644 --- a/apps/openmw/mwgui/itemselection.hpp +++ b/apps/openmw/mwgui/itemselection.hpp @@ -41,7 +41,6 @@ namespace MWGui void onSelectedItem(int index); void onCancelButtonClicked(MyGUI::Widget* sender); - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; }; } diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index 0afb3d3d76..ff05a8b2d6 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -7,12 +7,6 @@ #include #include -#include - -#include "../mwbase/environment.hpp" -#include "../mwbase/inputmanager.hpp" -#include "../mwbase/windowmanager.hpp" - #include "itemmodel.hpp" #include "itemwidget.hpp" @@ -21,7 +15,6 @@ namespace MWGui ItemView::ItemView() : mScrollView(nullptr) - , mControllerActiveWindow(false) { } @@ -53,16 +46,13 @@ namespace MWGui MyGUI::Widget* dragArea = mScrollView->getChildAt(0); int maxHeight = mScrollView->getHeight(); - mRows = std::max(maxHeight / 42, 1); - mItemCount = dragArea->getChildCount(); - bool showScrollbar = int(std::ceil(mItemCount / float(mRows))) > mScrollView->getWidth() / 42; + int rows = maxHeight / 42; + rows = std::max(rows, 1); + bool showScrollbar = int(std::ceil(dragArea->getChildCount() / float(rows))) > mScrollView->getWidth() / 42; if (showScrollbar) - { maxHeight -= 18; - mRows = std::max(maxHeight / 42, 1); - } - for (int i = 0; i < mItemCount; ++i) + for (unsigned int i = 0; i < dragArea->getChildCount(); ++i) { MyGUI::Widget* w = dragArea->getChildAt(i); @@ -70,7 +60,7 @@ namespace MWGui y += 42; - if (y > maxHeight - 42 && i < mItemCount - 1) + if (y > maxHeight - 42 && i < dragArea->getChildCount() - 1) { x += 42; y = 0; @@ -80,12 +70,6 @@ namespace MWGui MyGUI::IntSize size = MyGUI::IntSize(std::max(mScrollView->getSize().width, x), mScrollView->getSize().height); - if (Settings::gui().mControllerMenus) - { - mControllerFocus = std::clamp(mControllerFocus, 0, mItemCount - 1); - updateControllerFocus(-1, mControllerFocus); - } - // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the // scrollbar is hidden mScrollView->setVisibleVScroll(false); @@ -138,11 +122,6 @@ namespace MWGui void ItemView::resetScrollBars() { mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); - if (Settings::gui().mControllerMenus) - { - updateControllerFocus(mControllerFocus, 0); - mControllerFocus = 0; - } } void ItemView::onSelectedItem(MyGUI::Widget* sender) @@ -186,106 +165,4 @@ namespace MWGui MyGUI::FactoryManager::getInstance().registerFactory("Widget"); } - void ItemView::setActiveControllerWindow(bool active) - { - mControllerActiveWindow = active; - - MWBase::Environment::get().getWindowManager()->setControllerTooltip( - active && Settings::gui().mControllerTooltips); - - if (active) - updateControllerFocus(-1, mControllerFocus); - else - updateControllerFocus(mControllerFocus, -1); - } - - void ItemView::onControllerButton(const unsigned char button) - { - if (!mItemCount) - return; - - int prevFocus = mControllerFocus; - - if (button == SDL_CONTROLLER_BUTTON_A) - { - // Select the focused item, if any. - if (mControllerFocus >= 0 && mControllerFocus < mItemCount) - { - MyGUI::Widget* dragArea = mScrollView->getChildAt(0); - onSelectedItem(dragArea->getChildAt(mControllerFocus)); - } - } - else if (button == SDL_CONTROLLER_BUTTON_RIGHTSTICK) - { - // Toggle info tooltip - MWBase::Environment::get().getWindowManager()->setControllerTooltip( - !MWBase::Environment::get().getWindowManager()->getControllerTooltip()); - updateControllerFocus(-1, mControllerFocus); - } - else if (button == SDL_CONTROLLER_BUTTON_DPAD_UP) - { - if (mControllerFocus % mRows == 0) - mControllerFocus = std::min(mControllerFocus + mRows - 1, mItemCount - 1); - else - mControllerFocus--; - } - else if (button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - { - if (mControllerFocus % mRows == mRows - 1 || mControllerFocus == mItemCount - 1) - mControllerFocus -= mControllerFocus % mRows; - else - mControllerFocus++; - } - else if (button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && mControllerFocus >= mRows) - mControllerFocus -= mRows; - else if (button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) - { - if (mControllerFocus + mRows < mItemCount) - mControllerFocus += mRows; - else if (mControllerFocus / mRows != (mItemCount - 1) / mRows) - mControllerFocus = mItemCount - 1; - } - - if (prevFocus != mControllerFocus) - updateControllerFocus(prevFocus, mControllerFocus); - else - updateControllerFocus(-1, mControllerFocus); - } - - void ItemView::updateControllerFocus(int prevFocus, int newFocus) - { - MWBase::Environment::get().getWindowManager()->setCursorVisible( - !MWBase::Environment::get().getWindowManager()->getControllerTooltip()); - - if (!mItemCount) - return; - - MyGUI::Widget* dragArea = mScrollView->getChildAt(0); - - if (prevFocus >= 0 && prevFocus < mItemCount) - { - ItemWidget* prev = (ItemWidget*)dragArea->getChildAt(prevFocus); - if (prev) - prev->setControllerFocus(false); - } - - if (mControllerActiveWindow && newFocus >= 0 && newFocus < mItemCount) - { - ItemWidget* focused = (ItemWidget*)dragArea->getChildAt(newFocus); - if (focused) - { - focused->setControllerFocus(true); - - // Scroll the list to keep the active item in view - int column = newFocus / mRows; - if (column <= 3) - mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); - else - mScrollView->setViewOffset(MyGUI::IntPoint(-42 * (column - 3), 0)); - - if (MWBase::Environment::get().getWindowManager()->getControllerTooltip()) - MWBase::Environment::get().getInputManager()->warpMouseToWidget(focused); - } - } - } } diff --git a/apps/openmw/mwgui/itemview.hpp b/apps/openmw/mwgui/itemview.hpp index 7915a4dcf1..cfbc8a37ac 100644 --- a/apps/openmw/mwgui/itemview.hpp +++ b/apps/openmw/mwgui/itemview.hpp @@ -2,7 +2,6 @@ #define MWGUI_ITEMVIEW_H #include -#include #include "itemmodel.hpp" @@ -32,11 +31,6 @@ namespace MWGui void resetScrollBars(); - void setActiveControllerWindow(bool active); - int getControllerFocus() { return mControllerFocus; } - int getItemCount() { return mItemCount; } - void onControllerButton(const unsigned char button); - private: void initialiseOverride() override; @@ -51,12 +45,6 @@ namespace MWGui std::unique_ptr mModel; MyGUI::ScrollView* mScrollView; - - int mItemCount = 0; - int mRows; - int mControllerFocus = 0; - bool mControllerActiveWindow; - void updateControllerFocus(int prevFocus, int newFocus); }; } diff --git a/apps/openmw/mwgui/itemwidget.cpp b/apps/openmw/mwgui/itemwidget.cpp index 5e47577b27..05fff2d40f 100644 --- a/apps/openmw/mwgui/itemwidget.cpp +++ b/apps/openmw/mwgui/itemwidget.cpp @@ -58,7 +58,6 @@ namespace MWGui : mItem(nullptr) , mItemShadow(nullptr) , mFrame(nullptr) - , mControllerBorder(nullptr) , mText(nullptr) { } @@ -83,22 +82,10 @@ namespace MWGui assignWidget(mText, "Text"); if (mText) mText->setNeedMouseFocus(false); - if (Settings::gui().mControllerMenus) - { - assignWidget(mControllerBorder, "ControllerBorder"); - if (mControllerBorder) - mControllerBorder->setNeedMouseFocus(false); - } Base::initialiseOverride(); } - void ItemWidget::setControllerFocus(bool focus) - { - if (mControllerBorder) - mControllerBorder->setVisible(focus); - } - void ItemWidget::setCount(int count) { if (!mText) diff --git a/apps/openmw/mwgui/itemwidget.hpp b/apps/openmw/mwgui/itemwidget.hpp index 1191a23342..63837ae92f 100644 --- a/apps/openmw/mwgui/itemwidget.hpp +++ b/apps/openmw/mwgui/itemwidget.hpp @@ -40,15 +40,12 @@ namespace MWGui void setIcon(const MWWorld::Ptr& ptr); void setFrame(const std::string& frame, const MyGUI::IntCoord& coord); - void setControllerFocus(bool focus); - protected: void initialiseOverride() override; MyGUI::ImageBox* mItem; MyGUI::ImageBox* mItemShadow; MyGUI::ImageBox* mFrame; - MyGUI::ImageBox* mControllerBorder; MyGUI::TextBox* mText; std::string mCurrentIcon; diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index c127508062..86b45b4863 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -169,7 +169,7 @@ namespace MWGui { BookTypesetter::Ptr typesetter = createTypesetter(); - BookTypesetter::Style* header = typesetter->createStyle({}, journalHeaderColour); + BookTypesetter::Style* header = typesetter->createStyle({}, MyGUI::Colour(0.60f, 0.00f, 0.00f)); BookTypesetter::Style* body = typesetter->createStyle({}, MyGUI::Colour::Black); typesetter->write(header, to_utf8_span("You have no journal entries!")); @@ -184,7 +184,7 @@ namespace MWGui { BookTypesetter::Ptr typesetter = createTypesetter(); - BookTypesetter::Style* header = typesetter->createStyle({}, journalHeaderColour); + BookTypesetter::Style* header = typesetter->createStyle({}, MyGUI::Colour(0.60f, 0.00f, 0.00f)); BookTypesetter::Style* body = typesetter->createStyle({}, MyGUI::Colour::Black); mModel->visitJournalEntries({}, AddJournalEntry(typesetter, body, header, true)); @@ -196,7 +196,7 @@ namespace MWGui { BookTypesetter::Ptr typesetter = createTypesetter(); - BookTypesetter::Style* header = typesetter->createStyle({}, journalHeaderColour); + BookTypesetter::Style* header = typesetter->createStyle({}, MyGUI::Colour(0.60f, 0.00f, 0.00f)); BookTypesetter::Style* body = typesetter->createStyle({}, MyGUI::Colour::Black); mModel->visitTopicName(topicId, AddTopicName(typesetter, header)); @@ -212,7 +212,7 @@ namespace MWGui { BookTypesetter::Ptr typesetter = createTypesetter(); - BookTypesetter::Style* header = typesetter->createStyle({}, journalHeaderColour); + BookTypesetter::Style* header = typesetter->createStyle({}, MyGUI::Colour(0.60f, 0.00f, 0.00f)); BookTypesetter::Style* body = typesetter->createStyle({}, MyGUI::Colour::Black); AddQuestName addName(typesetter, header); diff --git a/apps/openmw/mwgui/journalbooks.hpp b/apps/openmw/mwgui/journalbooks.hpp index 2549b2ad5b..792edcc070 100644 --- a/apps/openmw/mwgui/journalbooks.hpp +++ b/apps/openmw/mwgui/journalbooks.hpp @@ -10,8 +10,6 @@ namespace MWGui { MWGui::BookTypesetter::Utf8Span to_utf8_span(std::string_view text); - const MyGUI::Colour journalHeaderColour = MyGUI::Colour(0.60f, 0.00f, 0.00f); - struct JournalBooks { typedef TypesetBook::Ptr Book; diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 8302f4faea..574c425d3e 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -218,10 +218,6 @@ namespace } } - mControllerButtons.a = "#{sSelect}"; - mControllerButtons.x = "#{OMWEngine:JournalQuests}"; - mControllerButtons.y = "#{sTopics}"; - mQuestMode = false; mAllQuests = false; mOptionsMode = false; @@ -252,9 +248,6 @@ namespace } updateShowingPages(); - if (Settings::gui().mControllerMenus) - setControllerFocusedQuest(0); - MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(getWidget(CloseBTN)); } @@ -282,8 +275,6 @@ namespace updateShowingPages(); updateCloseJournalButton(); - - MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay(); } void setOptionsMode() @@ -316,8 +307,6 @@ namespace notifyQuests(getWidget(QuestsList)); else notifyTopics(getWidget(TopicsList)); - - MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay(); } void pushBook(Book& book, unsigned int page) @@ -349,7 +338,6 @@ namespace { setVisible(CloseBTN, mStates.size() < 2); setVisible(JournalBTN, mStates.size() >= 2); - MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay(); } void updateShowingPages() @@ -392,8 +380,6 @@ namespace setText(PageOneNum, page + 1); setText(PageTwoNum, page + 2); - - MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay(); } void notifyKeyPress(MyGUI::Widget* sender, MyGUI::KeyCode key, MyGUI::Char character) @@ -421,7 +407,6 @@ namespace mTopicsMode = false; MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("book page")); - MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay(); } void notifyTopicSelected(const std::string& topicIdString, int id) @@ -454,7 +439,6 @@ namespace mOptionsMode = false; MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("book page")); - MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay(); } void notifyOptions(MyGUI::Widget* _sender) @@ -475,9 +459,6 @@ namespace getPage(LeftTopicIndex)->showPage(mTopicIndexBook, 0); getPage(RightTopicIndex)->showPage(mTopicIndexBook, 1); } - - if (Settings::gui().mControllerMenus) - setIndexControllerFocus(true); } void notifyJournal(MyGUI::Widget* _sender) @@ -486,22 +467,6 @@ namespace popBook(); MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("book page")); - MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay(); - } - - void addControllerButtons(Gui::MWList* _list, size_t _selectedIndex) - { - mButtons.clear(); - for (size_t i = 0; i < _list->getItemCount(); i++) - { - MyGUI::Button* listItem = _list->getItemWidget(_list->getItemNameAt(i)); - if (listItem) - { - listItem->setTextColour( - mButtons.size() == _selectedIndex ? MWGui::journalHeaderColour : MyGUI::Colour::Black); - mButtons.push_back(listItem); - } - } } void notifyIndexLinkClicked(MWGui::TypesetBook::InteractiveId index) @@ -522,14 +487,7 @@ namespace list->adjustSize(); - if (Settings::gui().mControllerMenus) - { - setControllerFocusedQuest(0); - addControllerButtons(list, mSelectedQuest); - } - MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("book page")); - MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay(); } void notifyTopics(MyGUI::Widget* _sender) @@ -545,7 +503,6 @@ namespace setVisible(ShowActiveBTN, false); MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("book page")); - MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay(); } struct AddNamesToList @@ -597,12 +554,6 @@ namespace list->sort(); list->adjustSize(); - if (Settings::gui().mControllerMenus) - { - addControllerButtons(list, mSelectedQuest); - setControllerFocusedQuest(MWGui::wrap(mSelectedQuest, mButtons.size())); - } - if (mAllQuests) { SetNamesInactive setInactive(list); @@ -610,7 +561,6 @@ namespace } MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("book page")); - MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay(); } void notifyShowAll(MyGUI::Widget* _sender) @@ -689,299 +639,6 @@ namespace } } } - - MWGui::ControllerButtonStr* getControllerButtons() override - { - mControllerButtons.b = mOptionsMode || mStates.size() > 1 ? "#{sBack}" : "#{sClose}"; - mControllerButtons.l1 = mOptionsMode ? "" : "#{sPrev}"; - mControllerButtons.r1 = mOptionsMode ? "" : "#{sNext}"; - mControllerButtons.r3 = mOptionsMode && mQuestMode ? "#{OMWEngine:JournalShowAll}" : ""; - return &mControllerButtons; - } - - void setIndexControllerFocus(bool focused) - { - int col, row; - bool isRussian = (mEncoding == ToUTF8::WINDOWS_1251); - if (isRussian) - { - // Cyrillic = 30 (10 + 10 + 10) - col = mSelectedIndex / 10; - row = mSelectedIndex % 10; - } - else - { - // Latin = 26 (13 + 13) - col = mSelectedIndex / 13; - row = mSelectedIndex % 13; - } - - mTopicIndexBook->setColour(col, row, 0, focused ? MWGui::journalHeaderColour : MyGUI::Colour::Black); - } - - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override - { - bool isRussian = (mEncoding == ToUTF8::WINDOWS_1251); - - if (arg.button == SDL_CONTROLLER_BUTTON_A) // A: Mouse click or Select - { - if (mOptionsMode && mQuestMode) - { - // Choose a quest - Gui::MWList* list = getWidget(QuestsList); - notifyQuestClicked(list->getItemNameAt(mSelectedQuest), 0); - } - else if (mOptionsMode && mTopicsMode) - { - // Choose a topic - Gui::MWList* list = getWidget(TopicsList); - notifyTopicSelected(list->getItemNameAt(mSelectedQuest), 0); - } - else if (mOptionsMode) - { - // Choose an index. Cyrillic capital A is a 0xd090 in UTF-8. - // Words can not be started with characters 26 or 28. - int russianOffset = 0xd090; - if (mSelectedIndex >= 26) - russianOffset++; - if (mSelectedIndex >= 27) - russianOffset++; // 27, not 28, because of skipping char 26 - notifyIndexLinkClicked(isRussian ? mSelectedIndex + russianOffset : mSelectedIndex + 'A'); - } - return true; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) // B: Back - { - if (mOptionsMode) - { - // Hide the options overlay - notifyCancel(getWidget(CancelBTN)); - mQuestMode = false; - } - else if (mStates.size() > 1) - { - // Pop the current book. If in quest mode, reopen the quest list. - notifyJournal(getWidget(JournalBTN)); - if (mQuestMode) - { - notifyOptions(getWidget(OptionsBTN)); - notifyQuests(getWidget(QuestsBTN)); - } - } - else - { - // Close the journal window - notifyClose(getWidget(CloseBTN)); - } - return true; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_X) // X: Quests - { - if (mOptionsMode && mQuestMode) - { - // Hide the quest overlay if visible - notifyCancel(getWidget(CancelBTN)); - mQuestMode = false; - } - else - { - // Show the quest overlay if viewing a journal entry or the topics - if (!mOptionsMode) - notifyOptions(getWidget(OptionsBTN)); - if (!mQuestMode) - notifyQuests(getWidget(QuestsBTN)); - } - return true; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_Y) // Y: Topics - { - if (mOptionsMode && !mQuestMode) - { - // Hide the topics overlay if visible - notifyCancel(getWidget(CancelBTN)); - mQuestMode = false; - } - else - { - // Show the topics overlay if viewing a journal entry or the quest list - if (!mOptionsMode) - notifyOptions(getWidget(OptionsBTN)); - if (mQuestMode) - notifyTopics(getWidget(TopicsBTN)); - } - return true; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK) // R3: Show All/Some - { - if (mAllQuests) - notifyShowActive(getWidget(ShowActiveBTN)); - else - notifyShowAll(getWidget(ShowAllBTN)); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) - { - if (mOptionsMode && (mQuestMode || mTopicsMode)) - { - if (mButtons.size() <= 1) - return true; - - // Scroll through the list of quests or topics - setControllerFocusedQuest(MWGui::wrap(mSelectedQuest - 1, mButtons.size())); - } - else if (mOptionsMode) - { - setIndexControllerFocus(false); - if (isRussian) - { - // Cyrillic = 30 (10 + 10 + 10) - if (mSelectedIndex == 0) - mSelectedIndex = 9; - else if (mSelectedIndex == 10) - mSelectedIndex = 19; - else if (mSelectedIndex == 20) - mSelectedIndex = 29; - else - mSelectedIndex--; - } - else - { - // Latin = 26 (13 + 13) - if (mSelectedIndex == 0) - mSelectedIndex = 12; - else if (mSelectedIndex == 13) - mSelectedIndex = 25; - else - mSelectedIndex--; - } - setIndexControllerFocus(true); - setText(PageOneNum, 1); // Redraw the list - } - return true; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - { - if (mOptionsMode && (mQuestMode || mTopicsMode)) - { - if (mButtons.size() <= 1) - return true; - - // Scroll through the list of quests or topics - setControllerFocusedQuest(MWGui::wrap(mSelectedQuest + 1, mButtons.size())); - } - else if (mOptionsMode) - { - setIndexControllerFocus(false); - if (isRussian) - { - // Cyrillic = 30 (10 + 10 + 10) - if (mSelectedIndex == 9) - mSelectedIndex = 0; - else if (mSelectedIndex == 19) - mSelectedIndex = 10; - else if (mSelectedIndex == 29) - mSelectedIndex = 20; - else - mSelectedIndex++; - } - else - { - // Latin = 26 (13 + 13) - if (mSelectedIndex == 12) - mSelectedIndex = 0; - else if (mSelectedIndex == 25) - mSelectedIndex = 13; - else - mSelectedIndex++; - } - setIndexControllerFocus(true); - setText(PageOneNum, 1); // Redraw the list - } - return true; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) - { - if (!mOptionsMode) - notifyPrevPage(getWidget(PrevPageBTN)); - else if (mOptionsMode && !mQuestMode && !mTopicsMode) - { - setIndexControllerFocus(false); - if (isRussian) - { - // Cyrillic = 30 (10 + 10 + 10) - mSelectedIndex = (mSelectedIndex + 20) % 30; - } - else - { - // Latin = 26 (13 + 13) - mSelectedIndex = (mSelectedIndex + 13) % 26; - } - setIndexControllerFocus(true); - setText(PageOneNum, 1); // Redraw the list - } - return true; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) - { - if (!mOptionsMode) - notifyNextPage(getWidget(NextPageBTN)); - else if (mOptionsMode && !mQuestMode && !mTopicsMode) - { - setIndexControllerFocus(false); - if (isRussian) - { - // Cyrillic = 30 (10 + 10 + 10) - mSelectedIndex = (mSelectedIndex + 10) % 30; - } - else - { - // Latin = 26 (13 + 13) - mSelectedIndex = (mSelectedIndex + 13) % 26; - } - setIndexControllerFocus(true); - setText(PageOneNum, 1); // Redraw the list - } - return true; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) // LB: Previous Page - { - if (!mOptionsMode) - notifyPrevPage(getWidget(PrevPageBTN)); - return true; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) // RB: Next Page - { - if (!mOptionsMode) - notifyNextPage(getWidget(NextPageBTN)); - return true; - } - - return false; - } - - void setControllerFocusedQuest(size_t index) - { - size_t listSize = mButtons.size(); - if (mSelectedQuest < listSize) - mButtons[mSelectedQuest]->setTextColour(MyGUI::Colour::Black); - - mSelectedQuest = index; - if (mSelectedQuest < listSize) - { - mButtons[mSelectedQuest]->setTextColour(MWGui::journalHeaderColour); - - // Scroll the list to keep the active item in view - Gui::MWList* list = getWidget(mQuestMode ? QuestsList : TopicsList); - if (mSelectedQuest <= 3) - list->setViewOffset(0); - else - { - int offset = 0; - for (int i = 0; i < static_cast(mSelectedQuest) - 3; i++) - offset += mButtons[i]->getHeight() + 3; - list->setViewOffset(-offset); - } - } - } }; } diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index 4a1f686ff1..f0f394156c 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -31,12 +31,6 @@ namespace MWGui void setVisible(bool newValue) override = 0; std::string_view getWindowIdForLua() const override { return "Journal"; } - - std::vector mButtons; - size_t mSelectedQuest = 0; - size_t mSelectedIndex = 0; - void setIndexControllerFocus(bool focused); - void setControllerFocusedQuest(size_t index); }; } diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index b9c90e51e2..87f2db55a5 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -8,7 +8,6 @@ #include #include -#include #include #include "../mwbase/environment.hpp" @@ -73,7 +72,6 @@ namespace MWGui widgets.mButton->setCaption(attribute.mName); widgets.mValue = hbox->createWidget("SandText", {}, MyGUI::Align::Default); mAttributeWidgets.emplace(attribute.mId, widgets); - mAttributeButtons.emplace_back(widgets.mButton); ++i; } @@ -92,15 +90,6 @@ namespace MWGui mCoins.push_back(image); } - if (Settings::gui().mControllerMenus) - { - mDisableGamepadCursor = true; - mControllerButtons.a = "#{sSelect}"; - mControllerButtons.x = "#{sDone}"; - mOkButton->setCaption( - MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sDone", {}))); - } - center(); } @@ -228,13 +217,6 @@ namespace MWGui center(); - if (Settings::gui().mControllerMenus) - { - mControllerFocus = 0; - for (size_t i = 0; i < mAttributeButtons.size(); i++) - setControllerFocus(mAttributeButtons, i, i == 0); - } - // Play LevelUp Music MWBase::Environment::get().getSoundManager()->streamMusic(MWSound::triumphMusic, MWSound::MusicType::Normal); } @@ -381,48 +363,4 @@ namespace MWGui return ret; } - - bool LevelupDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - if (mControllerFocus >= 0 && mControllerFocus < static_cast(mAttributeButtons.size())) - onAttributeClicked(mAttributeButtons[mControllerFocus]); - MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Item Gold Up")); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_X) - { - onOkButtonClicked(mOkButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) - { - setControllerFocus(mAttributeButtons, mControllerFocus, false); - if (mControllerFocus == 0) - mControllerFocus = 3; - else if (mControllerFocus == 4) - mControllerFocus = 7; - else - mControllerFocus--; - setControllerFocus(mAttributeButtons, mControllerFocus, true); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - { - setControllerFocus(mAttributeButtons, mControllerFocus, false); - if (mControllerFocus == 3) - mControllerFocus = 0; - else if (mControllerFocus == 7) - mControllerFocus = 4; - else - mControllerFocus++; - setControllerFocus(mAttributeButtons, mControllerFocus, true); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT || arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) - { - setControllerFocus(mAttributeButtons, mControllerFocus, false); - mControllerFocus = (mControllerFocus + 4) % mAttributeButtons.size(); - setControllerFocus(mAttributeButtons, mControllerFocus, true); - } - - return true; - } } diff --git a/apps/openmw/mwgui/levelupdialog.hpp b/apps/openmw/mwgui/levelupdialog.hpp index 8a34a94c8b..486390679b 100644 --- a/apps/openmw/mwgui/levelupdialog.hpp +++ b/apps/openmw/mwgui/levelupdialog.hpp @@ -49,10 +49,6 @@ namespace MWGui std::string_view getLevelupClassImage( const int combatIncreases, const int magicIncreases, const int stealthIncreases); - - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - std::vector mAttributeButtons; - int mControllerFocus; }; } diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index d9d5b5c33b..1b3619bd9f 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -1,7 +1,6 @@ #include "mainmenu.hpp" #include -#include #include #include @@ -106,7 +105,6 @@ namespace MWGui constexpr VFS::Path::NormalizedView menuBackgroundVideo("video/menu_background.bik"); mHasAnimatedMenu = mVFS->exists(menuBackgroundVideo); - mDisableGamepadCursor = Settings::gui().mControllerMenus; updateMenu(); } @@ -165,7 +163,9 @@ namespace MWGui const std::string& name = *sender->getUserData(); winMgr->playSound(ESM::RefId::stringRefId("Menu Click")); if (name == "return") + { winMgr->removeGuiMode(GM_MainMenu); + } else if (name == "credits") winMgr->playVideo("mw_credits.bik", true); else if (name == "exitgame") @@ -208,32 +208,6 @@ namespace MWGui } } - bool MainMenu::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Space, 0, false); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B || arg.button == SDL_CONTROLLER_BUTTON_START) - { - if (mButtons["return"]->getVisible()) - onButtonClicked(mButtons["return"]); - else - MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Escape, 0, false); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) - { - MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::LeftShift); - MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Tab, 0, false); - MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::LeftShift); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - { - MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Tab, 0, false); - } - return true; - } - void MainMenu::showBackground(bool show) { if (mVideo && !show) diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index 453a16b5e4..06a8c945c1 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -49,7 +49,6 @@ namespace MWGui MainMenu(int w, int h, const VFS::Manager* vfs, const std::string& versionDescription); void onResChange(int w, int h) override; - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; void setVisible(bool visible) override; diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 38cfbc1e58..bf4bd7644c 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include @@ -833,14 +832,6 @@ namespace MWGui mGlobalMap->setVisible(global); mLocalMap->setVisible(!global); - - if (Settings::gui().mControllerMenus) - { - mControllerButtons.b = "#{sBack}"; - mControllerButtons.x = global ? "#{sLocal}" : "#{sWorld}"; - mControllerButtons.y = "#{sCenter}"; - mControllerButtons.dpad = Settings::map().mAllowZooming ? "" : "#{sMove}"; - } } void MapWindow::onNoteEditOk() @@ -1029,20 +1020,7 @@ namespace MWGui void MapWindow::setVisible(bool visible) { WindowBase::setVisible(visible); - MWGui::GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode(); - mButton->setVisible(visible && mode != MWGui::GM_None); - - if (Settings::gui().mControllerMenus && mode == MWGui::GM_None && pinned() && visible) - { - // Restore the window to pinned size. - MyGUI::Window* window = mMainWidget->castType(); - MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - const float x = Settings::windows().mMapX * viewSize.width; - const float y = Settings::windows().mMapY * viewSize.height; - const float w = Settings::windows().mMapW * viewSize.width; - const float h = Settings::windows().mMapH * viewSize.height; - window->setCoord(x, y, w, h); - } + mButton->setVisible(visible && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_None); } void MapWindow::renderGlobalMap() @@ -1230,8 +1208,6 @@ namespace MWGui mLocalMap->setVisible(!global); mButton->setCaptionWithReplacing(global ? "#{sLocal}" : "#{sWorld}"); - mControllerButtons.x = global ? "#{sLocal}" : "#{sWorld}"; - MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay(); } void MapWindow::onPinToggled() @@ -1392,69 +1368,6 @@ namespace MWGui mGlobalMapRender->asyncWritePng(); } - bool MapWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_B) - MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); - else if (arg.button == SDL_CONTROLLER_BUTTON_X) - { - onWorldButtonClicked(mButton); - MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_Y) - { - centerView(); - MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) - shiftMap(0, 100); - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - shiftMap(0, -100); - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) - shiftMap(100, 0); - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) - shiftMap(-100, 0); - - return true; - } - - void MapWindow::shiftMap(int dx, int dy) - { - if (dx == 0 && dy == 0) - return; - - if (!Settings::map().mGlobal) - { - mNeedDoorMarkersUpdate = true; - mLocalMap->setViewOffset( - MyGUI::IntPoint(mLocalMap->getViewOffset().left + dx, mLocalMap->getViewOffset().top + dy)); - } - else - { - mGlobalMap->setViewOffset( - MyGUI::IntPoint(mGlobalMap->getViewOffset().left + dx, mGlobalMap->getViewOffset().top + dy)); - } - } - - void MapWindow::setActiveControllerWindow(bool active) - { - if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Inventory) - { - // Fill the screen, or limit to a certain size on large screens. Size chosen to - // show the entire local map without scrolling. - MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - int width = std::min(viewSize.width, 1552); - int height = std::min(viewSize.height - 48 - 48, 1572); - int x = (viewSize.width - width) / 2; - int y = (viewSize.height - height) / 2; - - MyGUI::Window* window = mMainWidget->castType(); - window->setCoord(x, active ? y : viewSize.height + 1, width, height); - } - - WindowBase::setActiveControllerWindow(active); - } - // ------------------------------------------------------------------- EditNoteDialog::EditNoteDialog() @@ -1468,12 +1381,6 @@ namespace MWGui mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EditNoteDialog::onCancelButtonClicked); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EditNoteDialog::onOkButtonClicked); mDeleteButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EditNoteDialog::onDeleteButtonClicked); - - if (Settings::gui().mControllerMenus) - { - mControllerButtons.a = "#{sOk}"; - mControllerButtons.b = "#{sCancel}"; - } } void EditNoteDialog::showDeleteButton(bool show) @@ -1501,13 +1408,6 @@ namespace MWGui WindowModal::onOpen(); center(); MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit); - - if (Settings::gui().mControllerMenus) - { - mControllerFocus = getDeleteButtonShown() ? 1 : 0; - mOkButton->setStateSelected(true); - mCancelButton->setStateSelected(false); - } } void EditNoteDialog::onCancelButtonClicked(MyGUI::Widget* sender) @@ -1525,78 +1425,6 @@ namespace MWGui eventDeleteClicked(); } - ControllerButtonStr* EditNoteDialog::getControllerButtons() - { - mControllerButtons.x = getDeleteButtonShown() ? "#{sDelete}" : ""; - return &mControllerButtons; - } - - bool EditNoteDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - if (getDeleteButtonShown()) - { - if (mControllerFocus == 0) - onDeleteButtonClicked(mDeleteButton); - else if (mControllerFocus == 1) - onOkButtonClicked(mOkButton); - else - onCancelButtonClicked(mCancelButton); - } - else - { - if (mControllerFocus == 0) - onOkButtonClicked(mOkButton); - else - onCancelButtonClicked(mCancelButton); - } - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - { - onCancelButtonClicked(mCancelButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_X) - { - if (getDeleteButtonShown()) - onDeleteButtonClicked(mDeleteButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) - { - if (getDeleteButtonShown()) - { - mControllerFocus = wrap(mControllerFocus - 1, 3); - mDeleteButton->setStateSelected(mControllerFocus == 0); - mOkButton->setStateSelected(mControllerFocus == 1); - mCancelButton->setStateSelected(mControllerFocus == 2); - } - else - { - mControllerFocus = 0; - mOkButton->setStateSelected(mControllerFocus == 0); - mCancelButton->setStateSelected(mControllerFocus == 1); - } - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) - { - if (getDeleteButtonShown()) - { - mControllerFocus = wrap(mControllerFocus + 1, 3); - mDeleteButton->setStateSelected(mControllerFocus == 0); - mOkButton->setStateSelected(mControllerFocus == 1); - mCancelButton->setStateSelected(mControllerFocus == 2); - } - else - { - mControllerFocus = 1; - mOkButton->setStateSelected(mControllerFocus == 0); - mCancelButton->setStateSelected(mControllerFocus == 1); - } - } - - return true; - } - bool LocalMapBase::MarkerUserData::isPositionExplored() const { if (!mLocalMapRender) diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 8730964094..ed070c5407 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -212,8 +212,6 @@ namespace MWGui EventHandle_Void eventDeleteClicked; EventHandle_Void eventOkClicked; - ControllerButtonStr* getControllerButtons() override; - private: void onCancelButtonClicked(MyGUI::Widget* sender); void onOkButtonClicked(MyGUI::Widget* sender); @@ -223,9 +221,6 @@ namespace MWGui MyGUI::Button* mOkButton; MyGUI::Button* mCancelButton; MyGUI::Button* mDeleteButton; - - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - int mControllerFocus; }; class MapWindow : public MWGui::WindowPinnableBase, public LocalMapBase, public NoDrop @@ -270,10 +265,6 @@ namespace MWGui std::string_view getWindowIdForLua() const override { return "Map"; } - protected: - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - void setActiveControllerWindow(bool active) override; - private: void onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); void onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); @@ -292,7 +283,6 @@ namespace MWGui void setGlobalMapMarkerTooltip(MyGUI::Widget* widget, int x, int y); float getMarkerSize(size_t agregatedWeight) const; void resizeGlobalMap(); - void shiftMap(int dx, int dy); void worldPosToGlobalMapImageSpace(float x, float z, float& imageX, float& imageY) const; MyGUI::IntCoord createMarkerCoords(float x, float y, float agregatedWeight) const; MyGUI::Widget* createMarker(const std::string& name, float x, float y, float agregatedWeight); diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 425c519175..54f9ae4187 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -28,13 +28,6 @@ namespace MWGui getWidget(mGoldLabel, "PlayerGold"); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MerchantRepair::onOkButtonClick); - - if (Settings::gui().mControllerMenus) - { - mDisableGamepadCursor = true; - mControllerButtons.a = "#{sRepair}"; - mControllerButtons.b = "#{sCancel}"; - } } void MerchantRepair::setPtr(const MWWorld::Ptr& actor) @@ -45,7 +38,6 @@ namespace MWGui while (mList->getChildCount()) MyGUI::Gui::getInstance().destroyWidget(mList->getChildAt(0)); - mButtons.clear(); const int lineHeight = Settings::gui().mFontSize + 2; int currentY = 0; @@ -109,15 +101,6 @@ namespace MWGui button->eventMouseWheel += MyGUI::newDelegate(this, &MerchantRepair::onMouseWheel); button->setUserString("ToolTipType", "ItemPtr"); button->eventMouseButtonClick += MyGUI::newDelegate(this, &MerchantRepair::onRepairButtonClick); - if (price <= playerGold) - mButtons.emplace_back(std::make_pair(button, mButtons.size())); - } - - if (Settings::gui().mControllerMenus) - { - mControllerFocus = 0; - if (mButtons.size() > 0) - mButtons[0].first->setStateSelected(true); } // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the @@ -174,49 +157,4 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_MerchantRepair); } - bool MerchantRepair::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - if (mControllerFocus >= 0 && mControllerFocus < static_cast(mButtons.size())) - onRepairButtonClick(mButtons[mControllerFocus].first); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - { - onOkButtonClick(mOkButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) - { - if (mButtons.size() <= 1) - return true; - - mButtons[mControllerFocus].first->setStateSelected(false); - mControllerFocus = wrap(mControllerFocus - 1, mButtons.size()); - mButtons[mControllerFocus].first->setStateSelected(true); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - { - if (mButtons.size() <= 1) - return true; - - mButtons[mControllerFocus].first->setStateSelected(false); - mControllerFocus = wrap(mControllerFocus + 1, mButtons.size()); - mButtons[mControllerFocus].first->setStateSelected(true); - } - - // Scroll the list to keep the active item in view - if (mControllerFocus >= 0 && mControllerFocus < static_cast(mButtons.size())) - { - int line = mButtons[mControllerFocus].second; - if (line <= 5) - mList->setViewOffset(MyGUI::IntPoint(0, 0)); - else - { - const int lineHeight = Settings::gui().mFontSize + 2; - mList->setViewOffset(MyGUI::IntPoint(0, -lineHeight * (line - 5))); - } - } - - return true; - } } diff --git a/apps/openmw/mwgui/merchantrepair.hpp b/apps/openmw/mwgui/merchantrepair.hpp index e878d34b7d..ffe5b86bdb 100644 --- a/apps/openmw/mwgui/merchantrepair.hpp +++ b/apps/openmw/mwgui/merchantrepair.hpp @@ -22,18 +22,13 @@ namespace MWGui MyGUI::ScrollView* mList; MyGUI::Button* mOkButton; MyGUI::TextBox* mGoldLabel; - /// List of enabled/repairable items and their index in the full list. - std::vector> mButtons; MWWorld::Ptr mActor; - int mControllerFocus; - protected: void onMouseWheel(MyGUI::Widget* _sender, int _rel); void onRepairButtonClick(MyGUI::Widget* sender); void onOkButtonClick(MyGUI::Widget* sender); - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; }; } diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 80b2a34a5b..1d6e1511c4 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -8,7 +8,6 @@ #include #include -#include #include "../mwbase/environment.hpp" #include "../mwbase/inputmanager.hpp" @@ -281,22 +280,6 @@ namespace MWGui } } - if (Settings::gui().mControllerMenus) - { - mDisableGamepadCursor = true; - mControllerButtons.a = "#{sOk}"; - - // If we have more than one button, we need to set the focus to the first one. - if (mButtons.size() > 1) - { - mControllerFocus = 0; - if (mDefaultFocus >= 0 && mDefaultFocus < static_cast(mButtons.size())) - mControllerFocus = mDefaultFocus; - for (int i = 0; i < static_cast(mButtons.size()); ++i) - mButtons[i]->setStateSelected(i == mControllerFocus); - } - } - MyGUI::IntSize mainWidgetSize; if (buttonsWidth < textSize.width) { @@ -448,41 +431,4 @@ namespace MWGui return mButtonPressed; } - bool InteractiveMessageBox::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - mControllerFocus = std::clamp(mControllerFocus, 0, static_cast(mButtons.size()) - 1); - buttonActivated(mButtons[mControllerFocus]); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - { - if (mButtons.size() == 1) - buttonActivated(mButtons[0]); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP || arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) - { - if (mButtons.size() <= 1) - return true; - if (mButtons.size() == 2 && mControllerFocus == 0) - return true; - - setControllerFocus(mButtons, mControllerFocus, false); - mControllerFocus = wrap(mControllerFocus - 1, mButtons.size()); - setControllerFocus(mButtons, mControllerFocus, true); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN || arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) - { - if (mButtons.size() <= 1) - return true; - if (mButtons.size() == 2 && mControllerFocus == static_cast(mButtons.size()) - 1) - return true; - - setControllerFocus(mButtons, mControllerFocus, false); - mControllerFocus = wrap(mControllerFocus + 1, mButtons.size()); - setControllerFocus(mButtons, mControllerFocus, true); - } - - return true; - } } diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index e6128ee0d1..feb717e0ad 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -103,8 +103,6 @@ namespace MWGui bool mMarkedToDelete; - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - private: void buttonActivated(MyGUI::Widget* _widget); @@ -116,7 +114,6 @@ namespace MWGui int mButtonPressed; int mDefaultFocus; bool mImmediate; - int mControllerFocus = 0; }; } diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 96045b8e21..c8932c97b6 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -58,12 +58,6 @@ namespace MWGui unassign(&mKey[i]); } - - if (Settings::gui().mControllerMenus) - { - mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sOK}"; - } } void QuickKeysMenu::clear() @@ -115,13 +109,6 @@ namespace MWGui { validate(index); } - - if (Settings::gui().mControllerMenus) - { - mControllerFocus = 0; - for (int i = 0; i < static_cast(mKey.size()); i++) - mKey[i].button->setControllerFocus(i == mControllerFocus); - } } void QuickKeysMenu::onClose() @@ -469,39 +456,6 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->updateSpellWindow(); } - bool QuickKeysMenu::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - onQuickKeyButtonClicked(mKey[mControllerFocus].button); - if (arg.button == SDL_CONTROLLER_BUTTON_B) - onOkButtonClicked(mOkButton); - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP || arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - mControllerFocus = (mControllerFocus + 5) % 10; - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) - { - if (mControllerFocus == 0) - mControllerFocus = 4; - else if (mControllerFocus == 5) - mControllerFocus = 9; - else - mControllerFocus--; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) - { - if (mControllerFocus == 4) - mControllerFocus = 0; - else if (mControllerFocus == 9) - mControllerFocus = 5; - else - mControllerFocus++; - } - - for (int i = 0; i < static_cast(mKey.size()); i++) - mKey[i].button->setControllerFocus(i == mControllerFocus); - - return true; - } - // --------------------------------------------------------------------------------------------------------- QuickKeysMenuAssign::QuickKeysMenuAssign(QuickKeysMenu* parent) @@ -537,45 +491,9 @@ namespace MWGui mCancelButton->setCoord((maxWidth - mCancelButton->getTextSize().width - 24) / 2 + 8, mCancelButton->getTop(), mCancelButton->getTextSize().width + 24, mCancelButton->getHeight()); - if (Settings::gui().mControllerMenus) - { - mDisableGamepadCursor = true; - mItemButton->setStateSelected(true); - mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sCancel}"; - } - center(); } - bool QuickKeysMenuAssign::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - if (mControllerFocus == 0) - mParent->onItemButtonClicked(mItemButton); - else if (mControllerFocus == 1) - mParent->onMagicButtonClicked(mMagicButton); - else if (mControllerFocus == 2) - mParent->onUnassignButtonClicked(mUnassignButton); - else if (mControllerFocus == 3) - mParent->onCancelButtonClicked(mCancelButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - mParent->onCancelButtonClicked(mCancelButton); - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) - mControllerFocus = wrap(mControllerFocus - 1, 4); - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - mControllerFocus = wrap(mControllerFocus + 1, 4); - - mItemButton->setStateSelected(mControllerFocus == 0); - mMagicButton->setStateSelected(mControllerFocus == 1); - mUnassignButton->setStateSelected(mControllerFocus == 2); - mCancelButton->setStateSelected(mControllerFocus == 3); - - return true; - } - void QuickKeysMenu::write(ESM::ESMWriter& writer) { writer.startRecord(ESM::REC_KEYS); @@ -685,12 +603,6 @@ namespace MWGui mMagicList->setHighlightSelected(false); mMagicList->eventSpellClicked += MyGUI::newDelegate(this, &MagicSelectionDialog::onModelIndexSelected); - if (Settings::gui().mControllerMenus) - { - mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sCancel}"; - } - center(); } @@ -722,13 +634,4 @@ namespace MWGui mParent->onAssignMagic(spell.mId); } - bool MagicSelectionDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_B) - onCancelButtonClicked(mCancelButton); - else - mMagicList->onControllerButton(arg.button); - - return true; - } } diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index 228eb926b4..904029b9a0 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -72,9 +72,6 @@ namespace MWGui // Check if quick key is still valid inline void validate(int index); void unassign(keyData* key); - - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - int mControllerFocus; }; class QuickKeysMenuAssign : public WindowModal @@ -90,9 +87,6 @@ namespace MWGui MyGUI::Button* mCancelButton; QuickKeysMenu* mParent; - - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - int mControllerFocus; }; class MagicSelectionDialog : public WindowModal @@ -111,9 +105,6 @@ namespace MWGui void onCancelButtonClicked(MyGUI::Widget* sender); void onModelIndexSelected(SpellModel::ModelIndex index); - - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - int mControllerFocus; }; } diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index fdc8725fa0..7b445d419f 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -23,6 +23,16 @@ namespace { + int wrap(int index, int max) + { + if (index < 0) + return max - 1; + else if (index >= max) + return 0; + else + return index; + } + bool sortRaces(const std::pair& left, const std::pair& right) { return left.second.compare(right.second) < 0; @@ -98,23 +108,15 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu7", "Specials")); getWidget(mSpellPowerList, "SpellPowerList"); - getWidget(mBackButton, "BackButton"); - mBackButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onBackClicked); + MyGUI::Button* backButton; + getWidget(backButton, "BackButton"); + backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onBackClicked); - getWidget(mOkButton, "OKButton"); - mOkButton->setCaption( + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + okButton->setCaption( MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", {}))); - mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onOkClicked); - - if (Settings::gui().mControllerMenus) - { - mControllerButtons.lStick = "#{sMouse}"; - mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sBack}"; - mControllerButtons.y = "#{sSex}"; - mControllerButtons.l1 = "#{sHair}"; - mControllerButtons.r1 = "#{sFace}"; - } + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onOkClicked); updateRaces(); updateSkills(); @@ -127,17 +129,8 @@ namespace MWGui getWidget(okButton, "OKButton"); if (shown) - { okButton->setCaption( MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", {}))); - mControllerButtons.x = "#{sNext}"; - } - else if (Settings::gui().mControllerMenus) - { - okButton->setCaption( - MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sDone", {}))); - mControllerButtons.x = "#{sDone}"; - } else okButton->setCaption( MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", {}))); @@ -469,56 +462,6 @@ namespace MWGui } } - bool RaceDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_B) - { - onBackClicked(mBackButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_X) - { - onOkClicked(mOkButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_Y) - { - onSelectNextGender(nullptr); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) - { - onSelectNextHair(nullptr); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) - { - onSelectNextFace(nullptr); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) - { - MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); - winMgr->setKeyFocusWidget(mRaceList); - winMgr->injectKeyPress(MyGUI::KeyCode::ArrowUp, 0, false); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - { - MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); - winMgr->setKeyFocusWidget(mRaceList); - winMgr->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); - } - - return true; - } - - bool RaceDialog::onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) - { - if (arg.axis == SDL_CONTROLLER_AXIS_RIGHTX) - { - if (arg.value < -1000 || arg.value > 1000) - onPreviewScroll(nullptr, arg.value < 0 ? 1 : -1); - return true; - } - - return false; - } - const ESM::NPC& RaceDialog::getResult() const { return mPreview->getPrototype(); diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index ead058214c..a6ac0e2813 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -3,7 +3,6 @@ #include "windowbase.hpp" #include -#include #include namespace MWRender @@ -101,9 +100,7 @@ namespace MWGui MyGUI::ImageBox* mPreviewImage; MyGUI::ListBox* mRaceList; - Gui::ScrollBar* mHeadRotate; - MyGUI::Button* mBackButton; - MyGUI::Button* mOkButton; + MyGUI::ScrollBar* mHeadRotate; MyGUI::Widget* mSkillList; std::vector mSkillItems; @@ -121,9 +118,6 @@ namespace MWGui std::unique_ptr mPreviewTexture; bool mPreviewDirty; - - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) override; }; } #endif diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 2dfb47fa23..7d57988d97 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -39,10 +39,6 @@ namespace MWGui mBox->setDisplayMode(ItemChargeView::DisplayMode_EnchantmentCharge); mGemIcon->eventMouseButtonClick += MyGUI::newDelegate(this, &Recharge::onSelectItem); - - mControllerButtons.a = "#{OMWEngine:RechargeSelect}"; - mControllerButtons.b = "#{sCancel}"; - mControllerButtons.y = "#{sSoulGem}"; } void Recharge::onOpen() @@ -140,18 +136,4 @@ namespace MWGui updateView(); } - bool Recharge::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if ((arg.button == SDL_CONTROLLER_BUTTON_A && !mGemBox->getVisible()) || arg.button == SDL_CONTROLLER_BUTTON_Y) - { - onSelectItem(mGemIcon); - MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - onCancel(mCancelButton); - else - mBox->onControllerButton(arg.button); - - return true; - } } diff --git a/apps/openmw/mwgui/recharge.hpp b/apps/openmw/mwgui/recharge.hpp index c10f96e71e..f8a037d2db 100644 --- a/apps/openmw/mwgui/recharge.hpp +++ b/apps/openmw/mwgui/recharge.hpp @@ -51,8 +51,6 @@ namespace MWGui void onItemClicked(MyGUI::Widget* sender, const MWWorld::Ptr& item); void onCancel(MyGUI::Widget* sender); void onMouseWheel(MyGUI::Widget* _sender, int _rel); - - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; }; } diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 8962ae2abd..c1602b8407 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -39,10 +39,6 @@ namespace MWGui mRepairBox->setDisplayMode(ItemChargeView::DisplayMode_Health); mToolIcon->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onSelectItem); - - mControllerButtons.a = "#{sRepair}"; - mControllerButtons.b = "#{sCancel}"; - mControllerButtons.y = "#{OMWEngine:RepairTool}"; } void Repair::onOpen() @@ -154,18 +150,4 @@ namespace MWGui updateRepairView(); } - bool Repair::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if ((arg.button == SDL_CONTROLLER_BUTTON_A && !mToolBox->getVisible()) || arg.button == SDL_CONTROLLER_BUTTON_Y) - { - onSelectItem(mToolIcon); - MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - onCancel(mCancelButton); - else - mRepairBox->onControllerButton(arg.button); - - return true; - } } diff --git a/apps/openmw/mwgui/repair.hpp b/apps/openmw/mwgui/repair.hpp index 986b28b613..093a10e3fa 100644 --- a/apps/openmw/mwgui/repair.hpp +++ b/apps/openmw/mwgui/repair.hpp @@ -50,8 +50,6 @@ namespace MWGui void onRepairItem(MyGUI::Widget* sender, const MWWorld::Ptr& ptr); void onCancel(MyGUI::Widget* sender); - - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; }; } diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index dcaa49b1e2..ddce2c5f50 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -46,25 +46,21 @@ namespace MWGui getWidget(button, "NameButton"); adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onNameClicked); - mButtons.push_back(button); getWidget(mRaceWidget, "RaceText"); getWidget(button, "RaceButton"); adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onRaceClicked); - mButtons.push_back(button); getWidget(mClassWidget, "ClassText"); getWidget(button, "ClassButton"); adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onClassClicked); - mButtons.push_back(button); getWidget(mBirthSignWidget, "SignText"); getWidget(button, "SignButton"); adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBirthSignClicked); - mButtons.push_back(button); // Setup dynamic stats getWidget(mHealth, "Health"); @@ -112,22 +108,10 @@ namespace MWGui MyGUI::Button* backButton; getWidget(backButton, "BackButton"); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBackClicked); - mButtons.push_back(backButton); MyGUI::Button* okButton; getWidget(okButton, "OKButton"); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onOkClicked); - mButtons.push_back(okButton); - - if (Settings::gui().mControllerMenus) - { - setControllerFocus(mButtons, mControllerFocus, true); - mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sBack}"; - mControllerButtons.x = "#{sDone}"; - okButton->setCaption( - MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sDone", {}))); - } } void ReviewDialog::onOpen() @@ -538,54 +522,4 @@ namespace MWGui MyGUI::IntPoint(0, static_cast(mSkillView->getViewOffset().top + _rel * 0.3))); } - bool ReviewDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - switch (mControllerFocus) - { - case 0: - onNameClicked(mButtons[0]); - break; - case 1: - onRaceClicked(mButtons[1]); - break; - case 2: - onClassClicked(mButtons[2]); - break; - case 3: - onBirthSignClicked(mButtons[3]); - break; - case 4: - onBackClicked(mButtons[4]); - break; - case 5: - onOkClicked(mButtons[5]); - break; - } - return true; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - { - onBackClicked(mButtons[4]); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_X) - { - onOkClicked(mButtons[5]); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP || arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) - { - setControllerFocus(mButtons, mControllerFocus, false); - mControllerFocus = wrap(mControllerFocus - 1, mButtons.size()); - setControllerFocus(mButtons, mControllerFocus, true); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN || arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) - { - setControllerFocus(mButtons, mControllerFocus, false); - mControllerFocus = wrap(mControllerFocus + 1, mButtons.size()); - setControllerFocus(mButtons, mControllerFocus, true); - } - - return true; - } } diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index fe53787fe3..7226ad628d 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -72,7 +72,6 @@ namespace MWGui void onBirthSignClicked(MyGUI::Widget* _sender); void onMouseWheel(MyGUI::Widget* _sender, int _rel); - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; private: void addSkills(const std::vector& skills, const std::string& titleId, @@ -101,10 +100,6 @@ namespace MWGui std::vector mSkillWidgets; //< Skills and other information bool mUpdateSkillArea; - - // 0 = Name, 1 = Race, 2 = Class, 3 = BirthSign, 4 = Back, 5 = OK - std::vector mButtons; - int mControllerFocus = 5; }; } #endif diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index e0b10f6b37..4957789ffd 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -29,7 +28,6 @@ #include "../mwbase/world.hpp" #include "../mwworld/datetimemanager.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwworld/timestamp.hpp" #include "../mwstate/character.hpp" @@ -66,9 +64,6 @@ namespace MWGui // To avoid accidental deletions mDeleteButton->setNeedKeyFocus(false); - - mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sCancel}"; } void SaveGameDialog::onSlotActivated(MyGUI::ListBox* sender, size_t pos) @@ -150,28 +145,6 @@ namespace MWGui WindowModal::onOpen(); mSaveNameEdit->setCaption({}); - if (Settings::gui().mControllerMenus && mSaving) - { - // For controller mode, set a default save file name. The format is - // "Day 24 - Last Steed 7 p.m." - const MWWorld::DateTimeManager& timeManager = *MWBase::Environment::get().getWorld()->getTimeManager(); - std::string_view month = timeManager.getMonthName(); - int hour = static_cast(timeManager.getTimeStamp().getHour()); - bool pm = hour >= 12; - if (hour >= 13) - hour -= 12; - if (hour == 0) - hour = 12; - - ESM::EpochTimeStamp currentDate = timeManager.getEpochTimeStamp(); - std::string daysPassed - = Misc::StringUtils::format("#{Calendar:day} %i", timeManager.getTimeStamp().getDay()); - std::string_view formattedHour(pm ? "#{Calendar:pm}" : "#{Calendar:am}"); - std::string autoFilename = Misc::StringUtils::format( - "%s - %i %s %i %s", daysPassed, currentDate.mDay, month, hour, formattedHour); - - mSaveNameEdit->setCaptionWithReplacing(autoFilename); - } if (mSaving) MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveNameEdit); else @@ -186,13 +159,6 @@ namespace MWGui mSaveList->removeAllItems(); onSlotSelected(mSaveList, MyGUI::ITEM_NONE); - if (Settings::gui().mControllerMenus) - { - mOkButtonFocus = true; - mOkButton->setStateSelected(true); - mCancelButton->setStateSelected(false); - } - MWBase::StateManager* mgr = MWBase::Environment::get().getStateManager(); if (mgr->characterBegin() == mgr->characterEnd()) return; @@ -251,7 +217,7 @@ namespace MWGui } mCharacterSelection->setIndexSelected(selectedIndex); if (selectedIndex == MyGUI::ITEM_NONE) - mCharacterSelection->setCaptionWithReplacing("#{OMWEngine:SelectCharacter}..."); + mCharacterSelection->setCaptionWithReplacing("#{OMWEngine:SelectCharacter}"); fillSaveList(); } @@ -525,55 +491,4 @@ namespace MWGui mScreenshotTexture = std::make_unique(texture); mScreenshot->setRenderItemTexture(mScreenshotTexture.get()); } - - ControllerButtonStr* SaveGameDialog::getControllerButtons() - { - mControllerButtons.y = mSaving ? "" : "#{OMWEngine:SelectCharacter}"; - return &mControllerButtons; - } - - bool SaveGameDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - if (mOkButtonFocus) - onOkButtonClicked(mOkButton); - else - onCancelButtonClicked(mCancelButton); - MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - { - onCancelButtonClicked(mCancelButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_Y) - { - uint32_t index = mCharacterSelection->getIndexSelected(); - index = wrap(index + 1, mCharacterSelection->getItemCount()); - mCharacterSelection->setIndexSelected(index); - onCharacterSelected(mCharacterSelection, index); - MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) - { - MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); - winMgr->setKeyFocusWidget(mSaveList); - winMgr->injectKeyPress(MyGUI::KeyCode::ArrowUp, 0, false); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - { - MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); - winMgr->setKeyFocusWidget(mSaveList); - winMgr->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); - } - else if ((arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && !mOkButtonFocus) - || (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && mOkButtonFocus)) - { - mOkButtonFocus = !mOkButtonFocus; - mOkButton->setStateSelected(mOkButtonFocus); - mCancelButton->setStateSelected(!mOkButtonFocus); - } - - return true; - } } diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index 13c4588d3f..af831f066e 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -24,8 +24,6 @@ namespace MWGui void setLoadOrSave(bool load); - ControllerButtonStr* getControllerButtons() override; - private: void confirmDeleteSave(); @@ -69,9 +67,6 @@ namespace MWGui const MWState::Character* mCurrentCharacter; const MWState::Slot* mCurrentSlot; - - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - bool mOkButtonFocus = true; }; } diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 59fb1f2d20..0b1658fd84 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -7,7 +7,6 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/inputmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwmechanics/actorutil.hpp" @@ -39,10 +38,6 @@ namespace MWGui mCloseButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &ScrollWindow::onKeyButtonPressed); mTakeButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &ScrollWindow::onKeyButtonPressed); - mControllerScrollWidget = mTextView; - mControllerButtons.b = "#{sClose}"; - mControllerButtons.dpad = "#{sScrolldown}"; - center(); } @@ -120,32 +115,4 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); } - - void ScrollWindow::onClose() - { - if (Settings::gui().mControllerMenus) - MWBase::Environment::get().getInputManager()->setGamepadGuiCursorEnabled(true); - BookWindowBase::onClose(); - } - - ControllerButtonStr* ScrollWindow::getControllerButtons() - { - mControllerButtons.a = mTakeButton->getVisible() ? "#{sTake}" : ""; - return &mControllerButtons; - } - - bool ScrollWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - if (mTakeButton->getVisible()) - onTakeButtonClicked(mTakeButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - onCloseButtonClicked(mCloseButton); - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP || arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - return false; // Fall through to keyboard - - return true; - } } diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 314925c7a7..7daea98894 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -20,19 +20,15 @@ namespace MWGui void setPtr(const MWWorld::Ptr& scroll) override; void setInventoryAllowed(bool allowed); - void onClose() override; void onResChange(int, int) override { center(); } std::string_view getWindowIdForLua() const override { return "Scroll"; } - ControllerButtonStr* getControllerButtons() override; - protected: void onCloseButtonClicked(MyGUI::Widget* _sender); void onTakeButtonClicked(MyGUI::Widget* _sender); void setTakeButtonShow(bool show); void onKeyButtonPressed(MyGUI::Widget* sender, MyGUI::KeyCode key, MyGUI::Char character); - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; private: Gui::ImageButton* mCloseButton; diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 726809c583..02353c5d41 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -459,10 +459,6 @@ namespace MWGui i++; } - - mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sOk}"; - mControllerButtons.lStick = "#{sMouse}"; } void SettingsWindow::onTabChanged(MyGUI::TabControl* /*_sender*/, size_t /*index*/) @@ -472,7 +468,7 @@ namespace MWGui void SettingsWindow::onOkButtonClicked(MyGUI::Widget* _sender) { - MWBase::Environment::get().getWindowManager()->toggleSettingsWindow(); + setVisible(false); } void SettingsWindow::onResolutionSelected(MyGUI::ListBox* _sender, size_t index) @@ -1132,32 +1128,4 @@ namespace MWGui mResolutionList->setScrollPosition(0); mControlsBox->setViewOffset(MyGUI::IntPoint(0, 0)); } - - bool SettingsWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_B) - { - onOkButtonClicked(mOkButton); - return true; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) - { - uint32_t index = mSettingsTab->getIndexSelected(); - index = wrap(index - 1, mSettingsTab->getItemCount()); - mSettingsTab->setIndexSelected(index); - MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); - return true; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) - { - uint32_t index = mSettingsTab->getIndexSelected(); - index = wrap(index + 1, mSettingsTab->getItemCount()); - mSettingsTab->setIndexSelected(index); - MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); - return true; - } - - return false; - } - } diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 555468d806..dc4e09f8ac 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -26,8 +26,6 @@ namespace MWGui void onResChange(int, int) override; - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - protected: MyGUI::TabControl* mSettingsTab; MyGUI::Button* mOkButton; diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index e43bbfc497..2a67af5498 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -9,7 +9,6 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/inputmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" @@ -33,14 +32,6 @@ namespace MWGui getWidget(mSpellsView, "SpellsView"); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellBuyingWindow::onCancelButtonClicked); - - if (Settings::gui().mControllerMenus) - { - mDisableGamepadCursor = true; - mControllerButtons.a = "#{sBuy}"; - mControllerButtons.b = "#{sCancel}"; - mControllerButtons.r3 = "#{sInfo}"; - } } bool SpellBuyingWindow::sortSpells(const ESM::Spell* left, const ESM::Spell* right) @@ -80,8 +71,6 @@ namespace MWGui toAdd->setUserString("SpellCost", std::to_string(spell.mData.mCost)); toAdd->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellBuyingWindow::onSpellButtonClick); mSpellsWidgetMap.insert(std::make_pair(toAdd, spell.mId)); - if (price <= playerGold) - mSpellButtons.emplace_back(std::make_pair(toAdd, mSpellsWidgetMap.size())); } void SpellBuyingWindow::clearSpells() @@ -91,7 +80,6 @@ namespace MWGui while (mSpellsView->getChildCount()) MyGUI::Gui::getInstance().destroyWidget(mSpellsView->getChildAt(0)); mSpellsWidgetMap.clear(); - mSpellButtons.clear(); } void SpellBuyingWindow::setPtr(const MWWorld::Ptr& actor) @@ -142,18 +130,6 @@ namespace MWGui updateLabels(); - if (Settings::gui().mControllerMenus) - { - mControllerFocus = 0; - if (mSpellButtons.size() > 0) - mSpellButtons[0].first->setStateSelected(true); - - MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); - winMgr->setControllerTooltip(Settings::gui().mControllerTooltips); - if (winMgr->getControllerTooltip()) - MWBase::Environment::get().getInputManager()->warpMouseToWidget(mSpellButtons[0].first); - } - // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the // scrollbar is hidden mSpellsView->setVisibleVScroll(false); @@ -224,60 +200,4 @@ namespace MWGui mSpellsView->setViewOffset( MyGUI::IntPoint(0, static_cast(mSpellsView->getViewOffset().top + _rel * 0.3f))); } - - bool SpellBuyingWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - if (mControllerFocus >= 0 && mControllerFocus < static_cast(mSpellButtons.size())) - onSpellButtonClick(mSpellButtons[mControllerFocus].first); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - { - onCancelButtonClicked(mCancelButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK) - { - // Toggle info tooltip - MWBase::Environment::get().getWindowManager()->setControllerTooltip( - !MWBase::Environment::get().getWindowManager()->getControllerTooltip()); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) - { - if (mSpellButtons.size() <= 1) - return true; - - mSpellButtons[mControllerFocus].first->setStateSelected(false); - mControllerFocus = wrap(mControllerFocus - 1, mSpellButtons.size()); - mSpellButtons[mControllerFocus].first->setStateSelected(true); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - { - if (mSpellButtons.size() <= 1) - return true; - - mSpellButtons[mControllerFocus].first->setStateSelected(false); - mControllerFocus = wrap(mControllerFocus + 1, mSpellButtons.size()); - mSpellButtons[mControllerFocus].first->setStateSelected(true); - } - - if (mControllerFocus >= 0 && mControllerFocus < static_cast(mSpellButtons.size())) - { - // Scroll the list to keep the active item in view - int line = mSpellButtons[mControllerFocus].second; - if (line <= 5) - mSpellsView->setViewOffset(MyGUI::IntPoint(0, 0)); - else - { - const int lineHeight = Settings::gui().mFontSize + 2; - mSpellsView->setViewOffset(MyGUI::IntPoint(0, -lineHeight * (line - 5))); - } - - // Warp the mouse to the selected spell to show the tooltip - if (MWBase::Environment::get().getWindowManager()->getControllerTooltip()) - MWBase::Environment::get().getInputManager()->warpMouseToWidget(mSpellButtons[mControllerFocus].first); - } - - return true; - } } diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index e67dfde76c..257b8a0df9 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -39,8 +39,6 @@ namespace MWGui MyGUI::ScrollView* mSpellsView; std::map mSpellsWidgetMap; - /// List of enabled/purchasable spells and their index in the full list. - std::vector> mSpellButtons; void onCancelButtonClicked(MyGUI::Widget* _sender); void onSpellButtonClick(MyGUI::Widget* _sender); @@ -57,8 +55,6 @@ namespace MWGui private: static bool sortSpells(const ESM::Spell* left, const ESM::Spell* right); - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - int mControllerFocus; }; } diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 976c2eebd8..d8302df87c 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -7,13 +7,11 @@ #include #include -#include #include #include #include "../mwbase/environment.hpp" -#include "../mwbase/inputmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" @@ -27,8 +25,8 @@ #include "../mwmechanics/spellutil.hpp" #include "class.hpp" -#include "textcolours.hpp" #include "tooltips.hpp" +#include "widgets.hpp" namespace { @@ -97,13 +95,6 @@ namespace MWGui += MyGUI::newDelegate(this, &EditEffectDialog::onMagnitudeMaxChanged); mDurationSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &EditEffectDialog::onDurationChanged); mAreaSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &EditEffectDialog::onAreaChanged); - - if (Settings::gui().mControllerMenus) - { - mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sCancel}"; - mControllerButtons.x = "#{sOk}"; - } } void EditEffectDialog::setConstantEffect(bool constant) @@ -163,15 +154,6 @@ namespace MWGui mMagnitudeMaxValue->setCaption(to + " 1"); mAreaValue->setCaption("0"); - if (Settings::gui().mControllerMenus) - { - mRangeButton->setStateSelected(true); - mDeleteButton->setStateSelected(false); - mOkButton->setStateSelected(false); - mCancelButton->setStateSelected(false); - mControllerFocus = 0; - } - setVisible(true); } @@ -205,15 +187,6 @@ namespace MWGui onDurationChanged(mDurationSlider, effect.mDuration - 1); eventEffectModified(mEffect); - if (Settings::gui().mControllerMenus) - { - mRangeButton->setStateSelected(true); - mDeleteButton->setStateSelected(false); - mOkButton->setStateSelected(false); - mCancelButton->setStateSelected(false); - mControllerFocus = 0; - } - updateBoxes(); } @@ -258,25 +231,6 @@ namespace MWGui mAreaBox->setVisible(true); // curY += mAreaBox->getSize().height; } - - if (Settings::gui().mControllerMenus) - { - mButtons.clear(); - mButtons.emplace_back(mRangeButton); - if (mMagnitudeBox->getVisible()) - { - mButtons.emplace_back(mMagnitudeMinValue); - mButtons.emplace_back(mMagnitudeMaxValue); - } - if (mDurationBox->getVisible()) - mButtons.emplace_back(mDurationValue); - if (mAreaBox->getVisible()) - mButtons.emplace_back(mAreaValue); - if (mDeleteButton->getVisible()) - mButtons.emplace_back(mDeleteButton); - mButtons.emplace_back(mOkButton); - mButtons.emplace_back(mCancelButton); - } } void EditEffectDialog::onRangeButtonClicked(MyGUI::Widget* sender) @@ -386,195 +340,6 @@ namespace MWGui eventEffectModified(mEffect); } - bool EditEffectDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - int prevFocus = mControllerFocus; - mControllerFocus = std::clamp(mControllerFocus, 0, static_cast(mButtons.size()) - 1); - MyGUI::TextBox* button = mButtons[mControllerFocus]; - - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - if (button == mRangeButton) - onRangeButtonClicked(mRangeButton); - else if (button == mCancelButton) - onCancelButtonClicked(mCancelButton); - else if (button == mOkButton) - onOkButtonClicked(mOkButton); - else if (button == mDeleteButton) - onDeleteButtonClicked(mDeleteButton); - MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - onCancelButtonClicked(mCancelButton); - else if (arg.button == SDL_CONTROLLER_BUTTON_X) - { - onOkButtonClicked(mOkButton); - MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) - { - if (mControllerFocus == 0) - mControllerFocus = static_cast(mButtons.size()) - 2; - else if (button == mCancelButton && mDeleteButton->getVisible()) - mControllerFocus -= 3; - else if (button == mCancelButton || (button == mOkButton && mDeleteButton->getVisible())) - mControllerFocus -= 2; - else - mControllerFocus = std::max(mControllerFocus - 1, 0); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - { - if (button == mDeleteButton || button == mOkButton || button == mCancelButton) - mControllerFocus = 0; - else - mControllerFocus++; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) - { - if (button == mMagnitudeMinValue) - { - mMagnitudeMinSlider->setScrollPosition(0); - onMagnitudeMinChanged(nullptr, mMagnitudeMinSlider->getScrollPosition()); - } - else if (button == mMagnitudeMaxValue) - { - mMagnitudeMaxSlider->setScrollPosition(mMagnitudeMinSlider->getScrollPosition()); - onMagnitudeMaxChanged(nullptr, mMagnitudeMaxSlider->getScrollPosition()); - } - else if (button == mDurationValue) - { - mDurationSlider->setScrollPosition(0); - onDurationChanged(nullptr, mDurationSlider->getScrollPosition()); - } - else if (button == mAreaValue) - { - mAreaSlider->setScrollPosition(0); - onAreaChanged(nullptr, mAreaSlider->getScrollPosition()); - } - } - else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) - { - if (button == mMagnitudeMinValue) - { - mMagnitudeMinSlider->setScrollPosition(mMagnitudeMaxSlider->getScrollPosition()); - onMagnitudeMinChanged(nullptr, mMagnitudeMinSlider->getScrollPosition()); - } - else if (button == mMagnitudeMaxValue) - { - mMagnitudeMaxSlider->setScrollPosition(mMagnitudeMaxSlider->getScrollRange() - 1); - onMagnitudeMaxChanged(nullptr, mMagnitudeMaxSlider->getScrollPosition()); - } - else if (button == mDurationValue) - { - mDurationSlider->setScrollPosition(mDurationSlider->getScrollRange() - 1); - onDurationChanged(nullptr, mDurationSlider->getScrollPosition()); - } - else if (button == mAreaValue) - { - mAreaSlider->setScrollPosition(mAreaSlider->getScrollRange() - 1); - onAreaChanged(nullptr, mAreaSlider->getScrollPosition()); - } - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) - { - if (button == mRangeButton) - onRangeButtonClicked(mRangeButton); - else if (button == mCancelButton) - mControllerFocus--; - else if (button == mOkButton && mDeleteButton->getVisible()) - mControllerFocus--; - else if (button == mMagnitudeMinValue) - { - mMagnitudeMinSlider->setScrollPosition(mMagnitudeMinSlider->getScrollPosition() - 1); - onMagnitudeMinChanged(nullptr, mMagnitudeMinSlider->getScrollPosition()); - } - else if (button == mMagnitudeMaxValue) - { - mMagnitudeMaxSlider->setScrollPosition( - std::max(mMagnitudeMaxSlider->getScrollPosition() - 1, mMagnitudeMinSlider->getScrollPosition())); - onMagnitudeMaxChanged(nullptr, mMagnitudeMaxSlider->getScrollPosition()); - } - else if (button == mDurationValue) - { - mDurationSlider->setScrollPosition(mDurationSlider->getScrollPosition() - 1); - onDurationChanged(nullptr, mDurationSlider->getScrollPosition()); - } - else if (button == mAreaValue) - { - mAreaSlider->setScrollPosition(mAreaSlider->getScrollPosition() - 1); - onAreaChanged(nullptr, mAreaSlider->getScrollPosition()); - } - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) - { - if (button == mRangeButton) - onRangeButtonClicked(mRangeButton); - else if (button == mDeleteButton) - mControllerFocus++; - else if (button == mOkButton) - mControllerFocus++; - else if (button == mMagnitudeMinValue) - { - mMagnitudeMinSlider->setScrollPosition( - std::min(mMagnitudeMinSlider->getScrollPosition() + 1, mMagnitudeMaxSlider->getScrollPosition())); - onMagnitudeMinChanged(nullptr, mMagnitudeMinSlider->getScrollPosition()); - } - else if (button == mMagnitudeMaxValue) - { - mMagnitudeMaxSlider->setScrollPosition(mMagnitudeMaxSlider->getScrollPosition() + 1); - onMagnitudeMaxChanged(nullptr, mMagnitudeMaxSlider->getScrollPosition()); - } - else if (button == mDurationValue) - { - mDurationSlider->setScrollPosition(mDurationSlider->getScrollPosition() + 1); - onDurationChanged(nullptr, mDurationSlider->getScrollPosition()); - } - else if (button == mAreaValue) - { - mAreaSlider->setScrollPosition(mAreaSlider->getScrollPosition() + 1); - onAreaChanged(nullptr, mAreaSlider->getScrollPosition()); - } - } - - if (prevFocus != mControllerFocus) - updateControllerFocus(prevFocus, mControllerFocus); - - return true; - } - - void EditEffectDialog::updateControllerFocus(int prevFocus, int newFocus) - { - const TextColours& textColours{ MWBase::Environment::get().getWindowManager()->getTextColours() }; - - if (prevFocus >= 0 && prevFocus < static_cast(mButtons.size())) - { - MyGUI::TextBox* button = mButtons[prevFocus]; - if (button == mMagnitudeMinValue || button == mMagnitudeMaxValue || button == mDurationValue - || button == mAreaValue) - { - button->setTextColour(textColours.normal); - } - else - { - ((MyGUI::Button*)button)->setStateSelected(false); - } - } - - if (newFocus >= 0 && newFocus < static_cast(mButtons.size())) - { - MyGUI::TextBox* button = mButtons[newFocus]; - if (button == mMagnitudeMinValue || button == mMagnitudeMaxValue || button == mDurationValue - || button == mAreaValue) - { - button->setTextColour(textColours.link); - } - else - { - ((MyGUI::Button*)button)->setStateSelected(true); - } - } - } - // ------------------------------------------------------------------------------------------------ SpellCreationDialog::SpellCreationDialog() @@ -595,14 +360,6 @@ namespace MWGui mNameEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &SpellCreationDialog::onAccept); setWidgets(mAvailableEffectsList, mUsedEffectsView); - - if (Settings::gui().mControllerMenus) - { - mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sCancel}"; - mControllerButtons.x = "#{sBuy}"; - mControllerButtons.r3 = "#{sInfo}"; - } } void SpellCreationDialog::setPtr(const MWWorld::Ptr& actor) @@ -733,22 +490,6 @@ namespace MWGui mSuccessChance->setCaption(MyGUI::utility::toString(intChance)); } - bool SpellCreationDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_B) - { - onCancelButtonClicked(mCancelButton); - return true; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_X) - { - onBuyButtonClicked(mBuyButton); - return true; - } - else - return EffectEditorBase::onControllerButtonEvent(arg); - } - // ------------------------------------------------------------------------------------------------ EffectEditorBase::EffectEditorBase(Type type) @@ -820,7 +561,6 @@ namespace MWGui mAvailableEffectsList->adjustSize(); mAvailableEffectsList->scrollToTop(); - mAvailableButtons.clear(); for (const short effectId : knownEffects) { const std::string& name = MWBase::Environment::get() @@ -828,27 +568,13 @@ namespace MWGui ->get() .find(ESM::MagicEffect::indexToGmstString(effectId)) ->mValue.getString(); - MyGUI::Button* w = mAvailableEffectsList->getItemWidget(name); - mAvailableButtons.emplace_back(w); + MyGUI::Widget* w = mAvailableEffectsList->getItemWidget(name); ToolTips::createMagicEffectToolTip(w, effectId); } mEffects.clear(); updateEffectsView(); - - if (Settings::gui().mControllerMenus) - { - mAvailableFocus = 0; - mEffectFocus = 0; - mRightColumn = false; - if (mAvailableButtons.size() > 0) - { - mAvailableButtons[0]->setStateSelected(true); - if (MWBase::Environment::get().getWindowManager()->getControllerTooltip()) - MWBase::Environment::get().getInputManager()->warpMouseToWidget(mAvailableButtons[0]); - } - } } void EffectEditorBase::setWidgets(Gui::MWList* availableEffectsList, MyGUI::ScrollView* usedEffectsView) @@ -960,7 +686,6 @@ namespace MWGui MyGUI::IntSize size(0, 0); - mEffectButtons.clear(); int i = 0; for (const ESM::ENAMstruct& effectInfo : mEffects) { @@ -993,8 +718,6 @@ namespace MWGui size.width = std::max(size.width, effect->getRequestedWidth()); size.height += 24; ++i; - - mEffectButtons.emplace_back(std::pair(effect, button)); } // Canvas size must be expressed with HScroll disabled, otherwise MyGUI would expand the scroll area when the @@ -1032,100 +755,4 @@ namespace MWGui effect.mRange = ESM::RT_Self; mConstantEffect = constant; } - - bool EffectEditorBase::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); - - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - if (!mRightColumn && mAvailableFocus >= 0 && mAvailableFocus < static_cast(mAvailableButtons.size())) - { - onAvailableEffectClicked(mAvailableButtons[mAvailableFocus]); - winMgr->playSound(ESM::RefId::stringRefId("Menu Click")); - } - else if (mRightColumn && mEffectFocus >= 0 && mEffectFocus < static_cast(mEffectButtons.size())) - { - onEditEffect(mEffectButtons[mEffectFocus].second); - winMgr->playSound(ESM::RefId::stringRefId("Menu Click")); - } - } - else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK) - { - // Toggle info tooltip - winMgr->setControllerTooltip(!mRightColumn && !winMgr->getControllerTooltip()); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) - { - if (mRightColumn && mEffectButtons.size() > 0) - { - if (mEffectFocus >= 0 && mEffectFocus < static_cast(mEffectButtons.size())) - mEffectButtons[mEffectFocus].first->setStateSelected(false); - mEffectFocus = wrap(mEffectFocus - 1, mEffectButtons.size()); - mEffectButtons[mEffectFocus].first->setStateSelected(true); - } - else if (!mRightColumn && mAvailableButtons.size() > 0) - { - if (mAvailableFocus >= 0 && mAvailableFocus < static_cast(mAvailableButtons.size())) - mAvailableButtons[mAvailableFocus]->setStateSelected(false); - mAvailableFocus = wrap(mAvailableFocus - 1, mAvailableButtons.size()); - mAvailableButtons[mAvailableFocus]->setStateSelected(true); - } - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - { - if (mRightColumn && mEffectButtons.size() > 0) - { - if (mEffectFocus >= 0 && mEffectFocus < static_cast(mEffectButtons.size())) - mEffectButtons[mEffectFocus].first->setStateSelected(false); - mEffectFocus = wrap(mEffectFocus + 1, mEffectButtons.size()); - mEffectButtons[mEffectFocus].first->setStateSelected(true); - } - else if (!mRightColumn && mAvailableButtons.size() > 0) - { - if (mAvailableFocus >= 0 && mAvailableFocus < static_cast(mAvailableButtons.size())) - mAvailableButtons[mAvailableFocus]->setStateSelected(false); - mAvailableFocus = wrap(mAvailableFocus + 1, mAvailableButtons.size()); - mAvailableButtons[mAvailableFocus]->setStateSelected(true); - } - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && mRightColumn) - { - mRightColumn = false; - if (mEffectFocus >= 0 && mEffectFocus < static_cast(mEffectButtons.size())) - mEffectButtons[mEffectFocus].first->setStateSelected(false); - if (mAvailableFocus >= 0 && mAvailableFocus < static_cast(mAvailableButtons.size())) - mAvailableButtons[mAvailableFocus]->setStateSelected(true); - - winMgr->setControllerTooltip(Settings::gui().mControllerTooltips); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && !mRightColumn && mEffectButtons.size() > 0) - { - mRightColumn = true; - if (mAvailableFocus >= 0 && mAvailableFocus < static_cast(mAvailableButtons.size())) - mAvailableButtons[mAvailableFocus]->setStateSelected(false); - if (mEffectFocus >= 0 && mEffectFocus < static_cast(mEffectButtons.size())) - mEffectButtons[mEffectFocus].first->setStateSelected(true); - - winMgr->setControllerTooltip(false); - } - - // Scroll the list to keep the active item in view - if (mAvailableFocus <= 5) - mAvailableEffectsList->setViewOffset(0); - else - { - const int lineHeight = Settings::gui().mFontSize + 3; - mAvailableEffectsList->setViewOffset(-lineHeight * (mAvailableFocus - 5)); - } - - if (!mRightColumn && mAvailableFocus >= 0 && mAvailableFocus < static_cast(mAvailableButtons.size())) - { - // Warp the mouse to the selected spell to show the tooltip - if (winMgr->getControllerTooltip()) - MWBase::Environment::get().getInputManager()->warpMouseToWidget(mAvailableButtons[mAvailableFocus]); - } - - return true; - } } diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index 2a4f5dcbb3..6dfe61fc57 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -1,15 +1,12 @@ #ifndef MWGUI_SPELLCREATION_H #define MWGUI_SPELLCREATION_H -#include #include #include #include -#include #include "referenceinterface.hpp" -#include "widgets.hpp" #include "windowbase.hpp" namespace Gui @@ -60,10 +57,10 @@ namespace MWGui MyGUI::TextBox* mDurationValue; MyGUI::TextBox* mAreaValue; - Gui::ScrollBar* mMagnitudeMinSlider; - Gui::ScrollBar* mMagnitudeMaxSlider; - Gui::ScrollBar* mDurationSlider; - Gui::ScrollBar* mAreaSlider; + MyGUI::ScrollBar* mMagnitudeMinSlider; + MyGUI::ScrollBar* mMagnitudeMaxSlider; + MyGUI::ScrollBar* mDurationSlider; + MyGUI::ScrollBar* mAreaSlider; MyGUI::TextBox* mAreaText; @@ -86,18 +83,13 @@ namespace MWGui void updateBoxes(); - private: + protected: ESM::ENAMstruct mEffect; ESM::ENAMstruct mOldEffect; const ESM::MagicEffect* mMagicEffect; bool mConstantEffect; - - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - void updateControllerFocus(int prevFocus, int newFocus); - int mControllerFocus; - std::vector mButtons; }; class EffectEditorBase @@ -150,16 +142,8 @@ namespace MWGui virtual void notifyEffectsChanged() {} - virtual bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg); - private: Type mType; - - int mAvailableFocus; - int mEffectFocus; - bool mRightColumn; - std::vector mAvailableButtons; - std::vector> mEffectButtons; }; class SpellCreationDialog : public WindowBase, public ReferenceInterface, public EffectEditorBase @@ -182,7 +166,6 @@ namespace MWGui void onCancelButtonClicked(MyGUI::Widget* sender); void onBuyButtonClicked(MyGUI::Widget* sender); void onAccept(MyGUI::EditBox* sender); - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; void notifyEffectsChanged() override; diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index a3eef23092..678f6ffe1f 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -9,10 +9,6 @@ #include #include -#include "../mwbase/environment.hpp" -#include "../mwbase/inputmanager.hpp" -#include "../mwbase/windowmanager.hpp" - #include "tooltips.hpp" namespace MWGui @@ -32,8 +28,6 @@ namespace MWGui : mScrollView(nullptr) , mShowCostColumn(true) , mHighlightSelected(true) - , mControllerActiveWindow(false) - , mControllerFocus(0) { } @@ -94,8 +88,6 @@ namespace MWGui const int spellHeight = Settings::gui().mFontSize + 2; mLines.clear(); - mButtons.clear(); - mGroupIndices.clear(); while (mScrollView->getChildCount()) MyGUI::Gui::getInstance().destroyWidget(mScrollView->getChildAt(0)); @@ -114,9 +106,7 @@ namespace MWGui curType = spell.mType; } - std::string skin = spell.mActive ? "SandTextButton" : "SpellTextUnequipped"; - if (Settings::gui().mControllerMenus) - skin = spell.mActive ? "SpellTextEquippedController" : "SpellTextUnequippedController"; + const std::string skin = spell.mActive ? "SandTextButton" : "SpellTextUnequipped"; const std::string captionSuffix = MWGui::ToolTips::getCountString(spell.mCount); Gui::SharedStateButton* t = mScrollView->createWidget( @@ -125,7 +115,6 @@ namespace MWGui t->setCaption(spell.mName + captionSuffix); t->setTextAlign(MyGUI::Align::Left); adjustSpellWidget(spell, i, t); - mButtons.emplace_back(std::make_pair(t, i)); if (!spell.mCostColumn.empty() && mShowCostColumn) { @@ -232,12 +221,6 @@ namespace MWGui height += lineHeight; } - if (Settings::gui().mControllerMenus) - { - mControllerFocus = wrap(mControllerFocus, mButtons.size()); - updateControllerFocus(-1, mControllerFocus); - } - // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the // scrollbar is hidden mScrollView->setVisibleVScroll(false); @@ -273,8 +256,6 @@ namespace MWGui } else mLines.emplace_back(groupWidget, (MyGUI::Widget*)nullptr, NoSpellIndex); - - mGroupIndices.push_back(mButtons.size()); } void SpellView::setSize(const MyGUI::IntSize& _value) @@ -335,110 +316,4 @@ namespace MWGui { mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); } - - void SpellView::setActiveControllerWindow(bool active) - { - mControllerActiveWindow = active; - if (active) - update(); - } - - void SpellView::onControllerButton(const unsigned char button) - { - if (mButtons.empty()) - return; - - int prevFocus = mControllerFocus; - - if (button == SDL_CONTROLLER_BUTTON_A) - { - // Select the focused item, if any. - if (mControllerFocus >= 0 && mControllerFocus < static_cast(mButtons.size())) - { - onSpellSelected(mButtons[mControllerFocus].first); - MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); - } - } - else if (button == SDL_CONTROLLER_BUTTON_RIGHTSTICK) - { - // Toggle info tooltip - MWBase::Environment::get().getWindowManager()->setControllerTooltip( - !MWBase::Environment::get().getWindowManager()->getControllerTooltip()); - } - else if (button == SDL_CONTROLLER_BUTTON_DPAD_UP) - mControllerFocus--; - else if (button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - mControllerFocus++; - else if (button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) - mControllerFocus = std::max(0, mControllerFocus - 10); - else if (button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) - mControllerFocus = std::min(mControllerFocus + 10, static_cast(mButtons.size()) - 1); - else if (button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) - { - // Jump to first item in previous group - int prevGroupIndex = 0; - for (int groupIndex : mGroupIndices) - { - if (groupIndex >= mControllerFocus) - break; - else - prevGroupIndex = groupIndex; - } - mControllerFocus = prevGroupIndex; - } - else if (button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) - { - // Jump to first item in next group - for (int groupIndex : mGroupIndices) - { - if (groupIndex > mControllerFocus) - { - mControllerFocus = groupIndex; - break; - } - } - } - - mControllerFocus = wrap(mControllerFocus, mButtons.size()); - - if (prevFocus != mControllerFocus) - updateControllerFocus(prevFocus, mControllerFocus); - else - updateControllerFocus(-1, mControllerFocus); - } - - void SpellView::updateControllerFocus(int prevFocus, int newFocus) - { - if (mButtons.empty()) - return; - - if (prevFocus >= 0 && prevFocus < static_cast(mButtons.size())) - { - Gui::SharedStateButton* prev = mButtons[prevFocus].first; - if (prev) - prev->onMouseLostFocus(nullptr); - } - - if (mControllerActiveWindow && newFocus >= 0 && newFocus < static_cast(mButtons.size())) - { - Gui::SharedStateButton* focused = mButtons[newFocus].first; - if (focused) - { - focused->onMouseSetFocus(nullptr); - - // Scroll the list to keep the active item in view - int line = mButtons[newFocus].second; - if (line <= 5) - mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); - else - { - const int lineHeight = focused->getHeight(); - mScrollView->setViewOffset(MyGUI::IntPoint(0, -lineHeight * (line - 5))); - } - - if (MWBase::Environment::get().getWindowManager()->getControllerTooltip()) - MWBase::Environment::get().getInputManager()->warpMouseToWidget(focused); - } - } - } } diff --git a/apps/openmw/mwgui/spellview.hpp b/apps/openmw/mwgui/spellview.hpp index a2571cd822..caff43a33e 100644 --- a/apps/openmw/mwgui/spellview.hpp +++ b/apps/openmw/mwgui/spellview.hpp @@ -5,9 +5,6 @@ #include #include -#include - -#include #include "spellmodel.hpp" @@ -57,9 +54,6 @@ namespace MWGui void resetScrollbars(); - void setActiveControllerWindow(bool active); - void onControllerButton(const unsigned char button); - private: MyGUI::ScrollView* mScrollView; @@ -95,15 +89,6 @@ namespace MWGui void addGroup(const std::string& label1, const std::string& label2); void adjustSpellWidget(const Spell& spell, SpellModel::ModelIndex index, MyGUI::Widget* widget); - /// Keep a list of buttons for controller navigation and their index in the full list. - std::vector> mButtons; - /// Keep a list of group offsets for controller navigation - std::vector mGroupIndices; - - bool mControllerActiveWindow; - int mControllerFocus; - void updateControllerFocus(int prevFocus, int newFocus); - void onSpellSelected(MyGUI::Widget* _sender); void onMouseWheelMoved(MyGUI::Widget* _sender, int _rel); diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index c8d9b2acd9..566b7f4ccd 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -2,8 +2,6 @@ #include #include -#include -#include #include #include @@ -57,14 +55,6 @@ namespace MWGui // Adjust the spell filtering widget size because of MyGUI limitations. int filterWidth = mSpellView->getSize().width - deleteButton->getSize().width - 3; mFilterEdit->setSize(filterWidth, mFilterEdit->getSize().height); - - if (Settings::gui().mControllerMenus) - { - setPinButtonVisible(false); - mControllerButtons.a = "#{sSelect}"; - mControllerButtons.b = "#{sBack}"; - mControllerButtons.r3 = "#{sInfo}"; - } } void SpellWindow::onPinToggled() @@ -298,38 +288,4 @@ namespace MWGui onSpellSelected(selectedSpell.mId); } } - - bool SpellWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_B) - MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); - else - mSpellView->onControllerButton(arg.button); - - return true; - } - - void SpellWindow::setActiveControllerWindow(bool active) - { - if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Inventory) - { - // Fill the screen, or limit to a certain size on large screens. Size chosen to - // match the size of the stats window. - MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - int width = std::min(viewSize.width, 600); - int height = std::min(viewSize.height - 48 - 48, 750); - int x = (viewSize.width - width) / 2; - int y = (viewSize.height - height) / 2; - - MyGUI::Window* window = mMainWidget->castType(); - window->setCoord(x, active ? y : viewSize.height + 1, width, height); - - MWBase::Environment::get().getWindowManager()->setControllerTooltip( - active && Settings::gui().mControllerTooltips); - } - - mSpellView->setActiveControllerWindow(active); - - WindowBase::setActiveControllerWindow(active); - } } diff --git a/apps/openmw/mwgui/spellwindow.hpp b/apps/openmw/mwgui/spellwindow.hpp index c27ec276a3..e35c5cdc4c 100644 --- a/apps/openmw/mwgui/spellwindow.hpp +++ b/apps/openmw/mwgui/spellwindow.hpp @@ -41,8 +41,6 @@ namespace MWGui void onPinToggled() override; void onTitleDoubleClicked() override; void onOpen() override; - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - void setActiveControllerWindow(bool active) override; SpellView* mSpellView; std::unique_ptr mSpellIcons; diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index 430101f069..69f0b4b449 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -81,14 +80,6 @@ namespace MWGui MyGUI::Window* t = mMainWidget->castType(); t->eventWindowChangeCoord += MyGUI::newDelegate(this, &StatsWindow::onWindowResize); - if (Settings::gui().mControllerMenus) - { - setPinButtonVisible(false); - mControllerButtons.lStick = "#{sMouse}"; - mControllerButtons.rStick = "#{sScrolldown}"; - mControllerButtons.b = "#{sBack}"; - } - onWindowResize(t); } @@ -732,34 +723,4 @@ namespace MWGui else if (!mPinned) MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Stats); } - - bool StatsWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_B) - MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); - - return true; - } - - void StatsWindow::setActiveControllerWindow(bool active) - { - if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Inventory) - { - // Fill the screen, or limit to a certain size on large screens. Size chosen to - // show all stats. - MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - int width = std::min(viewSize.width, 600); - int height = std::min(viewSize.height - 48 - 48, 750); - int x = (viewSize.width - width) / 2; - int y = (viewSize.height - height) / 2; - - MyGUI::Window* window = mMainWidget->castType(); - window->setCoord(x, active ? y : viewSize.height + 1, width, height); - - if (active) - onWindowResize(window); - } - - WindowBase::setActiveControllerWindow(active); - } } diff --git a/apps/openmw/mwgui/statswindow.hpp b/apps/openmw/mwgui/statswindow.hpp index 3021873aa8..a3fc3157c5 100644 --- a/apps/openmw/mwgui/statswindow.hpp +++ b/apps/openmw/mwgui/statswindow.hpp @@ -47,10 +47,6 @@ namespace MWGui std::string_view getWindowIdForLua() const override { return "Stats"; } - protected: - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - void setActiveControllerWindow(bool active) override; - private: void addSkills(const std::vector& skills, const std::string& titleId, const std::string& titleDefault, MyGUI::IntCoord& coord1, MyGUI::IntCoord& coord2); diff --git a/apps/openmw/mwgui/textinput.cpp b/apps/openmw/mwgui/textinput.cpp index 7612cf4c67..5f47b96f03 100644 --- a/apps/openmw/mwgui/textinput.cpp +++ b/apps/openmw/mwgui/textinput.cpp @@ -25,8 +25,6 @@ namespace MWGui // Make sure the edit box has focus MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit); - - mControllerButtons.a = "#{sOk}"; } void TextInputDialog::setNextButtonShow(bool shown) @@ -85,15 +83,4 @@ namespace MWGui mTextEdit->setCaption(text); } - bool TextInputDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - onOkClicked(nullptr); - MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); - return true; - } - - return false; - } } diff --git a/apps/openmw/mwgui/textinput.hpp b/apps/openmw/mwgui/textinput.hpp index ad7896ff27..c11d40f1a9 100644 --- a/apps/openmw/mwgui/textinput.hpp +++ b/apps/openmw/mwgui/textinput.hpp @@ -27,7 +27,6 @@ namespace MWGui protected: void onOkClicked(MyGUI::Widget* _sender); void onTextAccepted(MyGUI::EditBox* _sender); - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; private: MyGUI::EditBox* mTextEdit; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 67c10b980f..28f0b80010 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -94,7 +94,7 @@ namespace MWGui if (guiMode) { - if (!winMgr->getCursorVisible() && !winMgr->getControllerTooltip()) + if (!winMgr->getCursorVisible()) return; const MyGUI::IntPoint& mousePos = MyGUI::InputManager::getInstance().getMousePosition(); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index c26a7f030a..ba752303d2 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -168,25 +168,6 @@ namespace MWGui std::numeric_limits::min() + 1); // disallow INT_MIN since abs(INT_MIN) is undefined setCoord(400, 0, 400, 300); - - if (Settings::gui().mControllerMenus) - { - // Show L1 and R1 buttons next to tabs - MyGUI::Widget* image; - getWidget(image, "BtnL1Image"); - image->setVisible(true); - image->setUserString("Hidden", "false"); - - getWidget(image, "BtnR1Image"); - image->setVisible(true); - image->setUserString("Hidden", "false"); - - mControllerButtons.a = "#{sBuy}"; - mControllerButtons.b = "#{sCancel}"; - mControllerButtons.x = "#{sOffer}"; - mControllerButtons.r3 = "#{sInfo}"; - mControllerButtons.l2 = "#{sInventory}"; - } } void TradeWindow::setPtr(const MWWorld::Ptr& actor) @@ -220,10 +201,6 @@ namespace MWGui onFilterChanged(mFilterAll); mFilterEdit->setCaption({}); - - // Cycle to the buy window if it's not active. - if (Settings::gui().mControllerMenus && !mActiveControllerWindow) - MWBase::Environment::get().getWindowManager()->cycleActiveControllerWindow(true); } void TradeWindow::onFrame(float dt) @@ -362,13 +339,6 @@ namespace MWGui } } - void TradeWindow::onOfferSubmitted(MyGUI::Widget* _sender, int offerAmount) - { - mCurrentBalance = mCurrentBalance < 0 ? -offerAmount : offerAmount; - updateLabels(); - onOfferButtonClicked(mOfferButton); - } - void TradeWindow::onOfferButtonClicked(MyGUI::Widget* _sender) { TradeItemModel* playerItemModel @@ -673,89 +643,4 @@ namespace MWGui if (mTradeModel && mTradeModel->usesContainer(ptr)) MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); } - - bool TradeWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - int index = mItemView->getControllerFocus(); - if (index >= 0 && index < mItemView->getItemCount()) - onItemSelected(index); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - { - onCancelButtonClicked(mCancelButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_X) - { - if (mCurrentBalance == 0) - return true; - // Show a count dialog to allow for bartering. - CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); - if (mCurrentBalance < 0) - { - // Buying from the merchant - dialog->openCountDialog("#{sTotalcost}:", "#{sOffer}", -mCurrentMerchantOffer); - dialog->setCount(-mCurrentBalance); - } - else - { - // Selling to the merchant - dialog->openCountDialog("#{sTotalsold}:", "#{sOffer}", getMerchantGold()); - dialog->setCount(mCurrentBalance); - } - dialog->eventOkClicked.clear(); - dialog->eventOkClicked += MyGUI::newDelegate(this, &TradeWindow::onOfferSubmitted); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) - { - if (mFilterAll->getStateSelected()) - onFilterChanged(mFilterMisc); - else if (mFilterWeapon->getStateSelected()) - onFilterChanged(mFilterAll); - else if (mFilterApparel->getStateSelected()) - onFilterChanged(mFilterWeapon); - else if (mFilterMagic->getStateSelected()) - onFilterChanged(mFilterApparel); - else if (mFilterMisc->getStateSelected()) - onFilterChanged(mFilterMagic); - MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) - { - if (mFilterAll->getStateSelected()) - onFilterChanged(mFilterWeapon); - else if (mFilterWeapon->getStateSelected()) - onFilterChanged(mFilterApparel); - else if (mFilterApparel->getStateSelected()) - onFilterChanged(mFilterMagic); - else if (mFilterMagic->getStateSelected()) - onFilterChanged(mFilterMisc); - else if (mFilterMisc->getStateSelected()) - onFilterChanged(mFilterAll); - MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK || arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP - || arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN || arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT - || arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) - { - mItemView->onControllerButton(arg.button); - } - - return true; - } - - void TradeWindow::setActiveControllerWindow(bool active) - { - // Show L1 and R1 buttons next to tabs - MyGUI::Widget* image; - getWidget(image, "BtnL1Image"); - image->setVisible(active); - - getWidget(image, "BtnR1Image"); - image->setVisible(active); - - mItemView->setActiveControllerWindow(active); - WindowBase::setActiveControllerWindow(active); - } } diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index afd271ed2f..33c39cb269 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -47,9 +47,6 @@ namespace MWGui std::string_view getWindowIdForLua() const override { return "Trade"; } - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - void setActiveControllerWindow(bool active) override; - private: ItemView* mItemView; SortFilterItemModel* mSortModel; @@ -105,7 +102,6 @@ namespace MWGui void onBalanceButtonReleased(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); void onBalanceValueChanged(int value); void onRepeatClick(MyGUI::Widget* widget, MyGUI::ControllerItem* controller); - void onOfferSubmitted(MyGUI::Widget* _sender, int offerAmount); void addRepeatController(MyGUI::Widget* widget); diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 5b4d355e61..890aa0ba68 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -37,13 +37,6 @@ namespace MWGui mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &TrainingWindow::onTrainingProgressChanged); mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &TrainingWindow::onTrainingFinished); - - if (Settings::gui().mControllerMenus) - { - mDisableGamepadCursor = true; - mControllerButtons.a = "#{sBuy}"; - mControllerButtons.b = "#{sCancel}"; - } } void TrainingWindow::onOpen() @@ -112,7 +105,6 @@ namespace MWGui const int lineHeight = Settings::gui().mFontSize + 2; - mTrainingButtons.clear(); for (size_t i = 0; i < skills.size(); ++i) { const ESM::Skill* skill = skills[i].first; @@ -136,16 +128,6 @@ namespace MWGui button->setSize(button->getTextSize().width + 12, button->getSize().height); ToolTips::createSkillToolTip(button, skill->mId); - - if (price <= playerGold) - mTrainingButtons.emplace_back(button); - } - - if (Settings::gui().mControllerMenus) - { - mControllerFocus = 0; - if (mTrainingButtons.size() > 0) - mTrainingButtons[0]->setStateSelected(true); } center(); @@ -247,36 +229,4 @@ namespace MWGui return !mTimeAdvancer.isRunning(); } - bool TrainingWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - if (mControllerFocus >= 0 && mControllerFocus < static_cast(mTrainingButtons.size())) - onTrainingSelected(mTrainingButtons[mControllerFocus]); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - { - onCancelButtonClicked(mCancelButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) - { - if (mTrainingButtons.size() <= 1) - return true; - - setControllerFocus(mTrainingButtons, mControllerFocus, false); - mControllerFocus = wrap(mControllerFocus - 1, mTrainingButtons.size()); - setControllerFocus(mTrainingButtons, mControllerFocus, true); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - { - if (mTrainingButtons.size() <= 1) - return true; - - setControllerFocus(mTrainingButtons, mControllerFocus, false); - mControllerFocus = wrap(mControllerFocus + 1, mTrainingButtons.size()); - setControllerFocus(mTrainingButtons, mControllerFocus, true); - } - - return true; - } } diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index 4f866f820e..ee13f24b23 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -49,13 +49,9 @@ namespace MWGui MyGUI::Widget* mTrainingOptions; MyGUI::Button* mCancelButton; MyGUI::TextBox* mPlayerGold; - std::vector mTrainingButtons; WaitDialogProgressBar mProgressBar; TimeAdvancer mTimeAdvancer; - - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - int mControllerFocus; }; } diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 726e623eb3..e001cf9b43 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -37,13 +37,6 @@ namespace MWGui getWidget(mDestinationsView, "DestinationsView"); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TravelWindow::onCancelButtonClicked); - - if (Settings::gui().mControllerMenus) - { - mDisableGamepadCursor = true; - mControllerButtons.a = "#{sTravel}"; - mControllerButtons.b = "#{sCancel}"; - } } void TravelWindow::addDestination(const ESM::RefId& name, const ESM::Position& pos, bool interior) @@ -101,8 +94,6 @@ namespace MWGui toAdd->setUserString("Destination", nameString); toAdd->setUserData(pos); toAdd->eventMouseButtonClick += MyGUI::newDelegate(this, &TravelWindow::onTravelButtonClick); - if (price <= playerGold) - mDestinationButtons.emplace_back(toAdd); } void TravelWindow::clearDestinations() @@ -111,7 +102,6 @@ namespace MWGui mCurrentY = 0; while (mDestinationsView->getChildCount()) MyGUI::Gui::getInstance().destroyWidget(mDestinationsView->getChildAt(0)); - mDestinationButtons.clear(); } void TravelWindow::setPtr(const MWWorld::Ptr& actor) @@ -156,14 +146,6 @@ namespace MWGui } updateLabels(); - - if (Settings::gui().mControllerMenus) - { - mControllerFocus = 0; - if (mDestinationButtons.size() > 0) - mDestinationButtons[0]->setStateSelected(true); - } - // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the // scrollbar is hidden mDestinationsView->setVisibleVScroll(false); @@ -258,49 +240,4 @@ namespace MWGui mDestinationsView->setViewOffset( MyGUI::IntPoint(0, static_cast(mDestinationsView->getViewOffset().top + _rel * 0.3f))); } - - bool TravelWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - if (mControllerFocus >= 0 && mControllerFocus < static_cast(mDestinationButtons.size())) - { - onTravelButtonClick(mDestinationButtons[mControllerFocus]); - MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); - } - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - { - onCancelButtonClicked(mCancelButton); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) - { - if (mDestinationButtons.size() <= 1) - return true; - - setControllerFocus(mDestinationButtons, mControllerFocus, false); - mControllerFocus = wrap(mControllerFocus - 1, mDestinationButtons.size()); - setControllerFocus(mDestinationButtons, mControllerFocus, true); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) - { - if (mDestinationButtons.size() <= 1) - return true; - - setControllerFocus(mDestinationButtons, mControllerFocus, false); - mControllerFocus = wrap(mControllerFocus + 1, mDestinationButtons.size()); - setControllerFocus(mDestinationButtons, mControllerFocus, true); - } - - // Scroll the list to keep the active item in view - if (mControllerFocus <= 5) - mDestinationsView->setViewOffset(MyGUI::IntPoint(0, 0)); - else - { - const int lineHeight = Settings::gui().mFontSize + 2; - mDestinationsView->setViewOffset(MyGUI::IntPoint(0, -lineHeight * (mControllerFocus - 5))); - } - - return true; - } } diff --git a/apps/openmw/mwgui/travelwindow.hpp b/apps/openmw/mwgui/travelwindow.hpp index 79f5f9abc8..630e27518a 100644 --- a/apps/openmw/mwgui/travelwindow.hpp +++ b/apps/openmw/mwgui/travelwindow.hpp @@ -25,8 +25,6 @@ namespace MWGui MyGUI::Button* mCancelButton; MyGUI::TextBox* mPlayerGold; - std::vector mDestinationButtons; - MyGUI::ScrollView* mDestinationsView; void onCancelButtonClicked(MyGUI::Widget* _sender); @@ -39,10 +37,6 @@ namespace MWGui void updateLabels(); void onReferenceUnavailable() override; - - private: - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; - int mControllerFocus; }; } diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index f33695a982..222a34e53b 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -80,9 +80,6 @@ namespace MWGui mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &WaitDialog::onWaitingProgressChanged); mTimeAdvancer.eventInterrupted += MyGUI::newDelegate(this, &WaitDialog::onWaitingInterrupted); mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &WaitDialog::onWaitingFinished); - - mControllerButtons.b = "#{sCancel}"; - mDisableGamepadCursor = Settings::gui().mControllerMenus; } void WaitDialog::setPtr(const MWWorld::Ptr& ptr) @@ -329,45 +326,6 @@ namespace MWGui } } - ControllerButtonStr* WaitDialog::getControllerButtons() - { - mControllerButtons.a = mSleeping ? "#{sRest}" : "#{sWait}"; - mControllerButtons.x = mSleeping && mUntilHealedButton->getVisible() ? "#{sUntilHealed}" : ""; - return &mControllerButtons; - } - - bool WaitDialog::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) - { - if (arg.button == SDL_CONTROLLER_BUTTON_A) - { - onWaitButtonClicked(mWaitButton); - MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_B) - onCancelButtonClicked(mCancelButton); - else if (arg.button == SDL_CONTROLLER_BUTTON_X && mUntilHealedButton->getVisible()) - { - onUntilHealedButtonClicked(mUntilHealedButton); - MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click")); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) - MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) - MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::ArrowUp, 0, false); - else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) - { - mHourSlider->setScrollPosition(0); - onHourSliderChangedPosition(mHourSlider, mHourSlider->getScrollPosition()); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) - { - mHourSlider->setScrollPosition(mHourSlider->getScrollRange() - 1); - onHourSliderChangedPosition(mHourSlider, mHourSlider->getScrollPosition()); - } - - return true; - } - void WaitDialog::stopWaiting() { MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.2f); diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 4a7ccfcd00..3d66584f54 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -4,7 +4,6 @@ #include "timeadvancer.hpp" #include "windowbase.hpp" #include -#include namespace MWGui { @@ -37,7 +36,6 @@ namespace MWGui void clear() override; void onFrame(float dt) override; - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; bool getSleeping() { return mTimeAdvancer.isRunning() && mSleeping; } void wakeUp(); @@ -47,8 +45,6 @@ namespace MWGui std::string_view getWindowIdForLua() const override { return "WaitDialog"; } - ControllerButtonStr* getControllerButtons() override; - protected: MyGUI::TextBox* mDateTimeText; MyGUI::TextBox* mRestText; @@ -56,7 +52,7 @@ namespace MWGui MyGUI::Button* mUntilHealedButton; MyGUI::Button* mWaitButton; MyGUI::Button* mCancelButton; - Gui::ScrollBar* mHourSlider; + MyGUI::ScrollBar* mHourSlider; TimeAdvancer mTimeAdvancer; bool mSleeping; diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 8995f04b92..6cc5bdfdf5 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -14,8 +14,6 @@ #include #include -#include "textcolours.hpp" - #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" @@ -68,12 +66,6 @@ namespace MWGui::Widgets } } - void MWSkill::setStateSelected(bool selected) - { - const TextColours& textColours{ MWBase::Environment::get().getWindowManager()->getTextColours() }; - mSkillNameWidget->setTextColour(selected ? textColours.link : textColours.normal); - } - void MWSkill::onClicked(MyGUI::Widget* _sender) { eventClicked(this); @@ -158,12 +150,6 @@ namespace MWGui::Widgets } } - void MWAttribute::setStateSelected(bool selected) - { - const TextColours& textColours{ MWBase::Environment::get().getWindowManager()->getTextColours() }; - mAttributeNameWidget->setTextColour(selected ? textColours.link : textColours.normal); - } - void MWAttribute::initialiseOverride() { Base::initialiseOverride(); @@ -245,12 +231,6 @@ namespace MWGui::Widgets } } - void MWSpell::setStateSelected(bool selected) - { - const TextColours& textColours{ MWBase::Environment::get().getWindowManager()->getTextColours() }; - mSpellNameWidget->setTextColour(selected ? textColours.link : textColours.normal); - } - void MWSpell::initialiseOverride() { Base::initialiseOverride(); @@ -481,12 +461,6 @@ namespace MWGui::Widgets MWSpellEffect::~MWSpellEffect() {} - void MWSpellEffect::setStateSelected(bool selected) - { - const TextColours& textColours{ MWBase::Environment::get().getWindowManager()->getTextColours() }; - mTextWidget->setTextColour(selected ? textColours.link : textColours.normal); - } - void MWSpellEffect::initialiseOverride() { Base::initialiseOverride(); diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index c51846d9df..d562e4e07f 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -110,8 +110,6 @@ namespace MWGui */ EventHandle_SkillVoid eventClicked; - void setStateSelected(bool selected); - protected: virtual ~MWSkill(); @@ -151,8 +149,6 @@ namespace MWGui */ EventHandle_AttributeVoid eventClicked; - void setStateSelected(bool selected); - protected: ~MWAttribute() override = default; @@ -195,8 +191,6 @@ namespace MWGui const ESM::RefId& getSpellId() const { return mId; } - void setStateSelected(bool selected); - protected: virtual ~MWSpell(); @@ -262,8 +256,6 @@ namespace MWGui int getRequestedWidth() const { return mRequestedWidth; } - void setStateSelected(bool selected); - protected: virtual ~MWSpellEffect(); diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index b607ec50b2..f5d90590f8 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -7,7 +7,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" -#include #include #include "draganddrop.hpp" @@ -15,22 +14,6 @@ using namespace MWGui; -int MWGui::wrap(int index, int max) -{ - if (index < 0) - return max - 1; - else if (index >= max) - return 0; - else - return index; -} - -void MWGui::setControllerFocus(std::vector buttons, int index, bool focused) -{ - if (index >= 0 && index < static_cast(buttons.size())) - buttons[index]->setStateSelected(focused); -} - WindowBase::WindowBase(std::string_view parLayout) : Layout(parLayout) { @@ -139,7 +122,6 @@ void WindowModal::onOpen() void WindowModal::onClose() { MWBase::Environment::get().getWindowManager()->removeCurrentModal(this); - MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay(); MyGUI::InputManager::getInstance().removeWidgetModal(mMainWidget); } diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index b4d17a1ba3..466060c6ad 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -1,8 +1,6 @@ #ifndef MWGUI_WINDOW_BASE_H #define MWGUI_WINDOW_BASE_H -#include - #include "layout.hpp" namespace MWWorld @@ -14,28 +12,6 @@ namespace MWGui { class DragAndDrop; - int wrap(int index, int max); - void setControllerFocus(std::vector buttons, int index, bool selected); - - struct ControllerButtonStr - { - std::string a; - std::string b; - std::string dpad; - std::string l1; - std::string l2; - std::string l3; - std::string lStick; - std::string menu; - std::string r1; - std::string r2; - std::string r3; - std::string rStick; - std::string view; - std::string x; - std::string y; - }; - class WindowBase : public Layout { public: @@ -78,21 +54,9 @@ namespace MWGui static void clampWindowCoordinates(MyGUI::Window* window); - virtual ControllerButtonStr* getControllerButtons() { return &mControllerButtons; } - MyGUI::Widget* getControllerScrollWidget() { return mControllerScrollWidget; } - bool isGamepadCursorAllowed() { return !mDisableGamepadCursor; } - virtual bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) { return true; } - virtual bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) { return true; } - virtual void setActiveControllerWindow(bool active) { mActiveControllerWindow = active; } - protected: virtual void onTitleDoubleClicked(); - ControllerButtonStr mControllerButtons; - bool mActiveControllerWindow = false; - bool mDisableGamepadCursor = false; - MyGUI::Widget* mControllerScrollWidget = nullptr; - private: void onDoubleClick(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 3d98e28bde..565fb43127 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -181,8 +181,6 @@ namespace MWGui , mPostProcessorHud(nullptr) , mJailScreen(nullptr) , mContainerWindow(nullptr) - , mControllerButtonsOverlay(nullptr) - , mInventoryTabsOverlay(nullptr) , mTranslationDataStorage(translationDataStorage) , mInputBlocker(nullptr) , mHudEnabled(true) @@ -507,15 +505,6 @@ namespace MWGui mWindows.push_back(std::move(postProcessorHud)); trackWindow(mPostProcessorHud, makePostprocessorWindowSettingValues()); - auto controllerButtonsOverlay = std::make_unique(); - mControllerButtonsOverlay = controllerButtonsOverlay.get(); - mWindows.push_back(std::move(controllerButtonsOverlay)); - - auto inventoryTabsOverlay = std::make_unique(); - mInventoryTabsOverlay = inventoryTabsOverlay.get(); - mWindows.push_back(std::move(inventoryTabsOverlay)); - mActiveControllerWindows[GM_Inventory] = 1; // Start on Inventory page - mInputBlocker = MyGUI::Gui::getInstance().createWidget( {}, 0, 0, w, h, MyGUI::Align::Stretch, "InputBlocker"); @@ -673,14 +662,6 @@ namespace MWGui && !(mForceHidden & GW_Inventory) && (mAllowed & GW_Inventory)); mSpellWindow->setVisible( mSpellWindow->pinned() && !isConsoleMode() && !(mForceHidden & GW_Magic) && (mAllowed & GW_Magic)); - - if (Settings::gui().mControllerMenus) - { - if (mControllerButtonsOverlay) - mControllerButtonsOverlay->setVisible(false); - if (mInventoryTabsOverlay) - mInventoryTabsOverlay->setVisible(false); - } return; } else if (getMode() != GM_Inventory) @@ -710,8 +691,6 @@ namespace MWGui mStatsWindow->setVisible(eff & GW_Stats); } - updateControllerButtonsOverlay(); - switch (mode) { // FIXME: refactor chargen windows to use modes properly (or not use them at all) @@ -741,7 +720,6 @@ namespace MWGui return; dialog->setVisible(false); mGarbageDialogs.push_back(std::move(dialog)); - updateControllerButtonsOverlay(); } void WindowManager::exitCurrentGuiMode() @@ -881,95 +859,6 @@ namespace MWGui mHud->setPlayerPos(x, y, u, v); } - WindowBase* WindowManager::getActiveControllerWindow() - { - if (!mCurrentModals.empty()) - return mCurrentModals.back(); - - if (isSettingsWindowVisible()) - return mSettingsWindow; - - if (!mGuiModes.empty()) - { - GuiMode mode = mGuiModes.back(); - GuiModeState& state = mGuiModeStates[mode]; - if (state.mWindows.size() == 0) - return nullptr; - - int activeIndex = std::clamp(mActiveControllerWindows[mode], 0, (int)state.mWindows.size() - 1); - - Log(Debug::Debug) << "Getting active controller window: mode=" << mode << ", " << state.mWindows.size() - << " window(s), activeIndex=" << activeIndex; - - // If the active window is no longer visible, find the next visible window. - if (!state.mWindows[activeIndex]->isVisible()) - cycleActiveControllerWindow(true); - - return state.mWindows[activeIndex]; - } - - return nullptr; - } - - void WindowManager::cycleActiveControllerWindow(bool next) - { - if (!Settings::gui().mControllerMenus || mGuiModes.empty()) - return; - - GuiMode mode = mGuiModes.back(); - int winCount = mGuiModeStates[mode].mWindows.size(); - - int activeIndex = 0; - if (winCount > 1) - { - // Find next/previous visible window - activeIndex = mActiveControllerWindows[mode]; - int delta = next ? 1 : -1; - - for (int i = 0; i < winCount; i++) - { - activeIndex = wrap(activeIndex + delta, winCount); - if (mGuiModeStates[mode].mWindows[activeIndex]->isVisible()) - break; - } - } - - Log(Debug::Debug) << "Cycling active controller window: mode=" << mode << ", activeIndex=" << activeIndex; - - if (mActiveControllerWindows[mode] != activeIndex) - setActiveControllerWindow(mode, activeIndex); - } - - void WindowManager::setActiveControllerWindow(GuiMode mode, int activeIndex) - { - if (!Settings::gui().mControllerMenus) - return; - - int winCount = mGuiModeStates[mode].mWindows.size(); - if (winCount == 0) - return; - - activeIndex = std::clamp(activeIndex, 0, winCount - 1); - mActiveControllerWindows[mode] = activeIndex; - - // Set active window last so inactive windows don't stomp on changes it makes, e.g. to tooltips. - for (int i = 0; i < winCount; i++) - { - if (i != activeIndex) - mGuiModeStates[mode].mWindows[i]->setActiveControllerWindow(false); - } - mGuiModeStates[mode].mWindows[activeIndex]->setActiveControllerWindow(true); - - MWBase::Environment::get().getInputManager()->setGamepadGuiCursorEnabled( - mGuiModeStates[mode].mWindows[activeIndex]->isGamepadCursorAllowed()); - - updateControllerButtonsOverlay(); - setCursorActive(false); - - if (winCount > 1) - playSound(ESM::RefId::stringRefId("Menu Size")); - } - void WindowManager::update(float frameDuration) { handleScheduledMessageBoxes(); @@ -1033,12 +922,6 @@ namespace MWGui if (isSettingsWindowVisible()) mSettingsWindow->onFrame(frameDuration); - if (mControllerButtonsOverlay && mControllerButtonsOverlay->isVisible()) - mControllerButtonsOverlay->onFrame(frameDuration); - - if (mInventoryTabsOverlay && mInventoryTabsOverlay->isVisible()) - mInventoryTabsOverlay->onFrame(frameDuration); - if (!gameRunning) return; @@ -1410,15 +1293,6 @@ namespace MWGui updateVisible(); MWBase::Environment::get().getLuaManager()->uiModeChanged(arg); - - if (Settings::gui().mControllerMenus) - { - if (mode == GM_Container) - mActiveControllerWindows[mode] = 0; // Ensure controller focus is on container - // Activate first visible window. This needs to be called after updateVisible. - mActiveControllerWindows[mode] = std::max(mActiveControllerWindows[mode] - 1, -1); - cycleActiveControllerWindow(true); - } } void WindowManager::setCullMask(uint32_t mask) @@ -1473,25 +1347,6 @@ namespace MWGui // To make sure that console window get focus again if (mConsole && mConsole->isVisible()) mConsole->onOpen(); - - if (Settings::gui().mControllerMenus) - { - if (mGuiModes.empty()) - setControllerTooltip(false); - else - { - // Re-apply any controller-specific window changes. - const GuiMode mode = mGuiModes.back(); - int winCount = mGuiModeStates[mode].mWindows.size(); - - for (int i = 0; i < winCount; i++) - { - if (i != mActiveControllerWindows[mode]) - mGuiModeStates[mode].mWindows[i]->setActiveControllerWindow(false); - } - mGuiModeStates[mode].mWindows[mActiveControllerWindows[mode]]->setActiveControllerWindow(true); - } - } } void WindowManager::removeGuiMode(GuiMode mode) @@ -1617,10 +1472,6 @@ namespace MWGui mConsole->executeFile(path); } - std::vector WindowManager::getGuiModeWindows(GuiMode mode) - { - return mGuiModeStates[mode].mWindows; - } MWGui::InventoryWindow* WindowManager::getInventoryWindow() { return mInventoryWindow; @@ -1633,10 +1484,6 @@ namespace MWGui { return mConfirmationDialog; } - MWGui::HUD* WindowManager::getHud() - { - return mHud; - } MWGui::TradeWindow* WindowManager::getTradeWindow() { return mTradeWindow; @@ -1920,12 +1767,6 @@ namespace MWGui void WindowManager::onWindowChangeCoord(MyGUI::Window* window) { - // If using controller menus, don't persist changes to size of the stats or magic - // windows. - if (Settings::gui().mControllerMenus - && (window == (MyGUI::Window*)mStatsWindow || window == (MyGUI::Window*)mSpellWindow)) - return; - const auto it = mTrackedWindows.find(window); if (it == mTrackedWindows.end()) return; @@ -2119,7 +1960,6 @@ namespace MWGui if (!window->exit()) return; window->setVisible(false); - updateControllerButtonsOverlay(); } } @@ -2133,8 +1973,6 @@ namespace MWGui mKeyboardNavigation->setModalWindow(input->mMainWidget); mKeyboardNavigation->setDefaultFocus(input->mMainWidget, input->getDefaultKeyFocus()); - - updateControllerButtonsOverlay(); } void WindowManager::removeCurrentModal(WindowModal* input) @@ -2172,16 +2010,6 @@ namespace MWGui void WindowManager::updatePinnedWindows() { - if (Settings::gui().mControllerMenus) - { - // In controller mode, don't hide any menus and only allow pinning the map. - mInventoryWindow->setPinned(false); - mMap->setPinned(Settings::windows().mMapPin); - mSpellWindow->setPinned(false); - mStatsWindow->setPinned(false); - return; - } - mInventoryWindow->setPinned(Settings::windows().mInventoryPin); if (Settings::windows().mInventoryHidden) mShown = (GuiWindow)(mShown ^ GW_Inventory); @@ -2612,36 +2440,4 @@ namespace MWGui } return res; } - - void WindowManager::setControllerTooltip(bool enabled) - { - if (!Settings::gui().mControllerMenus) - return; - - mControllerTooltip = enabled; - } - - void WindowManager::updateControllerButtonsOverlay() - { - if (!Settings::gui().mControllerMenus || !mControllerButtonsOverlay) - return; - - WindowBase* topWin = this->getActiveControllerWindow(); - if (!topWin || !topWin->isVisible()) - { - mControllerButtonsOverlay->setVisible(false); - mInventoryTabsOverlay->setVisible(false); - return; - } - - // setButtons will handle setting visibility based on if any buttons are defined. - mControllerButtonsOverlay->setButtons(topWin->getControllerButtons()); - if (getMode() == GM_Inventory) - { - mInventoryTabsOverlay->setVisible(true); - mInventoryTabsOverlay->setTab(mActiveControllerWindows[GM_Inventory]); - } - else - mInventoryTabsOverlay->setVisible(false); - } } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index c8f1c7e06c..650e2bab78 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -25,9 +25,7 @@ #include #include "charactercreation.hpp" -#include "controllerbuttonsoverlay.hpp" #include "draganddrop.hpp" -#include "inventorytabsoverlay.hpp" #include "mapwindow.hpp" #include "messagebox.hpp" #include "settings.hpp" @@ -120,8 +118,6 @@ namespace MWGui class PostProcessorHud; class JailScreen; class KeyboardNavigation; - class ControllerButtonsOverlay; - class InventoryTabsOverlay; class WindowManager : public MWBase::WindowManager { @@ -187,9 +183,7 @@ namespace MWGui MWGui::CountDialog* getCountDialog() override; MWGui::ConfirmationDialog* getConfirmationDialog() override; MWGui::TradeWindow* getTradeWindow() override; - MWGui::HUD* getHud() override; MWGui::PostProcessorHud* getPostProcessorHud() override; - std::vector getGuiModeWindows(GuiMode mode) override; /// Make the player use an item, while updating GUI state accordingly void useItem(const MWWorld::Ptr& item, bool bypassBeastRestrictions = false) override; @@ -393,13 +387,6 @@ namespace MWGui void asyncPrepareSaveMap() override; - WindowBase* getActiveControllerWindow() override; - void cycleActiveControllerWindow(bool next) override; - void setActiveControllerWindow(GuiMode mode, int activeIndex) override; - bool getControllerTooltip() const override { return mControllerTooltip; } - void setControllerTooltip(bool enabled) override; - void updateControllerButtonsOverlay() override; - // Used in Lua bindings const std::vector& getGuiModeStack() const override { return mGuiModes; } void setDisabledByLua(std::string_view windowId, bool disabled) override; @@ -467,8 +454,6 @@ namespace MWGui PostProcessorHud* mPostProcessorHud; JailScreen* mJailScreen; ContainerWindow* mContainerWindow; - ControllerButtonsOverlay* mControllerButtonsOverlay; - InventoryTabsOverlay* mInventoryTabsOverlay; std::vector> mWindows; @@ -508,9 +493,6 @@ namespace MWGui std::map mGuiModeStates; // The currently active stack of GUI modes (top mode is the one we are in). std::vector mGuiModes; - // The active window for controller mode for each GUI mode. - std::map mActiveControllerWindows; - bool mControllerTooltip; std::unique_ptr mCursorManager; diff --git a/apps/openmw/mwinput/controllermanager.cpp b/apps/openmw/mwinput/controllermanager.cpp index 9962c639ad..1a8490d8b7 100644 --- a/apps/openmw/mwinput/controllermanager.cpp +++ b/apps/openmw/mwinput/controllermanager.cpp @@ -16,7 +16,6 @@ #include "../mwbase/luamanager.hpp" #include "../mwbase/statemanager.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwgui/inventorywindow.hpp" #include "actions.hpp" #include "bindingsmanager.hpp" @@ -32,7 +31,6 @@ namespace MWInput , mGamepadGuiCursorEnabled(true) , mGuiCursorEnabled(true) , mJoystickLastUsed(false) - , mGamepadMousePressed(false) { if (!controllerBindingsFile.empty()) { @@ -143,7 +141,6 @@ namespace MWInput if (arg.button == SDL_CONTROLLER_BUTTON_A) // We'll pretend that A is left click. { bool mousePressSuccess = mMouseManager->injectMouseButtonPress(SDL_BUTTON_LEFT); - mGamepadMousePressed = true; if (MyGUI::InputManager::getInstance().getMouseFocusWidget()) { MyGUI::Button* b @@ -188,13 +185,12 @@ namespace MWInput mJoystickLastUsed = true; if (MWBase::Environment::get().getWindowManager()->isGuiMode()) { - if (mGamepadGuiCursorEnabled && (!Settings::gui().mControllerMenus || mGamepadMousePressed)) + if (mGamepadGuiCursorEnabled) { // Temporary mouse binding until keyboard controls are available: if (arg.button == SDL_CONTROLLER_BUTTON_A) // We'll pretend that A is left click. { bool mousePressSuccess = mMouseManager->injectMouseButtonRelease(SDL_BUTTON_LEFT); - mGamepadMousePressed = false; if (mBindingsManager->isDetectingBindingState()) // If the player just triggered binding, don't let // button release bind. return; @@ -245,33 +241,6 @@ namespace MWInput bool ControllerManager::gamepadToGuiControl(const SDL_ControllerButtonEvent& arg) { - MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); - - if (Settings::gui().mControllerMenus) - { - // Update cursor state. - bool treatAsMouse = winMgr->getCursorVisible(); - winMgr->setCursorActive(false); - - MWGui::WindowBase* topWin = winMgr->getActiveControllerWindow(); - if (topWin) - { - // When the inventory tooltip is visible, we don't actually want the A button to - // act like a mouse button; it should act normally. - if (treatAsMouse && arg.button == SDL_CONTROLLER_BUTTON_A && winMgr->getControllerTooltip()) - treatAsMouse = false; - - mGamepadGuiCursorEnabled = topWin->isGamepadCursorAllowed(); - - // Fall through to mouse click - if (mGamepadGuiCursorEnabled && treatAsMouse && arg.button == SDL_CONTROLLER_BUTTON_A) - return false; - - if (topWin->onControllerButtonEvent(arg)) - return true; - } - } - // Presumption of GUI mode will be removed in the future. // MyGUI KeyCodes *may* change. MyGUI::KeyCode key = MyGUI::KeyCode::None; @@ -297,9 +266,9 @@ namespace MWInput break; case SDL_CONTROLLER_BUTTON_B: if (MyGUI::InputManager::getInstance().isModalAny()) - winMgr->exitCurrentModal(); + MWBase::Environment::get().getWindowManager()->exitCurrentModal(); else - winMgr->exitCurrentGuiMode(); + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); return true; case SDL_CONTROLLER_BUTTON_X: key = MyGUI::KeyCode::Semicolon; @@ -309,7 +278,7 @@ namespace MWInput break; case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::LeftShift); - winMgr->injectKeyPress(MyGUI::KeyCode::Tab, 0, false); + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Tab, 0, false); MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::LeftShift); return true; case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: @@ -317,7 +286,7 @@ namespace MWInput return true; case SDL_CONTROLLER_BUTTON_LEFTSTICK: mGamepadGuiCursorEnabled = !mGamepadGuiCursorEnabled; - winMgr->setCursorActive(mGamepadGuiCursorEnabled); + MWBase::Environment::get().getWindowManager()->setCursorActive(mGamepadGuiCursorEnabled); return true; default: return false; @@ -327,71 +296,21 @@ namespace MWInput if (SDL_IsTextInputActive()) return false; - winMgr->injectKeyPress(key, 0, false); + MWBase::Environment::get().getWindowManager()->injectKeyPress(key, 0, false); return true; } bool ControllerManager::gamepadToGuiControl(const SDL_ControllerAxisEvent& arg) { - MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); - - if (Settings::gui().mControllerMenus) - { - // Left and right triggers toggle through open GUI windows. - if (arg.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT) - { - if (arg.value == 32767) // Treat like a button. - winMgr->cycleActiveControllerWindow(true); - return true; - } - else if (arg.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT) - { - if (arg.value == 32767) // Treat like a button. - winMgr->cycleActiveControllerWindow(false); - return true; - } - - MWGui::WindowBase* topWin = winMgr->getActiveControllerWindow(); - if (topWin) - { - // Update cursor state - mGamepadGuiCursorEnabled = topWin->isGamepadCursorAllowed(); - if (!mGamepadGuiCursorEnabled) - winMgr->setCursorActive(false); - - if (mGamepadGuiCursorEnabled - && (arg.axis == SDL_CONTROLLER_AXIS_LEFTX || arg.axis == SDL_CONTROLLER_AXIS_LEFTY)) - { - // Treat the left stick like a cursor, which is the default behavior. - if (winMgr->getControllerTooltip() && std::abs(arg.value) > 2000) - { - winMgr->setControllerTooltip(false); - winMgr->setCursorVisible(true); - } - return false; - } - - // On some windows, treat right stick like a scroll wheel. - if (arg.axis == SDL_CONTROLLER_AXIS_RIGHTY && topWin->getControllerScrollWidget() != nullptr) - mMouseManager->warpMouseToWidget(topWin->getControllerScrollWidget()); - - if (topWin->onControllerThumbstickEvent(arg)) - { - // Window handled the event. - return true; - } - } - } - switch (arg.axis) { case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: if (arg.value == 32767) // Treat like a button. - winMgr->injectKeyPress(MyGUI::KeyCode::Minus, 0, false); + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Minus, 0, false); break; case SDL_CONTROLLER_AXIS_TRIGGERLEFT: if (arg.value == 32767) // Treat like a button. - winMgr->injectKeyPress(MyGUI::KeyCode::Equals, 0, false); + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Equals, 0, false); break; case SDL_CONTROLLER_AXIS_LEFTX: case SDL_CONTROLLER_AXIS_LEFTY: diff --git a/apps/openmw/mwinput/controllermanager.hpp b/apps/openmw/mwinput/controllermanager.hpp index 670a3c846f..596a9ef465 100644 --- a/apps/openmw/mwinput/controllermanager.hpp +++ b/apps/openmw/mwinput/controllermanager.hpp @@ -62,7 +62,6 @@ namespace MWInput bool mGamepadGuiCursorEnabled; bool mGuiCursorEnabled; bool mJoystickLastUsed; - bool mGamepadMousePressed; }; } #endif diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 12d56a3321..328757a954 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -189,13 +189,6 @@ namespace MWInput return mMouseManager->getMouseMoveY(); } - void InputManager::warpMouseToWidget(MyGUI::Widget* widget) - { - mMouseManager->warpMouseToWidget(widget); - mMouseManager->injectMouseMove(1, 0, 0); - MWBase::Environment::get().getWindowManager()->setCursorActive(true); - } - const std::initializer_list& InputManager::getActionKeySorting() { return mBindingsManager->getActionKeySorting(); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index b2899e6831..39a1133db5 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -81,7 +81,6 @@ namespace MWInput float getControllerAxisValue(SDL_GameControllerAxis axis) const override; int getMouseMoveX() const override; int getMouseMoveY() const override; - void warpMouseToWidget(MyGUI::Widget* widget) override; int getNumActions() override { return A_Last; } const std::initializer_list& getActionKeySorting() override; diff --git a/apps/openmw/mwinput/mousemanager.cpp b/apps/openmw/mwinput/mousemanager.cpp index 540c334b1e..eed95cf1c9 100644 --- a/apps/openmw/mwinput/mousemanager.cpp +++ b/apps/openmw/mwinput/mousemanager.cpp @@ -263,17 +263,4 @@ namespace MWInput mInputWrapper->warpMouse( static_cast(mGuiCursorX * guiUiScale), static_cast(mGuiCursorY * guiUiScale)); } - - void MouseManager::warpMouseToWidget(MyGUI::Widget* widget) - { - float widgetX = widget->getAbsoluteCoord().left + widget->getWidth() / 2; - float widgetY = widget->getAbsoluteCoord().top + widget->getHeight() / 4; - if (std::abs(mGuiCursorX - widgetX) > 1 || std::abs(mGuiCursorY - widgetY) > 1) - { - mGuiCursorX = widgetX; - mGuiCursorY = widgetY; - warpMouse(); - } - } - } diff --git a/apps/openmw/mwinput/mousemanager.hpp b/apps/openmw/mwinput/mousemanager.hpp index 0a9c4eccd7..5de8a8f3bc 100644 --- a/apps/openmw/mwinput/mousemanager.hpp +++ b/apps/openmw/mwinput/mousemanager.hpp @@ -32,7 +32,6 @@ namespace MWInput bool injectMouseButtonRelease(Uint8 button); void injectMouseMove(float xMove, float yMove, float mouseWheelMove); void warpMouse(); - void warpMouseToWidget(MyGUI::Widget* widget); void setMouseLookEnabled(bool enabled) { mMouseLookEnabled = enabled; } void setGuiCursorEnabled(bool enabled) { mGuiCursorEnabled = enabled; } diff --git a/apps/openmw/mwlua/inputbindings.cpp b/apps/openmw/mwlua/inputbindings.cpp index 7cb727a83e..c3b47c5061 100644 --- a/apps/openmw/mwlua/inputbindings.cpp +++ b/apps/openmw/mwlua/inputbindings.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include "../mwbase/environment.hpp" #include "../mwbase/inputmanager.hpp" @@ -240,7 +239,6 @@ namespace MWLua api["isMouseButtonPressed"] = [](int button) -> bool { return SDL_GetMouseState(nullptr, nullptr) & SDL_BUTTON(button); }; api["_isGamepadCursorActive"] = [input]() -> bool { return input->isGamepadGuiCursorEnabled(); }; - api["_isControllerMenusEnabled"] = []() -> bool { return Settings::gui().mControllerMenus; }; api["_setGamepadCursorActive"] = [input](bool v) { input->setGamepadGuiCursorEnabled(v); MWBase::Environment::get().getWindowManager()->setCursorActive(v); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 1426a797f7..aa6c8763bb 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -353,7 +353,7 @@ add_component_dir (myguiplatform ) add_component_dir (widgets - box fontwrapper imagebutton tags list numericeditbox scrollbar sharedstatebutton windowcaption widgets + box fontwrapper imagebutton tags list numericeditbox sharedstatebutton windowcaption widgets ) add_component_dir (fontloader diff --git a/components/settings/categories/gui.hpp b/components/settings/categories/gui.hpp index aea288ca65..a26364c5dd 100644 --- a/components/settings/categories/gui.hpp +++ b/components/settings/categories/gui.hpp @@ -25,8 +25,6 @@ namespace Settings SettingValue mMenuTransparency{ mIndex, "GUI", "menu transparency", makeClampSanitizerFloat(0, 1) }; SettingValue mTooltipDelay{ mIndex, "GUI", "tooltip delay", makeMaxSanitizerFloat(0) }; SettingValue mStretchMenuBackground{ mIndex, "GUI", "stretch menu background" }; - SettingValue mControllerMenus{ mIndex, "GUI", "controller menus" }; - SettingValue mControllerTooltips{ mIndex, "GUI", "controller tooltips" }; SettingValue mSubtitles{ mIndex, "GUI", "subtitles" }; SettingValue mHitFader{ mIndex, "GUI", "hit fader" }; SettingValue mWerewolfOverlay{ mIndex, "GUI", "werewolf overlay" }; diff --git a/components/widgets/list.cpp b/components/widgets/list.cpp index 739d50bff2..416590ed48 100644 --- a/components/widgets/list.cpp +++ b/components/widgets/list.cpp @@ -176,9 +176,4 @@ namespace Gui { mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); } - - void MWList::setViewOffset(int offset) - { - mScrollView->setViewOffset(MyGUI::IntPoint(0, offset)); - } } diff --git a/components/widgets/list.hpp b/components/widgets/list.hpp index 94829d93df..f67a7da97b 100644 --- a/components/widgets/list.hpp +++ b/components/widgets/list.hpp @@ -48,7 +48,6 @@ namespace Gui ///< get widget for an item name, useful to set up tooltip void scrollToTop(); - void setViewOffset(int offset); void setPropertyOverride(std::string_view _key, std::string_view _value) override; diff --git a/components/widgets/scrollbar.cpp b/components/widgets/scrollbar.cpp deleted file mode 100644 index 0384003e65..0000000000 --- a/components/widgets/scrollbar.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "scrollbar.hpp" - -#include - -namespace Gui -{ - std::vector ScrollBar::getAllWidgets() - { - std::vector widgets; - widgets.push_back(mWidgetStart); - widgets.push_back(mWidgetEnd); - widgets.push_back(mWidgetTrack); - widgets.push_back(mWidgetFirstPart); - widgets.push_back(mWidgetSecondPart); - return widgets; - } -} diff --git a/components/widgets/scrollbar.hpp b/components/widgets/scrollbar.hpp deleted file mode 100644 index fa4cee01f0..0000000000 --- a/components/widgets/scrollbar.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef OPENMW_COMPONENTS_WIDGETS_SCROLLBAR_H -#define OPENMW_COMPONENTS_WIDGETS_SCROLLBAR_H - -#include - -namespace Gui -{ - /// @brief A scrollbar that can return all its widgets for binding hover listeners. - class ScrollBar : public MyGUI::ScrollBar - { - MYGUI_RTTI_DERIVED(ScrollBar) - - public: - std::vector getAllWidgets(); - }; -} - -#endif diff --git a/components/widgets/sharedstatebutton.hpp b/components/widgets/sharedstatebutton.hpp index 1cf7364bf0..33dd70c763 100644 --- a/components/widgets/sharedstatebutton.hpp +++ b/components/widgets/sharedstatebutton.hpp @@ -21,14 +21,13 @@ namespace Gui public: SharedStateButton(); - void onMouseSetFocus(MyGUI::Widget* _old) override; - void onMouseLostFocus(MyGUI::Widget* _new) override; - protected: void updateButtonState(); void onMouseButtonPressed(int _left, int _top, MyGUI::MouseButton _id) override; void onMouseButtonReleased(int _left, int _top, MyGUI::MouseButton _id) override; + void onMouseSetFocus(MyGUI::Widget* _old) override; + void onMouseLostFocus(MyGUI::Widget* _new) override; void baseUpdateEnable() override; void shutdownOverride() override; diff --git a/components/widgets/widgets.cpp b/components/widgets/widgets.cpp index 58b5736b30..d27d7e5fc9 100644 --- a/components/widgets/widgets.cpp +++ b/components/widgets/widgets.cpp @@ -6,7 +6,6 @@ #include "imagebutton.hpp" #include "list.hpp" #include "numericeditbox.hpp" -#include "scrollbar.hpp" #include "sharedstatebutton.hpp" #include "windowcaption.hpp" @@ -27,7 +26,6 @@ namespace Gui MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); } diff --git a/files/data/CMakeLists.txt b/files/data/CMakeLists.txt index b1da9f6756..d9218b45b2 100644 --- a/files/data/CMakeLists.txt +++ b/files/data/CMakeLists.txt @@ -9,22 +9,6 @@ set(BUILTIN_DATA_FILES textures/omw_menu_scroll_right.dds textures/omw_menu_scroll_center_h.dds textures/omw_menu_scroll_center_v.dds - textures/omw_menu_icon_active.dds - textures/omw_steam_button_a.dds - textures/omw_steam_button_b.dds - textures/omw_steam_button_dpad.dds - textures/omw_steam_button_l1.dds - textures/omw_steam_button_l2.dds - textures/omw_steam_button_l3.dds - textures/omw_steam_button_lstick.dds - textures/omw_steam_button_menu.dds - textures/omw_steam_button_r1.dds - textures/omw_steam_button_r2.dds - textures/omw_steam_button_r3.dds - textures/omw_steam_button_rstick.dds - textures/omw_steam_button_view.dds - textures/omw_steam_button_x.dds - textures/omw_steam_button_y.dds textures/omw/water_nm.png fonts/DejaVuFontLicense.txt @@ -162,7 +146,6 @@ set(BUILTIN_DATA_FILES mygui/openmw_console.layout mygui/openmw_console.skin.xml mygui/openmw_container_window.layout - mygui/openmw_controllerbuttons.layout mygui/openmw_count_window.layout mygui/openmw_dialogue_window.layout mygui/openmw_dialogue_window.skin.xml @@ -173,7 +156,6 @@ set(BUILTIN_DATA_FILES mygui/openmw_infobox.layout mygui/openmw_interactive_messagebox.layout mygui/openmw_interactive_messagebox_notransp.layout - mygui/openmw_inventory_tabs.layout mygui/openmw_inventory_window.layout mygui/openmw_journal.layout mygui/openmw_journal.skin.xml diff --git a/files/data/l10n/OMWEngine/de.yaml b/files/data/l10n/OMWEngine/de.yaml index 25bc145159..a23dbebdae 100644 --- a/files/data/l10n/OMWEngine/de.yaml +++ b/files/data/l10n/OMWEngine/de.yaml @@ -58,7 +58,7 @@ MissingContentFilesListCopy: |- other{\n\nDrücken Sie „Kopieren“, um alle Namen in die Zwischenablage zu kopieren.} } OverwriteGameConfirmation: "Sind Sie sicher, dass Sie den Spielstand überschreiben wollen?" -SelectCharacter: "Charakter auswählen" +SelectCharacter: "Charakter auswählen..." TimePlayed: "Spielzeit" @@ -213,13 +213,3 @@ WindowModeWindowed: "Fenster" WindowModeWindowedFullscreen: "Fenster in Vollbildgröße" # More fitting translations of "wobbly" are welcome WobblyShores: "Wabbelige Uferlinien" - - -# Controller button names - -EnchantType: "Zaubertyp" -InventorySelect: "Geben" -JournalQuests: "Quests" -JournalShowAll: "Alle Anzeigen" -RechargeSelect: "Aufladen" -RepairTool: "Werkzeug" diff --git a/files/data/l10n/OMWEngine/en.yaml b/files/data/l10n/OMWEngine/en.yaml index 176e604f8e..8a3217a03c 100644 --- a/files/data/l10n/OMWEngine/en.yaml +++ b/files/data/l10n/OMWEngine/en.yaml @@ -58,7 +58,7 @@ MissingContentFilesListCopy: |- other{\n\nPress Copy to place their names to the clipboard.} } OverwriteGameConfirmation: "Are you sure you want to overwrite this saved game?" -SelectCharacter: "Select Character" +SelectCharacter: "Select Character..." TimePlayed: "Time Played" @@ -212,13 +212,3 @@ WindowModeHint: "Hint: Windowed Fullscreen mode\nalways uses the native display WindowModeWindowed: "Windowed" WindowModeWindowedFullscreen: "Windowed Fullscreen" WobblyShores: "Wobbly Shores" - - -# Controller button names - -EnchantType: "Cast Type" -InventorySelect: "Put" -JournalQuests: "Quests" -JournalShowAll: "Show All" -RechargeSelect: "Recharge" -RepairTool: "Tool" diff --git a/files/data/l10n/OMWEngine/fr.yaml b/files/data/l10n/OMWEngine/fr.yaml index bd96ae0d80..fc584d8293 100644 --- a/files/data/l10n/OMWEngine/fr.yaml +++ b/files/data/l10n/OMWEngine/fr.yaml @@ -58,7 +58,7 @@ MissingContentFilesListCopy: |- other{\n\nCliquez sur Copier pour placer ces noms dans le presse-papier.} } OverwriteGameConfirmation: "Écraser la sauvegarde précédente ?" -SelectCharacter: "Sélection du personnage" +SelectCharacter: "Sélection du personnage..." TimePlayed: "Temps de jeu" @@ -212,13 +212,3 @@ WindowModeHint: "Info : Le mode \"Fenêtré plein écran\" utilise toujours la r WindowModeWindowed: "Fenêtré" WindowModeWindowedFullscreen: "Fenêtré plein écran" WobblyShores: "Rivages vacillants" - - -# Controller button names - -EnchantType: "Type de lancement" -InventorySelect: "Placer" -JournalQuests: "Quêtes" -JournalShowAll: "Tout Afficher" -RechargeSelect: "Recharge" -RepairTool: "Outil" diff --git a/files/data/l10n/OMWEngine/ru.yaml b/files/data/l10n/OMWEngine/ru.yaml index 6bee247c9d..c50fbac38e 100644 --- a/files/data/l10n/OMWEngine/ru.yaml +++ b/files/data/l10n/OMWEngine/ru.yaml @@ -58,7 +58,7 @@ MissingContentFilesListCopy: |- other{\n\nНажмите Скопировать, чтобы поместить их названия в буфер обмена.} } OverwriteGameConfirmation: "Вы уверены, что хотите перезаписать это сохранение?" -SelectCharacter: "Выберите персонажа" +SelectCharacter: "Выберите персонажа..." TimePlayed: "Время в игре" @@ -212,13 +212,3 @@ WindowModeHint: "Подсказка: режим Оконный без полей WindowModeWindowed: "Оконный" WindowModeWindowedFullscreen: "Оконный без полей" WobblyShores: "Колеблющиеся берега" - - -# Controller button names - -EnchantType: "Тип заклинания" -InventorySelect: "Поместить" -JournalQuests: "Квесты" -JournalShowAll: "Показать все" -RechargeSelect: "Перезарядить" -RepairTool: "Инструмент" diff --git a/files/data/l10n/OMWEngine/sv.yaml b/files/data/l10n/OMWEngine/sv.yaml index 50a33582f3..b3bb6788ed 100644 --- a/files/data/l10n/OMWEngine/sv.yaml +++ b/files/data/l10n/OMWEngine/sv.yaml @@ -59,7 +59,7 @@ MissingContentFilesListCopy: |- other{\n\nKlicka på kopiera för att placera deras namn i urklipp.} } OverwriteGameConfirmation: "Är du säker på att du vill skriva över det här sparade spelet?" -SelectCharacter: "Välj spelfigur" +SelectCharacter: "Välj spelfigur..." # Settings menu @@ -213,13 +213,3 @@ WindowModeHint: "Notera: Helskärm i fönsterläge\nanvänder alltid skärmens n WindowModeWindowed: "Fönster" WindowModeWindowedFullscreen: "Helskärm i fönsterläge" WobblyShores: "Vaggande stränder" - - -# Controller button names - -EnchantType: "Typ" -InventorySelect: "Placera" -JournalQuests: "Uppdrag" -JournalShowAll: "Visa Alla" -RechargeSelect: "Ladda" -RepairTool: "Verktyg" diff --git a/files/data/mygui/openmw_controllerbuttons.layout b/files/data/mygui/openmw_controllerbuttons.layout deleted file mode 100644 index e0e68bf2ed..0000000000 --- a/files/data/mygui/openmw_controllerbuttons.layout +++ /dev/null @@ -1,211 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/data/mygui/openmw_inventory_tabs.layout b/files/data/mygui/openmw_inventory_tabs.layout deleted file mode 100644 index 3787452586..0000000000 --- a/files/data/mygui/openmw_inventory_tabs.layout +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/data/mygui/openmw_inventory_window.layout b/files/data/mygui/openmw_inventory_window.layout index 2f2af06021..a555c94031 100644 --- a/files/data/mygui/openmw_inventory_window.layout +++ b/files/data/mygui/openmw_inventory_window.layout @@ -30,13 +30,6 @@ - - - - - - - @@ -57,13 +50,6 @@ - - - - - - - diff --git a/files/data/mygui/openmw_layers.xml b/files/data/mygui/openmw_layers.xml index f2eed488e1..459db3fcb9 100644 --- a/files/data/mygui/openmw_layers.xml +++ b/files/data/mygui/openmw_layers.xml @@ -14,7 +14,6 @@ - diff --git a/files/data/mygui/openmw_resources.xml b/files/data/mygui/openmw_resources.xml index 47fa71e984..4c32512004 100644 --- a/files/data/mygui/openmw_resources.xml +++ b/files/data/mygui/openmw_resources.xml @@ -144,10 +144,6 @@ - - - - @@ -172,10 +168,6 @@ - - - - @@ -192,10 +184,7 @@ - - - - + diff --git a/files/data/mygui/openmw_savegame_dialog.layout b/files/data/mygui/openmw_savegame_dialog.layout index 5a45810943..8bb6a64401 100644 --- a/files/data/mygui/openmw_savegame_dialog.layout +++ b/files/data/mygui/openmw_savegame_dialog.layout @@ -6,7 +6,7 @@ - + diff --git a/files/data/mygui/openmw_text.skin.xml b/files/data/mygui/openmw_text.skin.xml index 1724458522..5f96d0a57c 100644 --- a/files/data/mygui/openmw_text.skin.xml +++ b/files/data/mygui/openmw_text.skin.xml @@ -120,38 +120,6 @@ color_misc=0,205,205 # ???? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/data/mygui/openmw_trade_window.layout b/files/data/mygui/openmw_trade_window.layout index e5cf8a0ba0..49ccf25ba2 100644 --- a/files/data/mygui/openmw_trade_window.layout +++ b/files/data/mygui/openmw_trade_window.layout @@ -7,13 +7,6 @@ - - - - - - - @@ -34,13 +27,6 @@ - - - - - - - diff --git a/files/data/scripts/omw/input/gamepadcontrols.lua b/files/data/scripts/omw/input/gamepadcontrols.lua index 75ca494a27..9b89d505b5 100644 --- a/files/data/scripts/omw/input/gamepadcontrols.lua +++ b/files/data/scripts/omw/input/gamepadcontrols.lua @@ -20,13 +20,6 @@ return { return input._isGamepadCursorActive() end, - --- Checks if the controller menu option is enabled. If true, UI is replaced with a more controller appropriate interface. - -- @function [parent=#GamepadControls] isControllerMenusEnabled - -- @return #boolean - isControllerMenusEnabled = function() - return input._isControllerMenusEnabled() - end, - --- Sets if the gamepad cursor is active. If it is active, the left stick can move the cursor, and A will be interpreted as a mouse click. -- @function [parent=#GamepadControls] setGamepadCursorActive -- @param #boolean value diff --git a/files/data/textures/omw_menu_icon_active.dds b/files/data/textures/omw_menu_icon_active.dds deleted file mode 100644 index be743ace7f84a7e9fa9a9dfa43097909bfec2ff1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5616 zcmeHLy-piJ5MG~;VCP3VMZy#yamA&K1Vy4qm%@NA$zqQak_g2V3BuM2l<)==79b?L z(-lY*yaS|gO-V_K^MJ^a`{1BN4gji01% z#K+`>J>b51)%pr%wwYm5fALlFWy(K>4#V5;4lXhA`J+DzB!7qagUDG7FU>!SZ+iXH z`?<#++W++?^a|JTodFn`AUc>f3GOGB6MX7crL|C@H-{15AaAekRy zyc$v_?QbsOC2@Y#s_s4_{G}zW9oz47GmU=%B)Y>` diff --git a/files/data/textures/omw_steam_button_a.dds b/files/data/textures/omw_steam_button_a.dds deleted file mode 100644 index 447aa6081540c570208bd37a9338954feaf6990d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22000 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 diff --git a/files/data/textures/omw_steam_button_b.dds b/files/data/textures/omw_steam_button_b.dds deleted file mode 100644 index 0be30636439019f9695ca56f5abfa614474cef26..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22000 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 diff --git a/files/data/textures/omw_steam_button_dpad.dds b/files/data/textures/omw_steam_button_dpad.dds deleted file mode 100644 index d730db44a84fb05bdd4fb87961ca61bdd2d9c8e5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22000 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 diff --git a/files/data/textures/omw_steam_button_l1.dds b/files/data/textures/omw_steam_button_l1.dds deleted file mode 100644 index 2b79a67b985b3e73eef56c54a3bb66e895456044..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22000 zcmeHPdr(x@89#TIU3smnkxkrKDx*7SG(PAEF=XOi1FgAjP^PerHnl||im6mhn=)wa zQp=>186UVl010B$`e^F-h_ei}oe(gsTmL8}iDpJSFp)UJXyhGbS@!fh_wG4&_lm4L zfP&sT2lU4|_nz~8zweyyeCM8X)6z2Ie}@nnXN*Ke@Gtp6Jo$xCIQ$6dixz($euUH? ziGLgHS3G2f!B5(z3G0xE(L4w3ZxZHJ>>H0CP#5t4p0B>g%KSAF`=x*xxy zt&?9q{_lsy_Bit=ljqrNHWN1vfL@;{ViSkrkl^rq{Kj~K$)k9U(20NRg7!!)cw-#k z{1-WjS4RP!9f2s$iw0~_@q_AP4bh(^is^5;PWTG1Gi;~#&qPA!^q!qx5bg882k>XO zx^=}TB41e<{DbkmGF2>ZGwHbRBqP4$sK__rcTJdZps8Rv@GbG{G`sBQXa9@w-TZ^z zZ}wfYFurg9rnkva5yslvwNq$x?DoT@LZj26Vye%sVEWi$f5qw0GkxA#@onnm#_&9P zf3?Y5?_Om%Lva#kZ=BwxbyKY5U+Uj0b12`>BjLccn!#lSY+(@T*VKrk6v#@ z$q`YTl0NbE9PP;>Jx}%7z5ejw9;4wT#akk}KU#Q5=3hCUPX)gJ?#H*`P?3K7vo9sn z`*XS*j-Sb?PoNlo_S_X=qRh7&Pr8(lF1H`)NJ;4e^8u$ok2Ko_49}TzSlKc{Q9rT=kW3wsy>1L{YU)yuQO^BAyK|dhmSrqI`s^k5Kt99$#4cdg27e|J}0I4UxxW{@pn5 zP{J?k*!(Qi_JmsAT7{>ebLkMTO7>_?!!Zb!5blTVRk#Y@-AS@V{}yU}!O91#KWKgx zj%i6=-!)S0Q?@@;{`X8uG)?s5zpwfOW8|?7tpB_5YmJul#)rngz4)}@DkNE7;wa1F z2O6)?e0wpFKZ5)#>kAdzi<5tK9TIJ?lCR;$q4HlE2ju(nUkCg{qV08KApZ&G-(F1C zFAdE8tagGcYpH&M*~6IQzh32^a7(U%=6CjDtEV24oF8m_8e{!m=aA?Bs{dyM3}nyh_|Mcc z;QTn4eFn=9wf|e~udagqC2YOGUW~E_!`7=RuUuzn4ZZwQ|J@C(a+4F;qN6LI_m9_sfdkF2Rg2mq<)TgXJ7#{2XKbU-K z{^0#j<$rMfJnr^0Wd0xV`v2q3&q&L65C1{-f9#z^-v8{%B)x|C+rE$B<=-*I`=8h9 z*nY2(Zom5cp^aY>|7Cj^pXXrnmoX-Z;=Pl|{-0?JDc%zC!i3Di(h7>Z*H>mow#ELM zVtidQkE<+U`^$UD)G1v9`}ZY#f%+Vl{8@sEAB{dlK7_x?`}3}&u)Ky8wqLV*eM97b ze`;m>{kB9LoSSkp)k^tF;$GOb*;V18xZ3pR<{uZ7H&J|R#l%`+PC1LOyLO;?!t8QZ zzN-|)3;7jne}IY~vOad8__eux(`CMj61L~&TPdzK8E0MoYa7E!+(D~#OD8MO>EC@T z)wvS*h5g++lWiut-G1Ix1$+{3fVkzl_nY_OO2+S+D3syABws3#7meVsj*1_ZK7bGY zte^gu>l!Xz_R4(BM9WrSJK2vd^2u|0)AL`RChKKz9wZ|x;Jg={{vzi?R!Zw<2$@9O zuv#mwufhFr;Dggoi}2r%#p&U&j^Fy5iXXZ@#s%uX0)0vO${>6J***+xiyRV5Ap8@) zmFr_FCfbqDtEl==_3l+|d61?7~Ak zdno=HoOiq6Du?qg;44Ak{~@z=~Pqip!?ICI&s$&+%bjfKm3R=6`h?e&d*_V$qFwOG}8Qz zJl|%+#@G_hT*CUJQeGtvCjb1NWq(Y9MC%WAzxUF%7*8!EA}gXyL379Hmm`Gk#RO#$krn>PcS zD(_d~k?#M>`bHZLCjXoP$G?Yn-fyJ!<&z)!o7Cf!^Pd~qwhi$9;~LH12&rV|@9-_5@7d^#4slw&D>+AP(MjF-H)3irw9jm1V~7+&_}^EMbST54BK^Wl5^ z`)cpfj#x;v{x`jOJ8nRtSUDcX-rP0842e9?2-l^C!1*+eZ_pk`;YIX*uCHA)7ZNES z2AA@A%KBFasXt6n|8t%FP4NCVo7Pw1Cc(?DDHMkdbN%z(f2b6elJx|HU^yH8q|eD^ zi|Y#zUjVM?@7?7eKZJSO&n61wCAIV|%wY0k)6?196eD}z{V9noAmpO*3^&FmFuvM_ z?0xJ4)KMaRKLv#0Y&LC5V7xcncmXQg&FbSJo+Rr%g#{X-FX--Q`W09&^68hXZ_Q9( zDBo#yL<0X%9`bSCgbbw1VEV$(B0g$cZ8+5*jz;nJym#NE_+)=zd~>ota6TV%H*M** zJ^R4_kQxwr$~(7g>xumgEAPihn<4bF_m#F8SHNF`%aZO!_h5Kv!U?>a`8SWIw@s*z z&!Y8t&BD~Rlh3_EvB$i1`nuhFSp8n}tRssYa{F3-zV@V{Ir|DNf9Ck2@A-cZ=P##- I6!LiXe`A%mtpET3 diff --git a/files/data/textures/omw_steam_button_l2.dds b/files/data/textures/omw_steam_button_l2.dds deleted file mode 100644 index 156b1ca96c57d9a3120871fd7994214482d2f7a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22000 zcmeHP4OCQB9=~sf8D$V=6vmIzFvU{S1XI*XXH>TBoeqdAv)Z;5A}N_5eHgmhLg~>w zrop)NWN%7NeH2N}r+LS5m9kDvJ4-@p$)`6=OVSNrG> zi9zraHzR5E<(})RGhX^z&09+c#E^* zbQmq~X%*j8n^6@^@thF82@eWJ6sL6q92LN~N*}W|p#RhmBdvd`lK%<+J@j3Qxqdmr z(JEa6;WrUXK(Np4!@m>wHYFuSb5+HkmiG#$&+BbD>UZyXESBOk&zAqsvThXElW0-R zf2pdqtO{cMHy7}SY?c6K`nk#aXj+jy$!1YAKI-{jCLcbcNu%vq8}jE#hLYTa6m$I) zkAD_nhW-p;rV*i;>hgl=i}Z|t$LyF338l#z`aJ$=$hX1a{aN{~F8kpqk_Z>^C>OEi z8yjyC{uIDBUmv*T{J?ZjJmuq{>$v$9zI7AD_59Y7^SwhE|5KIc9xLG2XKJ>Xng4HfeOc!GGS@}Zk&1j1FT!^KQ*DU-;a2Mdx7ZbDa=O8IF1Dv> z#SG)ICRq}#%CiEx%+g?AKYsB0`(JS z#OreX?;_^&li(&#ko4v?iOSJ%Q=HZf$oJqsnp>1Ny}a;Kntm{*z9B3|&-izJ9Z|I`TGDLM04VGIX-T-elFp^;OhKyJ$9#jusn^$3md~7nbTg*&ms~LdD=>f z>w-6%A$}C`MI65;>ZOejP<*rHyV>+*9LK3QTLcmW`}DUy`SW-L;V)<~tFIb2@A*ioKXU$?WIcqnN18uV`AL2$ z{=%rtTK6$z}!sgbmyT01i zT<78W&9wfG>QA2EU;d@`BBVE&Ouf;fyl2X#cyPzyMqPMJch>*g4_Grb8@%FyLs9Y9 z9}nDY{}&XJs*=g+Q}e^CnvDY`FD84Nd-XH!&6ci=yqV&|7Yz8C*M{vE`>p(6K< zBi1)y{Y&Ie&W{`$Dq=I5U(fhidY*g}FQPL;8E!OqV0nIDIJ=^?L;kF@`ak8r2P)5h zraZ3~5sCb5v&g@eVv+w$HXnp|@Xq4DdPVyV556iYZJ|Oi=ayHFt+lZU^&Zd5^*yB) zV*_rDB##I>Wb5tMhO;YRFmqZVH+^3CdfoVX`#-7OWYX*Vpz?xe7UeVkZ9`-9(El0# z?RMz=n;TgCC-CnP@5uGz3*T)2@2frjrW+jD&g$H2_a~87Tl!+#tfQU9x4gX_;UB_3 z{ZOvFV6g}P)nj2X075|8Ue^yB8iLo`*?xe$et+?u#=o{2`g?Z6ZmN&m)!VN+KY;kp zy`L)f?-7pI9qs$9B)i*R2wyu5`^!J<2hF_K_QEXE8kI`LB`M1b7cW}C#`_a9V$LTx zr2T+1uH=8zzjWYOXSM%!=O5;8gl`rvI?%$VC@+5}j+|5pb z z2R76N7aN(shw&cPf2I9CU+wXg?l1p_>?cz^`N&>|lCOph*3^unu^Cq!Z;3z0xS6f* zY0Gl^)qqQv`19`H@_1gG9qU(nE^Tj%1G~VDVN5|5ZBP5h z5%%Cx&;4K6{GX?|VdFtZ<-gnWU&6nS^B}NI-enRlZ#WsVGszxNozQj-qatBaodB~zBknGgMTPu z^TGXtRwZU+71q-FPd=yE9sjU|8@J(1u!U(=-*#`G_64W zUrcR#km|pl&nexOnr@(YZAkC&7tbAK>0G};BNsjl)~`uza01-DUqz5`$*|l%aNTsu zCu5TZ`v42k59f|&?y9mf{-y@4s#}94JTth5-Qt1ggrG!EoYoD&%R|!h0qmbXW@}KK z%|m}vmG*r{T#`Pyem{;1Rv_5#7T8VX)Ni@hGvR%ZB$J8qPtpOwCV*%L*NVOD1M+if z^K9xrNLie^rmN?9E=~9!EYe*g?vR$zb5+-WFa4Jd%s&S*AL!*RR;&g`1Xl;vR4L$uHkcD_+wo}&dfN8-jv zT3*+kFFuAo9`BwHB_(yOO$|Hu#C$l_ORS6IZi4v}LB_=K z=!0T$e;pv4$6kT5@)(8#+88P7fU+gx^KfLt$9}Od`4v54Q%YjzmXPw`{Ew=2EC|0v zl3#wl6V5Ax@RIyflIZz;@Re}s%AUwL1~(}W)Okt!a0t?z*sX}B@~cDW`6kct_+wRm zU$^|+#c?3~7SH`pa=ukM@6b{C)18J!VKVOKKkWiC1Np)Q;v)Q7AM%UIgOPpdptO%5 z3z@AO6SEKq&#w(47{ph7*wRvlomQ4#ZV$fXHzI!Rx~hWSq&z~G>vtP6HP*T-_WzE` zFK?e5LoiH&L@~a$A%#U6^TUu+R!ej4mkTV4z%BFJl+aC^HZ8_1SP?Ivugn~UNC8KJ>e4UtWz#e{(KG1zXdJ)DT*He z>%YYNT|<6Z`8oT^`3Wm2PH2z6{GSZH;5Gg?y4q{;SHGU|-p%xJYn&8sbwdA64`KfLcEflM3Q9Y4gsuPEx%bK@c&rD@=X+e&y(x74 zj#HUT6HuwS7ED0wU7SfdEq(y+;m@GUC)coaWV+q(RAiq^OxW!mOyQ{ED2u0zNo@U7 zux-J<**EdauY5i{mdp?N9x(qS{+dI|N4@=bXJc+Ol%LZN;%ic$5#jKd3tS|L_e6$1 zcY4P|osDrwiL!Bb*jKbZj5g~+TFq?yKP^mkrT9F;1^xT$p+bBN1`%}fEXj!@$psUGwwalwojFeA?BT7uhPs*Ae?i4j2eG zDJ=-Dx$WT0vRlaG?)s~WB8o`72)ov6^{qOu8mU2`M$?H^@)^zZFJ& z$}Tt7!|$E#Efv_~eNB1&?eM;K_{su7K6sp40DR;4xALfbpA%2dE0}-pD8?bXyPeS) zm_Jr&JoevV{xc4(H#7ePJw*8^RPK%kNss9$=0UfP7%{{GR1B8neEF?KEl=;^4hY^UEZ*> z@fi2*lR8nA#Po}Y#F(cakp7=sTc6~Au5)QwdY*HUy~`4_lppofO%e7Vp)t^;!QXnv z+j0!e9{eA?iuPAiV;_DbUzup4?QQMF4_MhZ?kS3!)vE{1%U?|(WJSo)Yt)X3mR}4M cAAV`4p?gaAHj0bh@0O#0=O`}TNODQ||4q~$wg3PC diff --git a/files/data/textures/omw_steam_button_l3.dds b/files/data/textures/omw_steam_button_l3.dds deleted file mode 100644 index 3b6b174e482c790cf00896e35d34f2683af53313..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22000 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 diff --git a/files/data/textures/omw_steam_button_menu.dds b/files/data/textures/omw_steam_button_menu.dds deleted file mode 100644 index ef0a0a501c8c3cc085b8de4b369fb96c36640bfb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22000 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 LO#U@*1mph)YI8aW diff --git a/files/data/textures/omw_steam_button_r1.dds b/files/data/textures/omw_steam_button_r1.dds deleted file mode 100644 index bdd93de2b2975c69b7d431ad106dcbad015f1b02..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22000 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 C_0qNg diff --git a/files/data/textures/omw_steam_button_r2.dds b/files/data/textures/omw_steam_button_r2.dds deleted file mode 100644 index 052e97ebe1aca5f4511a54f5170c846435b01567..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22000 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 X>*CL)FkD_ag@hq*KV=oP9*+MXXwoi9 diff --git a/files/data/textures/omw_steam_button_r3.dds b/files/data/textures/omw_steam_button_r3.dds deleted file mode 100644 index 73b4bea1f7bb3ecb45eb2df16d2e84757b7d2075..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22000 zcmeHP4_s7LzCUM%8D>CWhRxynYr(G?r_eXxuqkiZSAM~x#E21 zoO{mi|M{Iicb<4+M#wURkh{tQ8Q_2N4{6CCgcR^kH|_CXKMDVIQ=aC(yWO7*VzB{NQhueWM)|rx&(ReB z-)LR@kvcV|_}F8*_^K*7lizU>J|V&%i*V^g=jTtkz~cJi_Qd^(=@HZWp;|Y+Dp;97 z`B|lGKi2td8sitc_f}!I5GgJH_t(E6v2xXdrzyV%q{~>T+Y(A~Rj;?gm0MI%6n9j< z|K+q?6^jpF+mJR>m&xjLb-KxmGToScT(+We6NC`@{5K+8?*fbKi`#?#9?f*;b!?3>|n@#aw(UOcD2mRiZ_=e*EqlA`s*cuL8iSxcfF_Mu__RF5XP(;VC`-?j{ zU6$|Q3}4a<>HphcgIj_@5l%7Ae@Bm{y-Fw^1LK|LjVe zKeu>*-O2baA4d66W8IdE#aEfWvph?!M;`et^XE$w3SY{)JW5IH|E4{E+WG4_b1A+F z@nMI9JtWz5TP)u$w9xW@wf?!GBwZKu{Vl3I7Un>26Vh$j*ff`oXO||lAG;9b`68u1 z%X9g3ZjKkr2h=#KHmudb9^4^6NXuo<|J3XOE5W%}$%j*ZBvHsMp?o)se@BBlmS#P2 zj_J2OdCAqJoKcLQu7@*25R$X_*w3QdK7iS^h8QZbC0CnWbyCx zfWoCIH~zus>q?K97nu_-=o@0>?v2O7=<~Z#LUX7ta~Z`P#K(<;LfCjd@p^0?DI*t& zuNfQiU$4|y`cr(r?ZG}Nma};Nka@t=DhGW}y@Totucr@|)^+pXL4lY73@H06K zd1)!$4e_i_cZl)dg^(UM8FOfPSNittXUhe9I6a`Ppz~S59wH^nr)wH~+G&04o)7V% z-%*P1wLOT(?@_okx2Q0M*?&n8=zGNT%$~nT--__KkC^?-_v9xAo917p^m3?4kBOY% zBJy$-&x^~rmi}B*e_9_8I_Om?U%>L``BrtjV|#O)UQNDxz<)+y%J}~`YdBM8#Cl<`1?ThW< zMUg!OG(k;=c&<9^9M7@BG-t+@Pnm!Dn5_r6D|c>BV*15+%zLSg8bT~wL>{uerU6wM z){iI#duYW6jm#d~lD2PeQ+ckVR?+AK5Ul^I0JtXz=TkH4RSjz^f{MIP(v&yu?_6 zN;l`MS^og-|21V{c1pzmuz26PxT)29XF2nCY}I9yugPKd3gg{|KxKv}eg1CcA%5PK z{>A(N_O5}O(lh65ffc6;>jU0r)%nwOt9{qNz255u(F7nNo&E)?{?v+t4zW<)fx zcyB4Vn(VPf(7z4Etr(QNg5@*%GbhZ}8)lXd-D`RDRR5YMObfeA3xg?tnlkc9%JOp# zl}IK|6V_u~$wyPBPBOombl>put=uAjLigZY2a@Q47vCL`0o?X!21J@RUp|I7T+U$1=A z%H(;q1%ZoqsR7{3iR)NnwA$0-zFWuQCMFN!p#FU^>?oS2Qet$LH{LVn^Zn<)AnuE z@2EWBrg%v9o3EeWCFoy&=8W0))lWzN3;#g$m&p9zmA*A*Q{qT<(oD)V<;-t5wnnxG8-lV>hOagPY<9F(|(W`VS)dhY&!YFB*PT z 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 C+cc5@ diff --git a/files/data/textures/omw_steam_button_view.dds b/files/data/textures/omw_steam_button_view.dds deleted file mode 100644 index 8fb56f847fef49cf612c21ff664e4e25d661c561..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22000 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 diff --git a/files/data/textures/omw_steam_button_x.dds b/files/data/textures/omw_steam_button_x.dds deleted file mode 100644 index 9619ed243cfa4a27a4d5a4cfccd8a0f0551f12bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22000 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 Script After Startup: - - <html><head/><body><p>Make it easier to use game menus with a controller.</p></body></html> - - - - Enable Controller Menus - - - - <html><head/><body><p>When using controller menus, make tooltips visible by default.</p></body></html> - - - - Show Controller Tooltips By Default - - diff --git a/files/lang/launcher_en.ts b/files/lang/launcher_en.ts index 4097d29dd2..a0319318e8 100644 --- a/files/lang/launcher_en.ts +++ b/files/lang/launcher_en.ts @@ -1447,21 +1447,5 @@ to default Morrowind fonts. Check this box if you still prefer original fonts ov <html><head/><body><p>If enabled - makes transitions between different animations/poses much smoother. Also allows to load animation blending config YAML files that can be bundled with animations in order to customise blending styles.</p></body></html> - - <html><head/><body><p>Make it easier to use game menus with a controller.</p></body></html> - - - - Enable Controller Menus - - - - <html><head/><body><p>When using controller menus, make tooltips visible by default.</p></body></html> - - - - Show Controller Tooltips By Default - - diff --git a/files/lang/launcher_fr.ts b/files/lang/launcher_fr.ts index 3d2363130e..569a460cd0 100644 --- a/files/lang/launcher_fr.ts +++ b/files/lang/launcher_fr.ts @@ -1450,21 +1450,5 @@ to default Morrowind fonts. Check this box if you still prefer original fonts ov Run Script After Startup: Script à lancer après démarrage : - - Enable Controller Menus - Activer les menus du contrôleur - - - <html><head/><body><p>Make it easier to use game menus with a controller.</p></body></html> - <html><head/><body><p>Faciliter l'utilisation des menus de jeu avec une manette.</p></body></html> - - - <html><head/><body><p>When using controller menus, make tooltips visible by default.</p></body></html> - <html><head/><body><p>Lorsque vous utilisez les menus du contrôleur, rendez les info-bulles visibles par défaut.</p></body></html> - - - Show Controller Tooltips By Default - Afficher les info-bulles du contrôleur par défaut - diff --git a/files/lang/launcher_ru.ts b/files/lang/launcher_ru.ts index cd6768942f..879f24dc76 100644 --- a/files/lang/launcher_ru.ts +++ b/files/lang/launcher_ru.ts @@ -1462,21 +1462,5 @@ to default Morrowind fonts. Check this box if you still prefer original fonts ov Use the Camera as the Sound Listener Использовать камеру как слушателя - - <html><head/><body><p>Make it easier to use game menus with a controller.</p></body></html> - - - - Enable Controller Menus - - - - <html><head/><body><p>When using controller menus, make tooltips visible by default.</p></body></html> - - - - Show Controller Tooltips By Default - - diff --git a/files/lang/launcher_sv.ts b/files/lang/launcher_sv.ts index 63912de9e1..f2cca2346c 100644 --- a/files/lang/launcher_sv.ts +++ b/files/lang/launcher_sv.ts @@ -1466,21 +1466,5 @@ de ordinarie fonterna i Morrowind. Bocka denna ruta om du ändå föredrar ordin <html><head/><body><p>If enabled - makes transitions between different animations/poses much smoother. Also allows to load animation blending config YAML files that can be bundled with animations in order to customise blending styles.</p></body></html> <html><head/><body><p>Vid aktivering gör denna funktion att övergångarna mellan olika animationer och poser blir mycket mjukare. Funktionen gör det också möjligt att konfigurera animationsövergångarna i YAML-filer. Dessa filer kan buntas ihop tillsammans med nya animationsfiler.</p></body></html> - - <html><head/><body><p>Make it easier to use game menus with a controller.</p></body></html> - <html><head/><body><p>Gör det enklare att använda spelmenyer med en handkontroll.</p></body></html> - - - Enable Controller Menus - Aktivera handkontrollmenyer - - - <html><head/><body><p>When using controller menus, make tooltips visible by default.</p></body></html> - <html><head/><body><p>När du använder kontrollmenyer, synliggör verktygstips som standard.</p></body></html> - - - Show Controller Tooltips By Default - Visa verktygstips för kontrollenheter som standard - diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 16dc7b78ff..e5654794cc 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -201,12 +201,6 @@ tooltip delay = 0.0 # Stretch menus, load screens, etc. to the window aspect ratio. stretch menu background = false -# Make menus easier to navigate with a controller. -controller menus = false - -# When true, you do not need to press R3 to show tooltips. -controller tooltips = false - # Subtitles for NPC spoken dialog and some sound effects. subtitles = false From 2db9b91c1000e0ed154f4daf15f7321b4e2c8983 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 5 Jul 2025 17:10:02 +0400 Subject: [PATCH 147/330] Do not recreate animation object when harvesting a plant --- apps/openmw/mwrender/animation.cpp | 17 +++++++++++------ apps/openmw/mwrender/animation.hpp | 2 ++ apps/openmw/mwworld/actionharvest.cpp | 9 ++++++--- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index f07a325f7c..c7ea225d5f 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -2096,12 +2096,17 @@ namespace MWRender if (Settings::game().mGraphicHerbalism && ptr.getRefData().getCustomData() != nullptr && ObjectAnimation::canBeHarvested()) { - const MWWorld::ContainerStore& store = ptr.getClass().getContainerStore(ptr); - if (!store.hasVisibleItems()) - { - HarvestVisitor visitor; - mObjectRoot->accept(visitor); - } + harvest(ptr); + } + } + + void ObjectAnimation::harvest(const MWWorld::Ptr& ptr) + { + const MWWorld::ContainerStore& store = ptr.getClass().getContainerStore(ptr); + if (!store.hasVisibleItems()) + { + HarvestVisitor visitor; + mObjectRoot->accept(visitor); } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index b6cb6f333c..6e39c44614 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -483,6 +483,7 @@ namespace MWRender virtual void setAccurateAiming(bool enabled) {} virtual bool canBeHarvested() const { return false; } + virtual void harvest(const MWWorld::Ptr& ptr) {} virtual void removeFromScene(); @@ -498,6 +499,7 @@ namespace MWRender bool animated, bool allowLight); bool canBeHarvested() const override; + void harvest(const MWWorld::Ptr& ptr) override; }; class UpdateVfxCallback : public SceneUtil::NodeCallback diff --git a/apps/openmw/mwworld/actionharvest.cpp b/apps/openmw/mwworld/actionharvest.cpp index 30f316c2db..1d9e009afe 100644 --- a/apps/openmw/mwworld/actionharvest.cpp +++ b/apps/openmw/mwworld/actionharvest.cpp @@ -11,6 +11,8 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" +#include "../mwrender/animation.hpp" + #include "class.hpp" #include "containerstore.hpp" @@ -89,8 +91,9 @@ namespace MWWorld MWBase::Environment::get().getWindowManager()->messageBox(tooltip); } - // Update animation object - MWBase::Environment::get().getWorld()->disable(target); - MWBase::Environment::get().getWorld()->enable(target); + auto world = MWBase::Environment::get().getWorld(); + MWRender::Animation* anim = world->getAnimation(target); + if (anim != nullptr) + anim->harvest(target); } } From 30a852bb883fcb49572154f2346963b10a2cb6f9 Mon Sep 17 00:00:00 2001 From: Cody Glassman Date: Sat, 5 Jul 2025 08:32:21 -0700 Subject: [PATCH 148/330] disable blending in second color attachment on water node --- apps/openmw/mwrender/water.cpp | 2 ++ components/resource/scenemanager.cpp | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 81e44248ac..81688a3444 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -565,6 +565,8 @@ namespace MWRender else createSimpleWaterStateSet(mWaterGeom, Fallback::Map::getFloat("Water_World_Alpha")); + mResourceSystem->getSceneManager()->setUpNormalsRTForStateSet(mWaterGeom->getOrCreateStateSet(), true); + updateVisible(); } diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index cbda399120..7ee29ff0eb 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -607,6 +608,9 @@ namespace Resource if (!getSupportsNormalsRT()) return; stateset->setAttributeAndModes(new osg::ColorMaski(1, enabled, enabled, enabled, enabled)); + + if (enabled) + stateset->setAttributeAndModes(new osg::Disablei(GL_BLEND, 1)); } /// @brief Callback to read image files from the VFS. From 390589795cdbe7a0bea4c48eac665d4bd8986fce Mon Sep 17 00:00:00 2001 From: Cody Glassman Date: Fri, 4 Jul 2025 08:19:27 -0700 Subject: [PATCH 149/330] postprocessing - set mipmaps levels for rendertargets when requested --- apps/openmw/mwrender/postprocessor.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/openmw/mwrender/postprocessor.cpp b/apps/openmw/mwrender/postprocessor.cpp index 1f1b7258b3..c3c98d7cef 100644 --- a/apps/openmw/mwrender/postprocessor.cpp +++ b/apps/openmw/mwrender/postprocessor.cpp @@ -655,6 +655,14 @@ namespace MWRender const auto [w, h] = renderTarget.mSize.get(renderWidth(), renderHeight()); subPass.mStateSet->setAttributeAndModes(new osg::Viewport(0, 0, w, h)); + if (subPass.mMipMap) + { + subPass.mRenderTexture->setNumMipmapLevels(osg::Image::computeNumberOfMipmapLevels(w, h)); + } + else + { + subPass.mRenderTexture->setNumMipmapLevels(0); + } subPass.mRenderTexture->setTextureSize(w, h); subPass.mRenderTexture->dirtyTextureObject(); From da71ec6e4951a73fe6ee34a8e06bbd1a41b2f418 Mon Sep 17 00:00:00 2001 From: Cody Glassman Date: Fri, 4 Jul 2025 08:39:39 -0700 Subject: [PATCH 150/330] postprocessing - bump revision --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 123462b8fd..c755ad315f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,7 +83,7 @@ set(OPENMW_VERSION_MAJOR 0) set(OPENMW_VERSION_MINOR 50) set(OPENMW_VERSION_RELEASE 0) set(OPENMW_LUA_API_REVISION 79) -set(OPENMW_POSTPROCESSING_API_REVISION 2) +set(OPENMW_POSTPROCESSING_API_REVISION 3) set(OPENMW_VERSION_COMMITHASH "") set(OPENMW_VERSION_TAGHASH "") From bf92e551a7dfcc8f4117267dd8f479f39310d8c2 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 5 Jul 2025 18:09:36 +0100 Subject: [PATCH 151/330] Eliminate reference to vestigial MT_BUILD variable --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c755ad315f..acbd42589f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -786,7 +786,7 @@ if (WIN32) endif() if (BUILD_BULLETOBJECTTOOL) - target_compile_options(openmw-bulletobjecttool PRIVATE ${WARNINGS} ${MT_BUILD}) + target_compile_options(openmw-bulletobjecttool PRIVATE ${WARNINGS}) endif() if (BUILD_OPENCS_TESTS) From da32ccee50a44745bebfa1e9badae3fe62998536 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 5 Jul 2025 19:49:08 +0100 Subject: [PATCH 152/330] Apply warning flags consistently for all compilers This avoids a problem where a bunch of our targets weren't having the right warning flags set up with MSVC. It shouldn't make any difference for other compilers, except Clang in clang-cl mode, which wants MSVC warning flags, and will now get them. It doesn't seem to resolve https://gitlab.com/OpenMW/openmw/-/issues/7882, so you still have to disable precompiled headers to see warnings with MSVC. --- CMakeLists.txt | 141 +++++++++++++------------------------------------ 1 file changed, 38 insertions(+), 103 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index acbd42589f..8e4880a88e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -590,30 +590,10 @@ if(OPENMW_LTO_BUILD) endif() endif() - -if (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang) - set(OPENMW_CXX_FLAGS "-Wall -Wextra -Wundef -Wextra-semi -Wno-unused-parameter -pedantic -Wno-long-long -Wnon-virtual-dtor -Wunused ${OPENMW_CXX_FLAGS}") - - if (CMAKE_CXX_COMPILER_ID STREQUAL GNU) - # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105438 - set(OPENMW_CXX_FLAGS "-Wno-array-bounds ${OPENMW_CXX_FLAGS}") - endif() - - if (APPLE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++") - endif() - - if (CMAKE_CXX_COMPILER_ID STREQUAL Clang AND NOT APPLE) - if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 3.6 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 3.6) - set(OPENMW_CXX_FLAGS "${OPENMW_CXX_FLAGS} -Wno-potentially-evaluated-expression") - endif () - endif() - - if (CMAKE_CXX_COMPILER_ID STREQUAL GNU) - set(OPENMW_CXX_FLAGS "${OPENMW_CXX_FLAGS} -Wno-unused-but-set-parameter -Wduplicated-branches -Wduplicated-cond -Wlogical-op") - endif() -endif (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang) +if (APPLE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++") +endif() # Extern @@ -624,8 +604,41 @@ if (BUILD_OPENCS OR BUILD_OPENCS_TESTS) add_subdirectory (extern/osgQt) endif() +if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" OR CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC") + add_compile_options("/W4") + + set(WARNINGS_DISABLE + 4100 # Unreferenced formal parameter (-Wunused-parameter) + 4127 # Conditional expression is constant + 4996 # Function was declared deprecated + 5054 # Deprecated operations between enumerations of different types caused by Qt headers + ) + + foreach(d ${WARNINGS_DISABLE}) + add_compile_options("/wd${d}") + endforeach(d) + + if(OPENMW_MSVC_WERROR) + add_compile_options("/WX") + endif() +else () + add_compile_options("-Wall" "-Wextra" "-Wundef" "-Wextra-semi" "-Wno-unused-parameter" "-pedantic" "-Wno-long-long" "-Wnon-virtual-dtor" "-Wunused") + + if (CMAKE_CXX_COMPILER_ID STREQUAL Clang AND NOT APPLE) + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 3.6 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 3.6) + add_compile_options("-Wno-potentially-evaluated-expression") + endif () + endif() + + if (CMAKE_CXX_COMPILER_ID STREQUAL GNU) + add_compile_options("-Wno-unused-but-set-parameter" "-Wduplicated-branches" "-Wduplicated-cond" "-Wlogical-op") + # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105438 + add_compile_options("-Wno-array-bounds") + endif() +endif () + if (OPENMW_CXX_FLAGS) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OPENMW_CXX_FLAGS}") + add_compile_options(${OPENMW_CXX_FLAGS}) endif() # Components @@ -715,87 +728,9 @@ if (WIN32) set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:WINDOWS") endif() - # Play a bit with the warning levels - - set(WARNINGS "/W4") - - set(WARNINGS_DISABLE - 4100 # Unreferenced formal parameter (-Wunused-parameter) - 4127 # Conditional expression is constant - 4996 # Function was declared deprecated - 5054 # Deprecated operations between enumerations of different types caused by Qt headers - ) - - foreach(d ${WARNINGS_DISABLE}) - list(APPEND WARNINGS "/wd${d}") - endforeach(d) - - if(OPENMW_MSVC_WERROR) - list(APPEND WARNINGS "/WX") - endif() - - target_compile_options(components PRIVATE ${WARNINGS}) - target_compile_options(osg-ffmpeg-videoplayer PRIVATE ${WARNINGS}) - if (MSVC_VERSION GREATER_EQUAL 1915 AND MSVC_VERSION LESS 1920) target_compile_definitions(components INTERFACE _ENABLE_EXTENDED_ALIGNED_STORAGE) endif() - - if (BUILD_BSATOOL) - target_compile_options(bsatool PRIVATE ${WARNINGS}) - endif() - - if (BUILD_ESMTOOL) - target_compile_options(esmtool PRIVATE ${WARNINGS}) - endif() - - if (BUILD_ESSIMPORTER) - target_compile_options(openmw-essimporter PRIVATE ${WARNINGS}) - endif() - - if (BUILD_LAUNCHER) - target_compile_options(openmw-launcher PRIVATE ${WARNINGS}) - endif() - - if (BUILD_MWINIIMPORTER) - target_compile_options(openmw-iniimporter PRIVATE ${WARNINGS}) - endif() - - if (BUILD_OPENCS) - target_compile_options(openmw-cs PRIVATE ${WARNINGS}) - endif() - - if (BUILD_OPENMW) - target_compile_options(openmw PRIVATE ${WARNINGS}) - endif() - - if (BUILD_WIZARD) - target_compile_options(openmw-wizard PRIVATE ${WARNINGS}) - endif() - - if (BUILD_COMPONENTS_TESTS) - target_compile_options(components-tests PRIVATE ${WARNINGS}) - endif() - - if (BUILD_BENCHMARKS) - target_compile_options(openmw_detournavigator_navmeshtilescache_benchmark PRIVATE ${WARNINGS}) - endif() - - if (BUILD_NAVMESHTOOL) - target_compile_options(openmw-navmeshtool PRIVATE ${WARNINGS}) - endif() - - if (BUILD_BULLETOBJECTTOOL) - target_compile_options(openmw-bulletobjecttool PRIVATE ${WARNINGS}) - endif() - - if (BUILD_OPENCS_TESTS) - target_compile_options(openmw-cs-tests PRIVATE ${WARNINGS}) - endif() - - if (BUILD_OPENMW_TESTS) - target_compile_options(openmw-tests PRIVATE ${WARNINGS}) - endif() endif(MSVC) # TODO: At some point release builds should not use the console but rather write to a log file From c7e3f9b0cf47a0797572b61b0f0396592df64838 Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Fri, 4 Jul 2025 21:38:14 +0200 Subject: [PATCH 153/330] Add some events from the dehardcode spellcasting MR, that do not need to be specific to that MR. --- .../source/reference/lua-scripting/events.rst | 70 +++++++++++++++++++ files/data/CMakeLists.txt | 2 + files/data/builtin.omwscripts | 2 + .../scripts/omw/mechanics/actorcontroller.lua | 23 ++++++ .../omw/mechanics/globalcontroller.lua | 39 +++++++++++ .../omw/mechanics/playercontroller.lua | 6 ++ 6 files changed, 142 insertions(+) create mode 100644 files/data/scripts/omw/mechanics/actorcontroller.lua create mode 100644 files/data/scripts/omw/mechanics/globalcontroller.lua diff --git a/docs/source/reference/lua-scripting/events.rst b/docs/source/reference/lua-scripting/events.rst index 007e0e43d1..d6ccd93003 100644 --- a/docs/source/reference/lua-scripting/events.rst +++ b/docs/source/reference/lua-scripting/events.rst @@ -41,9 +41,53 @@ Example: core.sendGlobalEvent('UseItem', {object = potion, actor = player, force = true}) +**ModifyStat** + +Modify the corresponding stat. + +.. code-block:: Lua + + -- Consume 10 magicka + actor:sendEvent('ModifyStat', {name = 'magicka', amount = -10}) + +**AddVfx** + +Calls the corresponding method in openmw.animation + +.. code-block:: Lua + + local eventParams = { + model = 'vfx_default', + options = { + textureOverride = effect.particle, + }, + } + actor:sendEvent('AddVfx', eventParams) + +**PlaySound3d** + +Calls the corresponding function in openw.core on the target. Will use core.sound.playSoundFile3d instead of core.sound.playSound3d if you put `file` instead of `sound` in the event data. + +.. code-block:: Lua + actor:sendEvent('PlaySound3d', {sound = 'Open Lock'}) + + +**BreakInvisibility** + +Forces the actor to lose all active invisibility effects. + + UI events --------- +**ShowMessage** + +If sent to a player, shows a message as if a call to ui.showMessage was made. + +.. code-block:: Lua + + player:sendEvent('ShowMessage', {message = 'Lorem ipsum'}) + **UiModeChanged** Every time UI mode is changed built-in scripts send to player the event ``UiModeChanged`` with arguments ``oldMode, ``newMode`` (same as ``I.UI.getMode()``) @@ -91,3 +135,29 @@ Global events that just call the corresponding function in `openmw.world`. -- world.setSimulationTimeScale(scale) core.sendGlobalEvent('SetSimulationTimeScale', scale) + + +**SpawnVfx, PlaySound3d** + +Calls the corresponding function in openw.core. Note that PlaySound3d will call core.sound.playSoundFile3d instead of core.sound.playSound3d if you put `file` instead of `sound` in the event data. + +.. code-block:: Lua + core.sendGlobalEvent('SpawnVfx', {position = hitPos, model = 'vfx_destructarea', options = {scale = 10}}) + core.sendGlobalEvent('PlaySound3d', {sound = 'Open Lock', position = container.position}) + +**ConsumeItem** + +Reduces stack size of an item by a given amount, removing the item complete if removing all items in the stack are removed. + +.. code-block:: Lua + + core.sendGlobalEvent('ConsumeItem', {item = foobar, amount = 1}) + +**ModifyItemCharge** + +Modify a specified amount of enchantment charge of an item + +.. code-block:: Lua + + -- Reduce charge by 10 + core.sendGlobalEvent('ModifyItemCharge', {item = foobar, amount = -10}) diff --git a/files/data/CMakeLists.txt b/files/data/CMakeLists.txt index d9218b45b2..39715af75d 100644 --- a/files/data/CMakeLists.txt +++ b/files/data/CMakeLists.txt @@ -91,7 +91,9 @@ set(BUILTIN_DATA_FILES scripts/omw/console/local.lua scripts/omw/console/player.lua scripts/omw/console/menu.lua + scripts/omw/mechanics/actorcontroller.lua scripts/omw/mechanics/animationcontroller.lua + scripts/omw/mechanics/globalcontroller.lua scripts/omw/mechanics/playercontroller.lua scripts/omw/settings/menu.lua scripts/omw/music/actor.lua diff --git a/files/data/builtin.omwscripts b/files/data/builtin.omwscripts index 37367783ab..6126c0b761 100644 --- a/files/data/builtin.omwscripts +++ b/files/data/builtin.omwscripts @@ -23,6 +23,8 @@ PLAYER: scripts/omw/input/actionbindings.lua PLAYER: scripts/omw/input/smoothmovement.lua PLAYER: scripts/omw/input/gamepadcontrols.lua NPC,CREATURE: scripts/omw/ai.lua +GLOBAL: scripts/omw/mechanics/globalcontroller.lua +CREATURE, NPC, PLAYER: scripts/omw/mechanics/actorcontroller.lua # User interface PLAYER: scripts/omw/ui.lua diff --git a/files/data/scripts/omw/mechanics/actorcontroller.lua b/files/data/scripts/omw/mechanics/actorcontroller.lua new file mode 100644 index 0000000000..fe8c75b244 --- /dev/null +++ b/files/data/scripts/omw/mechanics/actorcontroller.lua @@ -0,0 +1,23 @@ +local self = require('openmw.self') +local core = require('openmw.core') +local types = require('openmw.types') +local Actor = types.Actor + +return { + eventHandlers = { + ModifyStat = function(data) + local stat = Actor.stats.dynamic[data.stat](self) + stat.current = stat.current + data.amount + end, + PlaySound3d = function(data) + if data.sound then + core.sound.playSound3d(data.sound, self, data.options) + else + core.sound.playSoundFile3d(data.file, self, data.options) + end + end, + BreakInvisibility = function(data) + Actor.activeEffects(self):remove(core.magic.EFFECT_TYPE.Invisibility) + end, + }, +} diff --git a/files/data/scripts/omw/mechanics/globalcontroller.lua b/files/data/scripts/omw/mechanics/globalcontroller.lua new file mode 100644 index 0000000000..22d92e7c24 --- /dev/null +++ b/files/data/scripts/omw/mechanics/globalcontroller.lua @@ -0,0 +1,39 @@ +local types = require('openmw.types') +local Lockable = types.Lockable +local Item = require('openmw.types').Item +local world = require('openmw.world') +local core = require('openmw.core') + +local function onConsumeItem(data) + local item = data.item + local amount = data.amount + if amount > item.count then + print('Warning: tried to consume '..tostring(amount)..' '..tostring(item)..'s, but there were only '..tostring(item.count)) + amount = item.count + end + item:remove(amount) +end + +local function onPlaySound3d(data) + if data.sound then + core.sound.playSound3d(data.sound, data.position, data.options) + elseif data.file then + core.sound.playSoundFile3d(data.file, data.position, data.options) + end +end + +return { + eventHandlers = { + SpawnVfx = function(data) + world.vfx.spawn(data.model, data.position, data.options) + end, + PlaySound3d = onPlaySound3d, + ConsumeItem = onConsumeItem, + Lock = function(data) + Lockable.lock(data.target, data.magnitude) + end, + Unlock = function(data) + Lockable.unlock(data.target) + end, + }, +} diff --git a/files/data/scripts/omw/mechanics/playercontroller.lua b/files/data/scripts/omw/mechanics/playercontroller.lua index 870f24415c..8b4d618917 100644 --- a/files/data/scripts/omw/mechanics/playercontroller.lua +++ b/files/data/scripts/omw/mechanics/playercontroller.lua @@ -111,4 +111,10 @@ return { engineHandlers = { onUpdate = onUpdate, }, + + eventHandlers = { + ShowMessage = function(data) + if data.message then ui.showMessage(data.message) end + end + }, } From 1b9802472da6b446b1f5fd2c2af0c4a1a30fd016 Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Sat, 5 Jul 2025 01:43:39 +0200 Subject: [PATCH 154/330] Doc updates --- docs/source/reference/lua-scripting/events.rst | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/docs/source/reference/lua-scripting/events.rst b/docs/source/reference/lua-scripting/events.rst index d6ccd93003..a4683b0dc2 100644 --- a/docs/source/reference/lua-scripting/events.rst +++ b/docs/source/reference/lua-scripting/events.rst @@ -147,7 +147,7 @@ Calls the corresponding function in openw.core. Note that PlaySound3d will call **ConsumeItem** -Reduces stack size of an item by a given amount, removing the item complete if removing all items in the stack are removed. +Reduces stack size of an item by a given amount, removing the item completely if stack size is reduced to 0 or less. .. code-block:: Lua @@ -161,3 +161,19 @@ Modify a specified amount of enchantment charge of an item -- Reduce charge by 10 core.sendGlobalEvent('ModifyItemCharge', {item = foobar, amount = -10}) + +**Lock** + +Lock a container or door + +.. code-block:: Lua + + core.sendGlobalEvent('Lock', {taret = selected, magnitude = 50}) + +**Unlock** + +Unlock a container or door + +.. code-block:: Lua + + core.sendGlobalEvent('Unlock', {taret = selected}) From 7143115e57011fca4f3fbbcb2af8d53116173929 Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Sat, 5 Jul 2025 13:09:27 +0200 Subject: [PATCH 155/330] Doc update --- docs/source/reference/lua-scripting/events.rst | 9 --------- 1 file changed, 9 deletions(-) diff --git a/docs/source/reference/lua-scripting/events.rst b/docs/source/reference/lua-scripting/events.rst index a4683b0dc2..15c9b52eea 100644 --- a/docs/source/reference/lua-scripting/events.rst +++ b/docs/source/reference/lua-scripting/events.rst @@ -153,15 +153,6 @@ Reduces stack size of an item by a given amount, removing the item completely if core.sendGlobalEvent('ConsumeItem', {item = foobar, amount = 1}) -**ModifyItemCharge** - -Modify a specified amount of enchantment charge of an item - -.. code-block:: Lua - - -- Reduce charge by 10 - core.sendGlobalEvent('ModifyItemCharge', {item = foobar, amount = -10}) - **Lock** Lock a container or door From c2535903386f3bdfd7ff164456443a9dd053a062 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 5 Jul 2025 22:56:42 +0100 Subject: [PATCH 156/330] Restore previous interpretation of OPENMW_CXX_FLAGS It used to be copied as-is into the command-line options for the compiler, whereas add_compile_options expects a list of arguments. separate_arguments can be used to split a string how the system would split a command line. --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e4880a88e..f5a7d55bd5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -638,6 +638,7 @@ else () endif () if (OPENMW_CXX_FLAGS) + separate_arguments(OPENMW_CXX_FLAGS NATIVE_COMMAND "${OPENMW_CXX_FLAGS}") add_compile_options(${OPENMW_CXX_FLAGS}) endif() From 779840deea0ec946ee0e062271d2be6a1fde3915 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 6 Jul 2025 11:18:23 +0400 Subject: [PATCH 157/330] Print a more verbose message when we failed to write savegame --- apps/openmw/mwstate/statemanagerimp.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 498d2ab25a..34aa3eaa46 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -332,14 +332,15 @@ void MWState::StateManager::saveGame(std::string_view description, const Slot* s writer.close(); if (stream.fail()) - throw std::runtime_error("Write operation failed (memory stream)"); + throw std::runtime_error( + "Write operation failed (memory stream): " + std::generic_category().message(errno)); // All good, write to file std::ofstream filestream(slot->mPath, std::ios::binary); filestream << stream.rdbuf(); if (filestream.fail()) - throw std::runtime_error("Write operation failed (file stream)"); + throw std::runtime_error("Write operation failed (file stream): " + std::generic_category().message(errno)); Settings::saves().mCharacter.set(Files::pathToUnicodeString(slot->mPath.parent_path().filename())); mLastSavegame = slot->mPath; From d455ff5f5e561af58fc9caebe5dc785fe02c7b7c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 6 Jul 2025 13:14:27 +0400 Subject: [PATCH 158/330] Treat formatting string arguments as UTF-8 string --- apps/components_tests/lua/testl10n.cpp | 26 ++++++++++++++++++++++++++ components/lua/l10n.cpp | 6 +++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/apps/components_tests/lua/testl10n.cpp b/apps/components_tests/lua/testl10n.cpp index b48028a730..5528c0520a 100644 --- a/apps/components_tests/lua/testl10n.cpp +++ b/apps/components_tests/lua/testl10n.cpp @@ -24,6 +24,8 @@ namespace constexpr VFS::Path::NormalizedView test2EnPath("l10n/test2/en.yaml"); constexpr VFS::Path::NormalizedView test3EnPath("l10n/test3/en.yaml"); constexpr VFS::Path::NormalizedView test3DePath("l10n/test3/de.yaml"); + constexpr VFS::Path::NormalizedView test4RuPath("l10n/test4/ru.yaml"); + constexpr VFS::Path::NormalizedView test4EnPath("l10n/test4/en.yaml"); VFSTestFile invalidScript("not a script"); VFSTestFile incorrectScript( @@ -69,6 +71,16 @@ currency: "You have {money, number, currency}" VFSTestFile test2En(R"X( good_morning: "Morning!" you_have_arrows: "Arrows count: {count}" +)X"); + + VFSTestFile test4Ru(R"X( +skill_increase: "Ваш навык {навык} увеличился до {value}" +acrobatics: "Акробатика" +)X"); + + VFSTestFile test4En(R"X( +stat_increase: "Your {stat} has increased to {value}" +speed: "Speed" )X"); struct LuaL10nTest : Test @@ -80,6 +92,8 @@ you_have_arrows: "Arrows count: {count}" { test2EnPath, &test2En }, { test3EnPath, &test1En }, { test3DePath, &test1De }, + { test4RuPath, &test4Ru }, + { test4EnPath, &test4En }, }); LuaUtil::ScriptsConfiguration mCfg; @@ -169,6 +183,18 @@ you_have_arrows: "Arrows count: {count}" l.safe_script("t3 = l10n('Test3', 'de')"); l10nManager.setPreferredLocales({ "en" }); EXPECT_EQ(get(l, "t3('Hello {name}!', {name='World'})"), "Hallo World!"); + + // Test that formatting arguments use a correct encoding + l.safe_script("t4 = l10n('Test4', 'ru')"); + l10nManager.setPreferredLocales({ "ru", "en" }); + EXPECT_EQ(get(l, "t4('skill_increase', {навык='Акробатика', value=100})"), + "Ваш навык Акробатика увеличился до 100"); + EXPECT_EQ(get(l, "t4('skill_increase', {навык=t4('acrobatics'), value=100})"), + "Ваш навык Акробатика увеличился до 100"); + EXPECT_EQ(get(l, "t4('stat_increase', {stat='Speed', value=100})"), + "Your Speed has increased to 100"); + EXPECT_EQ(get(l, "t4('stat_increase', {stat=t4('speed'), value=100})"), + "Your Speed has increased to 100"); }); } } diff --git a/components/lua/l10n.cpp b/components/lua/l10n.cpp index 15177bea65..ec42992ebb 100644 --- a/components/lua/l10n.cpp +++ b/components/lua/l10n.cpp @@ -18,7 +18,11 @@ namespace { // Argument values if (value.is()) - args.push_back(icu::Formattable(LuaUtil::cast(value).c_str())); + { + const auto& str = LuaUtil::cast(value); + args.push_back(icu::Formattable(icu::UnicodeString::fromUTF8(str.c_str()))); + } + // Note: While we pass all numbers as doubles, they still seem to be handled appropriately. // Numbers can be forced to be integers using the argType number and argStyle integer // E.g. {var, number, integer} From 3574cd552c68c8a614422471d8183050305eebb4 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 6 Jul 2025 12:10:49 +0200 Subject: [PATCH 159/330] Make ExtraSpell undress less --- apps/openmw/mwmechanics/spelleffects.cpp | 29 +++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/spelleffects.cpp b/apps/openmw/mwmechanics/spelleffects.cpp index 91e24f946f..3d1a5ed84e 100644 --- a/apps/openmw/mwmechanics/spelleffects.cpp +++ b/apps/openmw/mwmechanics/spelleffects.cpp @@ -519,8 +519,31 @@ namespace MWMechanics case ESM::MagicEffect::ExtraSpell: if (target.getClass().hasInventoryStore(target)) { - auto& store = target.getClass().getInventoryStore(target); - store.unequipAll(); + if (target != getPlayer()) + { + auto& store = target.getClass().getInventoryStore(target); + for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot) + { + // Unequip everything except weapons, torches, and pants + switch (slot) + { + case MWWorld::InventoryStore::Slot_Ammunition: + case MWWorld::InventoryStore::Slot_CarriedRight: + case MWWorld::InventoryStore::Slot_Pants: + continue; + case MWWorld::InventoryStore::Slot_CarriedLeft: + { + auto carried = store.getSlot(slot); + if (carried == store.end() + || carried.getType() != MWWorld::ContainerStore::Type_Armor) + continue; + [[fallthrough]]; + } + default: + store.unequipSlot(slot); + } + } + } } else invalid = true; @@ -1083,7 +1106,7 @@ namespace MWMechanics } break; case ESM::MagicEffect::ExtraSpell: - if (magnitudes.getOrDefault(effect.mEffectId).getMagnitude() <= 0.f) + if (magnitudes.getOrDefault(effect.mEffectId).getMagnitude() <= 0.f && target != getPlayer()) target.getClass().getInventoryStore(target).autoEquip(); break; case ESM::MagicEffect::TurnUndead: From df5625a1e385a94e8e7ab992288cdeada58b23bc Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sun, 6 Jul 2025 13:36:34 +0300 Subject: [PATCH 160/330] Unify creature/NPC armor autoequip --- apps/openmw/mwworld/inventorystore.cpp | 162 +++++++++++-------------- apps/openmw/mwworld/inventorystore.hpp | 1 - 2 files changed, 70 insertions(+), 93 deletions(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index f48f4e6e31..5f7e135847 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -378,110 +378,111 @@ void MWWorld::InventoryStore::autoEquipWeapon(TSlots& slots_) void MWWorld::InventoryStore::autoEquipArmor(TSlots& slots_) { - // Only NPCs can wear armor for now. - // For creatures we equip only shields. const Ptr& actor = getPtr(); - if (!actor.getClass().isNpc()) + + // Creatures only want shields and don't benefit from armor rating or unarmored skill + const MWWorld::Class& actorCls = actor.getClass(); + const bool actorIsNpc = actorCls.isNpc(); + + int equipmentTypes = ContainerStore::Type_Armor; + float unarmoredRating = 0.f; + if (actorIsNpc) { - autoEquipShield(slots_); - return; + equipmentTypes |= ContainerStore::Type_Clothing; + const auto& store = MWBase::Environment::get().getESMStore()->get(); + const float fUnarmoredBase1 = store.find("fUnarmoredBase1")->mValue.getFloat(); + const float fUnarmoredBase2 = store.find("fUnarmoredBase2")->mValue.getFloat(); + const float unarmoredSkill = actorCls.getSkill(actor, ESM::Skill::Unarmored); + unarmoredRating = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill); + unarmoredRating = std::max(unarmoredRating, 0.f); } - const MWWorld::Store& store = MWBase::Environment::get().getESMStore()->get(); - - static float fUnarmoredBase1 = store.find("fUnarmoredBase1")->mValue.getFloat(); - static float fUnarmoredBase2 = store.find("fUnarmoredBase2")->mValue.getFloat(); - - float unarmoredSkill = actor.getClass().getSkill(actor, ESM::Skill::Unarmored); - float unarmoredRating = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill); - - for (ContainerStoreIterator iter(begin(ContainerStore::Type_Clothing | ContainerStore::Type_Armor)); iter != end(); - ++iter) + for (ContainerStoreIterator iter(begin(equipmentTypes)); iter != end(); ++iter) { Ptr test = *iter; + const MWWorld::Class& testCls = test.getClass(); + const bool isArmor = iter.getType() == ContainerStore::Type_Armor; - switch (test.getClass().canBeEquipped(test, actor).first) + // Discard armor that is worse than unarmored for NPCs and non-shields for creatures + if (isArmor) { - case 0: - continue; - default: - break; + if (actorIsNpc) + { + if (testCls.getEffectiveArmorRating(test, actor) <= unarmoredRating) + continue; + } + else + { + if (test.get()->mBase->mData.mType != ESM::Armor::Shield) + continue; + } } - if (iter.getType() == ContainerStore::Type_Armor - && test.getClass().getEffectiveArmorRating(test, actor) <= std::max(unarmoredRating, 0.f)) - { + // Don't equip the item if it cannot be equipped + if (testCls.canBeEquipped(test, actor).first == 0) continue; - } - std::pair, bool> itemsSlots = iter->getClass().getEquipmentSlots(*iter); + const auto [itemSlots, canStack] = testCls.getEquipmentSlots(test); // checking if current item pointed by iter can be equipped - for (int slot : itemsSlots.first) + for (const int slot : itemSlots) { - // if true then it means slot is equipped already // check if slot may require swapping if current item is more valuable if (slots_.at(slot) != end()) { Ptr old = *slots_.at(slot); + const MWWorld::Class& oldCls = old.getClass(); + unsigned int oldType = old.getType(); - if (iter.getType() == ContainerStore::Type_Armor) + if (!isArmor) { - if (old.getType() == ESM::Armor::sRecordId) - { - if (old.get()->mBase->mData.mType < test.get()->mBase->mData.mType) - continue; + // Armor should replace clothing and weapons, but clothing should only replace clothing + if (oldType != ESM::Clothing::sRecordId) + continue; - if (old.get()->mBase->mData.mType == test.get()->mBase->mData.mType) - { - if (old.getClass().getEffectiveArmorRating(old, actor) - >= test.getClass().getEffectiveArmorRating(test, actor)) - // old armor had better armor rating - continue; - } - } - // suitable armor should replace already equipped clothing - } - else if (iter.getType() == ContainerStore::Type_Clothing) - { - // if left ring is equipped + // If the left ring slot is filled, don't swap if the right ring is cheaper if (slot == Slot_LeftRing) { - // if there is a place for right ring dont swap it if (slots_.at(Slot_RightRing) == end()) - { continue; - } - else // if right ring is equipped too - { - Ptr rightRing = *slots_.at(Slot_RightRing); - // we want to swap cheaper ring only if both are equipped - if (old.getClass().getValue(old) >= rightRing.getClass().getValue(rightRing)) + Ptr rightRing = *slots_.at(Slot_RightRing); + if (rightRing.getClass().getValue(rightRing) <= oldCls.getValue(old)) + continue; + } + + if (testCls.getValue(test) <= oldCls.getValue(old)) + continue; + } + else if (oldType == ESM::Armor::sRecordId) + { + const int32_t oldArmorType = old.get()->mBase->mData.mType; + const int32_t newArmorType = test.get()->mBase->mData.mType; + if (oldArmorType == newArmorType) + { + // For NPCs, compare armor rating; for creatures, compare condition + if (actorIsNpc) + { + const float rating = testCls.getEffectiveArmorRating(test, actor); + const float oldRating = oldCls.getEffectiveArmorRating(old, actor); + if (rating <= oldRating) + continue; + } + else + { + if (testCls.getItemHealth(test) <= oldCls.getItemHealth(old)) continue; } } - - if (old.getType() == ESM::Clothing::sRecordId) - { - // check value - if (old.getClass().getValue(old) >= test.getClass().getValue(test)) - // old clothing was more valuable - continue; - } - else - // suitable clothing should NOT replace already equipped armor + else if (oldArmorType < newArmorType) continue; } } - if (!itemsSlots.second) // if itemsSlots.second is true, item can stay stacked when equipped + // unstack the item if required + if (!canStack && test.getCellRef().getCount() > 1) { - // unstack item pointed to by iterator if required - if (iter->getCellRef().getCount() > 1) - { - unstack(*iter); - } + unstack(test); } // if we are here it means item can be equipped or swapped @@ -491,27 +492,6 @@ void MWWorld::InventoryStore::autoEquipArmor(TSlots& slots_) } } -void MWWorld::InventoryStore::autoEquipShield(TSlots& slots_) -{ - for (ContainerStoreIterator iter(begin(ContainerStore::Type_Armor)); iter != end(); ++iter) - { - if (iter->get()->mBase->mData.mType != ESM::Armor::Shield) - continue; - if (iter->getClass().canBeEquipped(*iter, getPtr()).first != 1) - continue; - std::pair, bool> shieldSlots = iter->getClass().getEquipmentSlots(*iter); - int slot = shieldSlots.first[0]; - const ContainerStoreIterator& shield = slots_[slot]; - if (shield != end() && shield.getType() == Type_Armor - && shield->get()->mBase->mData.mType == ESM::Armor::Shield) - { - if (shield->getClass().getItemHealth(*shield) >= iter->getClass().getItemHealth(*iter)) - continue; - } - slots_[slot] = iter; - } -} - void MWWorld::InventoryStore::autoEquip() { TSlots slots_; @@ -522,8 +502,6 @@ void MWWorld::InventoryStore::autoEquip() // Autoequip clothing, armor and weapons. // Equipping lights is handled in Actors::updateEquippedLight based on environment light. - // Note: creatures ignore equipment armor rating and only equip shields - // Use custom logic for them - select shield based on its health instead of armor rating autoEquipWeapon(slots_); autoEquipArmor(slots_); diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 0af6ee2b28..4e8f56f616 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -69,7 +69,6 @@ namespace MWWorld void autoEquipWeapon(TSlots& slots_); void autoEquipArmor(TSlots& slots_); - void autoEquipShield(TSlots& slots_); // selected magic item (for using enchantments of type "Cast once" or "Cast when used") ContainerStoreIterator mSelectedEnchantItem; From 45c187028fe23fde4eba4f021badb70c3ec402cd Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Sat, 5 Jul 2025 13:25:22 +0200 Subject: [PATCH 161/330] Bump --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c755ad315f..3a194450fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,7 +82,7 @@ message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) set(OPENMW_VERSION_MINOR 50) set(OPENMW_VERSION_RELEASE 0) -set(OPENMW_LUA_API_REVISION 79) +set(OPENMW_LUA_API_REVISION 80) set(OPENMW_POSTPROCESSING_API_REVISION 3) set(OPENMW_VERSION_COMMITHASH "") From 89d6f59388e6aa3747e6df5d68887ff50f6f37e5 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 6 Jul 2025 15:58:12 +0100 Subject: [PATCH 162/330] Use verbose status for ccache so we can see what caused hit failures --- .gitlab-ci.yml | 8 ++++---- CI/macos/ccache_save.sh | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index dc638729c4..782b042461 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -77,7 +77,7 @@ Ubuntu_GCC_preprocess: - if [[ "${BUILD_TESTS_ONLY}" && ! "${BUILD_WITH_CODE_COVERAGE}" ]]; then ./openmw_detournavigator_navmeshtilescache_benchmark; fi - if [[ "${BUILD_TESTS_ONLY}" && ! "${BUILD_WITH_CODE_COVERAGE}" ]]; then ./openmw_esm_refid_benchmark; fi - if [[ "${BUILD_TESTS_ONLY}" && ! "${BUILD_WITH_CODE_COVERAGE}" ]]; then ./openmw_settings_access_benchmark; fi - - ccache -s + - ccache -sv - df -h - if [[ "${BUILD_WITH_CODE_COVERAGE}" ]]; then gcovr --xml-pretty --exclude-unreachable-branches --print-summary --root "${CI_PROJECT_DIR}" -j $(nproc) -o ../coverage.xml; fi - ls | grep -v -e '^extern$' -e '^install$' -e '^components-tests.xml$' -e '^openmw-tests.xml$' -e '^openmw-cs-tests.xml$' | xargs -I '{}' rm -rf './{}' @@ -124,7 +124,7 @@ Coverity: - cov-analysis-linux64-*/bin/cov-configure --template --comptype prefix --compiler ccache # Remove the specific targets and build everything once we can do it under 3h - cov-analysis-linux64-*/bin/cov-build --dir cov-int cmake --build build -- -j $(nproc) - - ccache -s + - ccache -sv after_script: - tar cfz cov-int.tar.gz cov-int - curl https://scan.coverity.com/builds?project=$COVERITY_SCAN_PROJECT_NAME @@ -396,7 +396,7 @@ Ubuntu_Clang: - cd build - find . -name *.o -exec touch {} \; - cmake --build . -- -j $(nproc) ${BUILD_TARGETS} - - ccache -s + - ccache -sv artifacts: paths: - build/ @@ -940,7 +940,7 @@ Windows_MSBuild_CacheInit: - cd build - cmake --build . -- -j $(nproc) # - cmake --install . # no one uses builds anyway, disable until 'no space left' is resolved - - ccache -s + - ccache -sv - df -h - ls | grep -v -e '^extern$' -e '^install$' | xargs -I '{}' rm -rf './{}' - cd .. diff --git a/CI/macos/ccache_save.sh b/CI/macos/ccache_save.sh index d06d16fb0c..ca746b7085 100755 --- a/CI/macos/ccache_save.sh +++ b/CI/macos/ccache_save.sh @@ -1,7 +1,7 @@ #!/bin/sh -ex if [[ "${MACOS_AMD64}" ]]; then - arch -x86_64 ccache -s + arch -x86_64 ccache -sv else - ccache -s + ccache -sv fi From 266702e729b4351f60a458ad58c345abb68dc0c6 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Tue, 15 Apr 2025 00:42:22 -0600 Subject: [PATCH 163/330] Remove obsolete combat block for immobile creatures and autoformat --- apps/openmw/mwmechanics/actors.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 1e62cc4a21..01e5c21559 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -184,7 +184,7 @@ namespace MWWorld::ContainerStoreIterator gem = container.end(); float gemCapacity = std::numeric_limits::max(); for (auto it = container.begin(MWWorld::ContainerStore::Type_Miscellaneous); it != container.end(); - ++it) + ++it) { if (it->getClass().isSoulGem(*it)) { @@ -605,10 +605,6 @@ namespace MWMechanics void Actors::engageCombat( const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, SidingCache& cachedAllies, bool againstPlayer) const { - // No combat for totally static creatures - if (!actor1.getClass().isMobile(actor1)) - return; - CreatureStats& creatureStats1 = actor1.getClass().getCreatureStats(actor1); if (creatureStats1.isDead() || creatureStats1.getAiSequence().isInCombat(actor2)) return; @@ -1153,8 +1149,7 @@ namespace MWMechanics if (playerStats.getBounty() >= cutoff * iCrimeThresholdMultiplier) { mechanicsManager->startCombat(ptr, player, &cachedAllies.getActorsSidingWith(player)); - creatureStats.setHitAttemptActorId( - playerClass.getCreatureStats(player) + creatureStats.setHitAttemptActorId(playerClass.getCreatureStats(player) .getActorId()); // Stops the guard from quitting combat if player is unreachable } else From a77a8904e599207a58a5ebabf550259713857800 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Tue, 15 Apr 2025 17:25:58 -0600 Subject: [PATCH 164/330] Immobile creatures should enter combat, but not act --- apps/openmw/mwmechanics/aicombat.cpp | 8 +++++--- apps/openmw/mwmechanics/aipackage.cpp | 4 ++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 2399961a3a..a96270c2e3 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -104,10 +104,10 @@ namespace MWMechanics bool AiCombat::execute( const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) { - // get or create temporary storage + // Get or create temporary storage AiCombatStorage& storage = state.get(); - // General description + // No combat for dead creatures if (actor.getClass().getCreatureStats(actor).isDead()) return true; @@ -245,7 +245,9 @@ namespace MWMechanics float distToTarget = getDistanceToBounds(actor, target); - storage.mReadyToAttack = (currentAction->isAttackingOrSpell() && distToTarget <= rangeAttack && storage.mLOS); + // Must be attacking, within range, have line of sight, and not be immobile + storage.mReadyToAttack = (currentAction->isAttackingOrSpell() && distToTarget <= rangeAttack && storage.mLOS + && actor.getClass().isMobile(actor)); if (isRangedCombat) { diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 4bcfc7dedd..24792b5bbc 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -135,6 +135,10 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f& MWWorld::MovementDirectionFlags supportedMovementDirections, float destTolerance, float endTolerance, PathType pathType) { + // No pathing for totally static creatures + if (!actor.getClass().isMobile(actor)) + return false; + const Misc::TimerStatus timerStatus = mReaction.update(duration); const osg::Vec3f position = actor.getRefData().getPosition().asVec3(); // position of the actor From 23dc226dff12e0576389d2735259cb61ce121ed7 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Tue, 15 Apr 2025 17:56:48 -0600 Subject: [PATCH 165/330] Revert autoformat changes --- apps/openmw/mwmechanics/actors.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 01e5c21559..a4c2f42f0f 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -184,7 +184,7 @@ namespace MWWorld::ContainerStoreIterator gem = container.end(); float gemCapacity = std::numeric_limits::max(); for (auto it = container.begin(MWWorld::ContainerStore::Type_Miscellaneous); it != container.end(); - ++it) + ++it) { if (it->getClass().isSoulGem(*it)) { @@ -1149,7 +1149,8 @@ namespace MWMechanics if (playerStats.getBounty() >= cutoff * iCrimeThresholdMultiplier) { mechanicsManager->startCombat(ptr, player, &cachedAllies.getActorsSidingWith(player)); - creatureStats.setHitAttemptActorId(playerClass.getCreatureStats(player) + creatureStats.setHitAttemptActorId( + playerClass.getCreatureStats(player) .getActorId()); // Stops the guard from quitting combat if player is unreachable } else From 3df695df4a0f393a534736b558dc02cad983bcf7 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Tue, 15 Apr 2025 18:38:53 -0600 Subject: [PATCH 166/330] Found better place for early return --- apps/openmw/mwmechanics/aicombat.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index a96270c2e3..82fc9a67a1 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -231,6 +231,10 @@ namespace MWMechanics storage.stopFleeing(); } + // No attack actions for totally static creatures + if (!actor.getClass().isMobile(actor)) + return false; + bool isRangedCombat = false; float& rangeAttack = storage.mAttackRange; @@ -245,9 +249,7 @@ namespace MWMechanics float distToTarget = getDistanceToBounds(actor, target); - // Must be attacking, within range, have line of sight, and not be immobile - storage.mReadyToAttack = (currentAction->isAttackingOrSpell() && distToTarget <= rangeAttack && storage.mLOS - && actor.getClass().isMobile(actor)); + storage.mReadyToAttack = (currentAction->isAttackingOrSpell() && distToTarget <= rangeAttack && storage.mLOS); if (isRangedCombat) { From 09ed5bb234212484da5294ddfab723495edc62b4 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Tue, 15 Apr 2025 20:02:24 -0600 Subject: [PATCH 167/330] Allow immobile actors to initiate combat when attacked --- apps/openmw/mwclass/creature.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 324ba5f98b..b85bb9e996 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -360,16 +360,12 @@ namespace MWClass { stats.setAttacked(true); - // No retaliation for totally static creatures (they have no movement or attacks anyway) - if (isMobile(ptr)) - { - bool complain = sourceType == MWMechanics::DamageSourceType::Melee; - bool supportFriendlyFire = sourceType != MWMechanics::DamageSourceType::Ranged; - if (supportFriendlyFire && MWMechanics::friendlyHit(attacker, ptr, complain)) - setOnPcHitMe = false; - else - setOnPcHitMe = MWBase::Environment::get().getMechanicsManager()->actorAttacked(ptr, attacker); - } + bool complain = sourceType == MWMechanics::DamageSourceType::Melee; + bool supportFriendlyFire = sourceType != MWMechanics::DamageSourceType::Ranged; + if (supportFriendlyFire && MWMechanics::friendlyHit(attacker, ptr, complain)) + setOnPcHitMe = false; + else + setOnPcHitMe = MWBase::Environment::get().getMechanicsManager()->actorAttacked(ptr, attacker); } // Attacker and target store each other as hitattemptactor if they have no one stored yet From 2db36c49b5d6cd6dd129637e3fb5c06ca2b6f438 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Sun, 6 Jul 2025 11:41:02 -0600 Subject: [PATCH 168/330] Move early out to better place --- apps/openmw/mwmechanics/aicombat.cpp | 11 +++++++---- apps/openmw/mwmechanics/aipackage.cpp | 4 ---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 82fc9a67a1..1b0b0e5a89 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -124,6 +124,13 @@ namespace MWMechanics if (actor == target) // This should never happen. return true; + // No actions for totally static creatures + if (!actor.getClass().isMobile(actor)) + { + storage.mFleeState = AiCombatStorage::FleeState_Idle; + return false; + } + if (!storage.isFleeing()) { if (storage.mCurrentAction.get()) // need to wait to init action with its attack range @@ -231,10 +238,6 @@ namespace MWMechanics storage.stopFleeing(); } - // No attack actions for totally static creatures - if (!actor.getClass().isMobile(actor)) - return false; - bool isRangedCombat = false; float& rangeAttack = storage.mAttackRange; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 24792b5bbc..4bcfc7dedd 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -135,10 +135,6 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f& MWWorld::MovementDirectionFlags supportedMovementDirections, float destTolerance, float endTolerance, PathType pathType) { - // No pathing for totally static creatures - if (!actor.getClass().isMobile(actor)) - return false; - const Misc::TimerStatus timerStatus = mReaction.update(duration); const osg::Vec3f position = actor.getRefData().getPosition().asVec3(); // position of the actor From 6c70c403be951d8da2d9ea949c63dabd320a3e64 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Wed, 14 May 2025 23:04:11 -0600 Subject: [PATCH 169/330] Implement FillJournal console command --- apps/openmw/mwscript/dialogueextensions.cpp | 59 +++++++++++++++++---- apps/openmw/mwscript/docs/vmformat.txt | 3 +- components/compiler/extensions0.cpp | 1 + components/compiler/opcodes.hpp | 1 + 4 files changed, 53 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 6511fbdb01..643efb3d07 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -22,6 +22,20 @@ namespace MWScript { + static void addJournalEntry(ESM::RefId quest, int index, MWWorld::Ptr ptr) + { + // Invoking Journal with a non-existing index is allowed, and triggers no errors. Seriously? :( + try + { + MWBase::Environment::get().getJournal()->addEntry(quest, index, ptr); + } + catch (...) + { + if (MWBase::Environment::get().getJournal()->getJournalIndex(quest) < index) + MWBase::Environment::get().getJournal()->setJournalIndex(quest, index); + } + } + namespace Dialogue { template @@ -40,16 +54,7 @@ namespace MWScript Interpreter::Type_Integer index = runtime[0].mInteger; runtime.pop(); - // Invoking Journal with a non-existing index is allowed, and triggers no errors. Seriously? :( - try - { - MWBase::Environment::get().getJournal()->addEntry(quest, index, ptr); - } - catch (...) - { - if (MWBase::Environment::get().getJournal()->getJournalIndex(quest) < index) - MWBase::Environment::get().getJournal()->setJournalIndex(quest, index); - } + addJournalEntry(quest, index, ptr); } }; @@ -82,6 +87,39 @@ namespace MWScript } }; + class OpFillJournal : public Interpreter::Opcode0 + { + public: + void execute(Interpreter::Runtime& runtime) override + { + const MWWorld::Store& dialogues = MWBase::Environment::get().getESMStore()->get(); + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + + for (auto it = dialogues.begin(); it != dialogues.end(); ++it) + { + const ESM::Dialogue::Type type = it->mType; + if (type == ESM::Dialogue::Type::Journal) + { + ESM::RefId quest = ESM::RefId::stringRefId(it->mStringId); + const std::list orderedInfo = it->mInfoOrder.getOrderedInfo(); + for (auto info = orderedInfo.begin(); info != orderedInfo.end(); ++info) + { + addJournalEntry(quest, info->mData.mJournalIndex, ptr); + } + } + else if (type == ESM::Dialogue::Type::Topic) + { + ESM::RefId topic = ESM::RefId::stringRefId(it->mStringId); + const std::list orderedInfo = it->mInfoOrder.getOrderedInfo(); + for (auto info = orderedInfo.begin(); info != orderedInfo.end(); ++info) + { + MWBase::Environment::get().getJournal()->addTopic(topic, info->mId, ptr); + } + } + } + } + }; + class OpAddTopic : public Interpreter::Opcode0 { public: @@ -288,6 +326,7 @@ namespace MWScript interpreter.installSegment5>(Compiler::Dialogue::opcodeJournalExplicit); interpreter.installSegment5(Compiler::Dialogue::opcodeSetJournalIndex); interpreter.installSegment5(Compiler::Dialogue::opcodeGetJournalIndex); + interpreter.installSegment5(Compiler::Dialogue::opcodeFillJournal); interpreter.installSegment5(Compiler::Dialogue::opcodeAddTopic); interpreter.installSegment3(Compiler::Dialogue::opcodeChoice); interpreter.installSegment5>(Compiler::Dialogue::opcodeForceGreeting); diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index d34c39c9df..56eb1c2351 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -485,5 +485,6 @@ op 0x2000322: GetPCVisionBonus op 0x2000323: SetPCVisionBonus op 0x2000324: ModPCVisionBonus op 0x2000325: TestModels, T3D +op 0x2000326: FillJournal -opcodes 0x2000326-0x3ffffff unused +opcodes 0x2000327-0x3ffffff unused diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 6f57ee7673..103fb41641 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -163,6 +163,7 @@ namespace Compiler extensions.registerInstruction("journal", "cl", opcodeJournal, opcodeJournalExplicit); extensions.registerInstruction("setjournalindex", "cl", opcodeSetJournalIndex); extensions.registerFunction("getjournalindex", 'l', "c", opcodeGetJournalIndex); + extensions.registerInstruction("filljournal", "", opcodeFillJournal); extensions.registerInstruction("addtopic", "S", opcodeAddTopic); extensions.registerInstruction( "choice", "j/SlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSl", opcodeChoice); diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index 2ec31c7588..55f431f049 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -155,6 +155,7 @@ namespace Compiler const int opcodeJournalExplicit = 0x200030b; const int opcodeSetJournalIndex = 0x2000134; const int opcodeGetJournalIndex = 0x2000135; + const int opcodeFillJournal = 0x2000326; const int opcodeAddTopic = 0x200013a; const int opcodeChoice = 0x2000a; const int opcodeForceGreeting = 0x200014f; From 2e1f3d5d2c0da9e7a680ce6bd79fcb00d49a6dbe Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Wed, 14 May 2025 23:17:32 -0600 Subject: [PATCH 170/330] Clang format --- apps/openmw/mwscript/dialogueextensions.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 643efb3d07..93241c3ff4 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -92,7 +92,8 @@ namespace MWScript public: void execute(Interpreter::Runtime& runtime) override { - const MWWorld::Store& dialogues = MWBase::Environment::get().getESMStore()->get(); + const MWWorld::Store& dialogues + = MWBase::Environment::get().getESMStore()->get(); MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); for (auto it = dialogues.begin(); it != dialogues.end(); ++it) From 34194f9c0841fda8e06615b1bfbea2a9a7aac7ce Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Wed, 14 May 2025 23:28:05 -0600 Subject: [PATCH 171/330] Add topics as known topics in addition to journal topics --- apps/openmw/mwscript/dialogueextensions.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 93241c3ff4..17145e9b32 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -116,6 +116,7 @@ namespace MWScript { MWBase::Environment::get().getJournal()->addTopic(topic, info->mId, ptr); } + MWBase::Environment::get().getDialogueManager()->addTopic(topic); } } } From 4b9852026637ecaf39ac83fceb6d5341d1edca39 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Thu, 15 May 2025 12:32:05 -0600 Subject: [PATCH 172/330] Revert shared addJournalEntry --- apps/openmw/mwscript/dialogueextensions.cpp | 27 +++++++++------------ 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 17145e9b32..869b626728 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -22,20 +22,6 @@ namespace MWScript { - static void addJournalEntry(ESM::RefId quest, int index, MWWorld::Ptr ptr) - { - // Invoking Journal with a non-existing index is allowed, and triggers no errors. Seriously? :( - try - { - MWBase::Environment::get().getJournal()->addEntry(quest, index, ptr); - } - catch (...) - { - if (MWBase::Environment::get().getJournal()->getJournalIndex(quest) < index) - MWBase::Environment::get().getJournal()->setJournalIndex(quest, index); - } - } - namespace Dialogue { template @@ -54,7 +40,16 @@ namespace MWScript Interpreter::Type_Integer index = runtime[0].mInteger; runtime.pop(); - addJournalEntry(quest, index, ptr); + // Invoking Journal with a non-existing index is allowed, and triggers no errors. Seriously? :( + try + { + MWBase::Environment::get().getJournal()->addEntry(quest, index, ptr); + } + catch (...) + { + if (MWBase::Environment::get().getJournal()->getJournalIndex(quest) < index) + MWBase::Environment::get().getJournal()->setJournalIndex(quest, index); + } } }; @@ -105,7 +100,7 @@ namespace MWScript const std::list orderedInfo = it->mInfoOrder.getOrderedInfo(); for (auto info = orderedInfo.begin(); info != orderedInfo.end(); ++info) { - addJournalEntry(quest, info->mData.mJournalIndex, ptr); + MWBase::Environment::get().getJournal()->addEntry(quest, info->mData.mJournalIndex, ptr); } } else if (type == ESM::Dialogue::Type::Topic) From 83903455f9f22257cbc649ceda6bbd31b96a1c38 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Thu, 15 May 2025 12:51:53 -0600 Subject: [PATCH 173/330] Address review comments --- apps/openmw/mwscript/dialogueextensions.cpp | 22 +++++++++------------ 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 869b626728..ab48807c36 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -91,27 +91,23 @@ namespace MWScript = MWBase::Environment::get().getESMStore()->get(); MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); - for (auto it = dialogues.begin(); it != dialogues.end(); ++it) + for (const auto& dialogue : dialogues) { - const ESM::Dialogue::Type type = it->mType; - if (type == ESM::Dialogue::Type::Journal) + if (dialogue.mType == ESM::Dialogue::Type::Journal) { - ESM::RefId quest = ESM::RefId::stringRefId(it->mStringId); - const std::list orderedInfo = it->mInfoOrder.getOrderedInfo(); - for (auto info = orderedInfo.begin(); info != orderedInfo.end(); ++info) + for (const auto& journalInfo : dialogue.mInfoOrder.getOrderedInfo()) { - MWBase::Environment::get().getJournal()->addEntry(quest, info->mData.mJournalIndex, ptr); + MWBase::Environment::get().getJournal()->addEntry(dialogue.mId, + journalInfo.mData.mJournalIndex, ptr); } } - else if (type == ESM::Dialogue::Type::Topic) + else if (dialogue.mType == ESM::Dialogue::Type::Topic) { - ESM::RefId topic = ESM::RefId::stringRefId(it->mStringId); - const std::list orderedInfo = it->mInfoOrder.getOrderedInfo(); - for (auto info = orderedInfo.begin(); info != orderedInfo.end(); ++info) + for (const auto& topicInfo : dialogue.mInfoOrder.getOrderedInfo()) { - MWBase::Environment::get().getJournal()->addTopic(topic, info->mId, ptr); + MWBase::Environment::get().getJournal()->addTopic(dialogue.mId, topicInfo.mId, ptr); } - MWBase::Environment::get().getDialogueManager()->addTopic(topic); + MWBase::Environment::get().getDialogueManager()->addTopic(dialogue.mId); } } } From 565b199380c8176ebbc2910f0ee57dbff60d60ed Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Thu, 15 May 2025 12:54:27 -0600 Subject: [PATCH 174/330] Clang format --- apps/openmw/mwscript/dialogueextensions.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index ab48807c36..6b3787f948 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -97,8 +97,8 @@ namespace MWScript { for (const auto& journalInfo : dialogue.mInfoOrder.getOrderedInfo()) { - MWBase::Environment::get().getJournal()->addEntry(dialogue.mId, - journalInfo.mData.mJournalIndex, ptr); + MWBase::Environment::get().getJournal()->addEntry( + dialogue.mId, journalInfo.mData.mJournalIndex, ptr); } } else if (dialogue.mType == ESM::Dialogue::Type::Topic) From 30140d95488b13b8dfe6dbbb778fa32343a979ab Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Fri, 16 May 2025 11:34:00 -0600 Subject: [PATCH 175/330] Get the journal only once --- apps/openmw/mwscript/dialogueextensions.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 6b3787f948..1c7de21d57 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -90,6 +90,7 @@ namespace MWScript const MWWorld::Store& dialogues = MWBase::Environment::get().getESMStore()->get(); MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWBase::Journal* journal = MWBase::Environment::get().getJournal(); for (const auto& dialogue : dialogues) { @@ -97,7 +98,7 @@ namespace MWScript { for (const auto& journalInfo : dialogue.mInfoOrder.getOrderedInfo()) { - MWBase::Environment::get().getJournal()->addEntry( + journal->addEntry( dialogue.mId, journalInfo.mData.mJournalIndex, ptr); } } @@ -105,7 +106,7 @@ namespace MWScript { for (const auto& topicInfo : dialogue.mInfoOrder.getOrderedInfo()) { - MWBase::Environment::get().getJournal()->addTopic(dialogue.mId, topicInfo.mId, ptr); + journal->addTopic(dialogue.mId, topicInfo.mId, ptr); } MWBase::Environment::get().getDialogueManager()->addTopic(dialogue.mId); } From 73a3033e0ffd6a93386890690c1692550159c11a Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Fri, 16 May 2025 11:42:27 -0600 Subject: [PATCH 176/330] Get the dialogue manager once --- apps/openmw/mwscript/dialogueextensions.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 1c7de21d57..edf6f4b6df 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -89,8 +89,9 @@ namespace MWScript { const MWWorld::Store& dialogues = MWBase::Environment::get().getESMStore()->get(); - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayerPtr(); MWBase::Journal* journal = MWBase::Environment::get().getJournal(); + MWBase::DialogueManager* dialogueManager = MWBase::Environment::get().getDialogueManager(); for (const auto& dialogue : dialogues) { @@ -99,16 +100,16 @@ namespace MWScript for (const auto& journalInfo : dialogue.mInfoOrder.getOrderedInfo()) { journal->addEntry( - dialogue.mId, journalInfo.mData.mJournalIndex, ptr); + dialogue.mId, journalInfo.mData.mJournalIndex, playerPtr); } } else if (dialogue.mType == ESM::Dialogue::Type::Topic) { for (const auto& topicInfo : dialogue.mInfoOrder.getOrderedInfo()) { - journal->addTopic(dialogue.mId, topicInfo.mId, ptr); + journal->addTopic(dialogue.mId, topicInfo.mId, playerPtr); } - MWBase::Environment::get().getDialogueManager()->addTopic(dialogue.mId); + dialogueManager->addTopic(dialogue.mId); } } } From 0e1ed078e9380fc1b4ce3213de2bd8bee312daac Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Fri, 16 May 2025 11:56:43 -0600 Subject: [PATCH 177/330] Clang format --- apps/openmw/mwscript/dialogueextensions.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index edf6f4b6df..23d8049a5d 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -99,8 +99,7 @@ namespace MWScript { for (const auto& journalInfo : dialogue.mInfoOrder.getOrderedInfo()) { - journal->addEntry( - dialogue.mId, journalInfo.mData.mJournalIndex, playerPtr); + journal->addEntry(dialogue.mId, journalInfo.mData.mJournalIndex, playerPtr); } } else if (dialogue.mType == ESM::Dialogue::Type::Topic) From d207c2251ffe4693f73e275c8df95bc7127c0010 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Thu, 3 Jul 2025 11:38:15 -0600 Subject: [PATCH 178/330] Fix unneeded runtime errors --- apps/openmw/mwscript/interpretercontext.cpp | 26 ++++++-- components/interpreter/defines.cpp | 70 +++++++++++---------- 2 files changed, 60 insertions(+), 36 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 15c9100b98..9aeccfc886 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include "../mwworld/esmstore.hpp" @@ -300,7 +301,15 @@ namespace MWScript std::string_view InterpreterContext::getNPCFaction() const { - const ESM::NPC* npc = getReferenceImp().get()->mBase; + const MWWorld::Ptr& ptr = getReferenceImp(); + const ESM::RefId& factionId = ptr.getClass().getPrimaryFaction(ptr); + if (factionId.empty()) + { + Log(Debug::Warning) << "getNPCFaction(): NPC is not in a faction"; + return "%"; + } + + const ESM::NPC* npc = ptr.get()->mBase; const ESM::Faction* faction = MWBase::Environment::get().getESMStore()->get().find(npc->mFaction); return faction->mName; } @@ -310,7 +319,10 @@ namespace MWScript const MWWorld::Ptr& ptr = getReferenceImp(); const ESM::RefId& faction = ptr.getClass().getPrimaryFaction(ptr); if (faction.empty()) - throw std::runtime_error("getNPCRank(): NPC is not in a faction"); + { + Log(Debug::Warning) << "getNPCRank(): NPC is not in a faction"; + return "%"; + } int rank = ptr.getClass().getPrimaryFactionRank(ptr); if (rank < 0 || rank > 9) @@ -349,7 +361,10 @@ namespace MWScript const ESM::RefId& factionId = getReferenceImp().getClass().getPrimaryFaction(getReferenceImp()); if (factionId.empty()) - throw std::runtime_error("getPCRank(): NPC is not in a faction"); + { + Log(Debug::Warning) << "getPCRank(): NPC is not in a faction"; + return "%"; + } const auto& ranks = player.getClass().getNpcStats(player).getFactionRanks(); auto it = ranks.find(factionId); @@ -378,7 +393,10 @@ namespace MWScript const ESM::RefId& factionId = getReferenceImp().getClass().getPrimaryFaction(getReferenceImp()); if (factionId.empty()) - throw std::runtime_error("getPCNextRank(): NPC is not in a faction"); + { + Log(Debug::Warning) << "getPCNextRank(): NPC is not in a faction"; + return "%"; + } const auto& ranks = player.getClass().getNpcStats(player).getFactionRanks(); auto it = ranks.find(factionId); diff --git a/components/interpreter/defines.cpp b/components/interpreter/defines.cpp index e7a8e35328..6d51a72cca 100644 --- a/components/interpreter/defines.cpp +++ b/components/interpreter/defines.cpp @@ -26,40 +26,40 @@ namespace std::vector globals; const std::initializer_list> sActionBindings{ - { "actionslideright", "#{sRight}" }, - { "actionreadymagic", "#{sReady_Magic}" }, - { "actionprevweapon", "#{sPrevWeapon}" }, - { "actionnextweapon", "#{sNextWeapon}" }, - { "actiontogglerun", "#{sAuto_Run}" }, - { "actionslideleft", "#{sLeft}" }, - { "actionreadyitem", "#{sReady_Weapon}" }, - { "actionprevspell", "#{sPrevSpell}" }, - { "actionnextspell", "#{sNextSpell}" }, - { "actionrestmenu", "#{sRestKey}" }, - { "actionmenumode", "#{sInventory}" }, - { "actionactivate", "#{sActivate}" }, - { "actionjournal", "#{sJournal}" }, - { "actionforward", "#{sForward}" }, - { "actioncrouch", "#{sCrouch_Sneak}" }, - { "actionjump", "#{sJump}" }, - { "actionback", "#{sBack}" }, - { "actionuse", "#{sUse}" }, - { "actionrun", "#{sRun}" }, + { "ActionSlideRight", "#{sRight}" }, + { "ActionReadyMagic", "#{sReady_Magic}" }, + { "ActionPrevWeapon", "#{sPrevWeapon}" }, + { "ActionNextWeapon", "#{sNextWeapon}" }, + { "ActionToggleRun", "#{sAuto_Run}" }, + { "ActionSlideLeft", "#{sLeft}" }, + { "ActionReadyItem", "#{sReady_Weapon}" }, + { "ActionPrevSpell", "#{sPrevSpell}" }, + { "ActionNextSpell", "#{sNextSpell}" }, + { "ActionRestMenu", "#{sRestKey}" }, + { "ActionMenuMode", "#{sInventory}" }, + { "ActionActivate", "#{sActivate}" }, + { "ActionJournal", "#{sJournal}" }, + { "ActionForward", "#{sForward}" }, + { "ActionCrouch", "#{sCrouch_Sneak}" }, + { "ActionJump", "#{sJump}" }, + { "ActionBack", "#{sBack}" }, + { "ActionUse", "#{sUse}" }, + { "ActionRun", "#{sRun}" }, }; using ContextMethod = std::string_view (Interpreter::Context::*)() const; const std::initializer_list>> sContextMethods{ - { "nextpcrank", { &Interpreter::Context::getPCNextRank, nullptr } }, - { "pcnextrank", { &Interpreter::Context::getPCNextRank, nullptr } }, - { "faction", { &Interpreter::Context::getNPCFaction, nullptr } }, - { "pcclass", { &Interpreter::Context::getPCClass, &Interpreter::Context::getPCClass } }, - { "pcname", { &Interpreter::Context::getPCName, &Interpreter::Context::getPCName } }, - { "pcrace", { &Interpreter::Context::getPCRace, &Interpreter::Context::getPCRace } }, - { "pcrank", { &Interpreter::Context::getPCRank, nullptr } }, - { "class", { &Interpreter::Context::getNPCClass, &Interpreter::Context::getPCClass } }, - { "cell", { &Interpreter::Context::getCurrentCellName, &Interpreter::Context::getCurrentCellName } }, - { "race", { &Interpreter::Context::getNPCRace, &Interpreter::Context::getPCRace } }, - { "rank", { &Interpreter::Context::getNPCRank, nullptr } }, - { "name", { &Interpreter::Context::getActorName, &Interpreter::Context::getPCName } }, + { "NextPCRank", { &Interpreter::Context::getPCNextRank, nullptr } }, + { "PCNextRank", { &Interpreter::Context::getPCNextRank, nullptr } }, + { "Faction", { &Interpreter::Context::getNPCFaction, nullptr } }, + { "PCClass", { &Interpreter::Context::getPCClass, &Interpreter::Context::getPCClass } }, + { "PCName", { &Interpreter::Context::getPCName, &Interpreter::Context::getPCName } }, + { "PCRace", { &Interpreter::Context::getPCRace, &Interpreter::Context::getPCRace } }, + { "PCRank", { &Interpreter::Context::getPCRank, nullptr } }, + { "Class", { &Interpreter::Context::getNPCClass, &Interpreter::Context::getPCClass } }, + { "Cell", { &Interpreter::Context::getCurrentCellName, &Interpreter::Context::getCurrentCellName } }, + { "Race", { &Interpreter::Context::getNPCRace, &Interpreter::Context::getPCRace } }, + { "Rank", { &Interpreter::Context::getNPCRank, nullptr } }, + { "Name", { &Interpreter::Context::getActorName, &Interpreter::Context::getPCName } }, }; bool longerStr(std::string_view a, std::string_view b) @@ -78,7 +78,7 @@ namespace return true; } } - if (check(temp, "pccrimelevel", i, start)) + if (check(temp, "PCCrimeLevel", i, start)) { retval << context.getPCBounty(); return true; @@ -89,7 +89,13 @@ namespace if (check(temp, name, i, start)) { if (method) // Not all variables are available outside of dialogue + { retval << (context.*method)(); + + // Re-add the token if replacement failed without an error + if ((context.*method)() == "%") + retval << name; + } return true; } } From 555721141d8d1a6b1587b38400addbb2fc7e6d43 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Thu, 3 Jul 2025 15:22:52 -0600 Subject: [PATCH 179/330] Skip quest names (vanilla improvement) --- apps/openmw/mwscript/dialogueextensions.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 23d8049a5d..6c219a52a3 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -99,7 +99,8 @@ namespace MWScript { for (const auto& journalInfo : dialogue.mInfoOrder.getOrderedInfo()) { - journal->addEntry(dialogue.mId, journalInfo.mData.mJournalIndex, playerPtr); + if (journalInfo.mQuestStatus != ESM::DialInfo::QS_Name) + journal->addEntry(dialogue.mId, journalInfo.mData.mJournalIndex, playerPtr); } } else if (dialogue.mType == ESM::Dialogue::Type::Topic) From c4a4c435f1b49c7ff9f23bbc3e6743455fe2dcfc Mon Sep 17 00:00:00 2001 From: Kindi Date: Fri, 4 Apr 2025 11:53:55 +0800 Subject: [PATCH 180/330] refactor opshowvars --- apps/openmw/mwscript/miscextensions.cpp | 91 +++++++++++-------------- 1 file changed, 38 insertions(+), 53 deletions(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 06abbe5bb2..af81fd2d3c 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1146,9 +1146,18 @@ namespace MWScript { void printLocalVars(Interpreter::Runtime& runtime, const MWWorld::Ptr& ptr) { - std::stringstream str; + std::ostringstream str; const ESM::RefId& script = ptr.getClass().getScript(ptr); + + auto printVariables = [&str](const auto& names, const auto& values, std::string_view type) { + size_t size = std::min(names.size(), values.size()); + for (size_t i = 0; i < size; ++i) + { + str << "\n " << names[i] << " = " << values[i] << " (" << type << ")"; + } + }; + if (script.empty()) str << ptr.getCellRef().getRefId() << " does not have a script."; else @@ -1159,27 +1168,9 @@ namespace MWScript const Compiler::Locals& complocals = MWBase::Environment::get().getScriptManager()->getLocals(script); - const std::vector* names = &complocals.get('s'); - for (size_t i = 0; i < names->size(); ++i) - { - if (i >= locals.mShorts.size()) - break; - str << std::endl << " " << (*names)[i] << " = " << locals.mShorts[i] << " (short)"; - } - names = &complocals.get('l'); - for (size_t i = 0; i < names->size(); ++i) - { - if (i >= locals.mLongs.size()) - break; - str << std::endl << " " << (*names)[i] << " = " << locals.mLongs[i] << " (long)"; - } - names = &complocals.get('f'); - for (size_t i = 0; i < names->size(); ++i) - { - if (i >= locals.mFloats.size()) - break; - str << std::endl << " " << (*names)[i] << " = " << locals.mFloats[i] << " (float)"; - } + printVariables(complocals.get('s'), locals.mShorts, "short"); + printVariables(complocals.get('l'), locals.mLongs, "long"); + printVariables(complocals.get('f'), locals.mFloats, "float"); } runtime.getContext().report(str.str()); @@ -1187,50 +1178,43 @@ namespace MWScript void printGlobalVars(Interpreter::Runtime& runtime) { - std::stringstream str; - str << "Global variables:"; + std::ostringstream str; + str << "Global Variables:"; MWBase::World* world = MWBase::Environment::get().getWorld(); - std::vector names = runtime.getContext().getGlobals(); + auto& context = runtime.getContext(); + std::vector names = context.getGlobals(); - // sort for user convenience - std::sort(names.begin(), names.end()); - - for (size_t i = 0; i < names.size(); ++i) - { - char type = world->getGlobalVariableType(names[i]); - str << std::endl << " " << names[i] << " = "; + std::sort(names.begin(), names.end(), ::Misc::StringUtils::ciLess); + auto printVariable = [&str, &context](const std::string& name, char type) { + str << "\n " << name << " = "; switch (type) { case 's': - - str << runtime.getContext().getGlobalShort(names[i]) << " (short)"; + str << context.getGlobalShort(name) << " (short)"; break; - case 'l': - - str << runtime.getContext().getGlobalLong(names[i]) << " (long)"; + str << context.getGlobalLong(name) << " (long)"; break; - case 'f': - - str << runtime.getContext().getGlobalFloat(names[i]) << " (float)"; + str << context.getGlobalFloat(name) << " (float)"; break; - default: - str << ""; } - } + }; - runtime.getContext().report(str.str()); + for (const auto& name : names) + printVariable(name, world->getGlobalVariableType(name)); + + context.report(str.str()); } void printGlobalScriptsVars(Interpreter::Runtime& runtime) { - std::stringstream str; - str << std::endl << "Global Scripts:"; + std::ostringstream str; + str << "\nGlobal Scripts:"; const auto& scripts = MWBase::Environment::get().getScriptManager()->getGlobalScripts().getScripts(); @@ -1238,12 +1222,11 @@ namespace MWScript std::map> globalScripts(scripts.begin(), scripts.end()); auto printVariables - = [&str](const ESM::RefId& scptName, const auto& names, const auto& values, std::string_view type) { + = [&str](std::string_view scptName, const auto& names, const auto& values, std::string_view type) { size_t size = std::min(names.size(), values.size()); for (size_t i = 0; i < size; ++i) { - str << std::endl - << " " << scptName << "->" << names[i] << " = " << values[i] << " (" << type << ")"; + str << "\n " << scptName << "->" << names[i] << " = " << values[i] << " (" << type << ")"; } }; @@ -1253,18 +1236,20 @@ namespace MWScript if (!script->mRunning) continue; + std::string_view scptName = refId.getRefIdString(); + const Compiler::Locals& complocals = MWBase::Environment::get().getScriptManager()->getLocals(refId); const Locals& locals = MWBase::Environment::get().getScriptManager()->getGlobalScripts().getLocals(refId); if (locals.isEmpty()) - str << std::endl << " No variables in script " << refId; + str << "\n No variables in script " << scptName; else { - printVariables(refId, complocals.get('s'), locals.mShorts, "short"); - printVariables(refId, complocals.get('l'), locals.mLongs, "long"); - printVariables(refId, complocals.get('f'), locals.mFloats, "float"); + printVariables(scptName, complocals.get('s'), locals.mShorts, "short"); + printVariables(scptName, complocals.get('l'), locals.mLongs, "long"); + printVariables(scptName, complocals.get('f'), locals.mFloats, "float"); } } From 6a9b2d330210ccdeb6f98a69ad86a8a0928fb1f4 Mon Sep 17 00:00:00 2001 From: Sarah Sunday <1644563-ssunday@users.noreply.gitlab.com> Date: Sun, 6 Jul 2025 17:27:40 -0500 Subject: [PATCH 181/330] [CI] Brew cleanup/simplify --- .gitlab-ci.yml | 6 ++++++ CI/before_install.macos.sh | 4 ---- CI/macos/before_install.arm64.sh | 9 +-------- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index dc638729c4..f1c96b1776 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -546,6 +546,9 @@ macOS14_Xcode15_amd64: CCACHE_SIZE: 3G DMG_IDENTIFIER: amd64 MACOS_AMD64: true + HOMEBREW_NO_AUTO_UPDATE: 1 + HOMEBREW_NO_EMOJI: true + HOMEBREW_NO_INSTALL_CLEANUP: true macOS14_Xcode15_arm64: extends: .MacOS @@ -557,6 +560,9 @@ macOS14_Xcode15_arm64: variables: DMG_IDENTIFIER: arm64 CCACHE_SIZE: 3G + HOMEBREW_NO_AUTO_UPDATE: 1 + HOMEBREW_NO_EMOJI: true + HOMEBREW_NO_INSTALL_CLEANUP: true .Compress_And_Upload_Symbols_Base: extends: .Ubuntu_Image diff --git a/CI/before_install.macos.sh b/CI/before_install.macos.sh index f466dd06a7..60d2d3a38c 100755 --- a/CI/before_install.macos.sh +++ b/CI/before_install.macos.sh @@ -1,9 +1,5 @@ #!/bin/sh -ex -export HOMEBREW_NO_EMOJI=1 -export HOMEBREW_NO_INSTALL_CLEANUP=1 -export HOMEBREW_AUTOREMOVE=1 - if [[ "${MACOS_AMD64}" ]]; then ./CI/macos/before_install.amd64.sh else diff --git a/CI/macos/before_install.arm64.sh b/CI/macos/before_install.arm64.sh index 84120dfba2..d53d847b1c 100755 --- a/CI/macos/before_install.arm64.sh +++ b/CI/macos/before_install.arm64.sh @@ -3,14 +3,7 @@ brew tap --repair brew update --quiet -brew install curl xquartz gd fontconfig freetype harfbuzz brotli s3cmd - -command -v ccache >/dev/null 2>&1 || brew install ccache -command -v cmake >/dev/null 2>&1 || brew install cmake -command -v qmake >/dev/null 2>&1 || brew install qt@6 - -# Install deps -brew install openal-soft icu4c yaml-cpp sqlite +brew install curl xquartz gd fontconfig freetype harfbuzz brotli s3cmd ccache cmake qt@6 openal-soft icu4c yaml-cpp sqlite curl -fSL -R -J https://gitlab.com/OpenMW/openmw-deps/-/raw/main/macos/openmw-deps-20240818-arm64.tar.xz -o ~/openmw-deps.tar.xz tar xf ~/openmw-deps.tar.xz -C /tmp > /dev/null From 67795543a296a415e47a516c883a8f5e3a410f21 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Sun, 6 Jul 2025 20:51:53 -0600 Subject: [PATCH 182/330] Revert "Fix unneeded runtime errors" This reverts commit d207c2251ffe4693f73e275c8df95bc7127c0010. --- apps/openmw/mwscript/interpretercontext.cpp | 26 ++------ components/interpreter/defines.cpp | 70 ++++++++++----------- 2 files changed, 36 insertions(+), 60 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 9aeccfc886..15c9100b98 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include "../mwworld/esmstore.hpp" @@ -301,15 +300,7 @@ namespace MWScript std::string_view InterpreterContext::getNPCFaction() const { - const MWWorld::Ptr& ptr = getReferenceImp(); - const ESM::RefId& factionId = ptr.getClass().getPrimaryFaction(ptr); - if (factionId.empty()) - { - Log(Debug::Warning) << "getNPCFaction(): NPC is not in a faction"; - return "%"; - } - - const ESM::NPC* npc = ptr.get()->mBase; + const ESM::NPC* npc = getReferenceImp().get()->mBase; const ESM::Faction* faction = MWBase::Environment::get().getESMStore()->get().find(npc->mFaction); return faction->mName; } @@ -319,10 +310,7 @@ namespace MWScript const MWWorld::Ptr& ptr = getReferenceImp(); const ESM::RefId& faction = ptr.getClass().getPrimaryFaction(ptr); if (faction.empty()) - { - Log(Debug::Warning) << "getNPCRank(): NPC is not in a faction"; - return "%"; - } + throw std::runtime_error("getNPCRank(): NPC is not in a faction"); int rank = ptr.getClass().getPrimaryFactionRank(ptr); if (rank < 0 || rank > 9) @@ -361,10 +349,7 @@ namespace MWScript const ESM::RefId& factionId = getReferenceImp().getClass().getPrimaryFaction(getReferenceImp()); if (factionId.empty()) - { - Log(Debug::Warning) << "getPCRank(): NPC is not in a faction"; - return "%"; - } + throw std::runtime_error("getPCRank(): NPC is not in a faction"); const auto& ranks = player.getClass().getNpcStats(player).getFactionRanks(); auto it = ranks.find(factionId); @@ -393,10 +378,7 @@ namespace MWScript const ESM::RefId& factionId = getReferenceImp().getClass().getPrimaryFaction(getReferenceImp()); if (factionId.empty()) - { - Log(Debug::Warning) << "getPCNextRank(): NPC is not in a faction"; - return "%"; - } + throw std::runtime_error("getPCNextRank(): NPC is not in a faction"); const auto& ranks = player.getClass().getNpcStats(player).getFactionRanks(); auto it = ranks.find(factionId); diff --git a/components/interpreter/defines.cpp b/components/interpreter/defines.cpp index 6d51a72cca..e7a8e35328 100644 --- a/components/interpreter/defines.cpp +++ b/components/interpreter/defines.cpp @@ -26,40 +26,40 @@ namespace std::vector globals; const std::initializer_list> sActionBindings{ - { "ActionSlideRight", "#{sRight}" }, - { "ActionReadyMagic", "#{sReady_Magic}" }, - { "ActionPrevWeapon", "#{sPrevWeapon}" }, - { "ActionNextWeapon", "#{sNextWeapon}" }, - { "ActionToggleRun", "#{sAuto_Run}" }, - { "ActionSlideLeft", "#{sLeft}" }, - { "ActionReadyItem", "#{sReady_Weapon}" }, - { "ActionPrevSpell", "#{sPrevSpell}" }, - { "ActionNextSpell", "#{sNextSpell}" }, - { "ActionRestMenu", "#{sRestKey}" }, - { "ActionMenuMode", "#{sInventory}" }, - { "ActionActivate", "#{sActivate}" }, - { "ActionJournal", "#{sJournal}" }, - { "ActionForward", "#{sForward}" }, - { "ActionCrouch", "#{sCrouch_Sneak}" }, - { "ActionJump", "#{sJump}" }, - { "ActionBack", "#{sBack}" }, - { "ActionUse", "#{sUse}" }, - { "ActionRun", "#{sRun}" }, + { "actionslideright", "#{sRight}" }, + { "actionreadymagic", "#{sReady_Magic}" }, + { "actionprevweapon", "#{sPrevWeapon}" }, + { "actionnextweapon", "#{sNextWeapon}" }, + { "actiontogglerun", "#{sAuto_Run}" }, + { "actionslideleft", "#{sLeft}" }, + { "actionreadyitem", "#{sReady_Weapon}" }, + { "actionprevspell", "#{sPrevSpell}" }, + { "actionnextspell", "#{sNextSpell}" }, + { "actionrestmenu", "#{sRestKey}" }, + { "actionmenumode", "#{sInventory}" }, + { "actionactivate", "#{sActivate}" }, + { "actionjournal", "#{sJournal}" }, + { "actionforward", "#{sForward}" }, + { "actioncrouch", "#{sCrouch_Sneak}" }, + { "actionjump", "#{sJump}" }, + { "actionback", "#{sBack}" }, + { "actionuse", "#{sUse}" }, + { "actionrun", "#{sRun}" }, }; using ContextMethod = std::string_view (Interpreter::Context::*)() const; const std::initializer_list>> sContextMethods{ - { "NextPCRank", { &Interpreter::Context::getPCNextRank, nullptr } }, - { "PCNextRank", { &Interpreter::Context::getPCNextRank, nullptr } }, - { "Faction", { &Interpreter::Context::getNPCFaction, nullptr } }, - { "PCClass", { &Interpreter::Context::getPCClass, &Interpreter::Context::getPCClass } }, - { "PCName", { &Interpreter::Context::getPCName, &Interpreter::Context::getPCName } }, - { "PCRace", { &Interpreter::Context::getPCRace, &Interpreter::Context::getPCRace } }, - { "PCRank", { &Interpreter::Context::getPCRank, nullptr } }, - { "Class", { &Interpreter::Context::getNPCClass, &Interpreter::Context::getPCClass } }, - { "Cell", { &Interpreter::Context::getCurrentCellName, &Interpreter::Context::getCurrentCellName } }, - { "Race", { &Interpreter::Context::getNPCRace, &Interpreter::Context::getPCRace } }, - { "Rank", { &Interpreter::Context::getNPCRank, nullptr } }, - { "Name", { &Interpreter::Context::getActorName, &Interpreter::Context::getPCName } }, + { "nextpcrank", { &Interpreter::Context::getPCNextRank, nullptr } }, + { "pcnextrank", { &Interpreter::Context::getPCNextRank, nullptr } }, + { "faction", { &Interpreter::Context::getNPCFaction, nullptr } }, + { "pcclass", { &Interpreter::Context::getPCClass, &Interpreter::Context::getPCClass } }, + { "pcname", { &Interpreter::Context::getPCName, &Interpreter::Context::getPCName } }, + { "pcrace", { &Interpreter::Context::getPCRace, &Interpreter::Context::getPCRace } }, + { "pcrank", { &Interpreter::Context::getPCRank, nullptr } }, + { "class", { &Interpreter::Context::getNPCClass, &Interpreter::Context::getPCClass } }, + { "cell", { &Interpreter::Context::getCurrentCellName, &Interpreter::Context::getCurrentCellName } }, + { "race", { &Interpreter::Context::getNPCRace, &Interpreter::Context::getPCRace } }, + { "rank", { &Interpreter::Context::getNPCRank, nullptr } }, + { "name", { &Interpreter::Context::getActorName, &Interpreter::Context::getPCName } }, }; bool longerStr(std::string_view a, std::string_view b) @@ -78,7 +78,7 @@ namespace return true; } } - if (check(temp, "PCCrimeLevel", i, start)) + if (check(temp, "pccrimelevel", i, start)) { retval << context.getPCBounty(); return true; @@ -89,13 +89,7 @@ namespace if (check(temp, name, i, start)) { if (method) // Not all variables are available outside of dialogue - { retval << (context.*method)(); - - // Re-add the token if replacement failed without an error - if ((context.*method)() == "%") - retval << name; - } return true; } } From 40e9b2d707f432616717d296aa38876440c52781 Mon Sep 17 00:00:00 2001 From: Kuyondo Date: Tue, 27 May 2025 01:48:58 +0800 Subject: [PATCH 183/330] play down sound when equip fails --- apps/openmw/mwgui/inventorywindow.cpp | 63 +++++++++++---------------- apps/openmw/mwgui/quickkeysmenu.cpp | 32 +++++++++----- 2 files changed, 46 insertions(+), 49 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 410ed31a66..017616295f 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -522,33 +522,15 @@ namespace MWGui } MWWorld::Ptr player = MWMechanics::getPlayer(); + bool canUse = true; - // early-out for items that need to be equipped, but can't be equipped: we don't want to set OnPcEquip in that - // case - if (!ptr.getClass().getEquipmentSlots(ptr).first.empty()) - { - if (ptr.getClass().hasItemHealth(ptr) && ptr.getCellRef().getCharge() == 0) - { - MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage1}"); - updateItemView(); - return; - } - - if (!force) - { - auto canEquip = ptr.getClass().canBeEquipped(ptr, player); - - if (canEquip.first == 0) - { - MWBase::Environment::get().getWindowManager()->messageBox(canEquip.second); - updateItemView(); - return; - } - } - } + // We don't want to set OnPcEquip for items that need to be equipped; but cannot be equipped; + if (!ptr.getClass().getEquipmentSlots(ptr).first.empty() + && ptr.getClass().canBeEquipped(ptr, player).first == 0) + canUse = force && ptr.getClass().hasItemHealth(ptr) && ptr.getCellRef().getCharge() != 0; // If the item has a script, set OnPCEquip or PCSkipEquip to 1 - if (!script.empty()) + if (!script.empty() && canUse) { // Ingredients, books and repair hammers must not have OnPCEquip set to 1 here auto type = ptr.getType(); @@ -561,7 +543,25 @@ namespace MWGui } std::unique_ptr action = ptr.getClass().use(ptr, force); - action->execute(player); + + action->execute(player, !canUse); + + if (mDragAndDrop->mIsOnDragAndDrop && mDragAndDrop->mItem.mBase == ptr) + { + if (canUse) + { + mDragAndDrop->finish(); + // If item is ingredient or potion don't stop drag and drop + if ((ptr.getType() == ESM::Potion::sRecordId || ptr.getType() == ESM::Ingredient::sRecordId) + && mDragAndDrop->mDraggedCount > 1) + { + mSelectedItem = getModel()->getIndex(mDragAndDrop->mItem); + dragItem(nullptr, mDragAndDrop->mDraggedCount - 1); + } + } + else + mDragAndDrop->drop(mTradeModel, mItemView); + } // Handles partial equipping (final part) if (mEquippedStackableCount.has_value()) @@ -592,8 +592,6 @@ namespace MWGui { MWWorld::Ptr ptr = mDragAndDrop->mItem.mBase; - mDragAndDrop->finish(); - if (mDragAndDrop->mSourceModel != mTradeModel) { // Move item to the player's inventory @@ -617,17 +615,6 @@ namespace MWGui } MWBase::Environment::get().getLuaManager()->useItem(ptr, MWMechanics::getPlayer(), false); - - // If item is ingredient or potion don't stop drag and drop to simplify action of taking more than one 1 - // item - if ((ptr.getType() == ESM::Potion::sRecordId || ptr.getType() == ESM::Ingredient::sRecordId) - && mDragAndDrop->mDraggedCount > 1) - { - // Item can be provided from other window for example container. - // But after DragAndDrop::startDrag item automaticly always gets to player inventory. - mSelectedItem = getModel()->getIndex(mDragAndDrop->mItem); - dragItem(nullptr, mDragAndDrop->mDraggedCount - 1); - } } else { diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index c8932c97b6..deb844078b 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -84,9 +84,8 @@ namespace MWGui case ESM::QuickKeys::Type::MagicItem: { MWWorld::Ptr item = *mKey[index].button->getUserData(); - // Make sure the item is available and is not broken - if (item.isEmpty() || item.getCellRef().getCount() < 1 - || (item.getClass().hasItemHealth(item) && item.getClass().getItemHealth(item) <= 0)) + // Make sure the item is available + if (item.isEmpty() || item.getCellRef().getCount() < 1) { // Try searching for a compatible replacement item = store.findReplacement(mKey[index].id); @@ -382,18 +381,29 @@ namespace MWGui if (it == store.end()) item = nullptr; - // check the item is available and not broken - if (item.isEmpty() || item.getCellRef().getCount() < 1 - || (item.getClass().hasItemHealth(item) && item.getClass().getItemHealth(item) <= 0)) + // check the quickkey item is available + if (item.isEmpty() || item.getCellRef().getCount() < 1) { - item = store.findReplacement(key->id); + MWBase::Environment::get().getWindowManager()->messageBox("#{sQuickMenu5} " + key->name); + return; + } - if (item.isEmpty() || item.getCellRef().getCount() < 1) + // check the quickkey item is not broken + if (item.getClass().hasItemHealth(item) && item.getClass().getItemHealth(item) <= 0) + { + const std::vector& equipmentSlots = item.getClass().getEquipmentSlots(item).first; + if (!equipmentSlots.empty()) { - MWBase::Environment::get().getWindowManager()->messageBox("#{sQuickMenu5} " + key->name); - - return; + const auto& itSlot = store.getSlot(equipmentSlots.front()); + // Morrowind.exe behaviour: + // Only display item broken message if; + // no item in the to-be-equipped slot + // or broken quickkey item and currently equipped item id is different + // It doesn't find a replacement + if (itSlot == store.end() || (item.getCellRef().getRefId() != itSlot->getCellRef().getRefId())) + MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage1}"); } + return; } if (key->type == ESM::QuickKeys::Type::Item) From e4f0723a90efe1a2661dea6fc0db2d0c1ead1a1b Mon Sep 17 00:00:00 2001 From: Kuyondo Date: Tue, 27 May 2025 15:50:23 +0800 Subject: [PATCH 184/330] cleanup --- apps/openmw/mwclass/weapon.cpp | 6 +-- apps/openmw/mwgui/inventorywindow.cpp | 62 ++++++++++++++++----------- apps/openmw/mwgui/quickkeysmenu.cpp | 9 ++-- apps/openmw/mwworld/actionequip.cpp | 9 ++-- 4 files changed, 47 insertions(+), 39 deletions(-) diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 089c8c2894..3524446b26 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -270,14 +270,14 @@ namespace MWClass std::pair Weapon::canBeEquipped(const MWWorld::ConstPtr& ptr, const MWWorld::Ptr& npc) const { - if (hasItemHealth(ptr) && getItemHealth(ptr) == 0) - return { 0, "#{sInventoryMessage1}" }; - // Do not allow equip weapons from inventory during attack if (npc.isInCell() && MWBase::Environment::get().getWindowManager()->isGuiMode() && MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(npc)) return { 0, "#{sCantEquipWeapWarning}" }; + if (hasItemHealth(ptr) && getItemHealth(ptr) == 0) + return { 0, "#{sInventoryMessage1}" }; + std::pair, bool> slots_ = getEquipmentSlots(ptr); if (slots_.first.empty()) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 017616295f..1f6b6fdeb5 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -522,18 +522,25 @@ namespace MWGui } MWWorld::Ptr player = MWMechanics::getPlayer(); - bool canUse = true; + auto type = ptr.getType(); + bool isWeaponOrArmor = type == ESM::Weapon::sRecordId || type == ESM::Armor::sRecordId; + bool isBroken = ptr.getClass().hasItemHealth(ptr) && ptr.getCellRef().getCharge() == 0; - // We don't want to set OnPcEquip for items that need to be equipped; but cannot be equipped; - if (!ptr.getClass().getEquipmentSlots(ptr).first.empty() - && ptr.getClass().canBeEquipped(ptr, player).first == 0) - canUse = force && ptr.getClass().hasItemHealth(ptr) && ptr.getCellRef().getCharge() != 0; + // In vanilla, broken armor or weapons cannot be equipped + // tools with 0 charges is equippable + if (isBroken && isWeaponOrArmor) + { + MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage1}"); + return; + } + + bool canEquip = ptr.getClass().canBeEquipped(ptr, mPtr).first != 0; + bool shouldSetOnPcEquip = canEquip || force; // If the item has a script, set OnPCEquip or PCSkipEquip to 1 - if (!script.empty() && canUse) + if (!script.empty() && shouldSetOnPcEquip) { // Ingredients, books and repair hammers must not have OnPCEquip set to 1 here - auto type = ptr.getType(); bool isBook = type == ESM::Book::sRecordId; if (!isBook && type != ESM::Ingredient::sRecordId && type != ESM::Repair::sRecordId) ptr.getRefData().getLocals().setVarByInt(script, "onpcequip", 1); @@ -543,25 +550,7 @@ namespace MWGui } std::unique_ptr action = ptr.getClass().use(ptr, force); - - action->execute(player, !canUse); - - if (mDragAndDrop->mIsOnDragAndDrop && mDragAndDrop->mItem.mBase == ptr) - { - if (canUse) - { - mDragAndDrop->finish(); - // If item is ingredient or potion don't stop drag and drop - if ((ptr.getType() == ESM::Potion::sRecordId || ptr.getType() == ESM::Ingredient::sRecordId) - && mDragAndDrop->mDraggedCount > 1) - { - mSelectedItem = getModel()->getIndex(mDragAndDrop->mItem); - dragItem(nullptr, mDragAndDrop->mDraggedCount - 1); - } - } - else - mDragAndDrop->drop(mTradeModel, mItemView); - } + action->execute(player); // Handles partial equipping (final part) if (mEquippedStackableCount.has_value()) @@ -592,6 +581,16 @@ namespace MWGui { MWWorld::Ptr ptr = mDragAndDrop->mItem.mBase; + auto canEquip = ptr.getClass().canBeEquipped(ptr, mPtr); + if (canEquip.first == 0) // cannot equip + { + mDragAndDrop->drop(mTradeModel, mItemView); // also plays down sound + MWBase::Environment::get().getWindowManager()->messageBox(canEquip.second); + return; + } + + mDragAndDrop->finish(); + if (mDragAndDrop->mSourceModel != mTradeModel) { // Move item to the player's inventory @@ -615,6 +614,17 @@ namespace MWGui } MWBase::Environment::get().getLuaManager()->useItem(ptr, MWMechanics::getPlayer(), false); + + // If item is ingredient or potion don't stop drag and drop to simplify action of taking more than one 1 + // item + if ((ptr.getType() == ESM::Potion::sRecordId || ptr.getType() == ESM::Ingredient::sRecordId) + && mDragAndDrop->mDraggedCount > 1) + { + // Item can be provided from other window for example container. + // But after DragAndDrop::startDrag item automaticly always gets to player inventory. + mSelectedItem = getModel()->getIndex(mDragAndDrop->mItem); + dragItem(nullptr, mDragAndDrop->mDraggedCount - 1); + } } else { diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index deb844078b..5f3cd17732 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -395,11 +395,10 @@ namespace MWGui if (!equipmentSlots.empty()) { const auto& itSlot = store.getSlot(equipmentSlots.front()); - // Morrowind.exe behaviour: - // Only display item broken message if; - // no item in the to-be-equipped slot - // or broken quickkey item and currently equipped item id is different - // It doesn't find a replacement + // Morrowind.exe behavior: + // Only display the "item is broken" message if: + // - There is no item in the target equipment slot, or + // - The quickkey item is broken and the currently equipped item has a different ID if (itSlot == store.end() || (item.getCellRef().getRefId() != itSlot->getCellRef().getRefId())) MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage1}"); } diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 58e6f013aa..dbc548f585 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -21,12 +21,11 @@ namespace MWWorld MWWorld::Ptr object = getTarget(); MWWorld::InventoryStore& invStore = actor.getClass().getInventoryStore(actor); - if (object.getClass().hasItemHealth(object) && object.getCellRef().getCharge() == 0) + if (actor != MWMechanics::getPlayer()) { - if (actor == MWMechanics::getPlayer()) - MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage1}"); - - return; + // player logic is handled in InventoryWindow::useItem + if (object.getClass().hasItemHealth(object) && object.getCellRef().getCharge() == 0) + return; } if (!mForce) From d5e3703aa888add48cf1e6b3066001c12a90921a Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Mon, 7 Jul 2025 11:32:04 +0300 Subject: [PATCH 185/330] Changelog sync for 0.50.0 --- CHANGELOG.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cbffc23bc7..e847ec69fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,52 @@ 0.50.0 ------ + Bug #2967: Inventory windows don't update when changing items by script + Bug #5331: Pathfinding works incorrectly when actor is moved from one interior cell to another + Bug #6039: Next Spell keybind fails while selected enchanted item has multiple copies + Bug #6573: Editor: Selection behaves incorrectly on high-DPI displays + Bug #6792: Birth sign info box has no line breaks + Bug #7622: Player's marksman weapons don't work on close actors underwater + Bug #7740: Magic items in the HUD aren't composited correctly + Bug #7799: Picking up ingredients while object paging active grid is on may cause a hiccup + Bug #8245: The console command ShowVars does not list global mwscripts + Bug #8265: Topics are linked incorrectly + Bug #8303: On target spells cast by non-actors should fire underwater + Bug #8318: Missing global variables are not handled gracefully in dialogue conditions + Bug #8340: Multi-effect enchantments are too expensive + Bug #8341: Repeat shader visitor passes discard parallax + Bug #8349: Travel to non-existent cell causes persistent black screen + Bug #8371: Silence affects powers + Bug #8375: Moon phase cycle doesn't match Morrowind + Bug #8383: Casting bound helm or boots on beast races doesn't cleanup properly + Bug #8385: Russian encoding broken with locale parameters and calendar + Bug #8408: OpenMW doesn't report all the potential resting hindrances + Bug #8414: Waterwalking works when collision is disabled + Bug #8431: Behaviour of removed items from a container is buggy + Bug #8432: Changing to and from an interior cell doesn't update collision + Bug #8436: Spell selection in a pinned spellbook window doesn't update + Bug #8437: Pinned inventory window's pin button doesn't look pressed + Bug #8446: Travel prices are strangely inconsistent + Bug #8459: Changing magic effect base cost doesn't change spell price + Bug #8466: Showmap "" reveals nameless cells + Bug #8485: Witchwither disease and probably other common diseases don't work correctly + Bug #8490: Normals on Water disappear when Water Shader is Enabled but Refraction is Disabled + Bug #8500: OpenMW Alarm behaviour doesn't match morrowind.exe + Bug #8519: Multiple bounty is sometimes assigned to player when detected during a pickpocketing action + Bug #8585: Dialogue topic list doesn't have enough padding + Bug #8587: Minor INI importer problems + Bug #8593: Render targets do not generate mipmaps + Bug #8598: Post processing shaders don't interact with the vfs correctly + Bug #8599: Non-ASCII paths in BSA files don't work + Feature #3769: Allow GetSpellEffects on enchantments + Feature #8112: Expose landscape record data to Lua + Feature #8113: Support extended selection in autodetected subdirectory dialog Feature #8285: Expose list of active shaders in postprocessing API + Feature #8313: Show the character name in the savegame details + Feature #8320: Add access mwscript source text to lua api + Feature #8355: Lua: Window visibility checking in interfaces.UI + Feature #8580: Sort characters in the save loading menu + Feature #8597: Lua: Add more built-in event handlers 0.49.0 ------ From 3f352b24703b0b1447d70c2c6580da65b75b9887 Mon Sep 17 00:00:00 2001 From: Kuyondo Date: Mon, 7 Jul 2025 02:36:37 +0800 Subject: [PATCH 186/330] tests --- apps/components_tests/lua/testutilpackage.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/apps/components_tests/lua/testutilpackage.cpp b/apps/components_tests/lua/testutilpackage.cpp index a61c0e0306..600d476cd0 100644 --- a/apps/components_tests/lua/testutilpackage.cpp +++ b/apps/components_tests/lua/testutilpackage.cpp @@ -9,6 +9,17 @@ namespace { using namespace testing; + struct LuaUtilPackageTest : Test + { + LuaUtil::LuaState mLuaState{ nullptr, nullptr }; + + LuaUtilPackageTest() + { + mLuaState.addInternalLibSearchPath( + std::filesystem::path{ OPENMW_PROJECT_SOURCE_DIR } / "components" / "lua"); + } + }; + template T get(sol::state& lua, const std::string& luaCode) { @@ -203,6 +214,10 @@ namespace EXPECT_FLOAT_EQ(get(lua, "util.clamp(0.1, 0, 1.5)"), 0.1f); EXPECT_FLOAT_EQ(get(lua, "util.clamp(-0.1, 0, 1.5)"), 0); EXPECT_FLOAT_EQ(get(lua, "util.clamp(2.1, 0, 1.5)"), 1.5f); + EXPECT_FLOAT_EQ(get(lua, "util.round(2.1)"), 2.0f); + EXPECT_FLOAT_EQ(get(lua, "util.round(-2.1)"), -2.0f); + EXPECT_FLOAT_EQ(get(lua, "util.remap(5, 0, 10, 0, 100)"), 50.0f); + EXPECT_FLOAT_EQ(get(lua, "util.remap(-5, 0, 10, 0, 100)"), -50.0f); lua.safe_script("t = util.makeReadOnly({x = 1})"); EXPECT_FLOAT_EQ(get(lua, "t.x"), 1); EXPECT_ERROR(lua.safe_script("t.y = 2"), "userdata value"); From 36604777f28b88c747c35b9dd00ea866a9978589 Mon Sep 17 00:00:00 2001 From: Kuyondo Date: Mon, 7 Jul 2025 20:08:35 +0800 Subject: [PATCH 187/330] tests 2 --- apps/components_tests/lua/testutilpackage.cpp | 36 +++++++------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/apps/components_tests/lua/testutilpackage.cpp b/apps/components_tests/lua/testutilpackage.cpp index 600d476cd0..1a40886510 100644 --- a/apps/components_tests/lua/testutilpackage.cpp +++ b/apps/components_tests/lua/testutilpackage.cpp @@ -12,11 +12,17 @@ namespace struct LuaUtilPackageTest : Test { LuaUtil::LuaState mLuaState{ nullptr, nullptr }; + sol::state& lua; LuaUtilPackageTest() + : lua(mLuaState.unsafeState()) { mLuaState.addInternalLibSearchPath( std::filesystem::path{ OPENMW_PROJECT_SOURCE_DIR } / "components" / "lua"); + + lua["loadInternalLib"] = [this](const std::string& name) { return mLuaState.loadInternalLib(name); }; + lua.open_libraries(sol::lib::base, sol::lib::math, sol::lib::string); + lua["util"] = LuaUtil::initUtilPackage(lua); } }; @@ -31,11 +37,8 @@ namespace return LuaUtil::toString(lua.safe_script("return " + luaCode)); } - TEST(LuaUtilPackageTest, Vector2) + TEST_F(LuaUtilPackageTest, Vector2) { - sol::state lua; - lua.open_libraries(sol::lib::base, sol::lib::math, sol::lib::string); - lua["util"] = LuaUtil::initUtilPackage(lua); lua.safe_script("v = util.vector2(3, 4)"); EXPECT_FLOAT_EQ(get(lua, "v.x"), 3); EXPECT_FLOAT_EQ(get(lua, "v.y"), 4); @@ -66,11 +69,8 @@ namespace EXPECT_TRUE(get(lua, "swizzle['01'] == util.vector2(0, 1) and swizzle['0y'] == util.vector2(0, 2)")); } - TEST(LuaUtilPackageTest, Vector3) + TEST_F(LuaUtilPackageTest, Vector3) { - sol::state lua; - lua.open_libraries(sol::lib::base, sol::lib::math, sol::lib::string); - lua["util"] = LuaUtil::initUtilPackage(lua); lua.safe_script("v = util.vector3(5, 12, 13)"); EXPECT_FLOAT_EQ(get(lua, "v.x"), 5); EXPECT_FLOAT_EQ(get(lua, "v.y"), 12); @@ -105,11 +105,8 @@ namespace get(lua, "swizzle['001'] == util.vector3(0, 0, 1) and swizzle['0yx'] == util.vector3(0, 2, 1)")); } - TEST(LuaUtilPackageTest, Vector4) + TEST_F(LuaUtilPackageTest, Vector4) { - sol::state lua; - lua.open_libraries(sol::lib::base, sol::lib::math, sol::lib::string); - lua["util"] = LuaUtil::initUtilPackage(lua); lua.safe_script("v = util.vector4(5, 12, 13, 15)"); EXPECT_FLOAT_EQ(get(lua, "v.x"), 5); EXPECT_FLOAT_EQ(get(lua, "v.y"), 12); @@ -147,11 +144,8 @@ namespace lua, "swizzle['0001'] == util.vector4(0, 0, 0, 1) and swizzle['0yx1'] == util.vector4(0, 2, 1, 1)")); } - TEST(LuaUtilPackageTest, Color) + TEST_F(LuaUtilPackageTest, Color) { - sol::state lua; - lua.open_libraries(sol::lib::base, sol::lib::math, sol::lib::string); - lua["util"] = LuaUtil::initUtilPackage(lua); lua.safe_script("brown = util.color.rgba(0.75, 0.25, 0, 1)"); EXPECT_EQ(get(lua, "tostring(brown)"), "(0.75, 0.25, 0, 1)"); lua.safe_script("blue = util.color.rgb(0, 1, 0, 1)"); @@ -166,11 +160,8 @@ namespace EXPECT_TRUE(get(lua, "red:asRgb() == util.vector3(1, 0, 0)")); } - TEST(LuaUtilPackageTest, Transform) + TEST_F(LuaUtilPackageTest, Transform) { - sol::state lua; - lua.open_libraries(sol::lib::base, sol::lib::math, sol::lib::string); - lua["util"] = LuaUtil::initUtilPackage(lua); lua["T"] = lua["util"]["transform"]; lua["v"] = lua["util"]["vector3"]; EXPECT_ERROR(lua.safe_script("T.identity = nil"), "attempt to index"); @@ -202,11 +193,8 @@ namespace EXPECT_LT(get(lua, "(rz_move_rx:inverse() * v(0, 1, 2) - v(1, 2, 3)):length()"), 1e-6); } - TEST(LuaUtilPackageTest, UtilityFunctions) + TEST_F(LuaUtilPackageTest, UtilityFunctions) { - sol::state lua; - lua.open_libraries(sol::lib::base, sol::lib::math, sol::lib::string); - lua["util"] = LuaUtil::initUtilPackage(lua); lua.safe_script("v = util.vector2(1, 0):rotate(math.rad(120))"); EXPECT_FLOAT_EQ(get(lua, "v.x"), -0.5f); EXPECT_FLOAT_EQ(get(lua, "v.y"), 0.86602539f); From 0c4af81a695edfba658283020ef60a509a3b2ad3 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Mon, 7 Jul 2025 16:48:24 +0200 Subject: [PATCH 188/330] Fix tests --- apps/components_tests/lua/testutilpackage.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/apps/components_tests/lua/testutilpackage.cpp b/apps/components_tests/lua/testutilpackage.cpp index 1a40886510..47041985f6 100644 --- a/apps/components_tests/lua/testutilpackage.cpp +++ b/apps/components_tests/lua/testutilpackage.cpp @@ -12,33 +12,30 @@ namespace struct LuaUtilPackageTest : Test { LuaUtil::LuaState mLuaState{ nullptr, nullptr }; - sol::state& lua; LuaUtilPackageTest() - : lua(mLuaState.unsafeState()) { mLuaState.addInternalLibSearchPath( std::filesystem::path{ OPENMW_PROJECT_SOURCE_DIR } / "components" / "lua"); - - lua["loadInternalLib"] = [this](const std::string& name) { return mLuaState.loadInternalLib(name); }; - lua.open_libraries(sol::lib::base, sol::lib::math, sol::lib::string); - lua["util"] = LuaUtil::initUtilPackage(lua); + sol::state_view sol = mLuaState.unsafeState(); + sol["util"] = LuaUtil::initUtilPackage(sol); } }; template - T get(sol::state& lua, const std::string& luaCode) + T get(sol::state_view& lua, const std::string& luaCode) { return lua.safe_script("return " + luaCode).get(); } - std::string getAsString(sol::state& lua, std::string luaCode) + std::string getAsString(sol::state_view& lua, std::string luaCode) { return LuaUtil::toString(lua.safe_script("return " + luaCode)); } TEST_F(LuaUtilPackageTest, Vector2) { + sol::state_view lua = mLuaState.unsafeState(); lua.safe_script("v = util.vector2(3, 4)"); EXPECT_FLOAT_EQ(get(lua, "v.x"), 3); EXPECT_FLOAT_EQ(get(lua, "v.y"), 4); @@ -71,6 +68,7 @@ namespace TEST_F(LuaUtilPackageTest, Vector3) { + sol::state_view lua = mLuaState.unsafeState(); lua.safe_script("v = util.vector3(5, 12, 13)"); EXPECT_FLOAT_EQ(get(lua, "v.x"), 5); EXPECT_FLOAT_EQ(get(lua, "v.y"), 12); @@ -107,6 +105,7 @@ namespace TEST_F(LuaUtilPackageTest, Vector4) { + sol::state_view lua = mLuaState.unsafeState(); lua.safe_script("v = util.vector4(5, 12, 13, 15)"); EXPECT_FLOAT_EQ(get(lua, "v.x"), 5); EXPECT_FLOAT_EQ(get(lua, "v.y"), 12); @@ -146,6 +145,7 @@ namespace TEST_F(LuaUtilPackageTest, Color) { + sol::state_view lua = mLuaState.unsafeState(); lua.safe_script("brown = util.color.rgba(0.75, 0.25, 0, 1)"); EXPECT_EQ(get(lua, "tostring(brown)"), "(0.75, 0.25, 0, 1)"); lua.safe_script("blue = util.color.rgb(0, 1, 0, 1)"); @@ -162,6 +162,7 @@ namespace TEST_F(LuaUtilPackageTest, Transform) { + sol::state_view lua = mLuaState.unsafeState(); lua["T"] = lua["util"]["transform"]; lua["v"] = lua["util"]["vector3"]; EXPECT_ERROR(lua.safe_script("T.identity = nil"), "attempt to index"); @@ -195,6 +196,7 @@ namespace TEST_F(LuaUtilPackageTest, UtilityFunctions) { + sol::state_view lua = mLuaState.unsafeState(); lua.safe_script("v = util.vector2(1, 0):rotate(math.rad(120))"); EXPECT_FLOAT_EQ(get(lua, "v.x"), -0.5f); EXPECT_FLOAT_EQ(get(lua, "v.y"), 0.86602539f); From 1331318002a12c87ef85543d1e745bf719a4c77e Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 7 Jul 2025 16:28:52 +0100 Subject: [PATCH 189/330] Add another v --- .gitlab-ci.yml | 8 ++++---- CI/macos/ccache_save.sh | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 782b042461..1ca0d4251e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -77,7 +77,7 @@ Ubuntu_GCC_preprocess: - if [[ "${BUILD_TESTS_ONLY}" && ! "${BUILD_WITH_CODE_COVERAGE}" ]]; then ./openmw_detournavigator_navmeshtilescache_benchmark; fi - if [[ "${BUILD_TESTS_ONLY}" && ! "${BUILD_WITH_CODE_COVERAGE}" ]]; then ./openmw_esm_refid_benchmark; fi - if [[ "${BUILD_TESTS_ONLY}" && ! "${BUILD_WITH_CODE_COVERAGE}" ]]; then ./openmw_settings_access_benchmark; fi - - ccache -sv + - ccache -svv - df -h - if [[ "${BUILD_WITH_CODE_COVERAGE}" ]]; then gcovr --xml-pretty --exclude-unreachable-branches --print-summary --root "${CI_PROJECT_DIR}" -j $(nproc) -o ../coverage.xml; fi - ls | grep -v -e '^extern$' -e '^install$' -e '^components-tests.xml$' -e '^openmw-tests.xml$' -e '^openmw-cs-tests.xml$' | xargs -I '{}' rm -rf './{}' @@ -124,7 +124,7 @@ Coverity: - cov-analysis-linux64-*/bin/cov-configure --template --comptype prefix --compiler ccache # Remove the specific targets and build everything once we can do it under 3h - cov-analysis-linux64-*/bin/cov-build --dir cov-int cmake --build build -- -j $(nproc) - - ccache -sv + - ccache -svv after_script: - tar cfz cov-int.tar.gz cov-int - curl https://scan.coverity.com/builds?project=$COVERITY_SCAN_PROJECT_NAME @@ -396,7 +396,7 @@ Ubuntu_Clang: - cd build - find . -name *.o -exec touch {} \; - cmake --build . -- -j $(nproc) ${BUILD_TARGETS} - - ccache -sv + - ccache -svv artifacts: paths: - build/ @@ -940,7 +940,7 @@ Windows_MSBuild_CacheInit: - cd build - cmake --build . -- -j $(nproc) # - cmake --install . # no one uses builds anyway, disable until 'no space left' is resolved - - ccache -sv + - ccache -svv - df -h - ls | grep -v -e '^extern$' -e '^install$' | xargs -I '{}' rm -rf './{}' - cd .. diff --git a/CI/macos/ccache_save.sh b/CI/macos/ccache_save.sh index ca746b7085..d7cc48c25e 100755 --- a/CI/macos/ccache_save.sh +++ b/CI/macos/ccache_save.sh @@ -1,7 +1,7 @@ #!/bin/sh -ex if [[ "${MACOS_AMD64}" ]]; then - arch -x86_64 ccache -sv + arch -x86_64 ccache -svv else - ccache -sv + ccache -svv fi From ede768532c04d81f4e6e74019820b32cb6bc5657 Mon Sep 17 00:00:00 2001 From: Kuyondo Date: Tue, 8 Jul 2025 02:58:44 +0800 Subject: [PATCH 190/330] cleanup 2 --- apps/openmw/mwgui/inventorywindow.cpp | 8 ++++---- apps/openmw/mwgui/quickkeysmenu.cpp | 19 +------------------ apps/openmw/mwworld/inventorystore.cpp | 10 ++++++++++ apps/openmw/mwworld/inventorystore.hpp | 1 + 4 files changed, 16 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 1f6b6fdeb5..acc1dd6068 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -550,7 +550,7 @@ namespace MWGui } std::unique_ptr action = ptr.getClass().use(ptr, force); - action->execute(player); + action->execute(player, !canEquip); // Handles partial equipping (final part) if (mEquippedStackableCount.has_value()) @@ -581,11 +581,11 @@ namespace MWGui { MWWorld::Ptr ptr = mDragAndDrop->mItem.mBase; - auto canEquip = ptr.getClass().canBeEquipped(ptr, mPtr); - if (canEquip.first == 0) // cannot equip + auto [canEquipRes, canEquipMsg] = ptr.getClass().canBeEquipped(ptr, mPtr); + if (canEquipRes == 0) // cannot equip { mDragAndDrop->drop(mTradeModel, mItemView); // also plays down sound - MWBase::Environment::get().getWindowManager()->messageBox(canEquip.second); + MWBase::Environment::get().getWindowManager()->messageBox(canEquipMsg); return; } diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 5f3cd17732..191a2d8b3a 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -388,26 +388,9 @@ namespace MWGui return; } - // check the quickkey item is not broken - if (item.getClass().hasItemHealth(item) && item.getClass().getItemHealth(item) <= 0) - { - const std::vector& equipmentSlots = item.getClass().getEquipmentSlots(item).first; - if (!equipmentSlots.empty()) - { - const auto& itSlot = store.getSlot(equipmentSlots.front()); - // Morrowind.exe behavior: - // Only display the "item is broken" message if: - // - There is no item in the target equipment slot, or - // - The quickkey item is broken and the currently equipped item has a different ID - if (itSlot == store.end() || (item.getCellRef().getRefId() != itSlot->getCellRef().getRefId())) - MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage1}"); - } - return; - } - if (key->type == ESM::QuickKeys::Type::Item) { - if (!store.isEquipped(item)) + if (!store.isEquipped(item.getCellRef().getRefId())) MWBase::Environment::get().getWindowManager()->useItem(item); MWWorld::ConstContainerStoreIterator rightHand = store.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index f48f4e6e31..9143777531 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -754,6 +754,16 @@ bool MWWorld::InventoryStore::isEquipped(const MWWorld::ConstPtr& item) return false; } +bool MWWorld::InventoryStore::isEquipped(const ESM::RefId& id) +{ + for (int i = 0; i < MWWorld::InventoryStore::Slots; ++i) + { + if (getSlot(i) != end() && getSlot(i)->getCellRef().getRefId() == id) + return true; + } + return false; +} + bool MWWorld::InventoryStore::isFirstEquip() { bool first = mFirstAutoEquip; diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 0af6ee2b28..d0839dd1ed 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -118,6 +118,7 @@ namespace MWWorld ///< \warning \a iterator can not be an end()-iterator, use unequip function instead bool isEquipped(const MWWorld::ConstPtr& item); + bool isEquipped(const ESM::RefId& id); ///< Utility function, returns true if the given item is equipped in any slot void setSelectedEnchantItem(const ContainerStoreIterator& iterator); From f87d6818b7ab84c9ce85d6fffd732cfd9fd44f2f Mon Sep 17 00:00:00 2001 From: Kuyondo Date: Tue, 8 Jul 2025 05:02:53 +0800 Subject: [PATCH 191/330] pressing enter for newline --- components/lua/util.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lua/util.lua b/components/lua/util.lua index 10b2a46418..f37a2e52cc 100644 --- a/components/lua/util.lua +++ b/components/lua/util.lua @@ -18,4 +18,4 @@ function M.normalizeAngle(angle) return (fullTurns - math.floor(fullTurns) - 0.5) * (2 * math.pi) end -return M \ No newline at end of file +return M From 10dba7cda7fa24721421f451e7da632cdfdcf323 Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Wed, 17 Jan 2024 22:59:39 +0100 Subject: [PATCH 192/330] Initial support of ESM4 sounds; play opening sound of ESM4 doors. --- .../misc/testresourcehelpers.cpp | 9 +++++ apps/openmw/mwlua/types/door.cpp | 4 ++ apps/openmw/mwsound/soundbuffer.cpp | 32 ++++++++++++++- apps/openmw/mwsound/soundbuffer.hpp | 12 +++++- apps/openmw/mwworld/esmstore.hpp | 6 ++- apps/openmw/mwworld/store.cpp | 2 + components/esm/records.hpp | 2 + components/misc/resourcehelpers.cpp | 40 +++++++++++-------- components/misc/resourcehelpers.hpp | 8 ++-- files/data/scripts/omw/activationhandlers.lua | 4 +- files/lua_api/openmw/types.lua | 2 + 11 files changed, 94 insertions(+), 27 deletions(-) diff --git a/apps/components_tests/misc/testresourcehelpers.cpp b/apps/components_tests/misc/testresourcehelpers.cpp index 05079ae875..b21ecb2e14 100644 --- a/apps/components_tests/misc/testresourcehelpers.cpp +++ b/apps/components_tests/misc/testresourcehelpers.cpp @@ -26,6 +26,15 @@ namespace std::unique_ptr mVFS = TestingOpenMW::createTestVFS({}); constexpr VFS::Path::NormalizedView path("sound/foo.wav"); EXPECT_EQ(correctSoundPath(path, *mVFS), "sound/foo.mp3"); + + auto correctESM4SoundPath = [](auto path, auto* vfs) { + return Misc::ResourceHelpers::correctResourcePath({ { "sound" } }, path, vfs, ".mp3"); + }; + + EXPECT_EQ(correctESM4SoundPath("foo.WAV", mVFS.get()), "sound\\foo.mp3"); + EXPECT_EQ(correctESM4SoundPath("SOUND/foo.WAV", mVFS.get()), "sound\\foo.mp3"); + EXPECT_EQ(correctESM4SoundPath("DATA\\SOUND\\foo.WAV", mVFS.get()), "sound\\foo.mp3"); + EXPECT_EQ(correctESM4SoundPath("\\Data/Sound\\foo.WAV", mVFS.get()), "sound\\foo.mp3"); } namespace diff --git a/apps/openmw/mwlua/types/door.cpp b/apps/openmw/mwlua/types/door.cpp index 58a53a7124..5db6f9b875 100644 --- a/apps/openmw/mwlua/types/door.cpp +++ b/apps/openmw/mwlua/types/door.cpp @@ -149,5 +149,9 @@ namespace MWLua addModelProperty(record); record["isAutomatic"] = sol::readonly_property( [](const ESM4::Door& rec) -> bool { return rec.mDoorFlags & ESM4::Door::Flag_AutomaticDoor; }); + record["openSound"] = sol::readonly_property( + [](const ESM4::Door& rec) -> std::string { return ESM::RefId(rec.mOpenSound).serializeText(); }); + record["closeSound"] = sol::readonly_property( + [](const ESM4::Door& rec) -> std::string { return ESM::RefId(rec.mCloseSound).serializeText(); }); } } diff --git a/apps/openmw/mwsound/soundbuffer.cpp b/apps/openmw/mwsound/soundbuffer.cpp index 722d89f0eb..0c10ba5552 100644 --- a/apps/openmw/mwsound/soundbuffer.cpp +++ b/apps/openmw/mwsound/soundbuffer.cpp @@ -5,7 +5,10 @@ #include #include +#include +#include #include +#include #include #include @@ -99,7 +102,12 @@ namespace MWSound { if (mBufferNameMap.empty()) { - for (const ESM::Sound& sound : MWBase::Environment::get().getESMStore()->get()) + const MWWorld::ESMStore* esmstore = MWBase::Environment::get().getESMStore(); + for (const ESM::Sound& sound : esmstore->get()) + insertSound(sound.mId, sound); + for (const ESM4::Sound& sound : esmstore->get()) + insertSound(sound.mId, sound); + for (const ESM4::SoundReference& sound : esmstore->get()) insertSound(sound.mId, sound); } @@ -190,6 +198,28 @@ namespace MWSound return &sfx; } + SoundBuffer* SoundBufferPool::insertSound(const ESM::RefId& soundId, const ESM4::Sound& sound) + { + std::string path = Misc::ResourceHelpers::correctResourcePath( + { { "sound" } }, sound.mSoundFile, MWBase::Environment::get().getResourceSystem()->getVFS(), ".mp3"); + float volume = 1, min = 1, max = 255; // TODO: needs research + SoundBuffer& sfx = mSoundBuffers.emplace_back(VFS::Path::Normalized(std::move(path)), volume, min, max); + mBufferNameMap.emplace(soundId, &sfx); + return &sfx; + } + + SoundBuffer* SoundBufferPool::insertSound(const ESM::RefId& soundId, const ESM4::SoundReference& sound) + { + std::string path = Misc::ResourceHelpers::correctResourcePath( + { { "sound" } }, sound.mSoundFile, MWBase::Environment::get().getResourceSystem()->getVFS(), ".mp3"); + float volume = 1, min = 1, max = 255; // TODO: needs research + // TODO: sound.mSoundId can link to another SoundReference, probably we will need to add additional lookups to + // ESMStore. + SoundBuffer& sfx = mSoundBuffers.emplace_back(VFS::Path::Normalized(std::move(path)), volume, min, max); + mBufferNameMap.emplace(soundId, &sfx); + return &sfx; + } + void SoundBufferPool::unloadUnused() { while (!mUnusedBuffers.empty() && mBufferCacheSize > mBufferCacheMin) diff --git a/apps/openmw/mwsound/soundbuffer.hpp b/apps/openmw/mwsound/soundbuffer.hpp index f7e7639b2d..493577a9c3 100644 --- a/apps/openmw/mwsound/soundbuffer.hpp +++ b/apps/openmw/mwsound/soundbuffer.hpp @@ -15,6 +15,12 @@ namespace ESM struct Sound; } +namespace ESM4 +{ + struct Sound; + struct SoundReference; +} + namespace VFS { class Manager; @@ -112,8 +118,10 @@ namespace MWSound // NOTE: unused buffers are stored in front-newest order. std::deque mUnusedBuffers; - inline SoundBuffer* insertSound(const ESM::RefId& soundId, const ESM::Sound& sound); - inline SoundBuffer* insertSound(std::string_view fileName); + SoundBuffer* insertSound(const ESM::RefId& soundId, const ESM::Sound& sound); + SoundBuffer* insertSound(const ESM::RefId& soundId, const ESM4::Sound& sound); + SoundBuffer* insertSound(const ESM::RefId& soundId, const ESM4::SoundReference& sound); + SoundBuffer* insertSound(std::string_view fileName); inline void unloadUnused(); }; diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index 6c71ae0052..0c37f243e8 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -105,6 +105,8 @@ namespace ESM4 struct Potion; struct Race; struct Reference; + struct Sound; + struct SoundReference; struct Static; struct StaticCollection; struct Terminal; @@ -146,8 +148,8 @@ namespace MWWorld Store, Store, Store, Store, Store, Store, Store, Store, Store, Store, Store, Store, Store, - Store, Store, Store, Store, - Store, Store>; + Store, Store, Store, Store, + Store, Store, Store, Store>; private: template diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index b0684b1ab4..80bcdb056a 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1349,6 +1349,8 @@ template class MWWorld::TypedDynamicStore; template class MWWorld::TypedDynamicStore; template class MWWorld::TypedDynamicStore; template class MWWorld::TypedDynamicStore; +template class MWWorld::TypedDynamicStore; +template class MWWorld::TypedDynamicStore; template class MWWorld::TypedDynamicStore; template class MWWorld::TypedDynamicStore; template class MWWorld::TypedDynamicStore; diff --git a/components/esm/records.hpp b/components/esm/records.hpp index 0b60b44cf0..0b76fab0ff 100644 --- a/components/esm/records.hpp +++ b/components/esm/records.hpp @@ -74,6 +74,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/components/misc/resourcehelpers.cpp b/components/misc/resourcehelpers.cpp index 5279e2ad23..c3164b0dfe 100644 --- a/components/misc/resourcehelpers.cpp +++ b/components/misc/resourcehelpers.cpp @@ -33,14 +33,10 @@ bool Misc::ResourceHelpers::changeExtensionToDds(std::string& path) return changeExtension(path, ".dds"); } -std::string Misc::ResourceHelpers::correctResourcePath( - std::span topLevelDirectories, std::string_view resPath, const VFS::Manager* vfs) +// If `ext` is not empty we first search file with extension `ext`, then if not found fallback to original extension. +std::string Misc::ResourceHelpers::correctResourcePath(std::span topLevelDirectories, + std::string_view resPath, const VFS::Manager* vfs, std::string_view ext) { - /* Bethesda at some point converted all their BSA - * textures from tga to dds for increased load speed, but all - * texture file name references were kept as .tga. - */ - std::string correctedPath = Misc::StringUtils::lowerCase(resPath); // Flatten slashes @@ -80,14 +76,14 @@ std::string Misc::ResourceHelpers::correctResourcePath( std::string origExt = correctedPath; - // since we know all (GOTY edition or less) textures end - // in .dds, we change the extension - bool changedToDds = changeExtensionToDds(correctedPath); + // replace extension if `ext` is specified (used for .tga -> .dds, .wav -> .mp3) + bool isExtChanged = !ext.empty() && changeExtension(correctedPath, ext); + if (vfs->exists(correctedPath)) return correctedPath; - // if it turns out that the above wasn't true in all cases (not for vanilla, but maybe mods) - // verify, and revert if false (this call succeeds quickly, but fails slowly) - if (changedToDds && vfs->exists(origExt)) + + // fall back to original extension + if (isExtChanged && vfs->exists(origExt)) return origExt; // fall back to a resource in the top level directory if it exists @@ -98,7 +94,7 @@ std::string Misc::ResourceHelpers::correctResourcePath( if (vfs->exists(fallback)) return fallback; - if (changedToDds) + if (isExtChanged) { fallback = topLevelDirectories.front(); fallback += '\\'; @@ -110,19 +106,23 @@ std::string Misc::ResourceHelpers::correctResourcePath( return correctedPath; } +// Note: Bethesda at some point converted all their BSA textures from tga to dds for increased load speed, +// but all texture file name references were kept as .tga. So we pass ext=".dds" to all helpers +// looking for textures. + std::string Misc::ResourceHelpers::correctTexturePath(std::string_view resPath, const VFS::Manager* vfs) { - return correctResourcePath({ { "textures", "bookart" } }, resPath, vfs); + return correctResourcePath({ { "textures", "bookart" } }, resPath, vfs, ".dds"); } std::string Misc::ResourceHelpers::correctIconPath(std::string_view resPath, const VFS::Manager* vfs) { - return correctResourcePath({ { "icons" } }, resPath, vfs); + return correctResourcePath({ { "icons" } }, resPath, vfs, ".dds"); } std::string Misc::ResourceHelpers::correctBookartPath(std::string_view resPath, const VFS::Manager* vfs) { - return correctResourcePath({ { "bookart", "textures" } }, resPath, vfs); + return correctResourcePath({ { "bookart", "textures" } }, resPath, vfs, ".dds"); } std::string Misc::ResourceHelpers::correctBookartPath( @@ -199,6 +199,12 @@ std::string_view Misc::ResourceHelpers::meshPathForESM3(std::string_view resPath VFS::Path::Normalized Misc::ResourceHelpers::correctSoundPath( VFS::Path::NormalizedView resPath, const VFS::Manager& vfs) { + // Note: likely should be replaced with + // return correctResourcePath({ { "sound" } }, resPath, vfs, ".mp3"); + // but there is a slight difference in behaviour: + // - `correctResourcePath(..., ".mp3")` first checks `.mp3`, then tries the original extension + // - the implementation below first tries the original extension, then falls back to `.mp3`. + // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. if (!vfs.exists(resPath)) { diff --git a/components/misc/resourcehelpers.hpp b/components/misc/resourcehelpers.hpp index 9aaa89a861..fb355d6b94 100644 --- a/components/misc/resourcehelpers.hpp +++ b/components/misc/resourcehelpers.hpp @@ -1,12 +1,12 @@ #ifndef MISC_RESOURCEHELPERS_H #define MISC_RESOURCEHELPERS_H -#include - #include #include #include +#include + namespace VFS { class Manager; @@ -25,8 +25,8 @@ namespace Misc namespace ResourceHelpers { bool changeExtensionToDds(std::string& path); - std::string correctResourcePath( - std::span topLevelDirectories, std::string_view resPath, const VFS::Manager* vfs); + std::string correctResourcePath(std::span topLevelDirectories, std::string_view resPath, + const VFS::Manager* vfs, std::string_view ext = {}); std::string correctTexturePath(std::string_view resPath, const VFS::Manager* vfs); std::string correctIconPath(std::string_view resPath, const VFS::Manager* vfs); std::string correctBookartPath(std::string_view resPath, const VFS::Manager* vfs); diff --git a/files/data/scripts/omw/activationhandlers.lua b/files/data/scripts/omw/activationhandlers.lua index 419ffe6809..3850b207eb 100644 --- a/files/data/scripts/omw/activationhandlers.lua +++ b/files/data/scripts/omw/activationhandlers.lua @@ -1,4 +1,5 @@ local async = require('openmw.async') +local core = require('openmw.core') local types = require('openmw.types') local world = require('openmw.world') @@ -6,8 +7,9 @@ local EnableObject = async:registerTimerCallback('EnableObject', function(obj) o local function ESM4DoorActivation(door, actor) -- TODO: Implement lockpicking minigame - -- TODO: Play door opening animation and sound + -- TODO: Play door opening animation local Door4 = types.ESM4Door + core.sound.playSound3d(Door4.record(door).openSound, actor) if Door4.isTeleport(door) then actor:teleport(Door4.destCell(door), Door4.destPosition(door), Door4.destRotation(door)) else diff --git a/files/lua_api/openmw/types.lua b/files/lua_api/openmw/types.lua index 6cef253268..2481c0ae75 100644 --- a/files/lua_api/openmw/types.lua +++ b/files/lua_api/openmw/types.lua @@ -2450,5 +2450,7 @@ -- @field #string id Record id -- @field #string name Human-readable name -- @field #string model VFS path to the model +-- @field #string openSound FormId of the door opening sound +-- @field #string closeSound FormId of the door closing sound return nil From 08923572308277f184edd91d7aef0fc7d91449a2 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Tue, 8 Jul 2025 20:32:20 +0300 Subject: [PATCH 193/330] Only autoequip the shield in updateEquippedLight (#8404) --- apps/openmw/mwmechanics/actors.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 1e62cc4a21..b418515bf7 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1066,9 +1066,12 @@ namespace MWMechanics { if (heldIter != inventoryStore.end() && heldIter->getType() == ESM::Light::sRecordId) { - // At day, unequip lights and auto equip shields or other suitable items - // (Note: autoEquip will ignore lights) - inventoryStore.autoEquip(); + // At day, unequip lights and auto equip shields + auto shield = inventoryStore.getPreferredShield(); + if (shield != inventoryStore.end()) + inventoryStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, shield); + else + inventoryStore.unequipSlot(MWWorld::InventoryStore::Slot_CarriedLeft); } } } From 8b44b95830a5203f2b1ab0f8a441baabe6df86d3 Mon Sep 17 00:00:00 2001 From: Cody Glassman Date: Tue, 8 Jul 2025 11:26:16 -0700 Subject: [PATCH 194/330] docs - fix table padding and luadoc scroll padding --- docs/source/_static/luadoc.css | 4 ++++ docs/source/_static/theme-override.css | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/docs/source/_static/luadoc.css b/docs/source/_static/luadoc.css index b2efec85b4..96b7de9bb3 100644 --- a/docs/source/_static/luadoc.css +++ b/docs/source/_static/luadoc.css @@ -20,6 +20,10 @@ white-space: normal; } +html:has(#luadoc) { + scroll-padding-top: 4.0rem; +} + #content #luadoc code a:not(.toc-backref) { font-weight: 600; } diff --git a/docs/source/_static/theme-override.css b/docs/source/_static/theme-override.css index cf9ae168bc..756d920368 100644 --- a/docs/source/_static/theme-override.css +++ b/docs/source/_static/theme-override.css @@ -143,6 +143,10 @@ tbody tr:hover { margin-bottom: 1.5rem; } +#content table p { + margin-bottom: 0; +} + h5 { font-size: 1.15rem; font-weight: 600; From a68107712c0206a7c80c01e54b0bd4b1d5726b86 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 8 Jul 2025 22:33:35 +0400 Subject: [PATCH 195/330] Do not allow to select a screen resolution in the Windowed Fullscreen mode in the launcher --- apps/launcher/graphicspage.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 735bcf1df1..1e3caf7293 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -240,13 +240,26 @@ void Launcher::GraphicsPage::slotFullScreenChanged(int mode) void Launcher::GraphicsPage::handleWindowModeChange(Settings::WindowMode mode) { - if (mode == Settings::WindowMode::Fullscreen || mode == Settings::WindowMode::WindowedFullscreen) + if (mode == Settings::WindowMode::Fullscreen) { standardRadioButton->toggle(); customRadioButton->setEnabled(false); customWidthSpinBox->setEnabled(false); customHeightSpinBox->setEnabled(false); windowBorderCheckBox->setEnabled(false); + resolutionComboBox->setEnabled(true); + } + else if (mode == Settings::WindowMode::WindowedFullscreen) + { + standardRadioButton->toggle(); + customRadioButton->setEnabled(false); + customWidthSpinBox->setEnabled(false); + customHeightSpinBox->setEnabled(false); + windowBorderCheckBox->setEnabled(false); + resolutionComboBox->setEnabled(false); + + // Assume that a first item is a native screen resolution + resolutionComboBox->setCurrentIndex(0); } else { @@ -254,6 +267,7 @@ void Launcher::GraphicsPage::handleWindowModeChange(Settings::WindowMode mode) customWidthSpinBox->setEnabled(true); customHeightSpinBox->setEnabled(true); windowBorderCheckBox->setEnabled(true); + resolutionComboBox->setEnabled(true); } } From 3ec04f4ba754790040b634348f41ce3966170581 Mon Sep 17 00:00:00 2001 From: Cody Glassman Date: Tue, 8 Jul 2025 14:15:37 -0700 Subject: [PATCH 196/330] docs - improve link contrast in dark mode --- docs/source/_static/theme-override.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/_static/theme-override.css b/docs/source/_static/theme-override.css index 756d920368..25f7bd6f10 100644 --- a/docs/source/_static/theme-override.css +++ b/docs/source/_static/theme-override.css @@ -36,8 +36,8 @@ --muted: 223 27% 14%; --card: 220 14% 9%; - --link: #ffffff; - --link-hover: #ffffff; + --link: #95b1dd; + --link-hover: #dde2eb; } .contents ul li a.reference:hover, .sd-dropdown .toctree-wrapper ul li a.reference, details.sd-dropdown .sd-summary-title { From 759739eccaae3dbe716673c06e1f0aaf2d1a536f Mon Sep 17 00:00:00 2001 From: Cody Glassman Date: Tue, 8 Jul 2025 15:53:18 -0700 Subject: [PATCH 197/330] generate mipmaps after we draw, not before --- apps/openmw/mwrender/pingpongcanvas.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/pingpongcanvas.cpp b/apps/openmw/mwrender/pingpongcanvas.cpp index 54d8145fa9..303f2a9bae 100644 --- a/apps/openmw/mwrender/pingpongcanvas.cpp +++ b/apps/openmw/mwrender/pingpongcanvas.cpp @@ -280,15 +280,6 @@ namespace MWRender { pass.mRenderTarget->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER); - if (pass.mRenderTexture->getNumMipmapLevels() > 0) - { - state.setActiveTextureUnit(0); - state.applyTextureAttribute(0, - pass.mRenderTarget->getAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0) - .getTexture()); - ext->glGenerateMipmap(GL_TEXTURE_2D); - } - lastApplied = pass.mRenderTarget->getHandle(state.getContextID()); } else if (pass.mResolve && index == filtered.back()) @@ -325,6 +316,15 @@ namespace MWRender drawGeometry(renderInfo); + if (pass.mRenderTexture && pass.mRenderTexture->getNumMipmapLevels() > 0) + { + state.setActiveTextureUnit(0); + state.applyTextureAttribute(0, + pass.mRenderTarget->getAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0) + .getTexture()); + ext->glGenerateMipmap(GL_TEXTURE_2D); + } + state.popStateSet(); state.apply(); } From f3420bd1bd00135e222b18ac69c1310686a91136 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Wed, 9 Jul 2025 10:55:17 +0300 Subject: [PATCH 198/330] Move Quitting peacefully message to a more appropriate place --- apps/openmw/engine.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 29cfb41071..5807ef222b 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -433,6 +433,8 @@ OMW::Engine::~Engine() } SDL_Quit(); + + Log(Debug::Info) << "Quitting peacefully."; } // Set data dir @@ -1069,8 +1071,6 @@ void OMW::Engine::go() Settings::Manager::saveUser(mCfgMgr.getUserConfigPath() / "settings.cfg"); Settings::ShaderManager::get().save(); mLuaManager->savePermanentStorage(mCfgMgr.getUserConfigPath()); - - Log(Debug::Info) << "Quitting peacefully."; } void OMW::Engine::setCompileAll(bool all) From 064b8d3f9bc51d4623bde8f3ade78274918336a7 Mon Sep 17 00:00:00 2001 From: Cody Glassman Date: Wed, 9 Jul 2025 11:49:38 -0700 Subject: [PATCH 199/330] use more explicit null check --- apps/openmw/mwrender/pingpongcanvas.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/pingpongcanvas.cpp b/apps/openmw/mwrender/pingpongcanvas.cpp index 303f2a9bae..5a37e09d84 100644 --- a/apps/openmw/mwrender/pingpongcanvas.cpp +++ b/apps/openmw/mwrender/pingpongcanvas.cpp @@ -316,7 +316,7 @@ namespace MWRender drawGeometry(renderInfo); - if (pass.mRenderTexture && pass.mRenderTexture->getNumMipmapLevels() > 0) + if (pass.mRenderTarget && pass.mRenderTexture->getNumMipmapLevels() > 0) { state.setActiveTextureUnit(0); state.applyTextureAttribute(0, From dca83c2500276aed19d6a47e4eb26d4b65299782 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 9 Jul 2025 18:30:08 +0400 Subject: [PATCH 200/330] Add resolution hints to launcher --- apps/launcher/graphicspage.cpp | 30 ++++++++++++++++++++++++------ files/data/l10n/OMWEngine/ru.yaml | 2 +- files/lang/launcher_de.ts | 12 ++++++++++++ files/lang/launcher_en.ts | 12 ++++++++++++ files/lang/launcher_fr.ts | 12 ++++++++++++ files/lang/launcher_ru.ts | 12 ++++++++++++ files/lang/launcher_sv.ts | 12 ++++++++++++ 7 files changed, 85 insertions(+), 7 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 1e3caf7293..38b0446efc 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -240,23 +240,35 @@ void Launcher::GraphicsPage::slotFullScreenChanged(int mode) void Launcher::GraphicsPage::handleWindowModeChange(Settings::WindowMode mode) { - if (mode == Settings::WindowMode::Fullscreen) + if (mode == Settings::WindowMode::Fullscreen || mode == Settings::WindowMode::WindowedFullscreen) { + QString customSizeMessage = tr("Custom window size is available only in Windowed mode."); + QString windowBorderMessage = tr("Window border is available only in Windowed mode."); + standardRadioButton->toggle(); customRadioButton->setEnabled(false); customWidthSpinBox->setEnabled(false); customHeightSpinBox->setEnabled(false); windowBorderCheckBox->setEnabled(false); + windowBorderCheckBox->setToolTip(windowBorderMessage); + customWidthSpinBox->setToolTip(customSizeMessage); + customHeightSpinBox->setToolTip(customSizeMessage); + customRadioButton->setToolTip(customSizeMessage); + } + + if (mode == Settings::WindowMode::Fullscreen) + { resolutionComboBox->setEnabled(true); + resolutionComboBox->setToolTip(""); + standardRadioButton->setToolTip(""); } else if (mode == Settings::WindowMode::WindowedFullscreen) { - standardRadioButton->toggle(); - customRadioButton->setEnabled(false); - customWidthSpinBox->setEnabled(false); - customHeightSpinBox->setEnabled(false); - windowBorderCheckBox->setEnabled(false); + QString fullScreenMessage = tr("Windowed Fullscreen mode always uses the native display resolution."); + resolutionComboBox->setEnabled(false); + resolutionComboBox->setToolTip(fullScreenMessage); + standardRadioButton->setToolTip(fullScreenMessage); // Assume that a first item is a native screen resolution resolutionComboBox->setCurrentIndex(0); @@ -268,6 +280,12 @@ void Launcher::GraphicsPage::handleWindowModeChange(Settings::WindowMode mode) customHeightSpinBox->setEnabled(true); windowBorderCheckBox->setEnabled(true); resolutionComboBox->setEnabled(true); + resolutionComboBox->setToolTip(""); + standardRadioButton->setToolTip(""); + windowBorderCheckBox->setToolTip(""); + customWidthSpinBox->setToolTip(""); + customHeightSpinBox->setToolTip(""); + customRadioButton->setToolTip(""); } } diff --git a/files/data/l10n/OMWEngine/ru.yaml b/files/data/l10n/OMWEngine/ru.yaml index c50fbac38e..753d1fa219 100644 --- a/files/data/l10n/OMWEngine/ru.yaml +++ b/files/data/l10n/OMWEngine/ru.yaml @@ -208,7 +208,7 @@ WaterShaderTextureQuality: "Качество текстуры воды" WindowBorder: "Рамка окна" WindowMode: "Режим окна" WindowModeFullscreen: "Полный экран" -WindowModeHint: "Подсказка: режим Оконный без полей\nвсегда использует родное разрешение экрана." +WindowModeHint: "Подсказка: режим \"Оконный без полей\"\nвсегда использует родное разрешение экрана." WindowModeWindowed: "Оконный" WindowModeWindowedFullscreen: "Оконный без полей" WobblyShores: "Колеблющиеся берега" diff --git a/files/lang/launcher_de.ts b/files/lang/launcher_de.ts index 86773e5a54..94437fb822 100644 --- a/files/lang/launcher_de.ts +++ b/files/lang/launcher_de.ts @@ -425,6 +425,18 @@ to default Morrowind fonts. Check this box if you still prefer original fonts ov <br><b>SDL_GetDisplayMode failed:</b><br><br> + + Custom window size is available only in Windowed mode. + + + + Window border is available only in Windowed mode. + + + + Windowed Fullscreen mode always uses the native display resolution. + + Launcher::ImportPage diff --git a/files/lang/launcher_en.ts b/files/lang/launcher_en.ts index a0319318e8..25717d1454 100644 --- a/files/lang/launcher_en.ts +++ b/files/lang/launcher_en.ts @@ -425,6 +425,18 @@ to default Morrowind fonts. Check this box if you still prefer original fonts ov <br><b>SDL_GetDisplayMode failed:</b><br><br> + + Custom window size is available only in Windowed mode. + + + + Window border is available only in Windowed mode. + + + + Windowed Fullscreen mode always uses the native display resolution. + + Launcher::ImportPage diff --git a/files/lang/launcher_fr.ts b/files/lang/launcher_fr.ts index 569a460cd0..5f8f020981 100644 --- a/files/lang/launcher_fr.ts +++ b/files/lang/launcher_fr.ts @@ -425,6 +425,18 @@ to default Morrowind fonts. Check this box if you still prefer original fonts ov <br><b>SDL_GetDisplayMode failed:</b><br><br> <br><b>SDL_GetDisplayMode failed:</b><br><br> + + Custom window size is available only in Windowed mode. + La taille personalisée de fenêtre n'est disponible qu'en mode fenêtré. + + + Window border is available only in Windowed mode. + Les bordures de fenêtres ne sont disponibles qu'en mode fenêtré. + + + Windowed Fullscreen mode always uses the native display resolution. + Le mode "Fenêtré plein écran" utilise toujours la résolution native de l'écran. + Launcher::ImportPage diff --git a/files/lang/launcher_ru.ts b/files/lang/launcher_ru.ts index 879f24dc76..bf0ea467b2 100644 --- a/files/lang/launcher_ru.ts +++ b/files/lang/launcher_ru.ts @@ -427,6 +427,18 @@ to default Morrowind fonts. Check this box if you still prefer original fonts ov <br><b>SDL_GetDisplayMode failed:</b><br><br> <br><b>Вызов SDL_GetDisplayMode завершился с ошибкой:</b><br><br> + + Custom window size is available only in Windowed mode. + Особый размер окна доступен только в оконном режиме. + + + Window border is available only in Windowed mode. + Рамка окна доступна только в оконном режиме. + + + Windowed Fullscreen mode always uses the native display resolution. + Режим "Оконный без полей" всегда использует родное разрешение экрана. + Launcher::ImportPage diff --git a/files/lang/launcher_sv.ts b/files/lang/launcher_sv.ts index f2cca2346c..97de9603d7 100644 --- a/files/lang/launcher_sv.ts +++ b/files/lang/launcher_sv.ts @@ -428,6 +428,18 @@ de ordinarie fonterna i Morrowind. Bocka denna ruta om du ändå föredrar ordin <br><b>SDL_GetDisplayMode failed:</b><br><br> <br><b>SDL_GetDisplayMode misslyckades:</b><br><br> + + Custom window size is available only in Windowed mode. + Anpassad fönsterstorlek finns endast tillgänglig i fönsterläge. + + + Window border is available only in Windowed mode. + Fönsterram finns endast tillgänglig i fönsterläge + + + Windowed Fullscreen mode always uses the native display resolution. + Helskärm i fönsterläge använder alltid skärmens nativa upplösning. + Launcher::ImportPage From 7bc507eb587827b1fa75a6d842b08ed4df06b676 Mon Sep 17 00:00:00 2001 From: Dave Corley Date: Fri, 31 Jan 2025 18:00:05 -0700 Subject: [PATCH 201/330] FIX: Skip only the current subrecord when reading quest status --- components/esm3/loadinfo.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/esm3/loadinfo.cpp b/components/esm3/loadinfo.cpp index 8b1147ed45..89ba6d8aff 100644 --- a/components/esm3/loadinfo.cpp +++ b/components/esm3/loadinfo.cpp @@ -76,15 +76,15 @@ namespace ESM break; case fourCC("QSTN"): mQuestStatus = QS_Name; - esm.skipRecord(); + esm.skipHSub(); break; case fourCC("QSTF"): mQuestStatus = QS_Finished; - esm.skipRecord(); + esm.skipHSub(); break; case fourCC("QSTR"): mQuestStatus = QS_Restart; - esm.skipRecord(); + esm.skipHSub(); break; case SREC_DELE: esm.skipHSub(); From a00e5ec828cefd3e30a19c09d02180bd54171a6f Mon Sep 17 00:00:00 2001 From: Florian Heberer Date: Sun, 9 Jun 2024 01:45:08 +0200 Subject: [PATCH 202/330] Add documentation for update function of Generic Object Cache --- components/resource/objectcache.hpp | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/components/resource/objectcache.hpp b/components/resource/objectcache.hpp index e619b7102c..8fdc199e93 100644 --- a/components/resource/objectcache.hpp +++ b/components/resource/objectcache.hpp @@ -53,28 +53,48 @@ namespace Resource class GenericObjectCache : public osg::Referenced { public: - // Update last usage timestamp using referenceTime for each cache time if they are not nullptr and referenced - // from somewhere else. Remove items with last usage > expiryTime. Note: last usage might be updated from other - // places so nullptr or not references elsewhere items are not always removed. + /* + * @brief Updates usage timestamps and removes expired items + * + * Updates the lastUsage timestamp of cached items that have external references. + * Initializes lastUsage timestamp for new items. + * Removes items that haven't been referenced for longer than expiryDelay. + * + * @param referenceTime the timestamp indicating when the item was most recently used + * @param expiryDelay the delay after which the cache entry for an item expires + */ void update(double referenceTime, double expiryDelay) { std::vector> objectsToRemove; + { const double expiryTime = referenceTime - expiryDelay; + std::lock_guard lock(mMutex); + std::erase_if(mItems, [&](auto& v) { Item& item = v.second; + + // update last usage timestamp if item is being referenced externally + // or initialize if not set if ((item.mValue != nullptr && item.mValue->referenceCount() > 1) || item.mLastUsage == 0) item.mLastUsage = referenceTime; + + // skip items that have been accessed since expiryTime if (item.mLastUsage > expiryTime) return false; + ++mExpired; + + // just mark for removal here so objects can be removed in bulk outside the lock if (item.mValue != nullptr) objectsToRemove.push_back(std::move(item.mValue)); + return true; }); } - // note, actual unref happens outside of the lock + + // remove expired items from cache objectsToRemove.clear(); } From 6d74a4607c05629f662b9605dd85dba2a294ae33 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Thu, 10 Jul 2025 17:25:27 +0300 Subject: [PATCH 203/330] Restore some omitted object cache remarks that seemed useful --- components/resource/objectcache.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/components/resource/objectcache.hpp b/components/resource/objectcache.hpp index 8fdc199e93..2ff25c92f1 100644 --- a/components/resource/objectcache.hpp +++ b/components/resource/objectcache.hpp @@ -56,20 +56,22 @@ namespace Resource /* * @brief Updates usage timestamps and removes expired items * - * Updates the lastUsage timestamp of cached items that have external references. + * Updates the lastUsage timestamp of cached non-nullptr items that have external references. * Initializes lastUsage timestamp for new items. * Removes items that haven't been referenced for longer than expiryDelay. * + * \note + * Last usage might be updated from other places so nullptr items + * that are not referenced elsewhere are not always removed. + * * @param referenceTime the timestamp indicating when the item was most recently used * @param expiryDelay the delay after which the cache entry for an item expires */ void update(double referenceTime, double expiryDelay) { std::vector> objectsToRemove; - { const double expiryTime = referenceTime - expiryDelay; - std::lock_guard lock(mMutex); std::erase_if(mItems, [&](auto& v) { @@ -93,7 +95,6 @@ namespace Resource return true; }); } - // remove expired items from cache objectsToRemove.clear(); } From 25d9c80067a0d91b5820fc131da70ae8bb4d901b Mon Sep 17 00:00:00 2001 From: Kuyondo Date: Thu, 10 Jul 2025 23:46:22 +0800 Subject: [PATCH 204/330] Don't play vfx and sound on fully resisted debuffs --- apps/openmw/mwmechanics/activespells.cpp | 8 +++----- apps/openmw/mwmechanics/spelleffects.cpp | 11 +++++++---- apps/openmw/mwmechanics/spelleffects.hpp | 3 ++- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 0f361f7ffc..270faf8598 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -273,13 +273,14 @@ namespace MWMechanics } bool updateSpellWindow = false; + bool playNonLooping = false; if (ptr.getClass().hasInventoryStore(ptr) && !(creatureStats.isDead() && !creatureStats.isDeathAnimationFinished())) { auto& store = ptr.getClass().getInventoryStore(ptr); if (store.getInvListener() != nullptr) { - bool playNonLooping = !store.isFirstEquip(); + playNonLooping = !store.isFirstEquip(); const auto world = MWBase::Environment::get().getWorld(); for (int slotIndex = 0; slotIndex < MWWorld::InventoryStore::Slots; slotIndex++) { @@ -307,9 +308,6 @@ namespace MWMechanics applyPurges(ptr); ActiveSpellParams& params = mSpells.emplace_back(ActiveSpellParams{ *slot, enchantment, ptr }); params.setActiveSpellId(MWBase::Environment::get().getESMStore()->generateId()); - for (const auto& effect : params.mEffects) - MWMechanics::playEffects( - ptr, *world->getStore().get().find(effect.mEffectId), playNonLooping); updateSpellWindow = true; } } @@ -327,7 +325,7 @@ namespace MWMechanics std::optional reflected; for (auto it = spellIt->mEffects.begin(); it != spellIt->mEffects.end();) { - auto result = applyMagicEffect(ptr, caster, *spellIt, *it, duration); + auto result = applyMagicEffect(ptr, caster, *spellIt, *it, duration, playNonLooping); if (result.mType == MagicApplicationResult::Type::REFLECTED) { if (!reflected) diff --git a/apps/openmw/mwmechanics/spelleffects.cpp b/apps/openmw/mwmechanics/spelleffects.cpp index 3d1a5ed84e..99e5a09481 100644 --- a/apps/openmw/mwmechanics/spelleffects.cpp +++ b/apps/openmw/mwmechanics/spelleffects.cpp @@ -914,7 +914,7 @@ namespace MWMechanics } MagicApplicationResult applyMagicEffect(const MWWorld::Ptr& target, const MWWorld::Ptr& caster, - ActiveSpells::ActiveSpellParams& spellParams, ESM::ActiveEffect& effect, float dt) + ActiveSpells::ActiveSpellParams& spellParams, ESM::ActiveEffect& effect, float dt, bool playNonLooping) { const auto world = MWBase::Environment::get().getWorld(); bool invalid = false; @@ -1032,9 +1032,12 @@ namespace MWMechanics oldMagnitude = effect.mMagnitude; else { - if (!spellParams.hasFlag(ESM::ActiveSpells::Flag_Equipment) - && !spellParams.hasFlag(ESM::ActiveSpells::Flag_Lua)) - playEffects(target, *magicEffect, spellParams.hasFlag(ESM::ActiveSpells::Flag_Temporary)); + bool isTemporary = spellParams.hasFlag(ESM::ActiveSpells::Flag_Temporary); + bool isEquipment = spellParams.hasFlag(ESM::ActiveSpells::Flag_Equipment); + + if (!spellParams.hasFlag(ESM::ActiveSpells::Flag_Lua)) + playEffects(target, *magicEffect, (isTemporary || (isEquipment && playNonLooping))); + if (effect.mEffectId == ESM::MagicEffect::Soultrap && !target.getClass().isNpc() && target.getType() == ESM::Creature::sRecordId && target.get()->mBase->mData.mSoul == 0 && caster == getPlayer()) diff --git a/apps/openmw/mwmechanics/spelleffects.hpp b/apps/openmw/mwmechanics/spelleffects.hpp index 2dafedf31f..d9b05535a9 100644 --- a/apps/openmw/mwmechanics/spelleffects.hpp +++ b/apps/openmw/mwmechanics/spelleffects.hpp @@ -28,7 +28,8 @@ namespace MWMechanics // Applies a tick of a single effect. Returns true if the effect should be removed immediately MagicApplicationResult applyMagicEffect(const MWWorld::Ptr& target, const MWWorld::Ptr& caster, - ActiveSpells::ActiveSpellParams& spellParams, ESM::ActiveEffect& effect, float dt); + ActiveSpells::ActiveSpellParams& spellParams, ESM::ActiveEffect& effect, float dt, + bool playNonLoopingEffect = true); // Undoes permanent effects created by ESM::MagicEffect::AppliedOnce void onMagicEffectRemoved( From fe7970421f8b6a07a92026912987dbfeb17433c2 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Fri, 11 Jul 2025 11:10:02 +0300 Subject: [PATCH 205/330] Don't harvest if player activation is blocked (#8612) --- apps/openmw/mwclass/container.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index c8b1f05972..fff191c22d 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -192,12 +192,13 @@ namespace MWClass { if (!isTrapped) { - if (canBeHarvested(ptr)) - { - return std::make_unique(ptr); - } + if (!canBeHarvested(ptr)) + return std::make_unique(ptr); - return std::make_unique(ptr); + if (hasToolTip(ptr)) + return std::make_unique(ptr); + + return std::make_unique(std::string_view{}, ptr); } else { From 869881d227bbd412dd85bf3cc84ae96e4f86f59c Mon Sep 17 00:00:00 2001 From: wareya Date: Fri, 11 Jul 2025 12:23:22 -0400 Subject: [PATCH 206/330] fix terrain normal map handedness --- files/shaders/compatibility/terrain.frag | 2 +- files/shaders/compatibility/terrain.vert | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/files/shaders/compatibility/terrain.frag b/files/shaders/compatibility/terrain.frag index 9d89217f35..48183c0a92 100644 --- a/files/shaders/compatibility/terrain.frag +++ b/files/shaders/compatibility/terrain.frag @@ -49,7 +49,7 @@ void main() vec2 adjustedUV = (gl_TextureMatrix[0] * vec4(uv, 0.0, 1.0)).xy; #if @parallax - adjustedUV += getParallaxOffset(transpose(normalToViewMatrix) * normalize(-passViewPos), texture2D(normalMap, adjustedUV).a, 1.f); + adjustedUV += getParallaxOffset(transpose(normalToViewMatrix) * normalize(-passViewPos), texture2D(normalMap, adjustedUV).a, -1.0f); #endif vec4 diffuseTex = texture2D(diffuseMap, adjustedUV); gl_FragData[0] = vec4(diffuseTex.xyz, 1.0); diff --git a/files/shaders/compatibility/terrain.vert b/files/shaders/compatibility/terrain.vert index cbfb7769ba..40d69ff35d 100644 --- a/files/shaders/compatibility/terrain.vert +++ b/files/shaders/compatibility/terrain.vert @@ -46,8 +46,8 @@ void main(void) normalToViewMatrix = gl_NormalMatrix; #if @normalMap - mat3 tbnMatrix = generateTangentSpace(vec4(1.0, 0.0, 0.0, 1.0), passNormal); - tbnMatrix[0] = normalize(cross(tbnMatrix[2], tbnMatrix[1])); // note, now we need to re-cross to derive tangent again because it wasn't orthonormal + mat3 tbnMatrix = generateTangentSpace(vec4(1.0, 0.0, 0.0, -1.0), passNormal); + tbnMatrix[0] = -normalize(cross(tbnMatrix[2], tbnMatrix[1])); // our original tangent was not at a 90 degree angle to the normal, so we need to rederive it normalToViewMatrix *= tbnMatrix; #endif From 77c30a68c99871135a36190be1bc5383235ae3f0 Mon Sep 17 00:00:00 2001 From: Kuyondo Date: Sat, 12 Jul 2025 11:56:31 +0800 Subject: [PATCH 207/330] more similar to vanilla --- apps/openmw/mwgui/jailscreen.cpp | 2 +- apps/openmw/mwgui/timeadvancer.cpp | 5 ++--- apps/openmw/mwgui/timeadvancer.hpp | 4 ++-- apps/openmw/mwgui/trainingwindow.cpp | 2 +- apps/openmw/mwgui/waitdialog.cpp | 2 +- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index c6aefdd177..f482ec4de2 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -23,7 +23,7 @@ namespace MWGui : WindowBase("openmw_jail_screen.layout") , mDays(1) , mFadeTimeRemaining(0) - , mTimeAdvancer(0.01f) + , mTimeAdvancer() { getWidget(mProgressBar, "ProgressBar"); diff --git a/apps/openmw/mwgui/timeadvancer.cpp b/apps/openmw/mwgui/timeadvancer.cpp index 2cdab127b9..abe0a668d4 100644 --- a/apps/openmw/mwgui/timeadvancer.cpp +++ b/apps/openmw/mwgui/timeadvancer.cpp @@ -2,13 +2,12 @@ namespace MWGui { - TimeAdvancer::TimeAdvancer(float delay) + TimeAdvancer::TimeAdvancer() : mRunning(false) , mCurHour(0) , mHours(1) , mInterruptAt(-1) - , mDelay(delay) - , mRemainingTime(delay) + , mRemainingTime(mDelay) { } diff --git a/apps/openmw/mwgui/timeadvancer.hpp b/apps/openmw/mwgui/timeadvancer.hpp index bb6aa649cb..be19619d25 100644 --- a/apps/openmw/mwgui/timeadvancer.hpp +++ b/apps/openmw/mwgui/timeadvancer.hpp @@ -8,7 +8,7 @@ namespace MWGui class TimeAdvancer { public: - TimeAdvancer(float delay); + TimeAdvancer(); void run(int hours, int interruptAt = -1); void stop(); @@ -32,7 +32,7 @@ namespace MWGui int mHours; int mInterruptAt; - float mDelay; + static constexpr float mDelay = 1.0f / 60.0f; float mRemainingTime; }; } diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 890aa0ba68..94f001f26d 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -27,7 +27,7 @@ namespace MWGui TrainingWindow::TrainingWindow() : WindowBase("openmw_trainingwindow.layout") - , mTimeAdvancer(0.05f) + , mTimeAdvancer() { getWidget(mTrainingOptions, "TrainingOptions"); getWidget(mCancelButton, "CancelButton"); diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 222a34e53b..f6f1b86214 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -52,7 +52,7 @@ namespace MWGui WaitDialog::WaitDialog() : WindowBase("openmw_wait_dialog.layout") - , mTimeAdvancer(0.05f) + , mTimeAdvancer() , mSleeping(false) , mHours(1) , mManualHours(1) From bcfe06d85aa9db5338bc98b8c96d884b9efc0ec6 Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 3 May 2025 02:49:19 +0200 Subject: [PATCH 208/330] Use std::size_t for items count --- apps/openmw/mwgui/companionwindow.cpp | 2 +- apps/openmw/mwgui/companionwindow.hpp | 2 +- apps/openmw/mwgui/container.cpp | 2 +- apps/openmw/mwgui/container.hpp | 2 +- apps/openmw/mwgui/countdialog.hpp | 6 ++---- apps/openmw/mwgui/draganddrop.cpp | 2 +- apps/openmw/mwgui/draganddrop.hpp | 4 ++-- apps/openmw/mwgui/inventorywindow.cpp | 4 ++-- apps/openmw/mwgui/inventorywindow.hpp | 4 ++-- apps/openmw/mwgui/tradewindow.cpp | 2 +- apps/openmw/mwgui/tradewindow.hpp | 2 +- 11 files changed, 15 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index bdcb8abc9b..95dbc8ae22 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -106,7 +106,7 @@ namespace MWGui mItemView->update(); } - void CompanionWindow::dragItem(MyGUI::Widget* sender, int count) + void CompanionWindow::dragItem(MyGUI::Widget* /*sender*/, std::size_t count) { mDragAndDrop->startDrag(mSelectedItem, mSortModel, mModel, mItemView, count); } diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index 5a4b5880ff..8ecefa6931 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -55,7 +55,7 @@ namespace MWGui void onItemSelected(int index); void onNameFilterChanged(MyGUI::EditBox* _sender); void onBackgroundSelected(); - void dragItem(MyGUI::Widget* sender, int count); + void dragItem(MyGUI::Widget* sender, std::size_t count); void onMessageBoxButtonClicked(int button); diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 6e768f6e1e..6f07a2db2e 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -95,7 +95,7 @@ namespace MWGui dragItem(nullptr, count); } - void ContainerWindow::dragItem(MyGUI::Widget* sender, int count) + void ContainerWindow::dragItem(MyGUI::Widget* /*sender*/, std::size_t count) { if (!mModel) return; diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index a7702ebbfe..660493745b 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -60,7 +60,7 @@ namespace MWGui void onItemSelected(int index); void onBackgroundSelected(); - void dragItem(MyGUI::Widget* sender, int count); + void dragItem(MyGUI::Widget*, std::size_t count); void dropItem(); void onCloseButtonClicked(MyGUI::Widget* _sender); void onTakeAllButtonClicked(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/countdialog.hpp b/apps/openmw/mwgui/countdialog.hpp index 9cdf231549..70fc820899 100644 --- a/apps/openmw/mwgui/countdialog.hpp +++ b/apps/openmw/mwgui/countdialog.hpp @@ -16,12 +16,10 @@ namespace MWGui CountDialog(); void openCountDialog(const std::string& item, const std::string& message, const int maxCount); - typedef MyGUI::delegates::MultiDelegate EventHandle_WidgetInt; - /** Event : Ok button was clicked.\n - signature : void method(MyGUI::Widget* _sender, int _count)\n + signature : void method(MyGUI::Widget* sender, std::size_t count)\n */ - EventHandle_WidgetInt eventOkClicked; + MyGUI::delegates::MultiDelegate eventOkClicked; private: MyGUI::ScrollBar* mSlider; diff --git a/apps/openmw/mwgui/draganddrop.cpp b/apps/openmw/mwgui/draganddrop.cpp index 52b0939238..ee4dc92a7e 100644 --- a/apps/openmw/mwgui/draganddrop.cpp +++ b/apps/openmw/mwgui/draganddrop.cpp @@ -27,7 +27,7 @@ namespace MWGui } void DragAndDrop::startDrag( - int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, int count) + int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, std::size_t count) { mItem = sourceModel->getItem(index); mDraggedCount = count; diff --git a/apps/openmw/mwgui/draganddrop.hpp b/apps/openmw/mwgui/draganddrop.hpp index 94da6cce5f..afe4fd0df2 100644 --- a/apps/openmw/mwgui/draganddrop.hpp +++ b/apps/openmw/mwgui/draganddrop.hpp @@ -24,12 +24,12 @@ namespace MWGui ItemView* mSourceView; SortFilterItemModel* mSourceSortModel; ItemStack mItem; - int mDraggedCount; + std::size_t mDraggedCount; DragAndDrop(); void startDrag( - int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, int count); + int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, std::size_t count); void drop(ItemModel* targetModel, ItemView* targetView); void update(); void onFrame(); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index acc1dd6068..234df1040e 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -361,14 +361,14 @@ namespace MWGui } } - void InventoryWindow::dragItem(MyGUI::Widget* sender, int count) + void InventoryWindow::dragItem(MyGUI::Widget* /*sender*/, std::size_t count) { ensureSelectedItemUnequipped(count); mDragAndDrop->startDrag(mSelectedItem, mSortModel, mTradeModel, mItemView, count); notifyContentChanged(); } - void InventoryWindow::sellItem(MyGUI::Widget* sender, int count) + void InventoryWindow::sellItem(MyGUI::Widget* /*sender*/, std::size_t count) { ensureSelectedItemUnequipped(count); const ItemStack& item = mTradeModel->getItem(mSelectedItem); diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 7f0d64dce0..15c93d14eb 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -120,8 +120,8 @@ namespace MWGui void onBackgroundSelected(); - void sellItem(MyGUI::Widget* sender, int count); - void dragItem(MyGUI::Widget* sender, int count); + void sellItem(MyGUI::Widget* sender, std::size_t count); + void dragItem(MyGUI::Widget* sender, std::size_t count); void onWindowResize(MyGUI::Window* _sender); void onFilterChanged(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index ea124f0a97..bf5d4d4279 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -292,7 +292,7 @@ namespace MWGui } } - void TradeWindow::sellItem(MyGUI::Widget* sender, int count) + void TradeWindow::sellItem(MyGUI::Widget* /*sender*/, std::size_t count) { const ItemStack& item = mTradeModel->getItem(mItemToSell); const ESM::RefId& sound = item.mBase.getClass().getUpSoundId(item.mBase); diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index b0581d0d38..5a3889d2d8 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -95,7 +95,7 @@ namespace MWGui void updateOffer(); void onItemSelected(int index); - void sellItem(MyGUI::Widget* sender, int count); + void sellItem(MyGUI::Widget* sender, std::size_t count); void borrowItem(int index, size_t count); void returnItem(int index, size_t count); From a4af0372931ddf4cb150e3aae5fd14997ff29463 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 4 May 2025 10:26:21 +0200 Subject: [PATCH 209/330] Remove ContainerWindow::onTakeItem --- apps/openmw/mwgui/container.cpp | 13 +++++-------- apps/openmw/mwgui/container.hpp | 3 --- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 6f07a2db2e..28ec1b5060 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -100,7 +100,9 @@ namespace MWGui if (!mModel) return; - if (!onTakeItem(mModel->getItem(mSelectedItem), count)) + const ItemStack item = mModel->getItem(mSelectedItem); + + if (!mModel->onTakeItem(item.mBase, count)) return; mDragAndDrop->startDrag(mSelectedItem, mSortModel, mModel, mItemView, count); @@ -234,9 +236,9 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->playSound(sound); } - const ItemStack& item = mModel->getItem(i); + const ItemStack item = mModel->getItem(i); - if (!onTakeItem(item, item.mCount)) + if (!mModel->onTakeItem(item.mBase, item.mCount)) break; mModel->moveItem(item, item.mCount, playerModel); @@ -313,11 +315,6 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); } - bool ContainerWindow::onTakeItem(const ItemStack& item, int count) - { - return mModel->onTakeItem(item.mBase, count); - } - void ContainerWindow::onDeleteCustomData(const MWWorld::Ptr& ptr) { if (mModel && mModel->usesContainer(ptr)) diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 660493745b..697e47ee1b 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -66,9 +66,6 @@ namespace MWGui void onTakeAllButtonClicked(MyGUI::Widget* _sender); void onDisposeCorpseButtonClicked(MyGUI::Widget* sender); - /// @return is taking the item allowed? - bool onTakeItem(const ItemStack& item, int count); - void onReferenceUnavailable() override; }; } From eb7af832e4d705f0257e7ec19801fcbde16bbea0 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 6 Jul 2025 11:10:10 +0200 Subject: [PATCH 210/330] Remove trailing spaces --- docs/source/reference/modding/settings/GUI.rst | 8 ++++---- files/lang/launcher_sv.ts | 4 ++-- files/settings-default.cfg | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/source/reference/modding/settings/GUI.rst b/docs/source/reference/modding/settings/GUI.rst index b9065c8daf..63bbae5f8b 100644 --- a/docs/source/reference/modding/settings/GUI.rst +++ b/docs/source/reference/modding/settings/GUI.rst @@ -77,7 +77,7 @@ GUI Settings :type: boolean :range: true, false :default: true - + Enables or disables the red flash overlay when the character takes damage. Disabling causes the player to "bleed" like NPCs. @@ -87,7 +87,7 @@ GUI Settings :type: boolean :range: true, false :default: true - + Enable or disable the werewolf visual effect in first-person mode. @@ -96,7 +96,7 @@ GUI Settings :type: color :range: [0, 1] :default: 0.15 0.0 0.0 1.0 - + Background color of tooltip and crosshair when hovering over an NPC-owned item. Four floating point values: red, green, blue, alpha (alpha ignored). @@ -107,7 +107,7 @@ GUI Settings :type: color :range: [0, 1] :default: 1.0 0.15 0.15 1.0 - + Crosshair color when hovering over an NPC-owned item. Four floating point values: red, green, blue, alpha (alpha ignored). diff --git a/files/lang/launcher_sv.ts b/files/lang/launcher_sv.ts index 97de9603d7..3e6c5607eb 100644 --- a/files/lang/launcher_sv.ts +++ b/files/lang/launcher_sv.ts @@ -767,10 +767,10 @@ de ordinarie fonterna i Morrowind. Bocka denna ruta om du ändå föredrar ordin the specular map texture would have to be named foo_spec.dds). If this option is disabled, normal maps are only used if they are explicitly listed within the mesh file (.osg file, not supported in .nif files). Affects objects.</p></body></html> - <html><head/><body><p>Om den här funktionen är aktiverad kommer spekularitetskartor (specular maps) att hittas och användas + <html><head/><body><p>Om den här funktionen är aktiverad kommer spekularitetskartor (specular maps) att hittas och användas (see 'specular map pattern', t.ex. för en bastextur foo.dds, ska spekularitetskartan heta foo_spec.dds). - Om funktionen är inaktiverad kommer normalkartor bara användas om texturerna är explicit listade i 3D-modell-filen + Om funktionen är inaktiverad kommer normalkartor bara användas om texturerna är explicit listade i 3D-modell-filen (.nif eller .osg fil). Påverkar objekt.</p></body></html> diff --git a/files/settings-default.cfg b/files/settings-default.cfg index e5654794cc..b9bf113dee 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -372,8 +372,8 @@ unarmed creature attacks damage armor = false # 2 = Cylinder actor collision shape type = 0 -# When false the player character will base movement on animations. This will sway the camera -# while moving in third person like in vanilla, and reproduce movement bugs caused by glitchy +# When false the player character will base movement on animations. This will sway the camera +# while moving in third person like in vanilla, and reproduce movement bugs caused by glitchy # vanilla animations. player movement ignores animation = false @@ -1136,7 +1136,7 @@ xargonianswimknakf = meshes/xargonian_swimkna.kf # Sky atmosphere mesh skyatmosphere = meshes/sky_atmosphere.nif -# Sky clouds mesh +# Sky clouds mesh skyclouds = meshes/sky_clouds_01.nif # Sky stars mesh 01 @@ -1269,7 +1269,7 @@ right eye fov down = -0.8 [Post Processing] -# Enables post-processing +# Enables post-processing enabled = false # List of active shaders. This is more easily with the in-game shader HUD, by default accessible with the F2 key. From f5e66f3e244c7b8761058f459debc21294ac78a6 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 6 Jul 2025 11:13:00 +0200 Subject: [PATCH 211/330] Remove unused includes --- components/settings/categories/gui.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/settings/categories/gui.hpp b/components/settings/categories/gui.hpp index a26364c5dd..ffef047094 100644 --- a/components/settings/categories/gui.hpp +++ b/components/settings/categories/gui.hpp @@ -10,8 +10,6 @@ #include -#include -#include #include namespace Settings From 463de2d7910ecc5b5b686799df26f9fc58e3d6da Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 3 May 2025 00:02:06 +0200 Subject: [PATCH 212/330] Instantly transfer items if alt key is pressed Support player's inventory, container and companion windows with dropping and picking up items from the world. Add ItemTransfer class to handle transfers similar to DragAndDrop. When a container window is opened the view is added to the set of targets and removed when closed. If ALT is pressed instead of starting dragging an item perform a transfer. If there is 1 target which is not a source move item there. If there is no target drop item into the world using WorldItemModel. Special case is picking up an item. Don't start dragging, just update the player's inventory view because the item is already there. --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/companionwindow.cpp | 29 ++++++++- apps/openmw/mwgui/companionwindow.hpp | 13 +++- apps/openmw/mwgui/container.cpp | 45 ++++++++++---- apps/openmw/mwgui/container.hpp | 19 +++--- apps/openmw/mwgui/draganddrop.cpp | 24 ++++---- apps/openmw/mwgui/draganddrop.hpp | 4 +- apps/openmw/mwgui/hud.cpp | 75 +++-------------------- apps/openmw/mwgui/inventorywindow.cpp | 40 +++++++++++-- apps/openmw/mwgui/inventorywindow.hpp | 12 +++- apps/openmw/mwgui/itemtransfer.hpp | 78 ++++++++++++++++++++++++ apps/openmw/mwgui/itemview.hpp | 2 + apps/openmw/mwgui/windowmanagerimp.cpp | 9 ++- apps/openmw/mwgui/windowmanagerimp.hpp | 3 +- apps/openmw/mwgui/worlditemmodel.hpp | 82 ++++++++++++++++++++++++++ apps/openmw/mwworld/cellref.hpp | 12 ++++ 16 files changed, 337 insertions(+), 112 deletions(-) create mode 100644 apps/openmw/mwgui/itemtransfer.hpp create mode 100644 apps/openmw/mwgui/worlditemmodel.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index e3629d6f27..4dc2fd1fd1 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -44,7 +44,7 @@ add_openmw_dir (mwgui tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview draganddrop timeadvancer jailscreen itemchargeview keyboardnavigation textcolours statswatcher - postprocessorhud settings + postprocessorhud settings worlditemmodel itemtransfer ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 95dbc8ae22..52fc4cc4ce 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -14,6 +14,7 @@ #include "companionitemmodel.hpp" #include "countdialog.hpp" #include "draganddrop.hpp" +#include "itemtransfer.hpp" #include "itemview.hpp" #include "messagebox.hpp" #include "sortfilteritemmodel.hpp" @@ -38,13 +39,14 @@ namespace namespace MWGui { - CompanionWindow::CompanionWindow(DragAndDrop* dragAndDrop, MessageBoxManager* manager) + CompanionWindow::CompanionWindow(DragAndDrop& dragAndDrop, ItemTransfer& itemTransfer, MessageBoxManager* manager) : WindowBase("openmw_companion_window.layout") , mSortModel(nullptr) , mModel(nullptr) , mSelectedItem(-1) , mUpdateNextFrame(false) - , mDragAndDrop(dragAndDrop) + , mDragAndDrop(&dragAndDrop) + , mItemTransfer(&itemTransfer) , mMessageBoxManager(manager) { getWidget(mCloseButton, "CloseButton"); @@ -94,8 +96,14 @@ namespace MWGui name += MWGui::ToolTips::getSoulString(object.getCellRef()); dialog->openCountDialog(name, "#{sTake}", count); dialog->eventOkClicked.clear(); - dialog->eventOkClicked += MyGUI::newDelegate(this, &CompanionWindow::dragItem); + + if (MyGUI::InputManager::getInstance().isAltPressed()) + dialog->eventOkClicked += MyGUI::newDelegate(this, &CompanionWindow::transferItem); + else + dialog->eventOkClicked += MyGUI::newDelegate(this, &CompanionWindow::dragItem); } + else if (MyGUI::InputManager::getInstance().isAltPressed()) + transferItem(nullptr, count); else dragItem(nullptr, count); } @@ -111,6 +119,11 @@ namespace MWGui mDragAndDrop->startDrag(mSelectedItem, mSortModel, mModel, mItemView, count); } + void CompanionWindow::transferItem(MyGUI::Widget* /*sender*/, std::size_t count) + { + mItemTransfer->apply(mModel->getItem(mSelectedItem), count, *mItemView); + } + void CompanionWindow::onBackgroundSelected() { if (mDragAndDrop->mIsOnDragAndDrop) @@ -220,4 +233,14 @@ namespace MWGui { mUpdateNextFrame = true; } + + void CompanionWindow::onOpen() + { + mItemTransfer->addTarget(*mItemView); + } + + void CompanionWindow::onClose() + { + mItemTransfer->removeTarget(*mItemView); + } } diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index 8ecefa6931..5e78d17334 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -6,6 +6,8 @@ #include "../mwworld/containerstore.hpp" +#include + namespace MWGui { namespace Widgets @@ -18,11 +20,12 @@ namespace MWGui class DragAndDrop; class SortFilterItemModel; class CompanionItemModel; + class ItemTransfer; class CompanionWindow : public WindowBase, public ReferenceInterface, public MWWorld::ContainerStoreListener { public: - CompanionWindow(DragAndDrop* dragAndDrop, MessageBoxManager* manager); + explicit CompanionWindow(DragAndDrop& dragAndDrop, ItemTransfer& itemTransfer, MessageBoxManager* manager); bool exit() override; @@ -44,7 +47,8 @@ namespace MWGui int mSelectedItem; bool mUpdateNextFrame; - DragAndDrop* mDragAndDrop; + Misc::NotNullPtr mDragAndDrop; + Misc::NotNullPtr mItemTransfer; MyGUI::Button* mCloseButton; MyGUI::EditBox* mFilterEdit; @@ -56,6 +60,7 @@ namespace MWGui void onNameFilterChanged(MyGUI::EditBox* _sender); void onBackgroundSelected(); void dragItem(MyGUI::Widget* sender, std::size_t count); + void transferItem(MyGUI::Widget* sender, std::size_t count); void onMessageBoxButtonClicked(int button); @@ -64,6 +69,10 @@ namespace MWGui void onCloseButtonClicked(MyGUI::Widget* _sender); void onReferenceUnavailable() override; + + void onOpen() override; + + void onClose() override; }; } diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 28ec1b5060..937bab0851 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -18,12 +18,12 @@ #include "../mwscript/interpretercontext.hpp" -#include "countdialog.hpp" -#include "inventorywindow.hpp" - #include "containeritemmodel.hpp" +#include "countdialog.hpp" #include "draganddrop.hpp" #include "inventoryitemmodel.hpp" +#include "inventorywindow.hpp" +#include "itemtransfer.hpp" #include "itemview.hpp" #include "pickpocketitemmodel.hpp" #include "sortfilteritemmodel.hpp" @@ -32,9 +32,10 @@ namespace MWGui { - ContainerWindow::ContainerWindow(DragAndDrop* dragAndDrop) + ContainerWindow::ContainerWindow(DragAndDrop& dragAndDrop, ItemTransfer& itemTransfer) : WindowBase("openmw_container_window.layout") - , mDragAndDrop(dragAndDrop) + , mDragAndDrop(&dragAndDrop) + , mItemTransfer(&itemTransfer) , mSortModel(nullptr) , mModel(nullptr) , mSelectedItem(-1) @@ -89,15 +90,21 @@ namespace MWGui name += MWGui::ToolTips::getSoulString(object.getCellRef()); dialog->openCountDialog(name, "#{sTake}", count); dialog->eventOkClicked.clear(); - dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerWindow::dragItem); + + if (MyGUI::InputManager::getInstance().isAltPressed()) + dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerWindow::transferItem); + else + dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerWindow::dragItem); } + else if (MyGUI::InputManager::getInstance().isAltPressed()) + transferItem(nullptr, count); else dragItem(nullptr, count); } void ContainerWindow::dragItem(MyGUI::Widget* /*sender*/, std::size_t count) { - if (!mModel) + if (mModel == nullptr) return; const ItemStack item = mModel->getItem(mSelectedItem); @@ -108,9 +115,22 @@ namespace MWGui mDragAndDrop->startDrag(mSelectedItem, mSortModel, mModel, mItemView, count); } + void ContainerWindow::transferItem(MyGUI::Widget* /*sender*/, std::size_t count) + { + if (mModel == nullptr) + return; + + const ItemStack item = mModel->getItem(mSelectedItem); + + if (!mModel->onTakeItem(item.mBase, count)) + return; + + mItemTransfer->apply(item, count, *mItemView); + } + void ContainerWindow::dropItem() { - if (!mModel) + if (mModel == nullptr) return; bool success = mModel->onDropItem(mDragAndDrop->mItem.mBase, mDragAndDrop->mDraggedCount); @@ -175,10 +195,13 @@ namespace MWGui mSortModel = nullptr; } + void ContainerWindow::onOpen() + { + mItemTransfer->addTarget(*mItemView); + } + void ContainerWindow::onClose() { - WindowBase::onClose(); - // Make sure the window was actually closed and not temporarily hidden. if (MWBase::Environment::get().getWindowManager()->containsMode(GM_Container)) return; @@ -189,6 +212,8 @@ namespace MWGui if (!mPtr.isEmpty()) MWBase::Environment::get().getMechanicsManager()->onClose(mPtr); resetReference(); + + mItemTransfer->removeTarget(*mItemView); } void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 697e47ee1b..86ded2ff75 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -1,10 +1,11 @@ #ifndef MGUI_CONTAINER_H #define MGUI_CONTAINER_H +#include "itemmodel.hpp" #include "referenceinterface.hpp" #include "windowbase.hpp" -#include "itemmodel.hpp" +#include #include "../mwworld/containerstore.hpp" @@ -19,17 +20,19 @@ namespace MWGui class ContainerWindow; class ItemView; class SortFilterItemModel; -} + class ItemTransfer; -namespace MWGui -{ class ContainerWindow : public WindowBase, public ReferenceInterface, public MWWorld::ContainerStoreListener { public: - ContainerWindow(DragAndDrop* dragAndDrop); + explicit ContainerWindow(DragAndDrop& dragAndDrop, ItemTransfer& itemTransfer); void setPtr(const MWWorld::Ptr& container) override; + + void onOpen() override; + void onClose() override; + void clear() override { resetReference(); } void onFrame(float dt) override; @@ -46,7 +49,8 @@ namespace MWGui std::string_view getWindowIdForLua() const override { return "Container"; } private: - DragAndDrop* mDragAndDrop; + Misc::NotNullPtr mDragAndDrop; + Misc::NotNullPtr mItemTransfer; MWGui::ItemView* mItemView; SortFilterItemModel* mSortModel; @@ -60,7 +64,8 @@ namespace MWGui void onItemSelected(int index); void onBackgroundSelected(); - void dragItem(MyGUI::Widget*, std::size_t count); + void dragItem(MyGUI::Widget* sender, std::size_t count); + void transferItem(MyGUI::Widget* sender, std::size_t count); void dropItem(); void onCloseButtonClicked(MyGUI::Widget* _sender); void onTakeAllButtonClicked(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/draganddrop.cpp b/apps/openmw/mwgui/draganddrop.cpp index ee4dc92a7e..85229d0a13 100644 --- a/apps/openmw/mwgui/draganddrop.cpp +++ b/apps/openmw/mwgui/draganddrop.cpp @@ -125,18 +125,18 @@ namespace MWGui void DragAndDrop::update() { - if (mIsOnDragAndDrop) - { - int count = mItem.mBase.getCellRef().getCount(); - if (count < mDraggedCount) - { - mItem.mCount = count; - mDraggedCount = count; - mDraggedWidget->setCount(mDraggedCount); - mSourceSortModel->clearDragItems(); - mSourceSortModel->addDragItem(mItem.mBase, mDraggedCount); - } - } + if (!mIsOnDragAndDrop) + return; + + const unsigned count = mItem.mBase.getCellRef().getAbsCount(); + if (count >= mDraggedCount) + return; + + mItem.mCount = count; + mDraggedCount = count; + mDraggedWidget->setCount(mDraggedCount); + mSourceSortModel->clearDragItems(); + mSourceSortModel->addDragItem(mItem.mBase, mDraggedCount); } void DragAndDrop::onFrame() diff --git a/apps/openmw/mwgui/draganddrop.hpp b/apps/openmw/mwgui/draganddrop.hpp index afe4fd0df2..511e2b7765 100644 --- a/apps/openmw/mwgui/draganddrop.hpp +++ b/apps/openmw/mwgui/draganddrop.hpp @@ -4,6 +4,8 @@ #include "itemmodel.hpp" #include "itemwidget.hpp" +#include + namespace MyGUI { class Widget; @@ -29,7 +31,7 @@ namespace MWGui DragAndDrop(); void startDrag( - int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, std::size_t count); + int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, std::size_t count); void drop(ItemModel* targetModel, ItemView* targetView); void update(); void onFrame(); diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 0a37c93b4f..e5adce7624 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -25,67 +25,12 @@ #include "draganddrop.hpp" #include "inventorywindow.hpp" -#include "itemmodel.hpp" -#include "spellicons.hpp" - #include "itemwidget.hpp" +#include "spellicons.hpp" +#include "worlditemmodel.hpp" namespace MWGui { - - /** - * Makes it possible to use ItemModel::moveItem to move an item from an inventory to the world. - */ - class WorldItemModel : public ItemModel - { - public: - WorldItemModel(float left, float top) - : mLeft(left) - , mTop(top) - { - } - virtual ~WorldItemModel() override {} - - MWWorld::Ptr dropItemImpl(const ItemStack& item, size_t count, bool copy) - { - MWBase::World* world = MWBase::Environment::get().getWorld(); - - MWWorld::Ptr dropped; - if (world->canPlaceObject(mLeft, mTop)) - dropped = world->placeObject(item.mBase, mLeft, mTop, count, copy); - else - dropped = world->dropObjectOnGround(world->getPlayerPtr(), item.mBase, count, copy); - dropped.getCellRef().setOwner(ESM::RefId()); - - return dropped; - } - - MWWorld::Ptr addItem(const ItemStack& item, size_t count, bool /*allowAutoEquip*/) override - { - return dropItemImpl(item, count, false); - } - - MWWorld::Ptr copyItem(const ItemStack& item, size_t count, bool /*allowAutoEquip*/) override - { - return dropItemImpl(item, count, true); - } - - void removeItem(const ItemStack& item, size_t count) override - { - throw std::runtime_error("removeItem not implemented"); - } - ModelIndex getIndex(const ItemStack& item) override { throw std::runtime_error("getIndex not implemented"); } - void update() override {} - size_t getItemCount() override { return 0; } - ItemStack getItem(ModelIndex index) override { throw std::runtime_error("getItem not implemented"); } - bool usesContainer(const MWWorld::Ptr&) override { return false; } - - private: - // Where to drop the item - float mLeft; - float mTop; - }; - HUD::HUD(CustomMarkerCollection& customMarkers, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender) : WindowBase("openmw_hud.layout") , LocalMapBase(customMarkers, localMapRender, Settings::map().mLocalMapHudFogOfWar) @@ -251,16 +196,14 @@ namespace MWGui MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); if (mDragAndDrop->mIsOnDragAndDrop) { + const MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + const MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition(); + const float cursorX = cursorPosition.left / static_cast(viewSize.width); + const float cursorY = cursorPosition.top / static_cast(viewSize.height); + // drop item into the gameworld - MWBase::Environment::get().getWorld()->breakInvisibility(MWMechanics::getPlayer()); - - MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition(); - float mouseX = cursorPosition.left / float(viewSize.width); - float mouseY = cursorPosition.top / float(viewSize.height); - - WorldItemModel drop(mouseX, mouseY); - mDragAndDrop->drop(&drop, nullptr); + WorldItemModel worldItemModel(cursorX, cursorY); + mDragAndDrop->drop(&worldItemModel, nullptr); winMgr->changePointer("arrow"); } diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 234df1040e..c558f1bad9 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -34,6 +34,7 @@ #include "countdialog.hpp" #include "draganddrop.hpp" #include "inventoryitemmodel.hpp" +#include "itemtransfer.hpp" #include "itemview.hpp" #include "settings.hpp" #include "sortfilteritemmodel.hpp" @@ -74,10 +75,11 @@ namespace MWGui } } - InventoryWindow::InventoryWindow( - DragAndDrop* dragAndDrop, osg::Group* parent, Resource::ResourceSystem* resourceSystem) + InventoryWindow::InventoryWindow(DragAndDrop& dragAndDrop, ItemTransfer& itemTransfer, osg::Group* parent, + Resource::ResourceSystem* resourceSystem) : WindowPinnableBase("openmw_inventory_window.layout") - , mDragAndDrop(dragAndDrop) + , mDragAndDrop(&dragAndDrop) + , mItemTransfer(&itemTransfer) , mSelectedItem(-1) , mSortModel(nullptr) , mTradeModel(nullptr) @@ -312,17 +314,24 @@ namespace MWGui name += MWGui::ToolTips::getSoulString(object.getCellRef()); dialog->openCountDialog(name, message, count); dialog->eventOkClicked.clear(); + if (mTrading) dialog->eventOkClicked += MyGUI::newDelegate(this, &InventoryWindow::sellItem); + else if (MyGUI::InputManager::getInstance().isAltPressed()) + dialog->eventOkClicked += MyGUI::newDelegate(this, &InventoryWindow::transferItem); else dialog->eventOkClicked += MyGUI::newDelegate(this, &InventoryWindow::dragItem); + mSelectedItem = index; } else { mSelectedItem = index; + if (mTrading) sellItem(nullptr, count); + else if (MyGUI::InputManager::getInstance().isAltPressed()) + transferItem(nullptr, count); else dragItem(nullptr, count); } @@ -368,6 +377,13 @@ namespace MWGui notifyContentChanged(); } + void InventoryWindow::transferItem(MyGUI::Widget* /*sender*/, std::size_t count) + { + ensureSelectedItemUnequipped(count); + mItemTransfer->apply(mTradeModel->getItem(mSelectedItem), count, *mItemView); + notifyContentChanged(); + } + void InventoryWindow::sellItem(MyGUI::Widget* /*sender*/, std::size_t count) { ensureSelectedItemUnequipped(count); @@ -415,6 +431,13 @@ namespace MWGui notifyContentChanged(); } adjustPanes(); + + mItemTransfer->addTarget(*mItemView); + } + + void InventoryWindow::onClose() + { + mItemTransfer->removeTarget(*mItemView); } void InventoryWindow::onWindowResize(MyGUI::Window* _sender) @@ -776,7 +799,16 @@ namespace MWGui if (mDragAndDrop->mIsOnDragAndDrop) mDragAndDrop->finish(); - mDragAndDrop->startDrag(i, mSortModel, mTradeModel, mItemView, count); + if (MyGUI::InputManager::getInstance().isAltPressed()) + { + const MWWorld::Ptr item = mTradeModel->getItem(i).mBase; + MWBase::Environment::get().getWindowManager()->playSound(item.getClass().getDownSoundId(item)); + mItemView->update(); + } + else + { + mDragAndDrop->startDrag(i, mSortModel, mTradeModel, mItemView, count); + } MWBase::Environment::get().getWindowManager()->updateSpellWindow(); } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 15c93d14eb..2dc25144d5 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -8,6 +8,8 @@ #include "../mwworld/containerstore.hpp" #include "../mwworld/ptr.hpp" +#include + namespace osg { class Group; @@ -30,14 +32,18 @@ namespace MWGui class TradeItemModel; class DragAndDrop; class ItemModel; + class ItemTransfer; class InventoryWindow : public WindowPinnableBase, public MWWorld::ContainerStoreListener { public: - InventoryWindow(DragAndDrop* dragAndDrop, osg::Group* parent, Resource::ResourceSystem* resourceSystem); + explicit InventoryWindow(DragAndDrop& dragAndDrop, ItemTransfer& itemTransfer, osg::Group* parent, + Resource::ResourceSystem* resourceSystem); void onOpen() override; + void onClose() override; + /// start trading, disables item drag&drop void setTrading(bool trading); @@ -75,7 +81,8 @@ namespace MWGui void onTitleDoubleClicked() override; private: - DragAndDrop* mDragAndDrop; + Misc::NotNullPtr mDragAndDrop; + Misc::NotNullPtr mItemTransfer; int mSelectedItem; std::optional mEquippedStackableCount; @@ -122,6 +129,7 @@ namespace MWGui void sellItem(MyGUI::Widget* sender, std::size_t count); void dragItem(MyGUI::Widget* sender, std::size_t count); + void transferItem(MyGUI::Widget* sender, std::size_t count); void onWindowResize(MyGUI::Window* _sender); void onFilterChanged(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/itemtransfer.hpp b/apps/openmw/mwgui/itemtransfer.hpp new file mode 100644 index 0000000000..fbd37bf136 --- /dev/null +++ b/apps/openmw/mwgui/itemtransfer.hpp @@ -0,0 +1,78 @@ +#ifndef OPENMW_APPS_OPENMW_MWGUI_ITEMTRANSFER_H +#define OPENMW_APPS_OPENMW_MWGUI_ITEMTRANSFER_H + +#include "inventorywindow.hpp" +#include "itemmodel.hpp" +#include "itemview.hpp" +#include "windowmanagerimp.hpp" +#include "worlditemmodel.hpp" + +#include +#include + +#include + +#include + +namespace MWGui +{ + class ItemTransfer + { + public: + explicit ItemTransfer(WindowManager& windowManager) + : mWindowManager(&windowManager) + { + } + + void addTarget(ItemView& view) { mTargets.insert(&view); } + + void removeTarget(ItemView& view) { mTargets.erase(&view); } + + void apply(const ItemStack& item, std::size_t count, ItemView& sourceView) + { + if (item.mFlags & ItemStack::Flag_Bound) + { + mWindowManager->messageBox("#{sBarterDialog12}"); + return; + } + + ItemView* targetView = nullptr; + + for (ItemView* const view : mTargets) + { + if (view == &sourceView) + continue; + + if (targetView != nullptr) + { + mWindowManager->messageBox("#{sContentsMessage2}"); + return; + } + + targetView = view; + } + + WorldItemModel worldItemModel(0.5f, 0.5f); + ItemModel* const targetModel = targetView == nullptr ? &worldItemModel : targetView->getModel(); + + if (!targetModel->onDropItem(item.mBase, count)) + return; + + sourceView.getModel()->moveItem(item, count, targetModel); + + if (targetView != nullptr) + targetView->update(); + + sourceView.update(); + + mWindowManager->getInventoryWindow()->updateItemView(); + mWindowManager->playSound(item.mBase.getClass().getDownSoundId(item.mBase)); + } + + private: + Misc::NotNullPtr mWindowManager; + std::unordered_set mTargets; + }; +} + +#endif diff --git a/apps/openmw/mwgui/itemview.hpp b/apps/openmw/mwgui/itemview.hpp index cfbc8a37ac..aeed0a9113 100644 --- a/apps/openmw/mwgui/itemview.hpp +++ b/apps/openmw/mwgui/itemview.hpp @@ -17,6 +17,8 @@ namespace MWGui /// Register needed components with MyGUI's factory manager static void registerComponents(); + ItemModel* getModel() { return mModel.get(); } + /// Takes ownership of \a model void setModel(std::unique_ptr model); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 4ff297dd94..c7c4b575a5 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -93,6 +93,7 @@ #include "hud.hpp" #include "inventorywindow.hpp" #include "itemchargeview.hpp" +#include "itemtransfer.hpp" #include "itemview.hpp" #include "itemwidget.hpp" #include "jailscreen.hpp" @@ -312,6 +313,7 @@ namespace MWGui mTextColours.loadColours(); mDragAndDrop = std::make_unique(); + mItemTransfer = std::make_unique(*this); auto recharge = std::make_unique(); mGuiModeStates[GM_Recharge] = GuiModeState(recharge.get()); @@ -334,7 +336,7 @@ namespace MWGui trackWindow(mStatsWindow, makeStatsWindowSettingValues()); auto inventoryWindow = std::make_unique( - mDragAndDrop.get(), mViewer->getSceneData()->asGroup(), mResourceSystem); + *mDragAndDrop, *mItemTransfer, mViewer->getSceneData()->asGroup(), mResourceSystem); mInventoryWindow = inventoryWindow.get(); mWindows.push_back(std::move(inventoryWindow)); @@ -381,7 +383,7 @@ namespace MWGui mGuiModeStates[GM_Dialogue] = GuiModeState(mDialogueWindow); mTradeWindow->eventTradeDone += MyGUI::newDelegate(mDialogueWindow, &DialogueWindow::onTradeComplete); - auto containerWindow = std::make_unique(mDragAndDrop.get()); + auto containerWindow = std::make_unique(*mDragAndDrop, *mItemTransfer); mContainerWindow = containerWindow.get(); mWindows.push_back(std::move(containerWindow)); trackWindow(mContainerWindow, makeContainerWindowSettingValues()); @@ -457,7 +459,8 @@ namespace MWGui mSoulgemDialog = std::make_unique(mMessageBoxManager.get()); - auto companionWindow = std::make_unique(mDragAndDrop.get(), mMessageBoxManager.get()); + auto companionWindow + = std::make_unique(*mDragAndDrop, *mItemTransfer, mMessageBoxManager.get()); trackWindow(companionWindow.get(), makeCompanionWindowSettingValues()); mGuiModeStates[GM_Companion] = GuiModeState({ mInventoryWindow, companionWindow.get() }); mWindows.push_back(std::move(companionWindow)); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 1a96092b60..b04c648986 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -8,7 +8,6 @@ **/ #include -#include #include #include @@ -118,6 +117,7 @@ namespace MWGui class PostProcessorHud; class JailScreen; class KeyboardNavigation; + class ItemTransfer; class WindowManager : public MWBase::WindowManager { @@ -433,6 +433,7 @@ namespace MWGui Console* mConsole; DialogueWindow* mDialogueWindow; std::unique_ptr mDragAndDrop; + std::unique_ptr mItemTransfer; InventoryWindow* mInventoryWindow; ScrollWindow* mScrollWindow; BookWindow* mBookWindow; diff --git a/apps/openmw/mwgui/worlditemmodel.hpp b/apps/openmw/mwgui/worlditemmodel.hpp new file mode 100644 index 0000000000..137062eeb4 --- /dev/null +++ b/apps/openmw/mwgui/worlditemmodel.hpp @@ -0,0 +1,82 @@ +#ifndef OPENMW_APPS_OPENMW_MWGUI_WORLDITEMMODEL_H +#define OPENMW_APPS_OPENMW_MWGUI_WORLDITEMMODEL_H + +#include "itemmodel.hpp" + +#include +#include + +#include + +#include +#include + +#include + +namespace MWGui +{ + // Makes it possible to use ItemModel::moveItem to move an item from an inventory to the world. + class WorldItemModel : public ItemModel + { + public: + explicit WorldItemModel(float cursorX, float cursorY) + : mCursorX(cursorX) + , mCursorY(cursorY) + { + } + + MWWorld::Ptr dropItemImpl(const ItemStack& item, size_t count, bool copy) + { + MWBase::World& world = *MWBase::Environment::get().getWorld(); + + const MWWorld::Ptr player = world.getPlayerPtr(); + + world.breakInvisibility(player); + + const MWWorld::Ptr dropped = world.canPlaceObject(mCursorX, mCursorY) + ? world.placeObject(item.mBase, mCursorX, mCursorY, count, copy) + : world.dropObjectOnGround(player, item.mBase, count, copy); + + dropped.getCellRef().setOwner(ESM::RefId()); + + return dropped; + } + + MWWorld::Ptr addItem(const ItemStack& item, size_t count, bool /*allowAutoEquip*/) override + { + return dropItemImpl(item, count, false); + } + + MWWorld::Ptr copyItem(const ItemStack& item, size_t count, bool /*allowAutoEquip*/) override + { + return dropItemImpl(item, count, true); + } + + void removeItem(const ItemStack& /*item*/, size_t /*count*/) override + { + throw std::runtime_error("WorldItemModel::removeItem is not implemented"); + } + + ModelIndex getIndex(const ItemStack& /*item*/) override + { + throw std::runtime_error("WorldItemModel::getIndex is not implemented"); + } + + void update() override {} + + size_t getItemCount() override { return 0; } + + ItemStack getItem(ModelIndex /*index*/) override + { + throw std::runtime_error("WorldItemModel::getItem is not implemented"); + } + + bool usesContainer(const MWWorld::Ptr&) override { return false; } + + private: + float mCursorX; + float mCursorY; + }; +} + +#endif diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index 4dcac4def5..c290e2733c 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -244,6 +244,18 @@ namespace MWWorld return std::abs(count); return count; } + + unsigned getAbsCount() const + { + struct Visitor + { + int operator()(const ESM::CellRef& ref) { return ref.mCount; } + int operator()(const ESM4::Reference& ref) { return ref.mCount; } + int operator()(const ESM4::ActorCharacter& ref) { return ref.mCount; } + }; + return static_cast(std::abs(std::visit(Visitor(), mCellRef.mVariant))); + } + void setCount(int value); // Write the content of this CellRef into the given ObjectState From d2c78ee88cc89b41206c7703fed64eef3cdb2bbc Mon Sep 17 00:00:00 2001 From: Kuyondo Date: Sat, 12 Jul 2025 22:14:47 +0800 Subject: [PATCH 213/330] move member var to implementation --- apps/openmw/mwgui/timeadvancer.cpp | 12 +++++++++--- apps/openmw/mwgui/timeadvancer.hpp | 1 - 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/timeadvancer.cpp b/apps/openmw/mwgui/timeadvancer.cpp index abe0a668d4..c4bdc030c2 100644 --- a/apps/openmw/mwgui/timeadvancer.cpp +++ b/apps/openmw/mwgui/timeadvancer.cpp @@ -1,5 +1,11 @@ #include "timeadvancer.hpp" +namespace +{ + // Time per hour tick + constexpr float kProgressStepDelay = 1.0f / 60.0f; +} + namespace MWGui { TimeAdvancer::TimeAdvancer() @@ -7,7 +13,7 @@ namespace MWGui , mCurHour(0) , mHours(1) , mInterruptAt(-1) - , mRemainingTime(mDelay) + , mRemainingTime(kProgressStepDelay) { } @@ -16,7 +22,7 @@ namespace MWGui mHours = hours; mCurHour = 0; mInterruptAt = interruptAt; - mRemainingTime = mDelay; + mRemainingTime = kProgressStepDelay; mRunning = true; } @@ -42,7 +48,7 @@ namespace MWGui while (mRemainingTime <= 0) { - mRemainingTime += mDelay; + mRemainingTime += kProgressStepDelay; ++mCurHour; if (mCurHour <= mHours) diff --git a/apps/openmw/mwgui/timeadvancer.hpp b/apps/openmw/mwgui/timeadvancer.hpp index be19619d25..e69153aed4 100644 --- a/apps/openmw/mwgui/timeadvancer.hpp +++ b/apps/openmw/mwgui/timeadvancer.hpp @@ -32,7 +32,6 @@ namespace MWGui int mHours; int mInterruptAt; - static constexpr float mDelay = 1.0f / 60.0f; float mRemainingTime; }; } From def31cfb05a29fb65e199d45cba97c54358b5ae6 Mon Sep 17 00:00:00 2001 From: Kuyondo Date: Sat, 12 Jul 2025 22:44:28 +0800 Subject: [PATCH 214/330] cleanup --- apps/openmw/mwgui/jailscreen.cpp | 1 - apps/openmw/mwgui/trainingwindow.cpp | 1 - apps/openmw/mwgui/waitdialog.cpp | 1 - 3 files changed, 3 deletions(-) diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index f482ec4de2..2fbaa8d8ac 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -23,7 +23,6 @@ namespace MWGui : WindowBase("openmw_jail_screen.layout") , mDays(1) , mFadeTimeRemaining(0) - , mTimeAdvancer() { getWidget(mProgressBar, "ProgressBar"); diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 94f001f26d..4bde77a552 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -27,7 +27,6 @@ namespace MWGui TrainingWindow::TrainingWindow() : WindowBase("openmw_trainingwindow.layout") - , mTimeAdvancer() { getWidget(mTrainingOptions, "TrainingOptions"); getWidget(mCancelButton, "CancelButton"); diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index f6f1b86214..9609def96d 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -52,7 +52,6 @@ namespace MWGui WaitDialog::WaitDialog() : WindowBase("openmw_wait_dialog.layout") - , mTimeAdvancer() , mSleeping(false) , mHours(1) , mManualHours(1) From 6dd10f16666f06dcbd978844ba42b4d2fb437a4d Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sat, 12 Jul 2025 19:32:32 +0200 Subject: [PATCH 215/330] Prepend new characters so they're first on the list --- apps/openmw/mwstate/charactermanager.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwstate/charactermanager.cpp b/apps/openmw/mwstate/charactermanager.cpp index 6d2583776b..02d993d186 100644 --- a/apps/openmw/mwstate/charactermanager.cpp +++ b/apps/openmw/mwstate/charactermanager.cpp @@ -81,8 +81,7 @@ MWState::Character* MWState::CharacterManager::createCharacter(const std::string path = mPath / test.str(); } - mCharacters.emplace_back(path, mGame); - return &mCharacters.back(); + return &mCharacters.emplace_front(path, mGame); } std::list::iterator MWState::CharacterManager::findCharacter(const MWState::Character* character) From 4150f5fad6ae722cdcea43444efb50d4eb7e0ad2 Mon Sep 17 00:00:00 2001 From: Dave Corley Date: Sat, 1 Feb 2025 03:21:40 -0700 Subject: [PATCH 216/330] FEAT: AddTopic in Lua, close #8334 --- apps/openmw/mwlua/types/player.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/apps/openmw/mwlua/types/player.cpp b/apps/openmw/mwlua/types/player.cpp index 15dc719f2e..2235cfc49c 100644 --- a/apps/openmw/mwlua/types/player.cpp +++ b/apps/openmw/mwlua/types/player.cpp @@ -1,5 +1,6 @@ #include "types.hpp" +#include #include #include @@ -195,6 +196,18 @@ namespace MWLua throw std::runtime_error("Only player and global scripts can toggle teleportation."); MWBase::Environment::get().getWorld()->enableTeleporting(state); }; + player["addTopic"] = [](const Object& player, std::string topicId) { + if (dynamic_cast(&player) && !dynamic_cast(&player)) + throw std::runtime_error("Only player and global scripts may add topics."); + + ESM::RefId topic = ESM::RefId::stringRefId(topicId); + if (!MWBase::Environment::get().getESMStore()->get().search(topic)) + { + throw std::runtime_error("Failed to add topic " + topicId + ": topic record not found"); + } + + MWBase::Environment::get().getDialogueManager()->addTopic(topic); + }; player["sendMenuEvent"] = [context](const Object& player, std::string eventName, const sol::object& eventData) { verifyPlayer(player); context.mLuaEvents->addMenuEvent({ std::move(eventName), LuaUtil::serialize(eventData) }); From 05b12ac8799ed18369a8932dad44c0c89a348761 Mon Sep 17 00:00:00 2001 From: Dave Corley Date: Sat, 1 Feb 2025 04:32:20 -0700 Subject: [PATCH 217/330] CLEANUP: Use more appropriate object types & functions in addTopic binding --- apps/openmw/mwlua/types/player.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwlua/types/player.cpp b/apps/openmw/mwlua/types/player.cpp index 2235cfc49c..25056caa41 100644 --- a/apps/openmw/mwlua/types/player.cpp +++ b/apps/openmw/mwlua/types/player.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "../birthsignbindings.hpp" #include "../luamanagerimp.hpp" @@ -196,14 +197,14 @@ namespace MWLua throw std::runtime_error("Only player and global scripts can toggle teleportation."); MWBase::Environment::get().getWorld()->enableTeleporting(state); }; - player["addTopic"] = [](const Object& player, std::string topicId) { - if (dynamic_cast(&player) && !dynamic_cast(&player)) - throw std::runtime_error("Only player and global scripts may add topics."); + player["addTopic"] = [](const Object& player, std::string_view topicId) { + verifyPlayer(player); - ESM::RefId topic = ESM::RefId::stringRefId(topicId); + ESM::RefId topic = ESM::RefId::deserializeText(topicId); if (!MWBase::Environment::get().getESMStore()->get().search(topic)) { - throw std::runtime_error("Failed to add topic " + topicId + ": topic record not found"); + throw std::runtime_error( + Misc::StringUtils::format("Failed to add topic ", topicId, ": topic record not found")); } MWBase::Environment::get().getDialogueManager()->addTopic(topic); From 8ec4fcbf301d81fc21a3a5b60795400a8ad96a5d Mon Sep 17 00:00:00 2001 From: Dave Corley Date: Sat, 1 Feb 2025 12:01:16 -0700 Subject: [PATCH 218/330] CLEANUP: Actually check the record in question is a topic when using addTopic --- apps/openmw/mwlua/types/player.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwlua/types/player.cpp b/apps/openmw/mwlua/types/player.cpp index 25056caa41..a763575748 100644 --- a/apps/openmw/mwlua/types/player.cpp +++ b/apps/openmw/mwlua/types/player.cpp @@ -201,11 +201,15 @@ namespace MWLua verifyPlayer(player); ESM::RefId topic = ESM::RefId::deserializeText(topicId); - if (!MWBase::Environment::get().getESMStore()->get().search(topic)) - { + const ESM::Dialogue* dialogueRecord + = MWBase::Environment::get().getESMStore()->get().search(topic); + + if (!dialogueRecord) throw std::runtime_error( Misc::StringUtils::format("Failed to add topic ", topicId, ": topic record not found")); - } + else if (dialogueRecord->mType != ESM::Dialogue::Topic) + throw std::runtime_error( + Misc::StringUtils::format("Failed to add topic ", topicId, ": record is not a topic")); MWBase::Environment::get().getDialogueManager()->addTopic(topic); }; From 943cd765e77e370c19353b957aee01dd1202a7f9 Mon Sep 17 00:00:00 2001 From: Dave Corley Date: Thu, 10 Jul 2025 17:25:30 -0700 Subject: [PATCH 219/330] CLEANUP: Update for MR Comments --- apps/openmw/mwlua/types/player.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwlua/types/player.cpp b/apps/openmw/mwlua/types/player.cpp index a763575748..b0912f5bbd 100644 --- a/apps/openmw/mwlua/types/player.cpp +++ b/apps/openmw/mwlua/types/player.cpp @@ -1,13 +1,12 @@ #include "types.hpp" -#include #include #include -#include #include "../birthsignbindings.hpp" #include "../luamanagerimp.hpp" +#include "apps/openmw/mwbase/dialoguemanager.hpp" #include "apps/openmw/mwbase/inputmanager.hpp" #include "apps/openmw/mwbase/journal.hpp" #include "apps/openmw/mwbase/mechanicsmanager.hpp" @@ -205,11 +204,10 @@ namespace MWLua = MWBase::Environment::get().getESMStore()->get().search(topic); if (!dialogueRecord) - throw std::runtime_error( - Misc::StringUtils::format("Failed to add topic ", topicId, ": topic record not found")); - else if (dialogueRecord->mType != ESM::Dialogue::Topic) - throw std::runtime_error( - Misc::StringUtils::format("Failed to add topic ", topicId, ": record is not a topic")); + throw std::runtime_error("Failed to add topic " + std::string(topicId) + ": topic record not found"); + + if (dialogueRecord->mType != ESM::Dialogue::Topic) + throw std::runtime_error("Failed to add topic " + std::string(topicId) + ": record is not a topic"); MWBase::Environment::get().getDialogueManager()->addTopic(topic); }; From ced135bc87f832c611c21c6ed2c2eff006c681c3 Mon Sep 17 00:00:00 2001 From: Dave Corley Date: Fri, 11 Jul 2025 01:47:22 -0700 Subject: [PATCH 220/330] CLEANUP: No, record ids should totally be quoted --- apps/openmw/mwlua/types/player.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwlua/types/player.cpp b/apps/openmw/mwlua/types/player.cpp index b0912f5bbd..e8e0eaebb5 100644 --- a/apps/openmw/mwlua/types/player.cpp +++ b/apps/openmw/mwlua/types/player.cpp @@ -204,10 +204,11 @@ namespace MWLua = MWBase::Environment::get().getESMStore()->get().search(topic); if (!dialogueRecord) - throw std::runtime_error("Failed to add topic " + std::string(topicId) + ": topic record not found"); + throw std::runtime_error( + "Failed to add topic \"" + std::string(topicId) + "\": topic record not found"); if (dialogueRecord->mType != ESM::Dialogue::Topic) - throw std::runtime_error("Failed to add topic " + std::string(topicId) + ": record is not a topic"); + throw std::runtime_error("Failed to add topic \"" + std::string(topicId) + "\": record is not a topic"); MWBase::Environment::get().getDialogueManager()->addTopic(topic); }; From 1abaf706c81879d6cae95a2f0fe5f0717925b3ed Mon Sep 17 00:00:00 2001 From: Dave Corley Date: Sat, 12 Jul 2025 19:37:36 -0700 Subject: [PATCH 221/330] CLEANUP: Bump api revision --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a1d25f9350..a00dafc7ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,7 +82,7 @@ message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) set(OPENMW_VERSION_MINOR 50) set(OPENMW_VERSION_RELEASE 0) -set(OPENMW_LUA_API_REVISION 80) +set(OPENMW_LUA_API_REVISION 81) set(OPENMW_POSTPROCESSING_API_REVISION 3) set(OPENMW_VERSION_COMMITHASH "") From 61ebb4b259652f4267af0f47e12b3936ed318813 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Sun, 13 Jul 2025 02:07:49 -0600 Subject: [PATCH 222/330] Redo debug warnings in interpreter --- apps/openmw/mwscript/interpretercontext.cpp | 66 ++++++++++++++------- 1 file changed, 46 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 15c9100b98..3063e8b6bb 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include "../mwworld/esmstore.hpp" @@ -300,7 +301,16 @@ namespace MWScript std::string_view InterpreterContext::getNPCFaction() const { - const ESM::NPC* npc = getReferenceImp().get()->mBase; + const MWWorld::Ptr& ptr = getReferenceImp(); + const MWWorld::Class& ptrClass = ptr.getClass(); + const ESM::RefId& factionId = ptrClass.getPrimaryFaction(ptr); + if (factionId.empty()) + { + Log(Debug::Warning) << "getNPCFaction(): NPC " << ptrClass.getName(ptr) << " has no primary faction"; + return "%"; + } + + const ESM::NPC* npc = ptr.get()->mBase; const ESM::Faction* faction = MWBase::Environment::get().getESMStore()->get().find(npc->mFaction); return faction->mName; } @@ -308,18 +318,26 @@ namespace MWScript std::string_view InterpreterContext::getNPCRank() const { const MWWorld::Ptr& ptr = getReferenceImp(); - const ESM::RefId& faction = ptr.getClass().getPrimaryFaction(ptr); - if (faction.empty()) - throw std::runtime_error("getNPCRank(): NPC is not in a faction"); - - int rank = ptr.getClass().getPrimaryFactionRank(ptr); - if (rank < 0 || rank > 9) - throw std::runtime_error("getNPCRank(): invalid rank"); + const MWWorld::Class& ptrClass = ptr.getClass(); + const ESM::RefId& factionId = ptrClass.getPrimaryFaction(ptr); + if (factionId.empty()) + { + Log(Debug::Warning) << "getNPCRank(): NPC " << ptrClass.getName(ptr) << " has no primary faction"; + return "%"; + } MWBase::World* world = MWBase::Environment::get().getWorld(); const MWWorld::ESMStore& store = world->getStore(); - const ESM::Faction* fact = store.get().find(faction); - return fact->mRanks[rank]; + const ESM::Faction* faction = store.get().find(factionId); + + int rank = ptrClass.getPrimaryFactionRank(ptr); + if (rank < 0 || rank > 9) + { + Log(Debug::Warning) << "getNPCRank(): NPC " << ptrClass.getName(ptr) << " has invalid rank " << rank + << " in faction " << faction->mName; + return "%"; + } + return faction->mRanks[rank]; } std::string_view InterpreterContext::getPCName() const @@ -344,13 +362,17 @@ namespace MWScript std::string_view InterpreterContext::getPCRank() const { + const MWWorld::Ptr& ptr = getReferenceImp(); + const MWWorld::Class& ptrClass = ptr.getClass(); + const ESM::RefId& factionId = ptrClass.getPrimaryFaction(ptr); + if (factionId.empty()) + { + Log(Debug::Warning) << "getPCRank(): NPC " << ptrClass.getName(ptr) << " has no primary faction"; + return "%"; + } + MWBase::World* world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayerPtr(); - - const ESM::RefId& factionId = getReferenceImp().getClass().getPrimaryFaction(getReferenceImp()); - if (factionId.empty()) - throw std::runtime_error("getPCRank(): NPC is not in a faction"); - const auto& ranks = player.getClass().getNpcStats(player).getFactionRanks(); auto it = ranks.find(factionId); int rank = -1; @@ -373,13 +395,17 @@ namespace MWScript std::string_view InterpreterContext::getPCNextRank() const { + const MWWorld::Ptr& ptr = getReferenceImp(); + const MWWorld::Class& ptrClass = ptr.getClass(); + const ESM::RefId& factionId = ptrClass.getPrimaryFaction(ptr); + if (factionId.empty()) + { + Log(Debug::Warning) << "getPCNextRank(): NPC " << ptrClass.getName(ptr) << " has no primary faction"; + return "%"; + } + MWBase::World* world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayerPtr(); - - const ESM::RefId& factionId = getReferenceImp().getClass().getPrimaryFaction(getReferenceImp()); - if (factionId.empty()) - throw std::runtime_error("getPCNextRank(): NPC is not in a faction"); - const auto& ranks = player.getClass().getNpcStats(player).getFactionRanks(); auto it = ranks.find(factionId); int rank = -1; From cef180753667b0e0eab744cf099c02ea6218caa2 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Sun, 13 Jul 2025 02:30:55 -0600 Subject: [PATCH 223/330] Use RefId instead of name --- apps/openmw/mwscript/interpretercontext.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 3063e8b6bb..dbd139d180 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -306,7 +306,7 @@ namespace MWScript const ESM::RefId& factionId = ptrClass.getPrimaryFaction(ptr); if (factionId.empty()) { - Log(Debug::Warning) << "getNPCFaction(): NPC " << ptrClass.getName(ptr) << " has no primary faction"; + Log(Debug::Warning) << "getNPCFaction(): NPC " << ptr.mRef->mRef.getRefId() << " has no primary faction"; return "%"; } @@ -322,7 +322,7 @@ namespace MWScript const ESM::RefId& factionId = ptrClass.getPrimaryFaction(ptr); if (factionId.empty()) { - Log(Debug::Warning) << "getNPCRank(): NPC " << ptrClass.getName(ptr) << " has no primary faction"; + Log(Debug::Warning) << "getNPCRank(): NPC " << ptr.mRef->mRef.getRefId() << " has no primary faction"; return "%"; } @@ -333,7 +333,7 @@ namespace MWScript int rank = ptrClass.getPrimaryFactionRank(ptr); if (rank < 0 || rank > 9) { - Log(Debug::Warning) << "getNPCRank(): NPC " << ptrClass.getName(ptr) << " has invalid rank " << rank + Log(Debug::Warning) << "getNPCRank(): NPC " << ptr.mRef->mRef.getRefId() << " has invalid rank " << rank << " in faction " << faction->mName; return "%"; } @@ -367,7 +367,7 @@ namespace MWScript const ESM::RefId& factionId = ptrClass.getPrimaryFaction(ptr); if (factionId.empty()) { - Log(Debug::Warning) << "getPCRank(): NPC " << ptrClass.getName(ptr) << " has no primary faction"; + Log(Debug::Warning) << "getPCRank(): NPC " << ptr.mRef->mRef.getRefId() << " has no primary faction"; return "%"; } @@ -400,7 +400,7 @@ namespace MWScript const ESM::RefId& factionId = ptrClass.getPrimaryFaction(ptr); if (factionId.empty()) { - Log(Debug::Warning) << "getPCNextRank(): NPC " << ptrClass.getName(ptr) << " has no primary faction"; + Log(Debug::Warning) << "getPCNextRank(): NPC " << ptr.mRef->mRef.getRefId() << " has no primary faction"; return "%"; } From 87e41425bb1bb7e6cb9e4fedf801eb4b20cdc4df Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Sun, 13 Jul 2025 02:36:16 -0600 Subject: [PATCH 224/330] Unnecessary ptrClass --- apps/openmw/mwscript/interpretercontext.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index dbd139d180..d24420ec91 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -302,8 +302,7 @@ namespace MWScript std::string_view InterpreterContext::getNPCFaction() const { const MWWorld::Ptr& ptr = getReferenceImp(); - const MWWorld::Class& ptrClass = ptr.getClass(); - const ESM::RefId& factionId = ptrClass.getPrimaryFaction(ptr); + const ESM::RefId& factionId = ptr.getClass().getPrimaryFaction(ptr); if (factionId.empty()) { Log(Debug::Warning) << "getNPCFaction(): NPC " << ptr.mRef->mRef.getRefId() << " has no primary faction"; @@ -363,8 +362,7 @@ namespace MWScript std::string_view InterpreterContext::getPCRank() const { const MWWorld::Ptr& ptr = getReferenceImp(); - const MWWorld::Class& ptrClass = ptr.getClass(); - const ESM::RefId& factionId = ptrClass.getPrimaryFaction(ptr); + const ESM::RefId& factionId = ptr.getClass().getPrimaryFaction(ptr); if (factionId.empty()) { Log(Debug::Warning) << "getPCRank(): NPC " << ptr.mRef->mRef.getRefId() << " has no primary faction"; @@ -396,8 +394,7 @@ namespace MWScript std::string_view InterpreterContext::getPCNextRank() const { const MWWorld::Ptr& ptr = getReferenceImp(); - const MWWorld::Class& ptrClass = ptr.getClass(); - const ESM::RefId& factionId = ptrClass.getPrimaryFaction(ptr); + const ESM::RefId& factionId = ptr.getClass().getPrimaryFaction(ptr); if (factionId.empty()) { Log(Debug::Warning) << "getPCNextRank(): NPC " << ptr.mRef->mRef.getRefId() << " has no primary faction"; From 11947286d937e41c572e420a0eca709305e2d82e Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Sun, 13 Jul 2025 02:36:59 -0600 Subject: [PATCH 225/330] Reuse factionId --- apps/openmw/mwscript/interpretercontext.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index d24420ec91..7d71f3607c 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -309,8 +309,9 @@ namespace MWScript return "%"; } - const ESM::NPC* npc = ptr.get()->mBase; - const ESM::Faction* faction = MWBase::Environment::get().getESMStore()->get().find(npc->mFaction); + MWBase::World* world = MWBase::Environment::get().getWorld(); + const MWWorld::ESMStore& store = world->getStore(); + const ESM::Faction* faction = store.get().find(factionId); return faction->mName; } From bb1214ed69f855874f9fc13296cb65025e26b3c7 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Sun, 13 Jul 2025 02:48:37 -0600 Subject: [PATCH 226/330] factionId instead of faction->mName --- apps/openmw/mwscript/interpretercontext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 7d71f3607c..546968ebf7 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -334,7 +334,7 @@ namespace MWScript if (rank < 0 || rank > 9) { Log(Debug::Warning) << "getNPCRank(): NPC " << ptr.mRef->mRef.getRefId() << " has invalid rank " << rank - << " in faction " << faction->mName; + << " in faction " << factionId; return "%"; } return faction->mRanks[rank]; From 2dbe30ed5c790b0aed862a3dd90dca1e3d076c80 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Thu, 23 May 2024 17:15:56 +0200 Subject: [PATCH 227/330] Update effects upon applying them --- apps/openmw/mwmechanics/activespells.cpp | 258 +++++++++++++---------- apps/openmw/mwmechanics/activespells.hpp | 8 +- apps/openmw/mwmechanics/spellcasting.cpp | 4 - apps/openmw/mwmechanics/spelleffects.cpp | 6 +- 4 files changed, 156 insertions(+), 120 deletions(-) diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 270faf8598..f9b7ec57ea 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -73,6 +73,20 @@ namespace namespace MWMechanics { + struct ActiveSpells::UpdateContext + { + bool mUpdatedEnemy = false; + bool mUpdatedHitOverlay = false; + bool mUpdateSpellWindow = false; + bool mPlayNonLooping = false; + bool mUpdate; + + UpdateContext(bool update) + : mUpdate(update) + { + } + }; + ActiveSpells::IterationGuard::IterationGuard(ActiveSpells& spells) : mActiveSpells(spells) { @@ -256,8 +270,9 @@ namespace MWMechanics ++spellIt; } + UpdateContext context(duration > 0.f); for (const auto& spell : mQueue) - addToSpells(ptr, spell); + addToSpells(ptr, spell, context); mQueue.clear(); // Vanilla only does this on cell change I think @@ -267,20 +282,17 @@ namespace MWMechanics if (spell->mData.mType != ESM::Spell::ST_Spell && spell->mData.mType != ESM::Spell::ST_Power && !isSpellActive(spell->mId)) { - mSpells.emplace_back(ActiveSpellParams{ spell, ptr, true }); - mSpells.back().setActiveSpellId(MWBase::Environment::get().getESMStore()->generateId()); + initParams(ptr, ActiveSpellParams{ spell, ptr, true }, context); } } - bool updateSpellWindow = false; - bool playNonLooping = false; if (ptr.getClass().hasInventoryStore(ptr) && !(creatureStats.isDead() && !creatureStats.isDeathAnimationFinished())) { auto& store = ptr.getClass().getInventoryStore(ptr); if (store.getInvListener() != nullptr) { - playNonLooping = !store.isFirstEquip(); + context.mPlayNonLooping = !store.isFirstEquip(); const auto world = MWBase::Environment::get().getWorld(); for (int slotIndex = 0; slotIndex < MWWorld::InventoryStore::Slots; slotIndex++) { @@ -306,117 +318,18 @@ namespace MWMechanics // invisibility manually purgeEffect(ptr, ESM::MagicEffect::Invisibility); applyPurges(ptr); - ActiveSpellParams& params = mSpells.emplace_back(ActiveSpellParams{ *slot, enchantment, ptr }); - params.setActiveSpellId(MWBase::Environment::get().getESMStore()->generateId()); - updateSpellWindow = true; + ActiveSpellParams* params = initParams(ptr, ActiveSpellParams{ *slot, enchantment, ptr }, context); + if (params) + context.mUpdateSpellWindow = true; } } } const MWWorld::Ptr player = MWMechanics::getPlayer(); - bool updatedHitOverlay = false; - bool updatedEnemy = false; // Update effects for (auto spellIt = mSpells.begin(); spellIt != mSpells.end();) { - const auto caster = MWBase::Environment::get().getWorld()->searchPtrViaActorId( - spellIt->mCasterActorId); // Maybe make this search outside active grid? - bool removedSpell = false; - std::optional reflected; - for (auto it = spellIt->mEffects.begin(); it != spellIt->mEffects.end();) - { - auto result = applyMagicEffect(ptr, caster, *spellIt, *it, duration, playNonLooping); - if (result.mType == MagicApplicationResult::Type::REFLECTED) - { - if (!reflected) - { - if (Settings::game().mClassicReflectedAbsorbSpellsBehavior) - reflected = { *spellIt, caster }; - else - reflected = { *spellIt, ptr }; - } - auto& reflectedEffect = reflected->mEffects.emplace_back(*it); - reflectedEffect.mFlags - = ESM::ActiveEffect::Flag_Ignore_Reflect | ESM::ActiveEffect::Flag_Ignore_SpellAbsorption; - it = spellIt->mEffects.erase(it); - } - else if (result.mType == MagicApplicationResult::Type::REMOVED) - it = spellIt->mEffects.erase(it); - else - { - ++it; - if (!updatedEnemy && result.mShowHealth && caster == player && ptr != player) - { - MWBase::Environment::get().getWindowManager()->setEnemy(ptr); - updatedEnemy = true; - } - if (!updatedHitOverlay && result.mShowHit && ptr == player) - { - MWBase::Environment::get().getWindowManager()->activateHitOverlay(false); - updatedHitOverlay = true; - } - } - removedSpell = applyPurges(ptr, &spellIt, &it); - if (removedSpell) - break; - } - if (reflected) - { - const ESM::Static* reflectStatic = MWBase::Environment::get().getESMStore()->get().find( - ESM::RefId::stringRefId("VFX_Reflect")); - MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(ptr); - if (animation && !reflectStatic->mModel.empty()) - { - const VFS::Path::Normalized reflectStaticModel - = Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(reflectStatic->mModel)); - animation->addEffect( - reflectStaticModel, ESM::MagicEffect::indexToName(ESM::MagicEffect::Reflect), false); - } - caster.getClass().getCreatureStats(caster).getActiveSpells().addSpell(*reflected); - } - if (removedSpell) - continue; - - bool remove = false; - if (spellIt->hasFlag(ESM::ActiveSpells::Flag_SpellStore)) - { - try - { - remove = !spells.hasSpell(spellIt->mSourceSpellId); - } - catch (const std::runtime_error& e) - { - remove = true; - Log(Debug::Error) << "Removing active effect: " << e.what(); - } - } - else if (spellIt->hasFlag(ESM::ActiveSpells::Flag_Equipment)) - { - // Remove effects tied to equipment that has been unequipped - const auto& store = ptr.getClass().getInventoryStore(ptr); - remove = true; - for (int slotIndex = 0; slotIndex < MWWorld::InventoryStore::Slots; slotIndex++) - { - auto slot = store.getSlot(slotIndex); - if (slot != store.end() && slot->getCellRef().getRefNum().isSet() - && slot->getCellRef().getRefNum() == spellIt->mItem) - { - remove = false; - break; - } - } - } - if (remove) - { - auto params = *spellIt; - spellIt = mSpells.erase(spellIt); - for (const auto& effect : params.mEffects) - onMagicEffectRemoved(ptr, params, effect); - applyPurges(ptr, &spellIt); - updateSpellWindow = true; - continue; - } - ++spellIt; + updateActiveSpell(ptr, duration, spellIt, context); } if (Settings::game().mClassicCalmSpellsBehavior) @@ -427,7 +340,7 @@ namespace MWMechanics creatureStats.getAiSequence().stopCombat(); } - if (ptr == player && updateSpellWindow) + if (ptr == player && context.mUpdateSpellWindow) { // Something happened with the spell list -- possibly while the game is paused, // so we want to make the spell window get the memo. @@ -436,7 +349,125 @@ namespace MWMechanics } } - void ActiveSpells::addToSpells(const MWWorld::Ptr& ptr, const ActiveSpellParams& spell) + bool ActiveSpells::updateActiveSpell( + const MWWorld::Ptr& ptr, float duration, Collection::iterator& spellIt, UpdateContext& context) + { + const auto caster = MWBase::Environment::get().getWorld()->searchPtrViaActorId( + spellIt->mCasterActorId); // Maybe make this search outside active grid? + bool removedSpell = false; + std::optional reflected; + for (auto it = spellIt->mEffects.begin(); it != spellIt->mEffects.end();) + { + auto result = applyMagicEffect(ptr, caster, *spellIt, *it, duration, context.mPlayNonLooping); + if (result.mType == MagicApplicationResult::Type::REFLECTED) + { + if (!reflected) + { + if (Settings::game().mClassicReflectedAbsorbSpellsBehavior) + reflected = { *spellIt, caster }; + else + reflected = { *spellIt, ptr }; + } + auto& reflectedEffect = reflected->mEffects.emplace_back(*it); + reflectedEffect.mFlags + = ESM::ActiveEffect::Flag_Ignore_Reflect | ESM::ActiveEffect::Flag_Ignore_SpellAbsorption; + it = spellIt->mEffects.erase(it); + } + else if (result.mType == MagicApplicationResult::Type::REMOVED) + it = spellIt->mEffects.erase(it); + else + { + const MWWorld::Ptr player = MWMechanics::getPlayer(); + ++it; + if (!context.mUpdatedEnemy && result.mShowHealth && caster == player && ptr != player) + { + MWBase::Environment::get().getWindowManager()->setEnemy(ptr); + context.mUpdatedEnemy = true; + } + if (!context.mUpdatedHitOverlay && result.mShowHit && ptr == player) + { + MWBase::Environment::get().getWindowManager()->activateHitOverlay(false); + context.mUpdatedHitOverlay = true; + } + } + removedSpell = applyPurges(ptr, &spellIt, &it); + if (removedSpell) + break; + } + if (reflected) + { + const ESM::Static* reflectStatic = MWBase::Environment::get().getESMStore()->get().find( + ESM::RefId::stringRefId("VFX_Reflect")); + MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(ptr); + if (animation && !reflectStatic->mModel.empty()) + { + const VFS::Path::Normalized reflectStaticModel + = Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(reflectStatic->mModel)); + animation->addEffect( + reflectStaticModel, ESM::MagicEffect::indexToName(ESM::MagicEffect::Reflect), false); + } + caster.getClass().getCreatureStats(caster).getActiveSpells().addSpell(*reflected); + } + if (removedSpell) + return true; + + bool remove = false; + if (spellIt->hasFlag(ESM::ActiveSpells::Flag_SpellStore)) + { + try + { + auto& spells = ptr.getClass().getCreatureStats(ptr).getSpells(); + remove = !spells.hasSpell(spellIt->mSourceSpellId); + } + catch (const std::runtime_error& e) + { + remove = true; + Log(Debug::Error) << "Removing active effect: " << e.what(); + } + } + else if (spellIt->hasFlag(ESM::ActiveSpells::Flag_Equipment)) + { + // Remove effects tied to equipment that has been unequipped + const auto& store = ptr.getClass().getInventoryStore(ptr); + remove = true; + for (int slotIndex = 0; slotIndex < MWWorld::InventoryStore::Slots; slotIndex++) + { + auto slot = store.getSlot(slotIndex); + if (slot != store.end() && slot->getCellRef().getRefNum().isSet() + && slot->getCellRef().getRefNum() == spellIt->mItem) + { + remove = false; + break; + } + } + } + if (remove) + { + auto params = *spellIt; + spellIt = mSpells.erase(spellIt); + for (const auto& effect : params.mEffects) + onMagicEffectRemoved(ptr, params, effect); + applyPurges(ptr, &spellIt); + context.mUpdateSpellWindow = true; + return true; + } + ++spellIt; + return false; + } + + ActiveSpells::ActiveSpellParams* ActiveSpells::initParams( + const MWWorld::Ptr& ptr, const ActiveSpellParams& params, UpdateContext& context) + { + mSpells.emplace_back(params).setActiveSpellId(MWBase::Environment::get().getESMStore()->generateId()); + auto it = mSpells.end(); + --it; + // We instantly apply the effect with a duration of 0 so continuous effects can be purged before truly applying + if (context.mUpdate && updateActiveSpell(ptr, 0.f, it, context)) + return nullptr; + return &*it; + } + + void ActiveSpells::addToSpells(const MWWorld::Ptr& ptr, const ActiveSpellParams& spell, UpdateContext& context) { if (!spell.hasFlag(ESM::ActiveSpells::Flag_Stackable)) { @@ -454,8 +485,7 @@ namespace MWMechanics onMagicEffectRemoved(ptr, params, effect); } } - mSpells.emplace_back(spell); - mSpells.back().setActiveSpellId(MWBase::Environment::get().getESMStore()->generateId()); + initParams(ptr, spell, context); } ActiveSpells::ActiveSpells() @@ -608,6 +638,8 @@ namespace MWMechanics { purge( [=](const ActiveSpellParams&, const ESM::ActiveEffect& effect) { + if (!(effect.mFlags & ESM::ActiveEffect::Flag_Applied)) + return false; if (effectArg.empty()) return effect.mEffectId == effectId; return effect.mEffectId == effectId && effect.getSkillOrAttribute() == effectArg; diff --git a/apps/openmw/mwmechanics/activespells.hpp b/apps/openmw/mwmechanics/activespells.hpp index 3e4dafdb26..465e5aa456 100644 --- a/apps/openmw/mwmechanics/activespells.hpp +++ b/apps/openmw/mwmechanics/activespells.hpp @@ -116,17 +116,23 @@ namespace MWMechanics IterationGuard(ActiveSpells& spells); ~IterationGuard(); }; + struct UpdateContext; std::list mSpells; std::vector mQueue; std::queue mPurges; bool mIterating; - void addToSpells(const MWWorld::Ptr& ptr, const ActiveSpellParams& spell); + void addToSpells(const MWWorld::Ptr& ptr, const ActiveSpellParams& spell, UpdateContext& context); bool applyPurges(const MWWorld::Ptr& ptr, std::list::iterator* currentSpell = nullptr, std::vector::iterator* currentEffect = nullptr); + bool updateActiveSpell( + const MWWorld::Ptr& ptr, float duration, Collection::iterator& spellIt, UpdateContext& context); + + ActiveSpellParams* initParams(const MWWorld::Ptr& ptr, const ActiveSpellParams& params, UpdateContext& context); + public: ActiveSpells(); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 59e7e29a38..bf9d6aa025 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -215,10 +215,6 @@ namespace MWMechanics bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration); effect.mDuration = hasDuration ? static_cast(enam.mData.mDuration) : 1.f; - bool appliedOnce = magicEffect->mData.mFlags & ESM::MagicEffect::AppliedOnce; - if (!appliedOnce) - effect.mDuration = std::max(1.f, effect.mDuration); - effect.mTimeLeft = effect.mDuration; // add to list of active effects, to apply in next frame diff --git a/apps/openmw/mwmechanics/spelleffects.cpp b/apps/openmw/mwmechanics/spelleffects.cpp index 99e5a09481..822c394352 100644 --- a/apps/openmw/mwmechanics/spelleffects.cpp +++ b/apps/openmw/mwmechanics/spelleffects.cpp @@ -1011,11 +1011,13 @@ namespace MWMechanics else { // Morrowind.exe doesn't apply magic effects while the menu is open, we do because we like to see stats - // updated instantly. We don't want to teleport instantly though + // updated instantly. We don't want to teleport instantly though. Nor do we want to force players to drink + // invisibility potions in the "right" order if (!dt && (effect.mEffectId == ESM::MagicEffect::Recall || effect.mEffectId == ESM::MagicEffect::DivineIntervention - || effect.mEffectId == ESM::MagicEffect::AlmsiviIntervention)) + || effect.mEffectId == ESM::MagicEffect::AlmsiviIntervention + || effect.mEffectId == ESM::MagicEffect::Invisibility)) return { MagicApplicationResult::Type::APPLIED, receivedMagicDamage, affectedHealth }; auto& stats = target.getClass().getCreatureStats(target); auto& magnitudes = stats.getMagicEffects(); From c80b3d26b9cb0b8198b6d12364e0fb632b37019c Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 13 Jul 2025 11:18:15 +0200 Subject: [PATCH 228/330] Only check for spelllist/equipment changes in the update loop --- apps/openmw/mwmechanics/activespells.cpp | 73 +++++++++++++----------- 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index f9b7ec57ea..7a4369a464 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -79,6 +79,7 @@ namespace MWMechanics bool mUpdatedHitOverlay = false; bool mUpdateSpellWindow = false; bool mPlayNonLooping = false; + bool mEraseRemoved = false; bool mUpdate; UpdateContext(bool update) @@ -327,6 +328,7 @@ namespace MWMechanics const MWWorld::Ptr player = MWMechanics::getPlayer(); // Update effects + context.mEraseRemoved = true; for (auto spellIt = mSpells.begin(); spellIt != mSpells.end();) { updateActiveSpell(ptr, duration, spellIt, context); @@ -411,45 +413,48 @@ namespace MWMechanics if (removedSpell) return true; - bool remove = false; - if (spellIt->hasFlag(ESM::ActiveSpells::Flag_SpellStore)) + if (context.mEraseRemoved) { - try + bool remove = false; + if (spellIt->hasFlag(ESM::ActiveSpells::Flag_SpellStore)) { - auto& spells = ptr.getClass().getCreatureStats(ptr).getSpells(); - remove = !spells.hasSpell(spellIt->mSourceSpellId); - } - catch (const std::runtime_error& e) - { - remove = true; - Log(Debug::Error) << "Removing active effect: " << e.what(); - } - } - else if (spellIt->hasFlag(ESM::ActiveSpells::Flag_Equipment)) - { - // Remove effects tied to equipment that has been unequipped - const auto& store = ptr.getClass().getInventoryStore(ptr); - remove = true; - for (int slotIndex = 0; slotIndex < MWWorld::InventoryStore::Slots; slotIndex++) - { - auto slot = store.getSlot(slotIndex); - if (slot != store.end() && slot->getCellRef().getRefNum().isSet() - && slot->getCellRef().getRefNum() == spellIt->mItem) + try { - remove = false; - break; + auto& spells = ptr.getClass().getCreatureStats(ptr).getSpells(); + remove = !spells.hasSpell(spellIt->mSourceSpellId); + } + catch (const std::runtime_error& e) + { + remove = true; + Log(Debug::Error) << "Removing active effect: " << e.what(); } } - } - if (remove) - { - auto params = *spellIt; - spellIt = mSpells.erase(spellIt); - for (const auto& effect : params.mEffects) - onMagicEffectRemoved(ptr, params, effect); - applyPurges(ptr, &spellIt); - context.mUpdateSpellWindow = true; - return true; + else if (spellIt->hasFlag(ESM::ActiveSpells::Flag_Equipment)) + { + // Remove effects tied to equipment that has been unequipped + const auto& store = ptr.getClass().getInventoryStore(ptr); + remove = true; + for (int slotIndex = 0; slotIndex < MWWorld::InventoryStore::Slots; slotIndex++) + { + auto slot = store.getSlot(slotIndex); + if (slot != store.end() && slot->getCellRef().getRefNum().isSet() + && slot->getCellRef().getRefNum() == spellIt->mItem) + { + remove = false; + break; + } + } + } + if (remove) + { + auto params = *spellIt; + spellIt = mSpells.erase(spellIt); + for (const auto& effect : params.mEffects) + onMagicEffectRemoved(ptr, params, effect); + applyPurges(ptr, &spellIt); + context.mUpdateSpellWindow = true; + return true; + } } ++spellIt; return false; From 119a87b7f4189252ef61a9bdfaca4c8e8b500bab Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sun, 13 Jul 2025 18:02:15 +0300 Subject: [PATCH 229/330] Revert "Merge branch 'tbcornottbcwaititstcbactually' into 'master'" This reverts merge request !4539 --- components/nif/nifkey.hpp | 92 ++++++++------------------------ components/nifosg/controller.hpp | 2 +- 2 files changed, 23 insertions(+), 71 deletions(-) diff --git a/components/nif/nifkey.hpp b/components/nif/nifkey.hpp index bd362101c6..604cf92c33 100644 --- a/components/nif/nifkey.hpp +++ b/components/nif/nifkey.hpp @@ -3,9 +3,7 @@ #ifndef OPENMW_COMPONENTS_NIF_NIFKEY_HPP #define OPENMW_COMPONENTS_NIF_NIFKEY_HPP -#include #include -#include #include "exception.hpp" #include "niffile.hpp" @@ -19,7 +17,7 @@ namespace Nif InterpolationType_Unknown = 0, InterpolationType_Linear = 1, InterpolationType_Quadratic = 2, - InterpolationType_TCB = 3, + InterpolationType_TBC = 3, InterpolationType_XYZ = 4, InterpolationType_Constant = 5 }; @@ -30,19 +28,18 @@ namespace Nif T mValue; T mInTan; // Only for Quadratic interpolation, and never for QuaternionKeyList T mOutTan; // Only for Quadratic interpolation, and never for QuaternionKeyList - }; - template - struct TCBKey - { - float mTime; - T mValue{}; - T mInTan{}; - T mOutTan{}; - float mTension; - float mContinuity; - float mBias; + // FIXME: Implement TBC interpolation + /* + float mTension; // Only for TBC interpolation + float mBias; // Only for TBC interpolation + float mContinuity; // Only for TBC interpolation + */ }; + using FloatKey = KeyT; + using Vector3Key = KeyT; + using Vector4Key = KeyT; + using QuaternionKey = KeyT; template struct KeyMapT @@ -104,20 +101,15 @@ namespace Nif mKeys[time] = key; } } - else if (mInterpolationType == InterpolationType_TCB) + else if (mInterpolationType == InterpolationType_TBC) { - std::vector> tcbKeys(count); - for (TCBKey& key : tcbKeys) + for (size_t i = 0; i < count; i++) { - nif->read(key.mTime); - key.mValue = ((*nif).*getValue)(); - nif->read(key.mTension); - nif->read(key.mContinuity); - nif->read(key.mBias); + float time; + nif->read(time); + readTBC(*nif, key); + mKeys[time] = key; } - generateTCBTangents(tcbKeys); - for (TCBKey& key : tcbKeys) - mKeys[key.mTime] = KeyType{ std::move(key.mValue), std::move(key.mInTan), std::move(key.mOutTan) }; } else if (mInterpolationType == InterpolationType_XYZ) { @@ -148,52 +140,12 @@ namespace Nif static void readQuadratic(NIFStream& nif, KeyT& key) { readValue(nif, key); } - template - static void generateTCBTangents(std::vector>& keys) + static void readTBC(NIFStream& nif, KeyT& key) { - if (keys.size() <= 1) - return; - - std::sort(keys.begin(), keys.end(), [](const auto& a, const auto& b) { return a.mTime < b.mTime; }); - for (size_t i = 0; i < keys.size(); ++i) - { - TCBKey& curr = keys[i]; - const TCBKey& prev = (i == 0) ? curr : keys[i - 1]; - const TCBKey& next = (i == keys.size() - 1) ? curr : keys[i + 1]; - const float prevLen = curr.mTime - prev.mTime; - const float nextLen = next.mTime - curr.mTime; - if (prevLen + nextLen <= 0.f) - continue; - - const U prevDelta = curr.mValue - prev.mValue; - const U nextDelta = next.mValue - curr.mValue; - const float t = curr.mTension; - const float c = curr.mContinuity; - const float b = curr.mBias; - - U x{}, y{}, z{}, w{}; - if (prevLen > 0.f) - x = prevDelta / prevLen * (1 - t) * (1 - c) * (1 + b); - if (nextLen > 0.f) - y = nextDelta / nextLen * (1 - t) * (1 + c) * (1 - b); - if (prevLen > 0.f) - z = prevDelta / prevLen * (1 - t) * (1 + c) * (1 + b); - if (nextLen > 0.f) - w = nextDelta / nextLen * (1 - t) * (1 - c) * (1 - b); - - curr.mInTan = (x + y) * prevLen / (prevLen + nextLen); - curr.mOutTan = (z + w) * nextLen / (prevLen + nextLen); - } - } - - static void generateTCBTangents(std::vector>& keys) - { - // TODO: is this even legal? - } - - static void generateTCBTangents(std::vector>& keys) - { - // TODO: implement TCB interpolation for quaternions + readValue(nif, key); + /*key.mTension = */ nif.get(); + /*key.mBias = */ nif.get(); + /*key.mContinuity = */ nif.get(); } }; using FloatKeyMap = KeyMapT>; diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 468668ce76..99d3df9545 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -131,7 +131,6 @@ namespace NifOsg case Nif::InterpolationType_Constant: return fraction > 0.5f ? b.mValue : a.mValue; case Nif::InterpolationType_Quadratic: - case Nif::InterpolationType_TCB: { // Using a cubic Hermite spline. // b1(t) = 2t^3 - 3t^2 + 1 @@ -148,6 +147,7 @@ namespace NifOsg const float b4 = t3 - t2; return a.mValue * b1 + b.mValue * b2 + a.mOutTan * b3 + b.mInTan * b4; } + // TODO: Implement TBC interpolation default: return a.mValue + ((b.mValue - a.mValue) * fraction); } From 445cf1742de45836350bcff0ce560c6df6f15af0 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Sun, 13 Jul 2025 10:20:58 -0600 Subject: [PATCH 230/330] ptr.getCellRef().getRefId() --- apps/openmw/mwscript/interpretercontext.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 546968ebf7..f6c20c9c10 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -305,7 +305,7 @@ namespace MWScript const ESM::RefId& factionId = ptr.getClass().getPrimaryFaction(ptr); if (factionId.empty()) { - Log(Debug::Warning) << "getNPCFaction(): NPC " << ptr.mRef->mRef.getRefId() << " has no primary faction"; + Log(Debug::Warning) << "getNPCFaction(): NPC " << ptr.getCellRef().getRefId() << " has no primary faction"; return "%"; } @@ -322,7 +322,7 @@ namespace MWScript const ESM::RefId& factionId = ptrClass.getPrimaryFaction(ptr); if (factionId.empty()) { - Log(Debug::Warning) << "getNPCRank(): NPC " << ptr.mRef->mRef.getRefId() << " has no primary faction"; + Log(Debug::Warning) << "getNPCRank(): NPC " << ptr.getCellRef().getRefId() << " has no primary faction"; return "%"; } @@ -333,7 +333,7 @@ namespace MWScript int rank = ptrClass.getPrimaryFactionRank(ptr); if (rank < 0 || rank > 9) { - Log(Debug::Warning) << "getNPCRank(): NPC " << ptr.mRef->mRef.getRefId() << " has invalid rank " << rank + Log(Debug::Warning) << "getNPCRank(): NPC " << ptr.getCellRef().getRefId() << " has invalid rank " << rank << " in faction " << factionId; return "%"; } @@ -366,7 +366,7 @@ namespace MWScript const ESM::RefId& factionId = ptr.getClass().getPrimaryFaction(ptr); if (factionId.empty()) { - Log(Debug::Warning) << "getPCRank(): NPC " << ptr.mRef->mRef.getRefId() << " has no primary faction"; + Log(Debug::Warning) << "getPCRank(): NPC " << ptr.getCellRef().getRefId() << " has no primary faction"; return "%"; } @@ -398,7 +398,7 @@ namespace MWScript const ESM::RefId& factionId = ptr.getClass().getPrimaryFaction(ptr); if (factionId.empty()) { - Log(Debug::Warning) << "getPCNextRank(): NPC " << ptr.mRef->mRef.getRefId() << " has no primary faction"; + Log(Debug::Warning) << "getPCNextRank(): NPC " << ptr.getCellRef().getRefId() << " has no primary faction"; return "%"; } From 682f00bcff932cf5226b880e3b893af95a24c63a Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 13 Jul 2025 18:36:30 +0200 Subject: [PATCH 231/330] Don't play down sound while loading quick keys --- apps/openmw/mwgui/quickkeysmenu.cpp | 8 ++++++-- apps/openmw/mwgui/quickkeysmenu.hpp | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 93f98a295f..3c62400e0d 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -228,7 +228,7 @@ namespace MWGui mAssignDialog->setVisible(false); } - void QuickKeysMenu::onAssignItem(MWWorld::Ptr item) + void QuickKeysMenu::assignItem(MWWorld::Ptr item) { assert(mSelected); @@ -245,7 +245,11 @@ namespace MWGui if (mItemSelectionDialog) mItemSelectionDialog->setVisible(false); + } + void QuickKeysMenu::onAssignItem(MWWorld::Ptr item) + { + assignItem(item); MWBase::Environment::get().getWindowManager()->playSound(item.getClass().getDownSoundId(item)); } @@ -566,7 +570,7 @@ namespace MWGui else { if (quickKey.mType == ESM::QuickKeys::Type::Item) - onAssignItem(item); + assignItem(item); else // if (quickKey.mType == ESM::QuickKeys::Type::MagicItem) onAssignMagicItem(item); } diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index 904029b9a0..a43cce50b4 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -72,6 +72,7 @@ namespace MWGui // Check if quick key is still valid inline void validate(int index); void unassign(keyData* key); + void assignItem(MWWorld::Ptr item); }; class QuickKeysMenuAssign : public WindowModal From a03a2a5ff2a268f3d6a646f07a6922cdc63d7e05 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sun, 13 Jul 2025 19:20:44 +0300 Subject: [PATCH 232/330] Re-reimplement TCB interpolation for scalars and vectors (#2379) --- components/nif/nifkey.hpp | 82 +++++++++++++++++++++++--------- components/nifosg/controller.hpp | 2 +- 2 files changed, 60 insertions(+), 24 deletions(-) diff --git a/components/nif/nifkey.hpp b/components/nif/nifkey.hpp index 604cf92c33..5a755c8d0d 100644 --- a/components/nif/nifkey.hpp +++ b/components/nif/nifkey.hpp @@ -4,6 +4,7 @@ #define OPENMW_COMPONENTS_NIF_NIFKEY_HPP #include +#include #include "exception.hpp" #include "niffile.hpp" @@ -17,7 +18,7 @@ namespace Nif InterpolationType_Unknown = 0, InterpolationType_Linear = 1, InterpolationType_Quadratic = 2, - InterpolationType_TBC = 3, + InterpolationType_TCB = 3, InterpolationType_XYZ = 4, InterpolationType_Constant = 5 }; @@ -28,18 +29,19 @@ namespace Nif T mValue; T mInTan; // Only for Quadratic interpolation, and never for QuaternionKeyList T mOutTan; // Only for Quadratic interpolation, and never for QuaternionKeyList - - // FIXME: Implement TBC interpolation - /* - float mTension; // Only for TBC interpolation - float mBias; // Only for TBC interpolation - float mContinuity; // Only for TBC interpolation - */ }; - using FloatKey = KeyT; - using Vector3Key = KeyT; - using Vector4Key = KeyT; - using QuaternionKey = KeyT; + + template + struct TCBKey + { + float mTime; + T mValue{}; + T mInTan{}; + T mOutTan{}; + float mTension; + float mContinuity; + float mBias; + }; template struct KeyMapT @@ -101,15 +103,20 @@ namespace Nif mKeys[time] = key; } } - else if (mInterpolationType == InterpolationType_TBC) + else if (mInterpolationType == InterpolationType_TCB) { - for (size_t i = 0; i < count; i++) + std::vector> tcbKeys(count); + for (TCBKey& tcbKey : tcbKeys) { - float time; - nif->read(time); - readTBC(*nif, key); - mKeys[time] = key; + nif->read(tcbKey.mTime); + tcbKey.mValue = ((*nif).*getValue)(); + nif->read(tcbKey.mTension); + nif->read(tcbKey.mContinuity); + nif->read(tcbKey.mBias); } + generateTCBTangents(tcbKeys); + for (TCBKey& key : tcbKeys) + mKeys[key.mTime] = KeyType{ std::move(key.mValue), std::move(key.mInTan), std::move(key.mOutTan) }; } else if (mInterpolationType == InterpolationType_XYZ) { @@ -140,14 +147,43 @@ namespace Nif static void readQuadratic(NIFStream& nif, KeyT& key) { readValue(nif, key); } - static void readTBC(NIFStream& nif, KeyT& key) + template + static void generateTCBTangents(std::vector>& keys) { - readValue(nif, key); - /*key.mTension = */ nif.get(); - /*key.mBias = */ nif.get(); - /*key.mContinuity = */ nif.get(); + if (keys.size() <= 1) + return; + + for (std::size_t i = 0; i < keys.size(); ++i) + { + TCBKey& curr = keys[i]; + const TCBKey* prev = (i == 0) ? nullptr : &keys[i - 1]; + const TCBKey* next = (i == keys.size() - 1) ? nullptr : &keys[i + 1]; + const float prevLen = prev != nullptr && next != nullptr ? curr.mTime - prev->mTime : 1.f; + const float nextLen = prev != nullptr && next != nullptr ? next->mTime - curr.mTime : 1.f; + if (prevLen + nextLen == 0.f) + continue; + const float x = (1.f - curr.mTension) * (1.f - curr.mContinuity) * (1.f + curr.mBias); + const float y = (1.f - curr.mTension) * (1.f + curr.mContinuity) * (1.f - curr.mBias); + const float z = (1.f - curr.mTension) * (1.f + curr.mContinuity) * (1.f + curr.mBias); + const float w = (1.f - curr.mTension) * (1.f - curr.mContinuity) * (1.f - curr.mBias); + const U prevDelta = prev != nullptr ? curr.mValue - prev->mValue : next->mValue - curr.mValue; + const U nextDelta = next != nullptr ? next->mValue - curr.mValue : curr.mValue - prev->mValue; + curr.mInTan = (prevDelta * x + nextDelta * y) * prevLen / (prevLen + nextLen); + curr.mOutTan = (prevDelta * z + nextDelta * w) * nextLen / (prevLen + nextLen); + } + } + + static void generateTCBTangents(std::vector>& keys) + { + // TODO: is this even legal? + } + + static void generateTCBTangents(std::vector>& keys) + { + // TODO: implement TCB interpolation for quaternions } }; + using FloatKeyMap = KeyMapT>; using Vector3KeyMap = KeyMapT>; using Vector4KeyMap = KeyMapT>; diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 99d3df9545..468668ce76 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -131,6 +131,7 @@ namespace NifOsg case Nif::InterpolationType_Constant: return fraction > 0.5f ? b.mValue : a.mValue; case Nif::InterpolationType_Quadratic: + case Nif::InterpolationType_TCB: { // Using a cubic Hermite spline. // b1(t) = 2t^3 - 3t^2 + 1 @@ -147,7 +148,6 @@ namespace NifOsg const float b4 = t3 - t2; return a.mValue * b1 + b.mValue * b2 + a.mOutTan * b3 + b.mInTan * b4; } - // TODO: Implement TBC interpolation default: return a.mValue + ((b.mValue - a.mValue) * fraction); } From 9dd028b2602d22ba5c85ead605edb6b22e2a5748 Mon Sep 17 00:00:00 2001 From: Dave Corley Date: Mon, 14 Jul 2025 20:18:45 +0000 Subject: [PATCH 233/330] FEAT(CS): Replace selection markers with a real one (#8139) --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/prefs/state.cpp | 6 +- apps/opencs/model/prefs/values.hpp | 4 +- apps/opencs/view/render/cell.cpp | 38 +- apps/opencs/view/render/cell.hpp | 11 +- apps/opencs/view/render/instancemode.cpp | 112 +- apps/opencs/view/render/object.cpp | 285 - apps/opencs/view/render/object.hpp | 43 +- apps/opencs/view/render/objectmarker.cpp | 307 + apps/opencs/view/render/objectmarker.hpp | 77 + .../view/render/pagedworldspacewidget.cpp | 18 +- .../view/render/pagedworldspacewidget.hpp | 2 + apps/opencs/view/render/scenewidget.cpp | 26 + apps/opencs/view/render/scenewidget.hpp | 7 + .../view/render/unpagedworldspacewidget.cpp | 11 +- .../view/render/unpagedworldspacewidget.hpp | 2 + apps/opencs/view/render/worldspacewidget.cpp | 163 +- apps/opencs/view/render/worldspacewidget.hpp | 19 +- components/CMakeLists.txt | 2 +- components/resource/scenemanager.cpp | 8 + components/resource/scenemanager.hpp | 3 + files/opencs/resources.qrc | 3 + files/opencs/selectionmarker.osgt | 30805 ++++++++++++++++ 23 files changed, 31523 insertions(+), 431 deletions(-) create mode 100644 apps/opencs/view/render/objectmarker.cpp create mode 100644 apps/opencs/view/render/objectmarker.hpp create mode 100644 files/opencs/selectionmarker.osgt diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index a131c56358..0a278316e3 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -88,7 +88,7 @@ opencs_units (view/render scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget previewwidget editmode instancemode instanceselectionmode instancemovemode orbitcameramode pathgridmode selectionmode pathgridselectionmode cameracontroller - cellwater terraintexturemode actor terrainselection terrainshapemode brushdraw commands + cellwater terraintexturemode actor terrainselection terrainshapemode brushdraw commands objectmarker ) opencs_units (view/render diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 5c32ddb68b..b80d150448 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -180,7 +180,10 @@ void CSMPrefs::State::declare() declareInt(mValues->mRendering.mCameraOrthoSize, "Orthographic Projection Size Parameter") .setTooltip("Size of the orthographic frustum, greater value will allow the camera to see more of the world.") .setRange(10, 10000); - declareDouble(mValues->mRendering.mObjectMarkerAlpha, "Object Marker Transparency").setPrecision(2).setRange(0, 1); + declareDouble(mValues->mRendering.mObjectMarkerScale, "Object Marker Scale Factor") + .setPrecision(2) + .setRange(.01f, 100.f) + .setTooltip("Multiplier for the size of object selection markers."); declareBool(mValues->mRendering.mSceneUseGradient, "Use Gradient Background"); declareColour(mValues->mRendering.mSceneDayBackgroundColour, "Day Background Colour"); declareColour(mValues->mRendering.mSceneDayGradientColour, "Day Gradient Colour") @@ -376,6 +379,7 @@ void CSMPrefs::State::declare() declareShortcut(mValues->mKeyBindings.mSceneScaleSubmode, "Scale Object Submode"); declareShortcut(mValues->mKeyBindings.mSceneRotateSubmode, "Rotate Object Submode"); declareShortcut(mValues->mKeyBindings.mSceneCameraCycle, "Cycle Camera Mode"); + declareShortcut(mValues->mKeyBindings.mSceneToggleMarker, "Toggle Selection Marker"); declareSubcategory("1st/Free Camera"); declareShortcut(mValues->mKeyBindings.mFreeForward, "Forward"); diff --git a/apps/opencs/model/prefs/values.hpp b/apps/opencs/model/prefs/values.hpp index 1339fa62ed..16e5434d6b 100644 --- a/apps/opencs/model/prefs/values.hpp +++ b/apps/opencs/model/prefs/values.hpp @@ -258,7 +258,7 @@ namespace CSMPrefs Settings::SettingValue mCameraFov{ mIndex, sName, "camera-fov", 90 }; Settings::SettingValue mCameraOrtho{ mIndex, sName, "camera-ortho", false }; Settings::SettingValue mCameraOrthoSize{ mIndex, sName, "camera-ortho-size", 100 }; - Settings::SettingValue mObjectMarkerAlpha{ mIndex, sName, "object-marker-alpha", 0.5 }; + Settings::SettingValue mObjectMarkerScale{ mIndex, sName, "object-marker-scale", 5.0 }; Settings::SettingValue mSceneUseGradient{ mIndex, sName, "scene-use-gradient", true }; Settings::SettingValue mSceneDayBackgroundColour{ mIndex, sName, "scene-day-background-colour", "#6e7880" }; @@ -491,7 +491,7 @@ namespace CSMPrefs Settings::SettingValue mSceneScaleSubmode{ mIndex, sName, "scene-submode-scale", "V" }; Settings::SettingValue mSceneRotateSubmode{ mIndex, sName, "scene-submode-rotate", "R" }; Settings::SettingValue mSceneCameraCycle{ mIndex, sName, "scene-cam-cycle", "Tab" }; - Settings::SettingValue mSceneToggleMarkers{ mIndex, sName, "scene-toggle-markers", "F4" }; + Settings::SettingValue mSceneToggleMarker{ mIndex, sName, "scene-toggle-marker", "F4" }; Settings::SettingValue mFreeForward{ mIndex, sName, "free-forward", "W" }; Settings::SettingValue mFreeBackward{ mIndex, sName, "free-backward", "S" }; Settings::SettingValue mFreeLeft{ mIndex, sName, "free-left", "A" }; diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 3d3b82acf8..8399ea52a0 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -25,9 +25,10 @@ #include "cellwater.hpp" #include "instancedragmodes.hpp" #include "mask.hpp" -#include "object.hpp" +#include "objectmarker.hpp" #include "pathgrid.hpp" #include "terrainstorage.hpp" +#include "worldspacewidget.hpp" #include #include @@ -107,9 +108,6 @@ bool CSVRender::Cell::addObjects(int start, int end) auto object = std::make_unique(mData, mCellNode, id, false); - if (mSubModeElementMask & Mask_Reference) - object->setSubMode(mSubMode); - mObjects.insert(std::make_pair(id, object.release())); modified = true; } @@ -168,9 +166,10 @@ void CSVRender::Cell::unloadLand() mCellBorder.reset(); } -CSVRender::Cell::Cell( - CSMDoc::Document& document, osg::Group* rootNode, const std::string& id, bool deleted, bool isExterior) - : mData(document.getData()) +CSVRender::Cell::Cell(CSMDoc::Document& document, ObjectMarker* selectionMarker, osg::Group* rootNode, + const std::string& id, bool deleted, bool isExterior) + : mSelectionMarker(selectionMarker) + , mData(document.getData()) , mId(ESM::RefId::stringRefId(id)) , mDeleted(deleted) , mSubMode(0) @@ -466,7 +465,10 @@ void CSVRender::Cell::setSelection(int elementMask, Selection mode) } iter->second->setSelected(selected); + if (selected) + mSelectionMarker->addToSelectionHistory(iter->second->getReferenceId(), false); } + mSelectionMarker->updateSelectionMarker(); } if (mPathgrid && elementMask & Mask_Pathgrid) { @@ -506,8 +508,10 @@ void CSVRender::Cell::selectAllWithSameParentId(int elementMask) if (!iter->second->getSelected() && ids.find(iter->second->getReferenceableId()) != ids.end()) { iter->second->setSelected(true); + mSelectionMarker->addToSelectionHistory(iter->second->getReferenceId(), false); } } + mSelectionMarker->updateSelectionMarker(); } void CSVRender::Cell::handleSelectDrag(Object* object, DragMode dragMode) @@ -520,6 +524,9 @@ void CSVRender::Cell::handleSelectDrag(Object* object, DragMode dragMode) else if (dragMode == DragMode_Select_Invert) object->setSelected(!object->getSelected()); + + if (object->getSelected()) + mSelectionMarker->addToSelectionHistory(object->getReferenceId(), false); } void CSVRender::Cell::selectInsideCube(const osg::Vec3d& pointA, const osg::Vec3d& pointB, DragMode dragMode) @@ -542,6 +549,8 @@ void CSVRender::Cell::selectInsideCube(const osg::Vec3d& pointA, const osg::Vec3 } } } + + mSelectionMarker->updateSelectionMarker(); } void CSVRender::Cell::selectWithinDistance(const osg::Vec3d& point, float distance, DragMode dragMode) @@ -555,6 +564,8 @@ void CSVRender::Cell::selectWithinDistance(const osg::Vec3d& point, float distan if (distanceFromObject < distance) handleSelectDrag(object.second, dragMode); } + + mSelectionMarker->updateSelectionMarker(); } void CSVRender::Cell::setCellArrows(int mask) @@ -625,9 +636,11 @@ void CSVRender::Cell::selectFromGroup(const std::vector& group) if (objectName == object->getReferenceId()) { object->setSelected(true, osg::Vec4f(1, 0, 1, 1)); + mSelectionMarker->addToSelectionHistory(object->getReferenceId(), false); } } } + mSelectionMarker->updateSelectionMarker(); } void CSVRender::Cell::unhideAll() @@ -673,8 +686,7 @@ void CSVRender::Cell::setSubMode(int subMode, unsigned int elementMask) mSubModeElementMask = elementMask; if (elementMask & Mask_Reference) - for (std::map::const_iterator iter(mObjects.begin()); iter != mObjects.end(); ++iter) - iter->second->setSubMode(subMode); + mSelectionMarker->setSubMode(subMode); } void CSVRender::Cell::reset(unsigned int elementMask) @@ -685,3 +697,11 @@ void CSVRender::Cell::reset(unsigned int elementMask) if (mPathgrid && elementMask & Mask_Pathgrid) mPathgrid->resetIndicators(); } + +CSVRender::Object* CSVRender::Cell::getObjectByReferenceId(const std::string& referenceId) +{ + if (auto iter = mObjects.find(Misc::StringUtils::lowerCase(referenceId)); iter != mObjects.end()) + return iter->second; + else + return nullptr; +} diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 5ec8d87c33..093a047d65 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -9,9 +9,9 @@ #include #include -#include "../../model/doc/document.hpp" #include "../../model/world/cellcoordinates.hpp" #include "instancedragmodes.hpp" +#include "worldspacewidget.hpp" #include #include @@ -44,8 +44,11 @@ namespace CSVRender class CellBorder; class CellMarker; + class ObjectMarker; + class Cell { + ObjectMarker* const mSelectionMarker; CSMWorld::Data& mData; ESM::RefId mId; osg::ref_ptr mCellNode; @@ -90,8 +93,8 @@ namespace CSVRender public: /// \note Deleted covers both cells that are deleted and cells that don't exist in /// the first place. - Cell(CSMDoc::Document& document, osg::Group* rootNode, const std::string& id, bool deleted = false, - bool isExterior = false); + Cell(CSMDoc::Document& document, ObjectMarker* selectionMarker, osg::Group* rootNode, const std::string& id, + bool deleted = false, bool isExterior = false); ~Cell(); @@ -182,6 +185,8 @@ namespace CSVRender /// true state. void reset(unsigned int elementMask); + CSVRender::Object* getObjectByReferenceId(const std::string& referenceId); + friend class CellNodeCallback; }; } diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 03872a3d6c..76cfd57ba6 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -362,7 +362,29 @@ CSVRender::InstanceMode::InstanceMode( for (const char axis : "xyz") connect(new CSMPrefs::Shortcut(std::string("scene-axis-") + axis, worldspaceWidget), - qOverload<>(&CSMPrefs::Shortcut::activated), this, [this, axis] { this->setDragAxis(axis); }); + qOverload<>(&CSMPrefs::Shortcut::activated), this, [this, axis] { + this->setDragAxis(axis); + std::string axisStr(1, toupper(axis)); + switch (getSubMode()) + { + case (Object::Mode_Move): + axisStr += "_Axis"; + break; + case (Object::Mode_Rotate): + axisStr += "_Axis_Rot"; + break; + case (Object::Mode_Scale): + axisStr += "_Axis_Scale"; + break; + } + + auto selectionMarker = getWorldspaceWidget().getSelectionMarker(); + + if (mDragAxis != -1) + selectionMarker->updateMarkerHighlight(axisStr, axis - 'x'); + else + selectionMarker->resetMarkerHighlight(); + }); } void CSVRender::InstanceMode::activate(CSVWidget::SceneToolbar* toolbar) @@ -460,52 +482,58 @@ void CSVRender::InstanceMode::secondaryEditPressed(const WorldspaceHitResult& hi void CSVRender::InstanceMode::primarySelectPressed(const WorldspaceHitResult& hit) { - getWorldspaceWidget().clearSelection(Mask_Reference); + auto& worldspaceWidget = getWorldspaceWidget(); - if (hit.tag) + worldspaceWidget.clearSelection(Mask_Reference); + + if (!hit.tag) + return; + + if (CSVRender::ObjectTag* objectTag = dynamic_cast(hit.tag.get())) { - if (CSVRender::ObjectTag* objectTag = dynamic_cast(hit.tag.get())) - { - // hit an Object, select it - CSVRender::Object* object = objectTag->mObject; - object->setSelected(true); - return; - } + // hit an Object, select it + CSVRender::Object* object = objectTag->mObject; + object->setSelected(true); + worldspaceWidget.getSelectionMarker()->addToSelectionHistory(object->getReferenceId()); } } void CSVRender::InstanceMode::secondarySelectPressed(const WorldspaceHitResult& hit) { - if (hit.tag) + if (!hit.tag) + return; + + if (CSVRender::ObjectTag* objectTag = dynamic_cast(hit.tag.get())) { - if (CSVRender::ObjectTag* objectTag = dynamic_cast(hit.tag.get())) - { - // hit an Object, toggle its selection state - CSVRender::Object* object = objectTag->mObject; - object->setSelected(!object->getSelected()); - return; - } + // hit an Object, toggle its selection state + CSVRender::Object* object = objectTag->mObject; + object->setSelected(!object->getSelected()); + + const auto selectionMarker = getWorldspaceWidget().getSelectionMarker(); + + if (object->getSelected()) + selectionMarker->addToSelectionHistory(object->getReferenceId(), false); + + selectionMarker->updateSelectionMarker(); } } void CSVRender::InstanceMode::tertiarySelectPressed(const WorldspaceHitResult& hit) { - auto* snapTarget = dynamic_cast(getWorldspaceWidget().getSnapTarget(Mask_Reference).get()); - - if (snapTarget) + if (auto* snapTarget + = dynamic_cast(getWorldspaceWidget().getSnapTarget(Mask_Reference).get())) { snapTarget->mObject->setSnapTarget(false); } - if (hit.tag) + if (!hit.tag) + return; + + if (CSVRender::ObjectTag* objectTag = dynamic_cast(hit.tag.get())) { - if (CSVRender::ObjectTag* objectTag = dynamic_cast(hit.tag.get())) - { - // hit an Object, toggle its selection state - CSVRender::Object* object = objectTag->mObject; - object->setSnapTarget(!object->getSnapTarget()); - return; - } + // hit an Object, toggle its selection state + CSVRender::Object* object = objectTag->mObject; + object->setSnapTarget(!object->getSnapTarget()); } } @@ -514,23 +542,26 @@ bool CSVRender::InstanceMode::primaryEditStartDrag(const QPoint& pos) if (mDragMode != DragMode_None || mLocked) return false; - WorldspaceHitResult hit = getWorldspaceWidget().mousePick(pos, getWorldspaceWidget().getInteractionMask()); + auto& worldspaceWidget = getWorldspaceWidget(); - std::vector> selection = getWorldspaceWidget().getSelection(Mask_Reference); + WorldspaceHitResult hit = worldspaceWidget.mousePick(pos, worldspaceWidget.getInteractionMask()); + + std::vector> selection = worldspaceWidget.getSelection(Mask_Reference); if (selection.empty()) { // Only change selection at the start of drag if no object is already selected if (hit.tag && CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue()) { - getWorldspaceWidget().clearSelection(Mask_Reference); + worldspaceWidget.clearSelection(Mask_Reference); if (CSVRender::ObjectTag* objectTag = dynamic_cast(hit.tag.get())) { CSVRender::Object* object = objectTag->mObject; object->setSelected(true); + worldspaceWidget.getSelectionMarker()->addToSelectionHistory(object->getReferenceId()); } } - selection = getWorldspaceWidget().getSelection(Mask_Reference); + selection = worldspaceWidget.getSelection(Mask_Reference); if (selection.empty()) return false; } @@ -591,23 +622,26 @@ bool CSVRender::InstanceMode::secondaryEditStartDrag(const QPoint& pos) if (mDragMode != DragMode_None || mLocked) return false; - WorldspaceHitResult hit = getWorldspaceWidget().mousePick(pos, getWorldspaceWidget().getInteractionMask()); + auto& worldspaceWidget = getWorldspaceWidget(); - std::vector> selection = getWorldspaceWidget().getSelection(Mask_Reference); + WorldspaceHitResult hit = worldspaceWidget.mousePick(pos, worldspaceWidget.getInteractionMask()); + + std::vector> selection = worldspaceWidget.getSelection(Mask_Reference); if (selection.empty()) { // Only change selection at the start of drag if no object is already selected if (hit.tag && CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue()) { - getWorldspaceWidget().clearSelection(Mask_Reference); + worldspaceWidget.clearSelection(Mask_Reference); if (CSVRender::ObjectTag* objectTag = dynamic_cast(hit.tag.get())) { CSVRender::Object* object = objectTag->mObject; object->setSelected(true); + worldspaceWidget.getSelectionMarker()->addToSelectionHistory(object->getReferenceId()); } } - selection = getWorldspaceWidget().getSelection(Mask_Reference); + selection = worldspaceWidget.getSelection(Mask_Reference); if (selection.empty()) return false; } @@ -641,10 +675,10 @@ bool CSVRender::InstanceMode::secondaryEditStartDrag(const QPoint& pos) mDragMode = DragMode_Scale_Snap; // Calculate scale factor - std::vector> editedSelection = getWorldspaceWidget().getEdited(Mask_Reference); + std::vector> editedSelection = worldspaceWidget.getEdited(Mask_Reference); osg::Vec3f center = getScreenCoords(getSelectionCenter(editedSelection)); - int widgetHeight = getWorldspaceWidget().height(); + int widgetHeight = worldspaceWidget.height(); float dx = pos.x() - center.x(); float dy = (widgetHeight - pos.y()) - center.y(); diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index fe4b6e9b7f..30eac77eb9 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -18,25 +18,11 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include #include -#include -#include -#include #include -#include "../../model/prefs/state.hpp" #include "../../model/world/cellcoordinates.hpp" #include "../../model/world/commandmacro.hpp" #include "../../model/world/commands.hpp" @@ -63,11 +49,6 @@ namespace ESM struct Light; } -const float CSVRender::Object::MarkerShaftWidth = 30; -const float CSVRender::Object::MarkerShaftBaseLength = 70; -const float CSVRender::Object::MarkerHeadWidth = 50; -const float CSVRender::Object::MarkerHeadLength = 50; - namespace { @@ -95,12 +76,6 @@ QString CSVRender::ObjectTag::getToolTip(bool /*hideBasics*/, const WorldspaceHi return QString::fromUtf8(mObject->getReferenceableId().c_str()); } -CSVRender::ObjectMarkerTag::ObjectMarkerTag(Object* object, int axis) - : ObjectTag(object) - , mAxis(axis) -{ -} - void CSVRender::Object::clear() {} void CSVRender::Object::update() @@ -204,238 +179,6 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const return mData.getReferences().getRecord(mReferenceId).get(); } -void CSVRender::Object::updateMarker() -{ - for (int i = 0; i < 3; ++i) - { - if (mMarker[i]) - { - mRootNode->removeChild(mMarker[i]); - mMarker[i] = osg::ref_ptr(); - } - - if (mSelected) - { - if (mSubMode == 0) - { - mMarker[i] = makeMoveOrScaleMarker(i); - mMarker[i]->setUserData(new ObjectMarkerTag(this, i)); - - mRootNode->addChild(mMarker[i]); - } - else if (mSubMode == 1) - { - mMarker[i] = makeRotateMarker(i); - mMarker[i]->setUserData(new ObjectMarkerTag(this, i)); - - mRootNode->addChild(mMarker[i]); - } - else if (mSubMode == 2) - { - mMarker[i] = makeMoveOrScaleMarker(i); - mMarker[i]->setUserData(new ObjectMarkerTag(this, i)); - - mRootNode->addChild(mMarker[i]); - } - } - } -} - -osg::ref_ptr CSVRender::Object::makeMoveOrScaleMarker(int axis) -{ - osg::ref_ptr geometry(new osg::Geometry); - - float shaftLength = MarkerShaftBaseLength + mBaseNode->getBound().radius(); - - // shaft - osg::Vec3Array* vertices = new osg::Vec3Array; - - for (int i = 0; i < 2; ++i) - { - float length = i ? shaftLength : MarkerShaftWidth; - - vertices->push_back(getMarkerPosition(-MarkerShaftWidth / 2, -MarkerShaftWidth / 2, length, axis)); - vertices->push_back(getMarkerPosition(-MarkerShaftWidth / 2, MarkerShaftWidth / 2, length, axis)); - vertices->push_back(getMarkerPosition(MarkerShaftWidth / 2, MarkerShaftWidth / 2, length, axis)); - vertices->push_back(getMarkerPosition(MarkerShaftWidth / 2, -MarkerShaftWidth / 2, length, axis)); - } - - // head backside - vertices->push_back(getMarkerPosition(-MarkerHeadWidth / 2, -MarkerHeadWidth / 2, shaftLength, axis)); - vertices->push_back(getMarkerPosition(-MarkerHeadWidth / 2, MarkerHeadWidth / 2, shaftLength, axis)); - vertices->push_back(getMarkerPosition(MarkerHeadWidth / 2, MarkerHeadWidth / 2, shaftLength, axis)); - vertices->push_back(getMarkerPosition(MarkerHeadWidth / 2, -MarkerHeadWidth / 2, shaftLength, axis)); - - // head - vertices->push_back(getMarkerPosition(0, 0, shaftLength + MarkerHeadLength, axis)); - - geometry->setVertexArray(vertices); - - osg::DrawElementsUShort* primitives = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, 0); - - // shaft - for (int i = 0; i < 4; ++i) - { - int i2 = i == 3 ? 0 : i + 1; - primitives->push_back(i); - primitives->push_back(4 + i); - primitives->push_back(i2); - - primitives->push_back(4 + i); - primitives->push_back(4 + i2); - primitives->push_back(i2); - } - - // cap - primitives->push_back(0); - primitives->push_back(1); - primitives->push_back(2); - - primitives->push_back(2); - primitives->push_back(3); - primitives->push_back(0); - - // head, backside - primitives->push_back(0 + 8); - primitives->push_back(1 + 8); - primitives->push_back(2 + 8); - - primitives->push_back(2 + 8); - primitives->push_back(3 + 8); - primitives->push_back(0 + 8); - - for (int i = 0; i < 4; ++i) - { - primitives->push_back(12); - primitives->push_back(8 + (i == 3 ? 0 : i + 1)); - primitives->push_back(8 + i); - } - - geometry->addPrimitiveSet(primitives); - - osg::Vec4Array* colours = new osg::Vec4Array; - - for (int i = 0; i < 8; ++i) - colours->push_back( - osg::Vec4f(axis == 0 ? 1.0f : 0.2f, axis == 1 ? 1.0f : 0.2f, axis == 2 ? 1.0f : 0.2f, mMarkerTransparency)); - - for (int i = 8; i < 8 + 4 + 1; ++i) - colours->push_back( - osg::Vec4f(axis == 0 ? 1.0f : 0.0f, axis == 1 ? 1.0f : 0.0f, axis == 2 ? 1.0f : 0.0f, mMarkerTransparency)); - - geometry->setColorArray(colours, osg::Array::BIND_PER_VERTEX); - - setupCommonMarkerState(geometry); - - osg::ref_ptr group(new osg::Group); - group->addChild(geometry); - - return group; -} - -osg::ref_ptr CSVRender::Object::makeRotateMarker(int axis) -{ - const float InnerRadius = std::max(MarkerShaftBaseLength, mBaseNode->getBound().radius()); - const float OuterRadius = InnerRadius + MarkerShaftWidth; - - const float SegmentDistance = 100.f; - const size_t SegmentCount = std::clamp(OuterRadius * 2 * osg::PI / SegmentDistance, 24, 64); - const size_t VerticesPerSegment = 4; - const size_t IndicesPerSegment = 24; - - const size_t VertexCount = SegmentCount * VerticesPerSegment; - const size_t IndexCount = SegmentCount * IndicesPerSegment; - - const float Angle = 2 * osg::PI / SegmentCount; - - const unsigned short IndexPattern[IndicesPerSegment] - = { 0, 4, 5, 0, 5, 1, 2, 6, 4, 2, 4, 0, 3, 7, 6, 3, 6, 2, 1, 5, 7, 1, 7, 3 }; - - osg::ref_ptr geometry = new osg::Geometry(); - - osg::ref_ptr vertices = new osg::Vec3Array(VertexCount); - osg::ref_ptr colors = new osg::Vec4Array(1); - osg::ref_ptr primitives - = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, IndexCount); - - // prevent some depth collision issues from overlaps - osg::Vec3f offset = getMarkerPosition(0, MarkerShaftWidth / 4, 0, axis); - - for (size_t i = 0; i < SegmentCount; ++i) - { - size_t index = i * VerticesPerSegment; - - float innerX = InnerRadius * std::cos(i * Angle); - float innerY = InnerRadius * std::sin(i * Angle); - - float outerX = OuterRadius * std::cos(i * Angle); - float outerY = OuterRadius * std::sin(i * Angle); - - vertices->at(index++) = getMarkerPosition(innerX, innerY, MarkerShaftWidth / 2, axis) + offset; - vertices->at(index++) = getMarkerPosition(innerX, innerY, -MarkerShaftWidth / 2, axis) + offset; - vertices->at(index++) = getMarkerPosition(outerX, outerY, MarkerShaftWidth / 2, axis) + offset; - vertices->at(index++) = getMarkerPosition(outerX, outerY, -MarkerShaftWidth / 2, axis) + offset; - } - - colors->at(0) - = osg::Vec4f(axis == 0 ? 1.0f : 0.2f, axis == 1 ? 1.0f : 0.2f, axis == 2 ? 1.0f : 0.2f, mMarkerTransparency); - - for (size_t i = 0; i < SegmentCount; ++i) - { - size_t indices[IndicesPerSegment]; - for (size_t j = 0; j < IndicesPerSegment; ++j) - { - indices[j] = i * VerticesPerSegment + j; - - if (indices[j] >= VertexCount) - indices[j] -= VertexCount; - } - - size_t elementOffset = i * IndicesPerSegment; - for (size_t j = 0; j < IndicesPerSegment; ++j) - { - primitives->setElement(elementOffset++, indices[IndexPattern[j]]); - } - } - - geometry->setVertexArray(vertices); - geometry->setColorArray(colors, osg::Array::BIND_OVERALL); - geometry->addPrimitiveSet(primitives); - - setupCommonMarkerState(geometry); - - osg::ref_ptr group = new osg::Group(); - group->addChild(geometry); - - return group; -} - -void CSVRender::Object::setupCommonMarkerState(osg::ref_ptr geometry) -{ - osg::ref_ptr state = geometry->getOrCreateStateSet(); - state->setMode(GL_LIGHTING, osg::StateAttribute::OFF); - state->setMode(GL_BLEND, osg::StateAttribute::ON); - - state->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); -} - -osg::Vec3f CSVRender::Object::getMarkerPosition(float x, float y, float z, int axis) -{ - switch (axis) - { - case 2: - return osg::Vec3f(x, y, z); - case 0: - return osg::Vec3f(z, x, y); - case 1: - return osg::Vec3f(y, z, x); - - default: - - throw std::logic_error("invalid axis for marker geometry"); - } -} - CSVRender::Object::Object( CSMWorld::Data& data, osg::Group* parentNode, const std::string& id, bool referenceable, bool forceBaseToZero) : mData(data) @@ -446,8 +189,6 @@ CSVRender::Object::Object( , mForceBaseToZero(forceBaseToZero) , mScaleOverride(1) , mOverrideFlags(0) - , mSubMode(-1) - , mMarkerTransparency(0.5f) { mRootNode = new osg::PositionAttitudeTransform; @@ -476,7 +217,6 @@ CSVRender::Object::Object( adjustTransform(); update(); - updateMarker(); } CSVRender::Object::~Object() @@ -506,9 +246,6 @@ void CSVRender::Object::setSelected(bool selected, const osg::Vec4f& color) } else mRootNode->addChild(mBaseNode); - - mMarkerTransparency = CSMPrefs::get()["Rendering"]["object-marker-alpha"].toDouble(); - updateMarker(); } bool CSVRender::Object::getSelected() const @@ -536,9 +273,6 @@ void CSVRender::Object::setSnapTarget(bool isSnapTarget) } else mRootNode->addChild(mBaseNode); - - mMarkerTransparency = CSMPrefs::get()["Rendering"]["object-marker-alpha"].toDouble(); - updateMarker(); } bool CSVRender::Object::getSnapTarget() const @@ -566,7 +300,6 @@ bool CSVRender::Object::referenceableDataChanged(const QModelIndex& topLeft, con { adjustTransform(); update(); - updateMarker(); return true; } @@ -614,7 +347,6 @@ bool CSVRender::Object::referenceDataChanged(const QModelIndex& topLeft, const Q = ESM::RefId::stringRefId(references.getData(index, columnIndex).toString().toUtf8().constData()); update(); - updateMarker(); } return true; @@ -626,7 +358,6 @@ bool CSVRender::Object::referenceDataChanged(const QModelIndex& topLeft, const Q void CSVRender::Object::reloadAssets() { update(); - updateMarker(); } std::string CSVRender::Object::getReferenceId() const @@ -720,12 +451,6 @@ void CSVRender::Object::setScale(float scale) adjustTransform(); } -void CSVRender::Object::setMarkerTransparency(float value) -{ - mMarkerTransparency = value; - updateMarker(); -} - void CSVRender::Object::apply(CSMWorld::CommandMacro& commands) { const CSMWorld::RefCollection& collection = mData.getReferences(); @@ -796,18 +521,8 @@ void CSVRender::Object::apply(CSMWorld::CommandMacro& commands) mOverrideFlags = 0; } -void CSVRender::Object::setSubMode(int subMode) -{ - if (subMode != mSubMode) - { - mSubMode = subMode; - updateMarker(); - } -} - void CSVRender::Object::reset() { mOverrideFlags = 0; adjustTransform(); - updateMarker(); } diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 31f0d93ac4..fc36776c25 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -58,14 +58,6 @@ namespace CSVRender QString getToolTip(bool hideBasics, const WorldspaceHitResult& hit) const override; }; - class ObjectMarkerTag : public ObjectTag - { - public: - ObjectMarkerTag(Object* object, int axis); - - int mAxis; - }; - class Object { public: @@ -76,12 +68,22 @@ namespace CSVRender Override_Scale = 4 }; - private: - static const float MarkerShaftWidth; - static const float MarkerShaftBaseLength; - static const float MarkerHeadWidth; - static const float MarkerHeadLength; + enum SubMode + { + Mode_Move, + Mode_Rotate, + Mode_Scale, + Mode_None, + }; + enum Axis + { + Axis_X, + Axis_Y, + Axis_Z + }; + + private: CSMWorld::Data& mData; ESM::RefId mReferenceId; ESM::RefId mReferenceableId; @@ -96,9 +98,6 @@ namespace CSVRender ESM::Position mPositionOverride; float mScaleOverride; int mOverrideFlags; - osg::ref_ptr mMarker[3]; - int mSubMode; - float mMarkerTransparency; std::unique_ptr mActor; /// Not implemented @@ -120,16 +119,6 @@ namespace CSVRender /// Throws an exception if *this was constructed with referenceable const CSMWorld::CellRef& getReference() const; - void updateMarker(); - - osg::ref_ptr makeMoveOrScaleMarker(int axis); - osg::ref_ptr makeRotateMarker(int axis); - - /// Sets up a stateset with properties common to all marker types. - void setupCommonMarkerState(osg::ref_ptr geometry); - - osg::Vec3f getMarkerPosition(float x, float y, float z, int axis); - public: Object(CSMWorld::Data& data, osg::Group* cellNode, const std::string& id, bool referenceable, bool forceBaseToZero = false); @@ -199,8 +188,6 @@ namespace CSVRender /// Apply override changes via command and end edit mode void apply(CSMWorld::CommandMacro& commands); - void setSubMode(int subMode); - /// Erase all overrides and restore the visual representation of the object to its /// true state. void reset(); diff --git a/apps/opencs/view/render/objectmarker.cpp b/apps/opencs/view/render/objectmarker.cpp new file mode 100644 index 0000000000..e21436430f --- /dev/null +++ b/apps/opencs/view/render/objectmarker.cpp @@ -0,0 +1,307 @@ +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "../../model/prefs/state.hpp" +#include "objectmarker.hpp" +#include "worldspacewidget.hpp" + +namespace +{ + class FindMaterialVisitor : public osg::NodeVisitor + { + public: + FindMaterialVisitor(CSVRender::NodeMap& map) + : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) + , mMap(map) + { + } + + void apply(osg::Geometry& node) override + { + osg::StateSet* state = node.getStateSet(); + if (state->getAttribute(osg::StateAttribute::MATERIAL)) + mMap.emplace(node.getName(), &node); + + traverse(node); + } + + private: + CSVRender::NodeMap& mMap; + }; + + class ToCamera : public SceneUtil::NodeCallback + { + public: + ToCamera(osg::ref_ptr clipPlane) + : mClipPlane(std::move(clipPlane)) + { + } + void operator()(osg::Node* node, osgUtil::CullVisitor* cv) + { + osg::Vec3f normal = cv->getEyePoint(); + mClipPlane->setClipPlane(normal.x(), normal.y(), normal.z(), 0); + traverse(node, cv); + } + + private: + osg::ref_ptr mClipPlane; + }; + + auto addTagToActiveMarkerNodes = [](CSVRender::NodeMap& mMarkerNodes, CSVRender::Object* object, + std::initializer_list suffixes) { + for (const auto& markerSuffix : suffixes) + { + for (char axis = 'X'; axis <= 'Z'; ++axis) + mMarkerNodes[axis + markerSuffix]->setUserData(new CSVRender::ObjectMarkerTag(object, axis - 'X')); + } + }; +} + +namespace CSVRender +{ + ObjectMarkerTag::ObjectMarkerTag(Object* object, int axis) + : ObjectTag(object) + , mAxis(axis) + { + } + + ObjectMarker::ObjectMarker(WorldspaceWidget* worldspaceWidget, Resource::ResourceSystem* resourceSystem) + : mWorldspaceWidget(worldspaceWidget) + , mResourceSystem(resourceSystem) + , mMarkerScale(CSMPrefs::get()["Rendering"]["object-marker-scale"].toDouble()) + , mSubMode(Object::Mode_None) + { + mBaseNode = new osg::PositionAttitudeTransform; + mBaseNode->setNodeMask(Mask_Reference); + mBaseNode->setScale(osg::Vec3f(mMarkerScale, mMarkerScale, mMarkerScale)); + + mRootNode = new osg::PositionAttitudeTransform; + mRootNode->addChild(mBaseNode); + worldspaceWidget->setSelectionMarkerRoot(mRootNode); + + QFile file(":render/selection-marker"); + + if (!file.open(QIODevice::ReadOnly)) + throw std::runtime_error("Failed to open selection marker file"); + + auto markerData = file.readAll(); + + mResourceSystem->getSceneManager()->loadSelectionMarker(mBaseNode, markerData.data(), markerData.size()); + + osg::ref_ptr baseNodeState = mBaseNode->getOrCreateStateSet(); + baseNodeState->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE); + baseNodeState->setRenderBinDetails(1000, "RenderBin"); + + FindMaterialVisitor matMapper(mMarkerNodes); + + mBaseNode->accept(matMapper); + + for (const auto& [name, node] : mMarkerNodes) + { + osg::StateSet* state = node->getStateSet(); + osg::Material* mat = static_cast(state->getAttribute(osg::StateAttribute::MATERIAL)); + osg::Vec4f emis = mat->getEmission(osg::Material::FRONT_AND_BACK); + mat->setEmission(osg::Material::FRONT_AND_BACK, emis / 4); + mOriginalColors.emplace(name, emis); + } + + SceneUtil::NodeMap sceneNodes; + SceneUtil::NodeMapVisitor nodeMapper(sceneNodes); + mBaseNode->accept(nodeMapper); + + mMarkerNodes.insert(sceneNodes.begin(), sceneNodes.end()); + + osg::ref_ptr rotateMarkers = mMarkerNodes["rotateMarkers"]; + osg::ClipPlane* clip = new osg::ClipPlane(0); + rotateMarkers->setCullCallback(new ToCamera(clip)); + rotateMarkers->getStateSet()->setAttributeAndModes(clip, osg::StateAttribute::ON); + } + + void ObjectMarker::toggleVisibility() + { + bool isVisible = mBaseNode->getNodeMask() == Mask_Reference; + mBaseNode->setNodeMask(isVisible ? Mask_Hidden : Mask_Reference); + } + + void ObjectMarker::updateScale(const float scale) + { + mMarkerScale = scale; + mBaseNode->setScale(osg::Vec3f(scale, scale, scale)); + } + + void ObjectMarker::setSubMode(const int subMode) + { + if (subMode == mSubMode) + return; + mSubMode = subMode; + resetMarkerHighlight(); + updateSelectionMarker(); + } + + bool ObjectMarker::hitBehindMarker(const osg::Vec3d& hitPos, osg::ref_ptr camera) + { + if (mSubMode != Object::Mode_Rotate) + return false; + + osg::Vec3d center, eye, forwardVector, _; + std::vector rotMark = mMarkerNodes["rotateMarkers"]->getParentalNodePaths()[0]; + const osg::Vec3f markerPos = osg::computeLocalToWorld(rotMark).getTrans(); + + camera->getViewMatrixAsLookAt(eye, center, _); + forwardVector = center - eye; + forwardVector.normalize(); + + return (hitPos - markerPos) * forwardVector > 0; + } + + bool ObjectMarker::attachMarker(const std::string& refId) + { + const auto& object = mWorldspaceWidget->getObjectByReferenceId(refId); + + if (!object) + removeFromSelectionHistory(refId); + + if (!object || !object->getSelected()) + return false; + + if (!object->getRootNode()->addChild(mRootNode)) + throw std::runtime_error("Failed to add marker to object"); + + std::string parentMarkerNode; + + switch (mSubMode) + { + case (Object::Mode_Rotate): + parentMarkerNode = "rotateMarkers"; + addTagToActiveMarkerNodes(mMarkerNodes, object, { "_Axis_Rot" }); + break; + case (Object::Mode_Scale): + parentMarkerNode = "scaleMarkers"; + addTagToActiveMarkerNodes(mMarkerNodes, object, { "_Axis_Scale", "_Wall_Scale" }); + break; + case (Object::Mode_Move): + default: + parentMarkerNode = "moveMarkers"; + addTagToActiveMarkerNodes(mMarkerNodes, object, { "_Axis", "_Wall" }); + break; + } + + mMarkerNodes[parentMarkerNode]->asGroup()->setNodeMask(Mask_Reference); + + return true; + } + + void ObjectMarker::detachMarker() + { + for (std::size_t index = mRootNode->getNumParents(); index > 0;) + mRootNode->getParent(--index)->removeChild(mRootNode); + + osg::ref_ptr widgetRoot = mMarkerNodes["unitArrows"]->asGroup(); + for (std::size_t index = widgetRoot->getNumChildren(); index > 0;) + widgetRoot->getChild(--index)->setNodeMask(Mask_Hidden); + } + + void ObjectMarker::addToSelectionHistory(const std::string& refId, bool update) + { + auto foundObject = std::find_if(mSelectionHistory.begin(), mSelectionHistory.end(), + [&refId](const std::string& objId) { return objId == refId; }); + + if (foundObject == mSelectionHistory.end()) + mSelectionHistory.push_back(refId); + else + std::rotate(foundObject, foundObject + 1, mSelectionHistory.end()); + + if (update) + updateSelectionMarker(refId); + } + + void ObjectMarker::removeFromSelectionHistory(const std::string& refId) + { + mSelectionHistory.erase(std::remove_if(mSelectionHistory.begin(), mSelectionHistory.end(), + [&refId](const std::string& objId) { return objId == refId; }), + mSelectionHistory.end()); + } + + void ObjectMarker::updateSelectionMarker(const std::string& refId) + { + if (mSelectionHistory.empty()) + return; + + detachMarker(); + + if (refId.empty()) + { + for (std::size_t index = mSelectionHistory.size(); index > 0;) + if (attachMarker(mSelectionHistory[--index])) + break; + } + else + attachMarker(refId); + } + + void ObjectMarker::resetMarkerHighlight() + { + if (mLastHighlightedNodes.empty()) + return; + + for (const auto& [nodeName, mat] : mLastHighlightedNodes) + mat->setEmission(osg::Material::FRONT_AND_BACK, mat->getEmission(osg::Material::FRONT_AND_BACK) / 4); + + mLastHighlightedNodes.clear(); + mLastHitNode.clear(); + } + + void ObjectMarker::updateMarkerHighlight(const std::string_view hitNode, const int axis) + { + if (hitNode == mLastHitNode) + return; + + resetMarkerHighlight(); + + std::string colorName; + + switch (axis) + { + case Object::Axis_X: + colorName = "red"; + break; + case Object::Axis_Y: + colorName = "green"; + break; + case Object::Axis_Z: + colorName = "blue"; + break; + default: + throw std::runtime_error("Invalid axis for highlighting: " + std::to_string(axis)); + } + + std::vector targetMaterials = { colorName + "-material" }; + + if (mSubMode != Object::Mode_Rotate) + targetMaterials.emplace_back(colorName + "_alpha-material"); + + for (const auto& materialNodeName : targetMaterials) + { + osg::ref_ptr matNode = mMarkerNodes[materialNodeName]; + osg::StateSet* state = matNode->getStateSet(); + osg::StateAttribute* matAttr = state->getAttribute(osg::StateAttribute::MATERIAL); + + osg::Material* mat = static_cast(matAttr); + mat->setEmission(osg::Material::FRONT_AND_BACK, mOriginalColors[materialNodeName]); + + mLastHighlightedNodes.emplace(std::make_pair(matNode->getName(), mat)); + } + + mLastHitNode = hitNode; + } +} diff --git a/apps/opencs/view/render/objectmarker.hpp b/apps/opencs/view/render/objectmarker.hpp new file mode 100644 index 0000000000..483d6f6be6 --- /dev/null +++ b/apps/opencs/view/render/objectmarker.hpp @@ -0,0 +1,77 @@ +#ifndef OPENCS_VIEW_OBJECT_MARKER_H +#define OPENCS_VIEW_OBJECT_MARKER_H + +#include "object.hpp" + +namespace osg +{ + class Camera; + class Material; +} + +namespace CSVRender +{ + using NodeMap = std::unordered_map>; + class WorldspaceWidget; + + class ObjectMarkerTag : public ObjectTag + { + public: + ObjectMarkerTag(Object* object, int axis); + + int mAxis; + }; + + class ObjectMarker + { + friend class WorldspaceWidget; + + WorldspaceWidget* mWorldspaceWidget; + Resource::ResourceSystem* mResourceSystem; + NodeMap mMarkerNodes; + osg::ref_ptr mBaseNode; + osg::ref_ptr mRootNode; + std::unordered_map mOriginalColors; + std::vector mSelectionHistory; + std::string mLastHitNode; + std::unordered_map mLastHighlightedNodes; + float mMarkerScale; + int mSubMode; + + ObjectMarker(WorldspaceWidget* worldspaceWidget, Resource::ResourceSystem* resourceSystem); + + static std::unique_ptr create(WorldspaceWidget* widget, Resource::ResourceSystem* resourceSystem) + { + return std::unique_ptr(new ObjectMarker(widget, resourceSystem)); + } + + bool attachMarker(const std::string& refId); + + void removeFromSelectionHistory(const std::string& refId); + + public: + ObjectMarker(ObjectMarker&) = delete; + ObjectMarker(ObjectMarker&&) = delete; + ObjectMarker& operator=(const ObjectMarker&) = delete; + ObjectMarker& operator=(ObjectMarker&&) = delete; + + void toggleVisibility(); + + bool hitBehindMarker(const osg::Vec3d& hitPos, osg::ref_ptr camera); + + void detachMarker(); + + void addToSelectionHistory(const std::string& refId, bool update = true); + + void updateSelectionMarker(const std::string& refId = std::string()); + + void resetMarkerHighlight(); + + void updateMarkerHighlight(const std::string_view hitNode, const int axis); + + void setSubMode(const int subMode); + + void updateScale(const float scale); + }; +} +#endif // OPENCS_VIEW_OBJECT_MARKER_H diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 3fd35b7740..90670a4d62 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -86,8 +86,8 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() { modified = true; - auto cell - = std::make_unique(mDocument, mRootNode, iter->first.getId(mWorldspace), deleted, true); + auto cell = std::make_unique(getDocument(), mSelectionMarker.get(), mRootNode, + iter->first.getId(mWorldspace), deleted, true); delete iter->second; iter->second = cell.release(); @@ -465,7 +465,8 @@ void CSVRender::PagedWorldspaceWidget::addCellToScene(const CSMWorld::CellCoordi bool deleted = index == -1 || cells.getRecord(index).mState == CSMWorld::RecordBase::State_Deleted; - auto cell = std::make_unique(mDocument, mRootNode, coordinates.getId(mWorldspace), deleted, true); + auto cell = std::make_unique( + getDocument(), mSelectionMarker.get(), mRootNode, coordinates.getId(mWorldspace), deleted, true); EditMode* editMode = getEditMode(); cell->setSubMode(editMode->getSubMode(), editMode->getInteractionMask()); @@ -750,6 +751,7 @@ void CSVRender::PagedWorldspaceWidget::clearSelection(int elementMask) iter->second->setSelection(elementMask, Cell::Selection_Clear); flagAsModified(); + mSelectionMarker->detachMarker(); } void CSVRender::PagedWorldspaceWidget::invertSelection(int elementMask) @@ -907,6 +909,7 @@ void CSVRender::PagedWorldspaceWidget::setSubMode(int subMode, unsigned int elem { for (std::map::const_iterator iter = mCells.begin(); iter != mCells.end(); ++iter) iter->second->setSubMode(subMode, elementMask); + mSelectionMarker->updateSelectionMarker(); } void CSVRender::PagedWorldspaceWidget::reset(unsigned int elementMask) @@ -986,3 +989,12 @@ void CSVRender::PagedWorldspaceWidget::loadSouthCell() { addCellToSceneFromCamera(0, -1); } + +CSVRender::Object* CSVRender::PagedWorldspaceWidget::getObjectByReferenceId(const std::string& referenceId) +{ + for (const auto& [_, cell] : mCells) + if (const auto& object = cell->getObjectByReferenceId(referenceId)) + return object; + + return nullptr; +} diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 744cc7ccb9..dc47d5ea04 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -174,6 +174,8 @@ namespace CSVRender /// Erase all overrides and restore the visual representation to its true state. void reset(unsigned int elementMask) override; + CSVRender::Object* getObjectByReferenceId(const std::string& referenceId) override; + protected: void addVisibilitySelectorButtons(CSVWidget::SceneToolToggle2* tool) override; diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 716a087d02..e84433f14c 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -445,6 +445,32 @@ namespace CSVRender mCurrentCamControl->setup(mRootNode, Mask_Reference | Mask_Terrain, CameraController::WorldUp); mCamPositionSet = true; } + + if (mSelectionMarkerNode) + { + osg::MatrixList worldMats = mSelectionMarkerNode->getWorldMatrices(); + if (!worldMats.empty()) + { + osg::Matrixd markerWorldMat = worldMats[0]; + + osg::Vec3f eye, _; + mView->getCamera()->getViewMatrix().getLookAt(eye, _, _); + osg::Vec3f cameraLocalPos = eye * osg::Matrixd::inverse(markerWorldMat); + + bool isInFrontRightQuadrant = (cameraLocalPos.x() > 0.1f) && (cameraLocalPos.y() > 0.1f); + bool isSignificantlyBehind = (cameraLocalPos.x() < 1.f) && (cameraLocalPos.y() < 1.f); + + if (!isInFrontRightQuadrant && isSignificantlyBehind) + { + osg::Quat current = mSelectionMarkerNode->getAttitude(); + mSelectionMarkerNode->setAttitude(current * osg::Quat(osg::PI, osg::Vec3f(0, 0, 1))); + } + + float distance = (markerWorldMat.getTrans() - eye).length(); + float scale = std::max(distance / 75.0f, 1.0f); + mSelectionMarkerNode->setScale(osg::Vec3(scale, scale, scale)); + } + } } void SceneWidget::settingChanged(const CSMPrefs::Setting* setting) diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 228581a0ef..aeec5d191c 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -105,6 +106,11 @@ namespace CSVRender void setExterior(bool isExterior); + void setSelectionMarkerRoot(osg::ref_ptr selectionMarker) + { + mSelectionMarkerNode = selectionMarker; + } + protected: void setLighting(Lighting* lighting); ///< \attention The ownership of \a lighting is not transferred to *this. @@ -122,6 +128,7 @@ namespace CSVRender Lighting* mLighting; + osg::ref_ptr mSelectionMarkerNode; osg::ref_ptr mGradientCamera; osg::Vec4f mDefaultAmbient; bool mHasDefaultAmbient; diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index a7d8af0a62..3637663356 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -79,7 +79,7 @@ CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget( update(); - mCell = std::make_unique(document, mRootNode, mCellId); + mCell = std::make_unique(document, mSelectionMarker.get(), mRootNode, mCellId); } void CSVRender::UnpagedWorldspaceWidget::cellDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) @@ -127,7 +127,7 @@ bool CSVRender::UnpagedWorldspaceWidget::handleDrop( mCellId = universalIdData.begin()->getId(); - mCell = std::make_unique(getDocument(), mRootNode, mCellId); + mCell = std::make_unique(getDocument(), mSelectionMarker.get(), mRootNode, mCellId); mCamPositionSet = false; mOrbitCamControl->reset(); @@ -141,6 +141,7 @@ void CSVRender::UnpagedWorldspaceWidget::clearSelection(int elementMask) { mCell->setSelection(elementMask, Cell::Selection_Clear); flagAsModified(); + mSelectionMarker->detachMarker(); } void CSVRender::UnpagedWorldspaceWidget::invertSelection(int elementMask) @@ -218,6 +219,7 @@ std::vector> CSVRender::UnpagedWorldspaceWidget void CSVRender::UnpagedWorldspaceWidget::setSubMode(int subMode, unsigned int elementMask) { mCell->setSubMode(subMode, elementMask); + mSelectionMarker->updateSelectionMarker(); } void CSVRender::UnpagedWorldspaceWidget::reset(unsigned int elementMask) @@ -383,3 +385,8 @@ CSVRender::WorldspaceWidget::dropRequirments CSVRender::UnpagedWorldspaceWidget: return ignored; } } + +CSVRender::Object* CSVRender::UnpagedWorldspaceWidget::getObjectByReferenceId(const std::string& referenceId) +{ + return mCell->getObjectByReferenceId(referenceId); +} diff --git a/apps/opencs/view/render/unpagedworldspacewidget.hpp b/apps/opencs/view/render/unpagedworldspacewidget.hpp index 89c916415d..6eb5b97f56 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.hpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.hpp @@ -104,6 +104,8 @@ namespace CSVRender /// Erase all overrides and restore the visual representation to its true state. void reset(unsigned int elementMask) override; + CSVRender::Object* getObjectByReferenceId(const std::string& id) override; + private: void referenceableDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) override; diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 0a02ae456b..915282ab45 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -52,7 +52,6 @@ #include "cameracontroller.hpp" #include "instancemode.hpp" #include "mask.hpp" -#include "object.hpp" #include "pathgridmode.hpp" CSVRender::WorldspaceWidget::WorldspaceWidget(CSMDoc::Document& document, QWidget* parent) @@ -74,8 +73,8 @@ CSVRender::WorldspaceWidget::WorldspaceWidget(CSMDoc::Document& document, QWidge , mToolTipPos(-1, -1) , mShowToolTips(false) , mToolTipDelay(0) - , mInConstructor(true) , mSelectedNavigationMode(0) + , mSelectionMarker(ObjectMarker::create(this, document.getData().getResourceSystem().get())) { setAcceptDrops(true); @@ -145,13 +144,14 @@ CSVRender::WorldspaceWidget::WorldspaceWidget(CSMDoc::Document& document, QWidge &WorldspaceWidget::unhideAll); connect(new CSMPrefs::Shortcut("scene-clear-selection", this), qOverload<>(&CSMPrefs::Shortcut::activated), this, - [this] { this->clearSelection(Mask_Reference); }); + [this] { clearSelection(Mask_Reference); }); CSMPrefs::Shortcut* switchPerspectiveShortcut = new CSMPrefs::Shortcut("scene-cam-cycle", this); connect(switchPerspectiveShortcut, qOverload<>(&CSMPrefs::Shortcut::activated), this, &WorldspaceWidget::cycleNavigationMode); - mInConstructor = false; + connect(new CSMPrefs::Shortcut("scene-toggle-marker", this), qOverload<>(&CSMPrefs::Shortcut::activated), this, + [this]() { mSelectionMarker->toggleVisibility(); }); } void CSVRender::WorldspaceWidget::settingChanged(const CSMPrefs::Setting* setting) @@ -162,17 +162,8 @@ void CSVRender::WorldspaceWidget::settingChanged(const CSMPrefs::Setting* settin mDragWheelFactor = setting->toDouble(); else if (*setting == "3D Scene Input/drag-shift-factor") mDragShiftFactor = setting->toDouble(); - else if (*setting == "Rendering/object-marker-alpha" && !mInConstructor) - { - float alpha = setting->toDouble(); - // getSelection is virtual, thus this can not be called from the constructor - auto selection = getSelection(Mask_Reference); - for (osg::ref_ptr tag : selection) - { - if (auto objTag = dynamic_cast(tag.get())) - objTag->mObject->setMarkerTransparency(alpha); - } - } + else if (*setting == "Rendering/object-marker-scale") + mSelectionMarker->updateScale(setting->toDouble()); else if (*setting == "Tooltips/scene-delay") mToolTipDelay = setting->toInt(); else if (*setting == "Tooltips/scene") @@ -396,8 +387,29 @@ CSMDoc::Document& CSVRender::WorldspaceWidget::getDocument() return mDocument; } -CSVRender::WorldspaceHitResult CSVRender::WorldspaceWidget::mousePick( - const QPoint& localPos, unsigned int interactionMask) const +template +std::optional CSVRender::WorldspaceWidget::checkTag( + const osgUtil::LineSegmentIntersector::Intersection& intersection) const +{ + for (auto* node : intersection.nodePath) + { + if (auto* tag = dynamic_cast(node->getUserData())) + { + WorldspaceHitResult hit = { true, tag, 0, 0, 0, intersection.getWorldIntersectPoint() }; + if (intersection.indexList.size() >= 3) + { + hit.index0 = intersection.indexList[0]; + hit.index1 = intersection.indexList[1]; + hit.index2 = intersection.indexList[2]; + } + return hit; + } + } + return std::nullopt; +} + +std::tuple CSVRender::WorldspaceWidget::getStartEndDirection( + int pointX, int pointY) const { // may be okay to just use devicePixelRatio() directly QScreen* screen = SceneWidget::windowHandle() && SceneWidget::windowHandle()->screen() @@ -405,8 +417,8 @@ CSVRender::WorldspaceHitResult CSVRender::WorldspaceWidget::mousePick( : QGuiApplication::primaryScreen(); // (0,0) is considered the lower left corner of an OpenGL window - int x = localPos.x() * screen->devicePixelRatio(); - int y = height() * screen->devicePixelRatio() - localPos.y() * screen->devicePixelRatio(); + int x = pointX * screen->devicePixelRatio(); + int y = height() * screen->devicePixelRatio() - pointY * screen->devicePixelRatio(); // Convert from screen space to world space osg::Matrixd wpvMat; @@ -418,6 +430,13 @@ CSVRender::WorldspaceHitResult CSVRender::WorldspaceWidget::mousePick( osg::Vec3d start = wpvMat.preMult(osg::Vec3d(x, y, 0)); osg::Vec3d end = wpvMat.preMult(osg::Vec3d(x, y, 1)); osg::Vec3d direction = end - start; + return { start, end, direction }; +} + +CSVRender::WorldspaceHitResult CSVRender::WorldspaceWidget::mousePick( + const QPoint& localPos, unsigned int interactionMask) const +{ + auto [start, end, direction] = getStartEndDirection(localPos.x(), localPos.y()); // Get intersection osg::ref_ptr intersector( @@ -430,51 +449,46 @@ CSVRender::WorldspaceHitResult CSVRender::WorldspaceWidget::mousePick( mView->getCamera()->accept(visitor); - // Get relevant data - for (osgUtil::LineSegmentIntersector::Intersections::iterator it = intersector->getIntersections().begin(); - it != intersector->getIntersections().end(); ++it) - { - osgUtil::LineSegmentIntersector::Intersection intersection = *it; + auto intersections = intersector->getIntersections(); - // reject back-facing polygons - if (direction * intersection.getWorldIntersectNormal() > 0) - { - continue; - } + std::vector validIntersections + = { intersections.begin(), intersections.end() }; - for (std::vector::iterator nodeIter = intersection.nodePath.begin(); - nodeIter != intersection.nodePath.end(); ++nodeIter) - { - osg::Node* node = *nodeIter; - if (osg::ref_ptr tag = dynamic_cast(node->getUserData())) - { - WorldspaceHitResult hit = { true, std::move(tag), 0, 0, 0, intersection.getWorldIntersectPoint() }; - if (intersection.indexList.size() >= 3) - { - hit.index0 = intersection.indexList[0]; - hit.index1 = intersection.indexList[1]; - hit.index2 = intersection.indexList[2]; - } - return hit; - } - } + const auto& removeBackfaces = [direction = direction](const osgUtil::LineSegmentIntersector::Intersection& i) { + return direction * i.getWorldIntersectNormal() > 0; + }; - // Something untagged, probably terrain - WorldspaceHitResult hit = { true, nullptr, 0, 0, 0, intersection.getWorldIntersectPoint() }; - if (intersection.indexList.size() >= 3) - { - hit.index0 = intersection.indexList[0]; - hit.index1 = intersection.indexList[1]; - hit.index2 = intersection.indexList[2]; - } - return hit; - } + validIntersections.erase(std::remove_if(validIntersections.begin(), validIntersections.end(), removeBackfaces), + validIntersections.end()); // Default placement direction.normalize(); direction *= CSMPrefs::get()["3D Scene Editing"]["distance"].toInt(); - WorldspaceHitResult hit = { false, nullptr, 0, 0, 0, start + direction }; + if (validIntersections.empty()) + return WorldspaceHitResult{ false, nullptr, 0, 0, 0, start + direction }; + + const auto& firstHit = validIntersections.front(); + + for (const auto& hit : validIntersections) + if (const auto& markerHit = checkTag(hit)) + { + if (mSelectionMarker->hitBehindMarker(markerHit->worldPos, mView->getCamera())) + return WorldspaceHitResult{ false, nullptr, 0, 0, 0, start + direction }; + else + return *markerHit; + } + if (auto hit = checkTag(firstHit)) + return *hit; + + // Something untagged, probably terrain + WorldspaceHitResult hit = { true, nullptr, 0, 0, 0, firstHit.getWorldIntersectPoint() }; + if (firstHit.indexList.size() >= 3) + { + hit.index0 = firstHit.indexList[0]; + hit.index1 = firstHit.indexList[1]; + hit.index2 = firstHit.indexList[2]; + } return hit; } @@ -632,6 +646,41 @@ void CSVRender::WorldspaceWidget::elementSelectionChanged() void CSVRender::WorldspaceWidget::updateOverlay() {} +void CSVRender::WorldspaceWidget::handleMarkerHighlight(const int x, const int y) +{ + auto [start, end, _] = getStartEndDirection(x, y); + + osg::ref_ptr intersector( + new osgUtil::LineSegmentIntersector(osgUtil::Intersector::MODEL, start, end)); + + intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::NO_LIMIT); + osgUtil::IntersectionVisitor visitor(intersector); + + visitor.setTraversalMask(Mask_Reference); + + mView->getCamera()->accept(visitor); + + bool hitMarker = false; + for (const auto& intersection : intersector->getIntersections()) + { + if (mSelectionMarker->hitBehindMarker(intersection.getWorldIntersectPoint(), mView->getCamera())) + continue; + + for (const auto& node : intersection.nodePath) + { + if (const auto& marker = dynamic_cast(node->getUserData())) + { + hitMarker = true; + mSelectionMarker->updateMarkerHighlight(node->getName(), marker->mAxis); + break; + } + } + } + + if (!hitMarker) + mSelectionMarker->resetMarkerHighlight(); +} + void CSVRender::WorldspaceWidget::mouseMoveEvent(QMouseEvent* event) { dynamic_cast(*mEditMode->getCurrent()).mouseMoveEvent(event); @@ -685,6 +734,8 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent(QMouseEvent* event) } } + const QPointF& pos = event->localPos(); + handleMarkerHighlight(pos.x(), pos.y()); SceneWidget::mouseMoveEvent(event); } } diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 9a7df38620..a223a54388 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -13,6 +13,7 @@ #include #include "instancedragmodes.hpp" +#include "objectmarker.hpp" #include "scenewidget.hpp" class QDragEnterEvent; @@ -89,7 +90,6 @@ namespace CSVRender QPoint mToolTipPos; bool mShowToolTips; int mToolTipDelay; - bool mInConstructor; int mSelectedNavigationMode; public: @@ -186,6 +186,12 @@ namespace CSVRender virtual void selectWithinDistance(const osg::Vec3d& point, float distance, DragMode dragMode) = 0; + template + std::optional checkTag( + const osgUtil::LineSegmentIntersector::Intersection& intersection) const; + + std::tuple getStartEndDirection(int pointX, int pointY) const; + /// Return the next intersection with scene elements matched by /// \a interactionMask based on \a localPos and the camera vector. /// If there is no such intersection, instead a point "in front" of \a localPos will be @@ -216,7 +222,14 @@ namespace CSVRender EditMode* getEditMode(); + virtual CSVRender::Object* getObjectByReferenceId(const std::string& id) = 0; + + ObjectMarker* getSelectionMarker() { return mSelectionMarker.get(); } + const ObjectMarker* getSelectionMarker() const { return mSelectionMarker.get(); } + protected: + const std::unique_ptr mSelectionMarker; + /// Visual elements in a scene /// @note do not change the enumeration values, they are used in pre-existing button file names! enum ButtonId @@ -252,6 +265,10 @@ namespace CSVRender void cycleNavigationMode(); private: + bool hitBehindMarker(const osg::Vec3d& hitPos) const; + + void handleMarkerHighlight(const int x, const int y); + void dragEnterEvent(QDragEnterEvent* event) override; void dropEvent(QDropEvent* event) override; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 69c7ba462e..8a3325ea71 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -129,7 +129,7 @@ add_component_dir (vfs add_component_dir (resource scenemanager keyframemanager imagemanager animblendrulesmanager bulletshapemanager bulletshape niffilemanager objectcache multiobjectcache resourcesystem - resourcemanager stats animation foreachbulletobject errormarker cachestats bgsmfilemanager + resourcemanager stats animation foreachbulletobject errormarker selectionmarker cachestats bgsmfilemanager ) add_component_dir (shader diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 7ee29ff0eb..6100d0ccaa 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -975,6 +975,14 @@ namespace Resource return loadNonNif(errorMarker, file, mImageManager); } + void SceneManager::loadSelectionMarker( + osg::ref_ptr parentNode, const char* markerData, long long markerSize) const + { + Files::IMemStream file(markerData, markerSize); + constexpr VFS::Path::NormalizedView selectionMarker("selectionmarker.osgt"); + parentNode->addChild(loadNonNif(selectionMarker, file, mImageManager)); + } + osg::ref_ptr SceneManager::cloneErrorMarker() { if (!mErrorMarker) diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 219ecd2a94..8141b5308f 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -136,6 +136,9 @@ namespace Resource osg::ref_ptr getOpaqueDepthTex(size_t frame); + void loadSelectionMarker( + osg::ref_ptr parentNode, const char* markerData, long long markerSize) const; + enum class UBOBinding { // If we add more UBO's, we should probably assign their bindings dynamically according to the current count diff --git a/files/opencs/resources.qrc b/files/opencs/resources.qrc index 282ab23f9a..bf13a26a85 100644 --- a/files/opencs/resources.qrc +++ b/files/opencs/resources.qrc @@ -160,4 +160,7 @@ brush-circle.svg brush-custom.svg + + selectionmarker.osgt + diff --git a/files/opencs/selectionmarker.osgt b/files/opencs/selectionmarker.osgt new file mode 100644 index 0000000000..4958796ae6 --- /dev/null +++ b/files/opencs/selectionmarker.osgt @@ -0,0 +1,30805 @@ +#Ascii Scene +#Version 202 +#Generator OpenSceneGraph 3.7.0 + +osg::Group { + UniqueID 1 + Name "Collada visual scene group" + StateSet TRUE { + osg::StateSet { + UniqueID 2 + DataVariance STATIC + } + } + Children 1 { + osg::MatrixTransform { + UniqueID 3 + Name "unitArrows" + UserDataContainer TRUE { + osg::DefaultUserDataContainer { + UniqueID 4 + UDC_UserObjects 1 { + osg::StringValueObject { + UniqueID 5 + Name "dae_node_id" + Value "unitArrows" + } + } + } + } + StateSet TRUE { + osg::StateSet { + UniqueID 6 + DataVariance STATIC + ModeList 1 { + GL_RESCALE_NORMAL ON|OVERRIDE + } + } + } + Children 4 { + osg::Geode { + UniqueID 7 + } + osg::MatrixTransform { + UniqueID 8 + Name "moveMarkers" + UserDataContainer TRUE { + osg::DefaultUserDataContainer { + UniqueID 9 + UDC_UserObjects 1 { + osg::StringValueObject { + UniqueID 10 + Name "dae_node_id" + Value "moveMarkers" + } + } + } + } + StateSet TRUE { + osg::StateSet { + UniqueID 6 + } + } + Children 6 { + osg::MatrixTransform { + UniqueID 11 + Name "X_Axis" + UserDataContainer TRUE { + osg::DefaultUserDataContainer { + UniqueID 12 + UDC_UserObjects 1 { + osg::StringValueObject { + UniqueID 13 + Name "dae_node_id" + Value "X_Axis" + } + } + } + } + StateSet TRUE { + osg::StateSet { + UniqueID 6 + } + } + Children 1 { + osg::Geode { + UniqueID 14 + Drawables 1 { + osg::Geometry { + UniqueID 15 + Name "red-material" + DataVariance STATIC + StateSet TRUE { + osg::StateSet { + UniqueID 16 + Name "red" + DataVariance STATIC + ModeList 1 { + GL_CULL_FACE ON + } + AttributeList 1 { + osg::Material { + UniqueID 17 + Ambient TRUE Front 0.8 0.123281 0.11568 1 Back 0.8 0.123281 0.11568 1 + Diffuse TRUE Front 0 0 0 1 Back 0 0 0 1 + Specular TRUE Front 0 0 0 1 Back 0 0 0 1 + Emission TRUE Front 0.8 0.123281 0.11568 1 Back 0.8 0.123281 0.11568 1 + Shininess TRUE Front 0 Back 0 + } + Value OFF + } + } + } + PrimitiveSetList 1 { + osg::DrawElementsUInt { + UniqueID 18 + BufferObject TRUE { + osg::ElementBufferObject { + UniqueID 19 + Target 34963 + } + } + Mode TRIANGLES + vector 288 { + 0 80 4 5 + 81 9 10 82 + 14 15 83 19 + 20 84 24 25 + 85 29 30 86 + 34 35 87 39 + 40 88 45 46 + 89 50 51 90 + 55 56 91 60 + 61 92 65 66 + 93 70 71 94 + 75 76 95 1 + 182 204 177 187 + 198 183 172 215 + 167 251 72 77 + 227 52 57 36 + 199 31 16 270 + 11 96 117 112 + 97 122 118 98 + 127 123 99 132 + 128 100 137 133 + 101 142 138 102 + 147 143 103 152 + 148 104 157 153 + 105 162 158 106 + 168 163 107 173 + 169 108 178 174 + 109 184 179 110 + 188 185 111 113 + 189 221 47 53 + 134 264 129 245 + 67 73 130 271 + 124 12 265 6 + 180 210 175 164 + 228 159 32 192 + 26 119 282 114 + 170 222 165 115 + 193 190 139 257 + 135 144 252 140 + 233 58 62 41 + 205 37 21 276 + 17 258 78 2 + 216 42 48 154 + 239 149 240 63 + 68 150 246 145 + 7 259 3 125 + 277 120 27 283 + 22 160 234 155 + 186 200 206 191 + 194 201 176 211 + 217 253 247 74 + 229 223 54 38 + 207 202 18 278 + 272 224 218 49 + 136 260 266 248 + 241 69 131 267 + 273 13 274 268 + 181 208 212 166 + 225 230 33 203 + 195 121 279 284 + 171 219 226 116 + 285 196 141 254 + 261 146 249 255 + 235 231 59 43 + 213 209 23 286 + 280 262 256 79 + 220 214 44 156 + 236 242 243 237 + 64 151 244 250 + 8 269 263 126 + 275 281 28 197 + 287 161 232 238 + + } + } + } + VertexArray TRUE { + osg::Vec3Array { + UniqueID 20 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 21 + } + } + Binding BIND_PER_VERTEX + vector 288 { + 0.0078811 0 -0.000521402 + 0.0078811 0 -0.000521402 + 0.0078811 0 -0.000521402 + 0.0078811 0 -0.000521402 + 0.0078811 -0.000199529 -0.000481713 + 0.0078811 -0.000199529 -0.000481713 + 0.0078811 -0.000199529 -0.000481713 + 0.0078811 -0.000199529 -0.000481713 + 0.0078811 -0.000199529 -0.000481713 + 0.0078811 -0.000368683 -0.000368689 + 0.0078811 -0.000368683 -0.000368689 + 0.0078811 -0.000368683 -0.000368689 + 0.0078811 -0.000368683 -0.000368689 + 0.0078811 -0.000368683 -0.000368689 + 0.0078811 -0.000481707 -0.000199536 + 0.0078811 -0.000481707 -0.000199536 + 0.0078811 -0.000481707 -0.000199536 + 0.0078811 -0.000481707 -0.000199536 + 0.0078811 -0.000481707 -0.000199536 + 0.0078811 -0.000521396 0 + 0.0078811 -0.000521396 0 + 0.0078811 -0.000521396 0 + 0.0078811 -0.000521396 0 + 0.0078811 -0.000521396 0 + 0.0078811 -0.000481707 0.000199523 + 0.0078811 -0.000481707 0.000199523 + 0.0078811 -0.000481707 0.000199523 + 0.0078811 -0.000481707 0.000199523 + 0.0078811 -0.000481707 0.000199523 + 0.0078811 -0.000368683 0.000368675 + 0.0078811 -0.000368683 0.000368675 + 0.0078811 -0.000368683 0.000368675 + 0.0078811 -0.000368683 0.000368675 + 0.0078811 -0.000368683 0.000368675 + 0.0078811 -0.000199529 0.000481701 + 0.0078811 -0.000199529 0.000481701 + 0.0078811 -0.000199529 0.000481701 + 0.0078811 -0.000199529 0.000481701 + 0.0078811 -0.000199529 0.000481701 + 0.0078811 0 0.000521388 + 0.0078811 0 0.000521388 + 0.0078811 0 0.000521388 + 0.0078811 0 0.000521388 + 0.0078811 0 0.000521388 + 0.0078811 0 0.000521388 + 0.0078811 0.000199529 0.000481701 + 0.0078811 0.000199529 0.000481701 + 0.0078811 0.000199529 0.000481701 + 0.0078811 0.000199529 0.000481701 + 0.0078811 0.000199529 0.000481701 + 0.0078811 0.000368683 0.000368675 + 0.0078811 0.000368683 0.000368675 + 0.0078811 0.000368683 0.000368675 + 0.0078811 0.000368683 0.000368675 + 0.0078811 0.000368683 0.000368675 + 0.0078811 0.000481707 0.000199523 + 0.0078811 0.000481707 0.000199523 + 0.0078811 0.000481707 0.000199523 + 0.0078811 0.000481707 0.000199523 + 0.0078811 0.000481707 0.000199523 + 0.0078811 0.000521396 0 + 0.0078811 0.000521396 0 + 0.0078811 0.000521396 0 + 0.0078811 0.000521396 0 + 0.0078811 0.000521396 0 + 0.0078811 0.000481707 -0.000199536 + 0.0078811 0.000481707 -0.000199536 + 0.0078811 0.000481707 -0.000199536 + 0.0078811 0.000481707 -0.000199536 + 0.0078811 0.000481707 -0.000199536 + 0.0078811 0.000368683 -0.000368689 + 0.0078811 0.000368683 -0.000368689 + 0.0078811 0.000368683 -0.000368689 + 0.0078811 0.000368683 -0.000368689 + 0.0078811 0.000368683 -0.000368689 + 0.0078811 0.000199529 -0.000481713 + 0.0078811 0.000199529 -0.000481713 + 0.0078811 0.000199529 -0.000481713 + 0.0078811 0.000199529 -0.000481713 + 0.0078811 0.000199529 -0.000481713 + 0.00999188 0 0 + 0.00999188 0 0 + 0.00999188 0 0 + 0.00999188 0 0 + 0.00999188 0 0 + 0.00999188 0 0 + 0.00999188 0 0 + 0.00999188 0 0 + 0.00999188 0 0 + 0.00999188 0 0 + 0.00999188 0 0 + 0.00999188 0 0 + 0.00999188 0 0 + 0.00999188 0 0 + 0.00999188 0 0 + 0.00999188 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 -0.000128021 0 + 0.00149989 -0.000128021 0 + 0.00149989 -0.000128021 0 + 0.00149989 -0.000128021 0 + 0.00149989 -0.000128021 0 + 0.00149989 -0.000118276 -4.89919e-05 + 0.00149989 -0.000118276 -4.89919e-05 + 0.00149989 -0.000118276 -4.89919e-05 + 0.00149989 -0.000118276 -4.89919e-05 + 0.00149989 -0.000118276 -4.89919e-05 + 0.00149989 -9.05247e-05 -9.05248e-05 + 0.00149989 -9.05247e-05 -9.05248e-05 + 0.00149989 -9.05247e-05 -9.05248e-05 + 0.00149989 -9.05247e-05 -9.05248e-05 + 0.00149989 -9.05247e-05 -9.05248e-05 + 0.00149989 -4.89918e-05 -0.000118277 + 0.00149989 -4.89918e-05 -0.000118277 + 0.00149989 -4.89918e-05 -0.000118277 + 0.00149989 -4.89918e-05 -0.000118277 + 0.00149989 -4.89918e-05 -0.000118277 + 0.00149989 0 -0.000128021 + 0.00149989 0 -0.000128021 + 0.00149989 0 -0.000128021 + 0.00149989 0 -0.000128021 + 0.00149989 0 -0.000128021 + 0.00149989 4.89918e-05 -0.000118277 + 0.00149989 4.89918e-05 -0.000118277 + 0.00149989 4.89918e-05 -0.000118277 + 0.00149989 4.89918e-05 -0.000118277 + 0.00149989 4.89918e-05 -0.000118277 + 0.00149989 9.05247e-05 -9.05248e-05 + 0.00149989 9.05247e-05 -9.05248e-05 + 0.00149989 9.05247e-05 -9.05248e-05 + 0.00149989 9.05247e-05 -9.05248e-05 + 0.00149989 9.05247e-05 -9.05248e-05 + 0.00149989 0.000118276 -4.89919e-05 + 0.00149989 0.000118276 -4.89919e-05 + 0.00149989 0.000118276 -4.89919e-05 + 0.00149989 0.000118276 -4.89919e-05 + 0.00149989 0.000118276 -4.89919e-05 + 0.00149989 0.000128021 0 + 0.00149989 0.000128021 0 + 0.00149989 0.000128021 0 + 0.00149989 0.000128021 0 + 0.00149989 0.000128021 0 + 0.00149989 0.000118276 4.89918e-05 + 0.00149989 0.000118276 4.89918e-05 + 0.00149989 0.000118276 4.89918e-05 + 0.00149989 0.000118276 4.89918e-05 + 0.00149989 0.000118276 4.89918e-05 + 0.00149989 9.05247e-05 9.05246e-05 + 0.00149989 9.05247e-05 9.05246e-05 + 0.00149989 9.05247e-05 9.05246e-05 + 0.00149989 9.05247e-05 9.05246e-05 + 0.00149989 9.05247e-05 9.05246e-05 + 0.00149989 4.89918e-05 0.000118276 + 0.00149989 4.89918e-05 0.000118276 + 0.00149989 4.89918e-05 0.000118276 + 0.00149989 4.89918e-05 0.000118276 + 0.00149989 4.89918e-05 0.000118276 + 0.00149989 0 0.000128021 + 0.00149989 0 0.000128021 + 0.00149989 0 0.000128021 + 0.00149989 0 0.000128021 + 0.00149989 0 0.000128021 + 0.00149989 -4.89918e-05 0.000118276 + 0.00149989 -4.89918e-05 0.000118276 + 0.00149989 -4.89918e-05 0.000118276 + 0.00149989 -4.89918e-05 0.000118276 + 0.00149989 -4.89918e-05 0.000118276 + 0.00149989 -9.05247e-05 9.05246e-05 + 0.00149989 -9.05247e-05 9.05246e-05 + 0.00149989 -9.05247e-05 9.05246e-05 + 0.00149989 -9.05247e-05 9.05246e-05 + 0.00149989 -9.05247e-05 9.05246e-05 + 0.00149989 -0.000118276 4.89918e-05 + 0.00149989 -0.000118276 4.89918e-05 + 0.00149989 -0.000118276 4.89918e-05 + 0.00149989 -0.000118276 4.89918e-05 + 0.00149989 -0.000118276 4.89918e-05 + 0.00789094 -0.000118276 4.89917e-05 + 0.00789094 -0.000118276 4.89917e-05 + 0.00789094 -0.000118276 4.89917e-05 + 0.00789094 -0.000118276 4.89917e-05 + 0.00789094 -0.000118276 4.89917e-05 + 0.00789094 -0.000118276 4.89917e-05 + 0.00789094 -9.05247e-05 9.05245e-05 + 0.00789094 -9.05247e-05 9.05245e-05 + 0.00789094 -9.05247e-05 9.05245e-05 + 0.00789094 -9.05247e-05 9.05245e-05 + 0.00789094 -9.05247e-05 9.05245e-05 + 0.00789094 -9.05247e-05 9.05245e-05 + 0.00789094 -4.89918e-05 0.000118276 + 0.00789094 -4.89918e-05 0.000118276 + 0.00789094 -4.89918e-05 0.000118276 + 0.00789094 -4.89918e-05 0.000118276 + 0.00789094 -4.89918e-05 0.000118276 + 0.00789094 -4.89918e-05 0.000118276 + 0.00789094 0 0.000128021 + 0.00789094 0 0.000128021 + 0.00789094 0 0.000128021 + 0.00789094 0 0.000128021 + 0.00789094 0 0.000128021 + 0.00789094 4.89918e-05 0.000118276 + 0.00789094 4.89918e-05 0.000118276 + 0.00789094 4.89918e-05 0.000118276 + 0.00789094 4.89918e-05 0.000118276 + 0.00789094 4.89918e-05 0.000118276 + 0.00789094 4.89918e-05 0.000118276 + 0.00789094 9.05247e-05 9.05245e-05 + 0.00789094 9.05247e-05 9.05245e-05 + 0.00789094 9.05247e-05 9.05245e-05 + 0.00789094 9.05247e-05 9.05245e-05 + 0.00789094 9.05247e-05 9.05245e-05 + 0.00789094 9.05247e-05 9.05245e-05 + 0.00789094 0.000118276 4.89917e-05 + 0.00789094 0.000118276 4.89917e-05 + 0.00789094 0.000118276 4.89917e-05 + 0.00789094 0.000118276 4.89917e-05 + 0.00789094 0.000118276 4.89917e-05 + 0.00789094 0.000118276 4.89917e-05 + 0.00789094 0.000128021 0 + 0.00789094 0.000128021 0 + 0.00789094 0.000128021 0 + 0.00789094 0.000128021 0 + 0.00789094 0.000128021 0 + 0.00789094 0.000128021 0 + 0.00789094 0.000118276 -4.8992e-05 + 0.00789094 0.000118276 -4.8992e-05 + 0.00789094 0.000118276 -4.8992e-05 + 0.00789094 0.000118276 -4.8992e-05 + 0.00789094 0.000118276 -4.8992e-05 + 0.00789094 0.000118276 -4.8992e-05 + 0.00789094 9.05247e-05 -9.05249e-05 + 0.00789094 9.05247e-05 -9.05249e-05 + 0.00789094 9.05247e-05 -9.05249e-05 + 0.00789094 9.05247e-05 -9.05249e-05 + 0.00789094 9.05247e-05 -9.05249e-05 + 0.00789094 9.05247e-05 -9.05249e-05 + 0.00789094 4.89918e-05 -0.000118277 + 0.00789094 4.89918e-05 -0.000118277 + 0.00789094 4.89918e-05 -0.000118277 + 0.00789094 4.89918e-05 -0.000118277 + 0.00789094 4.89918e-05 -0.000118277 + 0.00789094 4.89918e-05 -0.000118277 + 0.00789094 0 -0.000128021 + 0.00789094 0 -0.000128021 + 0.00789094 0 -0.000128021 + 0.00789094 0 -0.000128021 + 0.00789094 0 -0.000128021 + 0.00789094 0 -0.000128021 + 0.00789094 0 -0.000128021 + 0.00789094 -4.89918e-05 -0.000118277 + 0.00789094 -4.89918e-05 -0.000118277 + 0.00789094 -4.89918e-05 -0.000118277 + 0.00789094 -4.89918e-05 -0.000118277 + 0.00789094 -4.89918e-05 -0.000118277 + 0.00789094 -4.89918e-05 -0.000118277 + 0.00789094 -9.05247e-05 -9.05249e-05 + 0.00789094 -9.05247e-05 -9.05249e-05 + 0.00789094 -9.05247e-05 -9.05249e-05 + 0.00789094 -9.05247e-05 -9.05249e-05 + 0.00789094 -9.05247e-05 -9.05249e-05 + 0.00789094 -9.05247e-05 -9.05249e-05 + 0.00789094 -0.000118276 -4.8992e-05 + 0.00789094 -0.000118276 -4.8992e-05 + 0.00789094 -0.000118276 -4.8992e-05 + 0.00789094 -0.000118276 -4.8992e-05 + 0.00789094 -0.000118276 -4.8992e-05 + 0.00789094 -0.000118276 -4.8992e-05 + 0.00789094 -0.000128021 0 + 0.00789094 -0.000128021 0 + 0.00789094 -0.000128021 0 + 0.00789094 -0.000128021 0 + 0.00789094 -0.000128021 0 + 0.00789094 -0.000128021 0 + } + } + } + NormalArray TRUE { + osg::Vec3Array { + UniqueID 22 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 21 + } + } + Binding BIND_PER_VERTEX + vector 288 { + -0.582047 2.85261e-07 -0.813155 + -0.582047 2.85261e-07 -0.813155 + -0.582047 2.85261e-07 -0.813155 + -0.582047 2.85261e-07 -0.813155 + -0.582048 -0.311179 -0.751257 + -0.582048 -0.311179 -0.751257 + -0.582048 -0.311179 -0.751257 + -0.582048 -0.311179 -0.751257 + -0.582048 -0.311179 -0.751257 + -0.582047 -0.574986 -0.574989 + -0.582047 -0.574986 -0.574989 + -0.582047 -0.574986 -0.574989 + -0.582047 -0.574986 -0.574989 + -0.582047 -0.574986 -0.574989 + -0.582049 -0.751257 -0.311179 + -0.582049 -0.751257 -0.311179 + -0.582049 -0.751257 -0.311179 + -0.582049 -0.751257 -0.311179 + -0.582049 -0.751257 -0.311179 + -0.582048 -0.813155 4.94071e-06 + -0.582048 -0.813155 4.94071e-06 + -0.582048 -0.813155 4.94071e-06 + -0.582048 -0.813155 4.94071e-06 + -0.582048 -0.813155 4.94071e-06 + -0.582049 -0.751255 0.311183 + -0.582049 -0.751255 0.311183 + -0.582049 -0.751255 0.311183 + -0.582049 -0.751255 0.311183 + -0.582049 -0.751255 0.311183 + -0.58205 -0.574986 0.574986 + -0.58205 -0.574986 0.574986 + -0.58205 -0.574986 0.574986 + -0.58205 -0.574986 0.574986 + -0.58205 -0.574986 0.574986 + -0.582049 -0.311176 0.751258 + -0.582049 -0.311176 0.751258 + -0.582049 -0.311176 0.751258 + -0.582049 -0.311176 0.751258 + -0.582049 -0.311176 0.751258 + -0.582052 9.38735e-07 0.813152 + -0.582052 9.38735e-07 0.813152 + -0.582052 9.38735e-07 0.813152 + -0.582052 9.38735e-07 0.813152 + -0.582052 9.38735e-07 0.813152 + -0.582052 9.38735e-07 0.813152 + -0.582048 0.311178 0.751257 + -0.582048 0.311178 0.751257 + -0.582048 0.311178 0.751257 + -0.582048 0.311178 0.751257 + -0.582048 0.311178 0.751257 + -0.58205 0.574987 0.574985 + -0.58205 0.574987 0.574985 + -0.58205 0.574987 0.574985 + -0.58205 0.574987 0.574985 + -0.58205 0.574987 0.574985 + -0.582049 0.751255 0.311183 + -0.582049 0.751255 0.311183 + -0.582049 0.751255 0.311183 + -0.582049 0.751255 0.311183 + -0.582049 0.751255 0.311183 + -0.582048 0.813155 4.94073e-06 + -0.582048 0.813155 4.94073e-06 + -0.582048 0.813155 4.94073e-06 + -0.582048 0.813155 4.94073e-06 + -0.582048 0.813155 4.94073e-06 + -0.582048 0.751257 -0.311179 + -0.582048 0.751257 -0.311179 + -0.582048 0.751257 -0.311179 + -0.582048 0.751257 -0.311179 + -0.582048 0.751257 -0.311179 + -0.582046 0.574987 -0.574989 + -0.582046 0.574987 -0.574989 + -0.582046 0.574987 -0.574989 + -0.582046 0.574987 -0.574989 + -0.582046 0.574987 -0.574989 + -0.582048 0.311179 -0.751258 + -0.582048 0.311179 -0.751258 + -0.582048 0.311179 -0.751258 + -0.582048 0.311179 -0.751258 + -0.582048 0.311179 -0.751258 + 1 1.84875e-07 -1.05643e-06 + 1 1.84875e-07 -1.05643e-06 + 1 1.84875e-07 -1.05643e-06 + 1 1.84875e-07 -1.05643e-06 + 1 1.84875e-07 -1.05643e-06 + 1 1.84875e-07 -1.05643e-06 + 1 1.84875e-07 -1.05643e-06 + 1 1.84875e-07 -1.05643e-06 + 1 1.84875e-07 -1.05643e-06 + 1 1.84875e-07 -1.05643e-06 + 1 1.84875e-07 -1.05643e-06 + 1 1.84875e-07 -1.05643e-06 + 1 1.84875e-07 -1.05643e-06 + 1 1.84875e-07 -1.05643e-06 + 1 1.84875e-07 -1.05643e-06 + 1 1.84875e-07 -1.05643e-06 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -0.66572 -0.746202 -1.33156e-07 + -0.66572 -0.746202 -1.33156e-07 + -0.66572 -0.746202 -1.33156e-07 + -0.66572 -0.746202 -1.33156e-07 + -0.66572 -0.746202 -1.33156e-07 + -0.665719 -0.689402 -0.285558 + -0.665719 -0.689402 -0.285558 + -0.665719 -0.689402 -0.285558 + -0.665719 -0.689402 -0.285558 + -0.665719 -0.689402 -0.285558 + -0.66572 -0.527648 -0.52764 + -0.66572 -0.527648 -0.52764 + -0.66572 -0.527648 -0.52764 + -0.66572 -0.527648 -0.52764 + -0.66572 -0.527648 -0.52764 + -0.665716 -0.285558 -0.689405 + -0.665716 -0.285558 -0.689405 + -0.665716 -0.285558 -0.689405 + -0.665716 -0.285558 -0.689405 + -0.665716 -0.285558 -0.689405 + -0.665724 1.55766e-07 -0.746199 + -0.665724 1.55766e-07 -0.746199 + -0.665724 1.55766e-07 -0.746199 + -0.665724 1.55766e-07 -0.746199 + -0.665724 1.55766e-07 -0.746199 + -0.665716 0.285558 -0.689405 + -0.665716 0.285558 -0.689405 + -0.665716 0.285558 -0.689405 + -0.665716 0.285558 -0.689405 + -0.665716 0.285558 -0.689405 + -0.66572 0.527649 -0.52764 + -0.66572 0.527649 -0.52764 + -0.66572 0.527649 -0.52764 + -0.66572 0.527649 -0.52764 + -0.66572 0.527649 -0.52764 + -0.665719 0.689402 -0.285558 + -0.665719 0.689402 -0.285558 + -0.665719 0.689402 -0.285558 + -0.665719 0.689402 -0.285558 + -0.665719 0.689402 -0.285558 + -0.66572 0.746202 4.29748e-07 + -0.66572 0.746202 4.29748e-07 + -0.66572 0.746202 4.29748e-07 + -0.66572 0.746202 4.29748e-07 + -0.66572 0.746202 4.29748e-07 + -0.665719 0.689401 0.285559 + -0.665719 0.689401 0.285559 + -0.665719 0.689401 0.285559 + -0.665719 0.689401 0.285559 + -0.665719 0.689401 0.285559 + -0.665719 0.527646 0.527645 + -0.665719 0.527646 0.527645 + -0.665719 0.527646 0.527645 + -0.665719 0.527646 0.527645 + -0.665719 0.527646 0.527645 + -0.665719 0.28556 0.689401 + -0.665719 0.28556 0.689401 + -0.665719 0.28556 0.689401 + -0.665719 0.28556 0.689401 + -0.665719 0.28556 0.689401 + -0.66572 -1.61998e-07 0.746202 + -0.66572 -1.61998e-07 0.746202 + -0.66572 -1.61998e-07 0.746202 + -0.66572 -1.61998e-07 0.746202 + -0.66572 -1.61998e-07 0.746202 + -0.665719 -0.28556 0.689401 + -0.665719 -0.28556 0.689401 + -0.665719 -0.28556 0.689401 + -0.665719 -0.28556 0.689401 + -0.665719 -0.28556 0.689401 + -0.665719 -0.527646 0.527644 + -0.665719 -0.527646 0.527644 + -0.665719 -0.527646 0.527644 + -0.665719 -0.527646 0.527644 + -0.665719 -0.527646 0.527644 + -0.665719 -0.689402 0.285558 + -0.665719 -0.689402 0.285558 + -0.665719 -0.689402 0.285558 + -0.665719 -0.689402 0.285558 + -0.665719 -0.689402 0.285558 + -0.763025 -0.597167 0.247355 + -0.763025 -0.597167 0.247355 + -0.763025 -0.597167 0.247355 + -0.763025 -0.597167 0.247355 + -0.763025 -0.597167 0.247355 + -0.763025 -0.597167 0.247355 + -0.763022 -0.457057 0.457051 + -0.763022 -0.457057 0.457051 + -0.763022 -0.457057 0.457051 + -0.763022 -0.457057 0.457051 + -0.763022 -0.457057 0.457051 + -0.763022 -0.457057 0.457051 + -0.763023 -0.24736 0.597167 + -0.763023 -0.24736 0.597167 + -0.763023 -0.24736 0.597167 + -0.763023 -0.24736 0.597167 + -0.763023 -0.24736 0.597167 + -0.763023 -0.24736 0.597167 + -0.763024 -9.96434e-07 0.64637 + -0.763024 -9.96434e-07 0.64637 + -0.763024 -9.96434e-07 0.64637 + -0.763024 -9.96434e-07 0.64637 + -0.763024 -9.96434e-07 0.64637 + -0.763024 0.247356 0.597168 + -0.763024 0.247356 0.597168 + -0.763024 0.247356 0.597168 + -0.763024 0.247356 0.597168 + -0.763024 0.247356 0.597168 + -0.763024 0.247356 0.597168 + -0.763023 0.457057 0.457051 + -0.763023 0.457057 0.457051 + -0.763023 0.457057 0.457051 + -0.763023 0.457057 0.457051 + -0.763023 0.457057 0.457051 + -0.763023 0.457057 0.457051 + -0.763024 0.597169 0.247354 + -0.763024 0.597169 0.247354 + -0.763024 0.597169 0.247354 + -0.763024 0.597169 0.247354 + -0.763024 0.597169 0.247354 + -0.763024 0.597169 0.247354 + -0.763024 0.64637 -1.48037e-07 + -0.763024 0.64637 -1.48037e-07 + -0.763024 0.64637 -1.48037e-07 + -0.763024 0.64637 -1.48037e-07 + -0.763024 0.64637 -1.48037e-07 + -0.763024 0.64637 -1.48037e-07 + -0.763025 0.597168 -0.247355 + -0.763025 0.597168 -0.247355 + -0.763025 0.597168 -0.247355 + -0.763025 0.597168 -0.247355 + -0.763025 0.597168 -0.247355 + -0.763025 0.597168 -0.247355 + -0.763022 0.457059 -0.45705 + -0.763022 0.457059 -0.45705 + -0.763022 0.457059 -0.45705 + -0.763022 0.457059 -0.45705 + -0.763022 0.457059 -0.45705 + -0.763022 0.457059 -0.45705 + -0.76303 0.247343 -0.597166 + -0.76303 0.247343 -0.597166 + -0.76303 0.247343 -0.597166 + -0.76303 0.247343 -0.597166 + -0.76303 0.247343 -0.597166 + -0.76303 0.247343 -0.597166 + -0.763019 -3.05831e-06 -0.646377 + -0.763019 -3.05831e-06 -0.646377 + -0.763019 -3.05831e-06 -0.646377 + -0.763019 -3.05831e-06 -0.646377 + -0.763019 -3.05831e-06 -0.646377 + -0.763019 -3.05831e-06 -0.646377 + -0.763019 -3.05831e-06 -0.646377 + -0.76303 -0.247345 -0.597166 + -0.76303 -0.247345 -0.597166 + -0.76303 -0.247345 -0.597166 + -0.76303 -0.247345 -0.597166 + -0.76303 -0.247345 -0.597166 + -0.76303 -0.247345 -0.597166 + -0.763023 -0.457057 -0.457051 + -0.763023 -0.457057 -0.457051 + -0.763023 -0.457057 -0.457051 + -0.763023 -0.457057 -0.457051 + -0.763023 -0.457057 -0.457051 + -0.763023 -0.457057 -0.457051 + -0.763024 -0.597169 -0.247354 + -0.763024 -0.597169 -0.247354 + -0.763024 -0.597169 -0.247354 + -0.763024 -0.597169 -0.247354 + -0.763024 -0.597169 -0.247354 + -0.763024 -0.597169 -0.247354 + -0.763024 -0.64637 3.49074e-07 + -0.763024 -0.64637 3.49074e-07 + -0.763024 -0.64637 3.49074e-07 + -0.763024 -0.64637 3.49074e-07 + -0.763024 -0.64637 3.49074e-07 + -0.763024 -0.64637 3.49074e-07 + } + } + } + ColorArray TRUE { + osg::Vec4Array { + UniqueID 23 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 21 + } + } + Binding BIND_PER_VERTEX + vector 288 { + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + } + } + } + } + } + } + } + Matrix { + 253.52 0 0 0 + 0 253.52 0 0 + 0 0 253.52 0 + 0 0 0 1 + } + + } + osg::MatrixTransform { + UniqueID 24 + Name "Z_Axis" + UserDataContainer TRUE { + osg::DefaultUserDataContainer { + UniqueID 25 + UDC_UserObjects 1 { + osg::StringValueObject { + UniqueID 26 + Name "dae_node_id" + Value "Z_Axis" + } + } + } + } + StateSet TRUE { + osg::StateSet { + UniqueID 6 + } + } + Children 1 { + osg::Geode { + UniqueID 27 + Drawables 1 { + osg::Geometry { + UniqueID 28 + Name "blue-material" + DataVariance STATIC + StateSet TRUE { + osg::StateSet { + UniqueID 29 + Name "blue" + DataVariance STATIC + ModeList 1 { + GL_CULL_FACE ON + } + AttributeList 1 { + osg::Material { + UniqueID 30 + Ambient TRUE Front 0.0512699 0.38982 0.8 1 Back 0.0512699 0.38982 0.8 1 + Diffuse TRUE Front 0 0 0 1 Back 0 0 0 1 + Specular TRUE Front 0 0 0 1 Back 0 0 0 1 + Emission TRUE Front 0.0512699 0.38982 0.8 1 Back 0.0512699 0.38982 0.8 1 + Shininess TRUE Front 0 Back 0 + } + Value OFF + } + } + } + PrimitiveSetList 1 { + osg::DrawElementsUInt { + UniqueID 31 + BufferObject TRUE { + osg::ElementBufferObject { + UniqueID 32 + Target 34963 + } + } + Mode TRIANGLES + vector 288 { + 0 80 4 5 + 81 9 10 82 + 15 16 83 19 + 20 84 24 25 + 85 29 30 86 + 35 36 87 39 + 40 88 45 46 + 89 49 50 90 + 55 56 91 60 + 61 92 65 66 + 93 69 70 94 + 75 76 95 1 + 96 117 112 97 + 122 118 98 127 + 123 99 132 128 + 100 137 133 101 + 142 138 102 147 + 143 103 152 148 + 104 157 153 105 + 162 158 106 167 + 163 107 172 168 + 108 177 173 109 + 182 178 110 187 + 183 111 113 188 + 51 239 47 129 + 270 124 275 71 + 77 179 210 174 + 11 192 6 119 + 281 114 159 234 + 154 227 31 37 + 134 263 130 203 + 12 17 139 257 + 135 164 228 160 + 184 204 180 189 + 198 185 175 216 + 169 258 57 62 + 251 52 58 21 + 205 18 240 41 + 48 149 246 144 + 72 264 67 125 + 276 120 7 282 + 2 32 217 26 + 155 241 150 145 + 252 140 170 222 + 165 115 193 190 + 283 78 3 265 + 63 68 42 229 + 38 27 211 22 + 53 247 242 131 + 266 271 277 272 + 73 181 206 212 + 13 199 194 121 + 278 284 161 230 + 235 231 223 33 + 136 259 267 207 + 200 14 141 253 + 260 166 224 232 + 186 201 208 191 + 195 202 176 213 + 218 261 254 59 + 255 248 54 23 + 214 209 243 236 + 43 151 244 249 + 74 273 268 126 + 274 279 8 196 + 285 34 225 219 + 156 237 245 146 + 250 256 171 220 + 226 116 286 197 + 287 280 79 269 + 262 64 44 238 + 233 28 221 215 + + } + } + } + VertexArray TRUE { + osg::Vec3Array { + UniqueID 33 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 34 + } + } + Binding BIND_PER_VERTEX + vector 288 { + 0 -0.000521396 0.00789094 + 0 -0.000521396 0.00789094 + 0 -0.000521396 0.00789094 + 0 -0.000521396 0.00789094 + -0.000199529 -0.000481707 0.00789094 + -0.000199529 -0.000481707 0.00789094 + -0.000199529 -0.000481707 0.00789094 + -0.000199529 -0.000481707 0.00789094 + -0.000199529 -0.000481707 0.00789094 + -0.000368682 -0.000368683 0.00789094 + -0.000368682 -0.000368683 0.00789094 + -0.000368682 -0.000368683 0.00789094 + -0.000368682 -0.000368683 0.00789094 + -0.000368682 -0.000368683 0.00789094 + -0.000368682 -0.000368683 0.00789094 + -0.000481707 -0.00019953 0.00789094 + -0.000481707 -0.00019953 0.00789094 + -0.000481707 -0.00019953 0.00789094 + -0.000481707 -0.00019953 0.00789094 + -0.000521396 0 0.00789094 + -0.000521396 0 0.00789094 + -0.000521396 0 0.00789094 + -0.000521396 0 0.00789094 + -0.000521396 0 0.00789094 + -0.000481707 0.000199529 0.00789094 + -0.000481707 0.000199529 0.00789094 + -0.000481707 0.000199529 0.00789094 + -0.000481707 0.000199529 0.00789094 + -0.000481707 0.000199529 0.00789094 + -0.000368682 0.000368682 0.00789094 + -0.000368682 0.000368682 0.00789094 + -0.000368682 0.000368682 0.00789094 + -0.000368682 0.000368682 0.00789094 + -0.000368682 0.000368682 0.00789094 + -0.000368682 0.000368682 0.00789094 + -0.000199529 0.000481707 0.00789094 + -0.000199529 0.000481707 0.00789094 + -0.000199529 0.000481707 0.00789094 + -0.000199529 0.000481707 0.00789094 + 0 0.000521394 0.00789094 + 0 0.000521394 0.00789094 + 0 0.000521394 0.00789094 + 0 0.000521394 0.00789094 + 0 0.000521394 0.00789094 + 0 0.000521394 0.00789094 + 0.000199529 0.000481707 0.00789094 + 0.000199529 0.000481707 0.00789094 + 0.000199529 0.000481707 0.00789094 + 0.000199529 0.000481707 0.00789094 + 0.000368682 0.000368682 0.00789094 + 0.000368682 0.000368682 0.00789094 + 0.000368682 0.000368682 0.00789094 + 0.000368682 0.000368682 0.00789094 + 0.000368682 0.000368682 0.00789094 + 0.000368682 0.000368682 0.00789094 + 0.000481707 0.000199529 0.00789094 + 0.000481707 0.000199529 0.00789094 + 0.000481707 0.000199529 0.00789094 + 0.000481707 0.000199529 0.00789094 + 0.000481707 0.000199529 0.00789094 + 0.000521396 0 0.00789094 + 0.000521396 0 0.00789094 + 0.000521396 0 0.00789094 + 0.000521396 0 0.00789094 + 0.000521396 0 0.00789094 + 0.000481707 -0.00019953 0.00789094 + 0.000481707 -0.00019953 0.00789094 + 0.000481707 -0.00019953 0.00789094 + 0.000481707 -0.00019953 0.00789094 + 0.000368682 -0.000368683 0.00789094 + 0.000368682 -0.000368683 0.00789094 + 0.000368682 -0.000368683 0.00789094 + 0.000368682 -0.000368683 0.00789094 + 0.000368682 -0.000368683 0.00789094 + 0.000368682 -0.000368683 0.00789094 + 0.000199529 -0.000481707 0.00789094 + 0.000199529 -0.000481707 0.00789094 + 0.000199529 -0.000481707 0.00789094 + 0.000199529 -0.000481707 0.00789094 + 0.000199529 -0.000481707 0.00789094 + 0 0 0.0100016 + 0 0 0.0100016 + 0 0 0.0100016 + 0 0 0.0100016 + 0 0 0.0100016 + 0 0 0.0100016 + 0 0 0.0100016 + 0 0 0.0100016 + 0 0 0.0100016 + 0 0 0.0100016 + 0 0 0.0100016 + 0 0 0.0100016 + 0 0 0.0100016 + 0 0 0.0100016 + 0 0 0.0100016 + 0 0 0.0100016 + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 -0.000128021 0.00149989 + 0 -0.000128021 0.00149989 + 0 -0.000128021 0.00149989 + 0 -0.000128021 0.00149989 + 0 -0.000128021 0.00149989 + 4.89918e-05 -0.000118276 0.00149989 + 4.89918e-05 -0.000118276 0.00149989 + 4.89918e-05 -0.000118276 0.00149989 + 4.89918e-05 -0.000118276 0.00149989 + 4.89918e-05 -0.000118276 0.00149989 + 9.05247e-05 -9.05247e-05 0.00149989 + 9.05247e-05 -9.05247e-05 0.00149989 + 9.05247e-05 -9.05247e-05 0.00149989 + 9.05247e-05 -9.05247e-05 0.00149989 + 9.05247e-05 -9.05247e-05 0.00149989 + 0.000118276 -4.89918e-05 0.00149989 + 0.000118276 -4.89918e-05 0.00149989 + 0.000118276 -4.89918e-05 0.00149989 + 0.000118276 -4.89918e-05 0.00149989 + 0.000118276 -4.89918e-05 0.00149989 + 0.000128021 0 0.00149989 + 0.000128021 0 0.00149989 + 0.000128021 0 0.00149989 + 0.000128021 0 0.00149989 + 0.000128021 0 0.00149989 + 0.000118276 4.89918e-05 0.00149989 + 0.000118276 4.89918e-05 0.00149989 + 0.000118276 4.89918e-05 0.00149989 + 0.000118276 4.89918e-05 0.00149989 + 0.000118276 4.89918e-05 0.00149989 + 9.05247e-05 9.05247e-05 0.00149989 + 9.05247e-05 9.05247e-05 0.00149989 + 9.05247e-05 9.05247e-05 0.00149989 + 9.05247e-05 9.05247e-05 0.00149989 + 9.05247e-05 9.05247e-05 0.00149989 + 4.89918e-05 0.000118276 0.00149989 + 4.89918e-05 0.000118276 0.00149989 + 4.89918e-05 0.000118276 0.00149989 + 4.89918e-05 0.000118276 0.00149989 + 4.89918e-05 0.000118276 0.00149989 + 0 0.000128021 0.00149989 + 0 0.000128021 0.00149989 + 0 0.000128021 0.00149989 + 0 0.000128021 0.00149989 + 0 0.000128021 0.00149989 + -4.89918e-05 0.000118276 0.00149989 + -4.89918e-05 0.000118276 0.00149989 + -4.89918e-05 0.000118276 0.00149989 + -4.89918e-05 0.000118276 0.00149989 + -4.89918e-05 0.000118276 0.00149989 + -9.05247e-05 9.05247e-05 0.00149989 + -9.05247e-05 9.05247e-05 0.00149989 + -9.05247e-05 9.05247e-05 0.00149989 + -9.05247e-05 9.05247e-05 0.00149989 + -9.05247e-05 9.05247e-05 0.00149989 + -0.000118276 4.89918e-05 0.00149989 + -0.000118276 4.89918e-05 0.00149989 + -0.000118276 4.89918e-05 0.00149989 + -0.000118276 4.89918e-05 0.00149989 + -0.000118276 4.89918e-05 0.00149989 + -0.000128021 0 0.00149989 + -0.000128021 0 0.00149989 + -0.000128021 0 0.00149989 + -0.000128021 0 0.00149989 + -0.000128021 0 0.00149989 + -0.000118276 -4.89918e-05 0.00149989 + -0.000118276 -4.89918e-05 0.00149989 + -0.000118276 -4.89918e-05 0.00149989 + -0.000118276 -4.89918e-05 0.00149989 + -0.000118276 -4.89918e-05 0.00149989 + -9.05247e-05 -9.05247e-05 0.00149989 + -9.05247e-05 -9.05247e-05 0.00149989 + -9.05247e-05 -9.05247e-05 0.00149989 + -9.05247e-05 -9.05247e-05 0.00149989 + -9.05247e-05 -9.05247e-05 0.00149989 + -4.89918e-05 -0.000118276 0.00149989 + -4.89918e-05 -0.000118276 0.00149989 + -4.89918e-05 -0.000118276 0.00149989 + -4.89918e-05 -0.000118276 0.00149989 + -4.89918e-05 -0.000118276 0.00149989 + -4.89918e-05 -0.000118276 0.00789094 + -4.89918e-05 -0.000118276 0.00789094 + -4.89918e-05 -0.000118276 0.00789094 + -4.89918e-05 -0.000118276 0.00789094 + -4.89918e-05 -0.000118276 0.00789094 + -4.89918e-05 -0.000118276 0.00789094 + -9.05247e-05 -9.05247e-05 0.00789094 + -9.05247e-05 -9.05247e-05 0.00789094 + -9.05247e-05 -9.05247e-05 0.00789094 + -9.05247e-05 -9.05247e-05 0.00789094 + -9.05247e-05 -9.05247e-05 0.00789094 + -0.000118276 -4.89918e-05 0.00789094 + -0.000118276 -4.89918e-05 0.00789094 + -0.000118276 -4.89918e-05 0.00789094 + -0.000118276 -4.89918e-05 0.00789094 + -0.000118276 -4.89918e-05 0.00789094 + -0.000118276 -4.89918e-05 0.00789094 + -0.000118276 -4.89918e-05 0.00789094 + -0.000128021 0 0.00789094 + -0.000128021 0 0.00789094 + -0.000128021 0 0.00789094 + -0.000128021 0 0.00789094 + -0.000128021 0 0.00789094 + -0.000128021 0 0.00789094 + -0.000118276 4.89918e-05 0.00789094 + -0.000118276 4.89918e-05 0.00789094 + -0.000118276 4.89918e-05 0.00789094 + -0.000118276 4.89918e-05 0.00789094 + -0.000118276 4.89918e-05 0.00789094 + -0.000118276 4.89918e-05 0.00789094 + -9.05247e-05 9.05247e-05 0.00789094 + -9.05247e-05 9.05247e-05 0.00789094 + -9.05247e-05 9.05247e-05 0.00789094 + -9.05247e-05 9.05247e-05 0.00789094 + -9.05247e-05 9.05247e-05 0.00789094 + -4.89918e-05 0.000118276 0.00789094 + -4.89918e-05 0.000118276 0.00789094 + -4.89918e-05 0.000118276 0.00789094 + -4.89918e-05 0.000118276 0.00789094 + -4.89918e-05 0.000118276 0.00789094 + -4.89918e-05 0.000118276 0.00789094 + -4.89918e-05 0.000118276 0.00789094 + 0 0.000128021 0.00789094 + 0 0.000128021 0.00789094 + 0 0.000128021 0.00789094 + 0 0.000128021 0.00789094 + 0 0.000128021 0.00789094 + 4.89918e-05 0.000118276 0.00789094 + 4.89918e-05 0.000118276 0.00789094 + 4.89918e-05 0.000118276 0.00789094 + 4.89918e-05 0.000118276 0.00789094 + 4.89918e-05 0.000118276 0.00789094 + 4.89918e-05 0.000118276 0.00789094 + 4.89918e-05 0.000118276 0.00789094 + 9.05247e-05 9.05247e-05 0.00789094 + 9.05247e-05 9.05247e-05 0.00789094 + 9.05247e-05 9.05247e-05 0.00789094 + 9.05247e-05 9.05247e-05 0.00789094 + 9.05247e-05 9.05247e-05 0.00789094 + 0.000118276 4.89918e-05 0.00789094 + 0.000118276 4.89918e-05 0.00789094 + 0.000118276 4.89918e-05 0.00789094 + 0.000118276 4.89918e-05 0.00789094 + 0.000118276 4.89918e-05 0.00789094 + 0.000118276 4.89918e-05 0.00789094 + 0.000128021 0 0.00789094 + 0.000128021 0 0.00789094 + 0.000128021 0 0.00789094 + 0.000128021 0 0.00789094 + 0.000128021 0 0.00789094 + 0.000128021 0 0.00789094 + 0.000118276 -4.89918e-05 0.00789094 + 0.000118276 -4.89918e-05 0.00789094 + 0.000118276 -4.89918e-05 0.00789094 + 0.000118276 -4.89918e-05 0.00789094 + 0.000118276 -4.89918e-05 0.00789094 + 0.000118276 -4.89918e-05 0.00789094 + 0.000118276 -4.89918e-05 0.00789094 + 9.05247e-05 -9.05247e-05 0.00789094 + 9.05247e-05 -9.05247e-05 0.00789094 + 9.05247e-05 -9.05247e-05 0.00789094 + 9.05247e-05 -9.05247e-05 0.00789094 + 9.05247e-05 -9.05247e-05 0.00789094 + 4.89918e-05 -0.000118276 0.00789094 + 4.89918e-05 -0.000118276 0.00789094 + 4.89918e-05 -0.000118276 0.00789094 + 4.89918e-05 -0.000118276 0.00789094 + 4.89918e-05 -0.000118276 0.00789094 + 4.89918e-05 -0.000118276 0.00789094 + 0 -0.000128021 0.00789094 + 0 -0.000128021 0.00789094 + 0 -0.000128021 0.00789094 + 0 -0.000128021 0.00789094 + 0 -0.000128021 0.00789094 + 0 -0.000128021 0.00789094 + 0 -0.000128021 0.00789094 + } + } + } + NormalArray TRUE { + osg::Vec3Array { + UniqueID 35 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 34 + } + } + Binding BIND_PER_VERTEX + vector 288 { + -5.6158e-07 -0.81957 -0.572979 + -5.6158e-07 -0.81957 -0.572979 + -5.6158e-07 -0.81957 -0.572979 + -5.6158e-07 -0.81957 -0.572979 + -0.313636 -0.757184 -0.572979 + -0.313636 -0.757184 -0.572979 + -0.313636 -0.757184 -0.572979 + -0.313636 -0.757184 -0.572979 + -0.313636 -0.757184 -0.572979 + -0.579523 -0.579525 -0.572979 + -0.579523 -0.579525 -0.572979 + -0.579523 -0.579525 -0.572979 + -0.579523 -0.579525 -0.572979 + -0.579523 -0.579525 -0.572979 + -0.579523 -0.579525 -0.572979 + -0.757183 -0.313638 -0.572979 + -0.757183 -0.313638 -0.572979 + -0.757183 -0.313638 -0.572979 + -0.757183 -0.313638 -0.572979 + -0.81957 3.78311e-07 -0.57298 + -0.81957 3.78311e-07 -0.57298 + -0.81957 3.78311e-07 -0.57298 + -0.81957 3.78311e-07 -0.57298 + -0.81957 3.78311e-07 -0.57298 + -0.757183 0.313638 -0.57298 + -0.757183 0.313638 -0.57298 + -0.757183 0.313638 -0.57298 + -0.757183 0.313638 -0.57298 + -0.757183 0.313638 -0.57298 + -0.579522 0.579524 -0.57298 + -0.579522 0.579524 -0.57298 + -0.579522 0.579524 -0.57298 + -0.579522 0.579524 -0.57298 + -0.579522 0.579524 -0.57298 + -0.579522 0.579524 -0.57298 + -0.313632 0.757186 -0.572978 + -0.313632 0.757186 -0.572978 + -0.313632 0.757186 -0.572978 + -0.313632 0.757186 -0.572978 + 0 0.819569 -0.572981 + 0 0.819569 -0.572981 + 0 0.819569 -0.572981 + 0 0.819569 -0.572981 + 0 0.819569 -0.572981 + 0 0.819569 -0.572981 + 0.313632 0.757186 -0.572978 + 0.313632 0.757186 -0.572978 + 0.313632 0.757186 -0.572978 + 0.313632 0.757186 -0.572978 + 0.579521 0.579524 -0.57298 + 0.579521 0.579524 -0.57298 + 0.579521 0.579524 -0.57298 + 0.579521 0.579524 -0.57298 + 0.579521 0.579524 -0.57298 + 0.579521 0.579524 -0.57298 + 0.757182 0.313638 -0.57298 + 0.757182 0.313638 -0.57298 + 0.757182 0.313638 -0.57298 + 0.757182 0.313638 -0.57298 + 0.757182 0.313638 -0.57298 + 0.819569 3.78311e-07 -0.57298 + 0.819569 3.78311e-07 -0.57298 + 0.819569 3.78311e-07 -0.57298 + 0.819569 3.78311e-07 -0.57298 + 0.819569 3.78311e-07 -0.57298 + 0.757183 -0.313637 -0.572979 + 0.757183 -0.313637 -0.572979 + 0.757183 -0.313637 -0.572979 + 0.757183 -0.313637 -0.572979 + 0.579522 -0.579525 -0.572979 + 0.579522 -0.579525 -0.572979 + 0.579522 -0.579525 -0.572979 + 0.579522 -0.579525 -0.572979 + 0.579522 -0.579525 -0.572979 + 0.579522 -0.579525 -0.572979 + 0.313635 -0.757184 -0.572979 + 0.313635 -0.757184 -0.572979 + 0.313635 -0.757184 -0.572979 + 0.313635 -0.757184 -0.572979 + 0.313635 -0.757184 -0.572979 + 2.0599e-07 -2.83104e-06 1 + 2.0599e-07 -2.83104e-06 1 + 2.0599e-07 -2.83104e-06 1 + 2.0599e-07 -2.83104e-06 1 + 2.0599e-07 -2.83104e-06 1 + 2.0599e-07 -2.83104e-06 1 + 2.0599e-07 -2.83104e-06 1 + 2.0599e-07 -2.83104e-06 1 + 2.0599e-07 -2.83104e-06 1 + 2.0599e-07 -2.83104e-06 1 + 2.0599e-07 -2.83104e-06 1 + 2.0599e-07 -2.83104e-06 1 + 2.0599e-07 -2.83104e-06 1 + 2.0599e-07 -2.83104e-06 1 + 2.0599e-07 -2.83104e-06 1 + 2.0599e-07 -2.83104e-06 1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 1.47817e-07 -0.746202 -0.66572 + 1.47817e-07 -0.746202 -0.66572 + 1.47817e-07 -0.746202 -0.66572 + 1.47817e-07 -0.746202 -0.66572 + 1.47817e-07 -0.746202 -0.66572 + 0.285558 -0.689401 -0.665719 + 0.285558 -0.689401 -0.665719 + 0.285558 -0.689401 -0.665719 + 0.285558 -0.689401 -0.665719 + 0.285558 -0.689401 -0.665719 + 0.527646 -0.527645 -0.665719 + 0.527646 -0.527645 -0.665719 + 0.527646 -0.527645 -0.665719 + 0.527646 -0.527645 -0.665719 + 0.527646 -0.527645 -0.665719 + 0.689402 -0.285558 -0.665719 + 0.689402 -0.285558 -0.665719 + 0.689402 -0.285558 -0.665719 + 0.689402 -0.285558 -0.665719 + 0.689402 -0.285558 -0.665719 + 0.746202 2.91827e-07 -0.66572 + 0.746202 2.91827e-07 -0.66572 + 0.746202 2.91827e-07 -0.66572 + 0.746202 2.91827e-07 -0.66572 + 0.746202 2.91827e-07 -0.66572 + 0.689402 0.285558 -0.665719 + 0.689402 0.285558 -0.665719 + 0.689402 0.285558 -0.665719 + 0.689402 0.285558 -0.665719 + 0.689402 0.285558 -0.665719 + 0.527645 0.527645 -0.665719 + 0.527645 0.527645 -0.665719 + 0.527645 0.527645 -0.665719 + 0.527645 0.527645 -0.665719 + 0.527645 0.527645 -0.665719 + 0.285558 0.689402 -0.665719 + 0.285558 0.689402 -0.665719 + 0.285558 0.689402 -0.665719 + 0.285558 0.689402 -0.665719 + 0.285558 0.689402 -0.665719 + -1.76686e-07 0.746202 -0.66572 + -1.76686e-07 0.746202 -0.66572 + -1.76686e-07 0.746202 -0.66572 + -1.76686e-07 0.746202 -0.66572 + -1.76686e-07 0.746202 -0.66572 + -0.285558 0.689401 -0.665719 + -0.285558 0.689401 -0.665719 + -0.285558 0.689401 -0.665719 + -0.285558 0.689401 -0.665719 + -0.285558 0.689401 -0.665719 + -0.527646 0.527645 -0.665719 + -0.527646 0.527645 -0.665719 + -0.527646 0.527645 -0.665719 + -0.527646 0.527645 -0.665719 + -0.527646 0.527645 -0.665719 + -0.689402 0.285558 -0.665719 + -0.689402 0.285558 -0.665719 + -0.689402 0.285558 -0.665719 + -0.689402 0.285558 -0.665719 + -0.689402 0.285558 -0.665719 + -0.746202 -2.84638e-07 -0.66572 + -0.746202 -2.84638e-07 -0.66572 + -0.746202 -2.84638e-07 -0.66572 + -0.746202 -2.84638e-07 -0.66572 + -0.746202 -2.84638e-07 -0.66572 + -0.689402 -0.285558 -0.665719 + -0.689402 -0.285558 -0.665719 + -0.689402 -0.285558 -0.665719 + -0.689402 -0.285558 -0.665719 + -0.689402 -0.285558 -0.665719 + -0.527645 -0.527645 -0.665719 + -0.527645 -0.527645 -0.665719 + -0.527645 -0.527645 -0.665719 + -0.527645 -0.527645 -0.665719 + -0.527645 -0.527645 -0.665719 + -0.285558 -0.689402 -0.665719 + -0.285558 -0.689402 -0.665719 + -0.285558 -0.689402 -0.665719 + -0.285558 -0.689402 -0.665719 + -0.285558 -0.689402 -0.665719 + -0.251474 -0.607119 -0.753769 + -0.251474 -0.607119 -0.753769 + -0.251474 -0.607119 -0.753769 + -0.251474 -0.607119 -0.753769 + -0.251474 -0.607119 -0.753769 + -0.251474 -0.607119 -0.753769 + -0.464669 -0.464667 -0.753769 + -0.464669 -0.464667 -0.753769 + -0.464669 -0.464667 -0.753769 + -0.464669 -0.464667 -0.753769 + -0.464669 -0.464667 -0.753769 + -0.607123 -0.251474 -0.753765 + -0.607123 -0.251474 -0.753765 + -0.607123 -0.251474 -0.753765 + -0.607123 -0.251474 -0.753765 + -0.607123 -0.251474 -0.753765 + -0.607123 -0.251474 -0.753765 + -0.607123 -0.251474 -0.753765 + -0.657142 2.5498e-07 -0.753767 + -0.657142 2.5498e-07 -0.753767 + -0.657142 2.5498e-07 -0.753767 + -0.657142 2.5498e-07 -0.753767 + -0.657142 2.5498e-07 -0.753767 + -0.657142 2.5498e-07 -0.753767 + -0.607122 0.251475 -0.753766 + -0.607122 0.251475 -0.753766 + -0.607122 0.251475 -0.753766 + -0.607122 0.251475 -0.753766 + -0.607122 0.251475 -0.753766 + -0.607122 0.251475 -0.753766 + -0.464671 0.464667 -0.753768 + -0.464671 0.464667 -0.753768 + -0.464671 0.464667 -0.753768 + -0.464671 0.464667 -0.753768 + -0.464671 0.464667 -0.753768 + -0.251478 0.607118 -0.753768 + -0.251478 0.607118 -0.753768 + -0.251478 0.607118 -0.753768 + -0.251478 0.607118 -0.753768 + -0.251478 0.607118 -0.753768 + -0.251478 0.607118 -0.753768 + -0.251478 0.607118 -0.753768 + -3.48568e-06 0.65714 -0.753768 + -3.48568e-06 0.65714 -0.753768 + -3.48568e-06 0.65714 -0.753768 + -3.48568e-06 0.65714 -0.753768 + -3.48568e-06 0.65714 -0.753768 + 0.251476 0.607118 -0.753768 + 0.251476 0.607118 -0.753768 + 0.251476 0.607118 -0.753768 + 0.251476 0.607118 -0.753768 + 0.251476 0.607118 -0.753768 + 0.251476 0.607118 -0.753768 + 0.251476 0.607118 -0.753768 + 0.464669 0.464667 -0.753769 + 0.464669 0.464667 -0.753769 + 0.464669 0.464667 -0.753769 + 0.464669 0.464667 -0.753769 + 0.464669 0.464667 -0.753769 + 0.607119 0.251475 -0.753768 + 0.607119 0.251475 -0.753768 + 0.607119 0.251475 -0.753768 + 0.607119 0.251475 -0.753768 + 0.607119 0.251475 -0.753768 + 0.607119 0.251475 -0.753768 + 0.657141 -2.53502e-07 -0.753768 + 0.657141 -2.53502e-07 -0.753768 + 0.657141 -2.53502e-07 -0.753768 + 0.657141 -2.53502e-07 -0.753768 + 0.657141 -2.53502e-07 -0.753768 + 0.657141 -2.53502e-07 -0.753768 + 0.607121 -0.251475 -0.753767 + 0.607121 -0.251475 -0.753767 + 0.607121 -0.251475 -0.753767 + 0.607121 -0.251475 -0.753767 + 0.607121 -0.251475 -0.753767 + 0.607121 -0.251475 -0.753767 + 0.607121 -0.251475 -0.753767 + 0.464665 -0.464669 -0.75377 + 0.464665 -0.464669 -0.75377 + 0.464665 -0.464669 -0.75377 + 0.464665 -0.464669 -0.75377 + 0.464665 -0.464669 -0.75377 + 0.25147 -0.60712 -0.75377 + 0.25147 -0.60712 -0.75377 + 0.25147 -0.60712 -0.75377 + 0.25147 -0.60712 -0.75377 + 0.25147 -0.60712 -0.75377 + 0.25147 -0.60712 -0.75377 + -2.86657e-06 -0.65714 -0.753768 + -2.86657e-06 -0.65714 -0.753768 + -2.86657e-06 -0.65714 -0.753768 + -2.86657e-06 -0.65714 -0.753768 + -2.86657e-06 -0.65714 -0.753768 + -2.86657e-06 -0.65714 -0.753768 + -2.86657e-06 -0.65714 -0.753768 + } + } + } + ColorArray TRUE { + osg::Vec4Array { + UniqueID 36 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 34 + } + } + Binding BIND_PER_VERTEX + vector 288 { + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + } + } + } + } + } + } + } + Matrix { + 253.52 0 0 0 + 0 253.52 0 0 + 0 0 253.52 0 + 0 0 0 1 + } + + } + osg::MatrixTransform { + UniqueID 37 + Name "Y_Axis" + UserDataContainer TRUE { + osg::DefaultUserDataContainer { + UniqueID 38 + UDC_UserObjects 1 { + osg::StringValueObject { + UniqueID 39 + Name "dae_node_id" + Value "Y_Axis" + } + } + } + } + StateSet TRUE { + osg::StateSet { + UniqueID 6 + } + } + Children 1 { + osg::Geode { + UniqueID 40 + Drawables 1 { + osg::Geometry { + UniqueID 41 + Name "green-material" + DataVariance STATIC + StateSet TRUE { + osg::StateSet { + UniqueID 42 + Name "green" + DataVariance STATIC + ModeList 1 { + GL_CULL_FACE ON + } + AttributeList 1 { + osg::Material { + UniqueID 43 + Ambient TRUE Front 0.190456 0.8 0.229407 1 Back 0.190456 0.8 0.229407 1 + Diffuse TRUE Front 0 0 0 1 Back 0 0 0 1 + Specular TRUE Front 0 0 0 1 Back 0 0 0 1 + Emission TRUE Front 0.190456 0.8 0.229407 1 Back 0.190456 0.8 0.229407 1 + Shininess TRUE Front 0 Back 0 + } + Value OFF + } + } + } + PrimitiveSetList 1 { + osg::DrawElementsUInt { + UniqueID 44 + BufferObject TRUE { + osg::ElementBufferObject { + UniqueID 45 + Target 34963 + } + } + Mode TRIANGLES + vector 288 { + 0 80 5 6 + 81 10 11 82 + 15 16 83 20 + 21 84 25 26 + 85 30 31 86 + 35 36 87 40 + 41 88 46 47 + 89 51 52 90 + 56 57 91 61 + 62 92 66 67 + 93 71 72 94 + 76 77 95 1 + 42 187 37 12 + 247 7 125 234 + 120 105 259 100 + 216 58 63 22 + 260 17 121 241 + 115 265 170 96 + 228 68 73 204 + 48 53 135 222 + 130 116 248 110 + 101 266 97 2 + 235 78 131 229 + 126 111 253 106 + 38 181 32 8 + 242 3 165 188 + 160 145 210 140 + 211 54 59 18 + 254 13 161 193 + 155 141 217 136 + 223 64 69 33 + 176 27 28 267 + 23 156 198 150 + 199 43 49 236 + 74 79 171 182 + 166 151 205 146 + 147 142 272 112 + 107 273 152 148 + 274 117 113 275 + 157 153 276 122 + 118 277 162 158 + 278 127 123 279 + 167 163 280 132 + 128 281 172 168 + 282 137 133 283 + 102 98 284 99 + 173 285 143 138 + 286 108 103 287 + 44 194 189 14 + 255 249 129 230 + 237 109 256 261 + 218 212 60 24 + 268 262 124 238 + 243 269 177 174 + 231 224 70 206 + 200 50 139 219 + 225 119 244 250 + 104 263 270 4 + 245 239 134 226 + 232 114 251 257 + 39 190 183 9 + 252 246 169 184 + 191 149 207 213 + 214 208 55 19 + 264 258 164 192 + 195 144 215 220 + 227 221 65 34 + 185 178 29 179 + 271 159 196 201 + 202 197 45 240 + 233 75 175 180 + 186 154 203 209 + + } + } + } + VertexArray TRUE { + osg::Vec3Array { + UniqueID 46 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 47 + } + } + Binding BIND_PER_VERTEX + vector 288 { + 0 0.0078811 -0.000521402 + 0 0.0078811 -0.000521402 + 0 0.0078811 -0.000521402 + 0 0.0078811 -0.000521402 + 0 0.0078811 -0.000521402 + 0.000199529 0.0078811 -0.000481713 + 0.000199529 0.0078811 -0.000481713 + 0.000199529 0.0078811 -0.000481713 + 0.000199529 0.0078811 -0.000481713 + 0.000199529 0.0078811 -0.000481713 + 0.000368682 0.0078811 -0.000368689 + 0.000368682 0.0078811 -0.000368689 + 0.000368682 0.0078811 -0.000368689 + 0.000368682 0.0078811 -0.000368689 + 0.000368682 0.0078811 -0.000368689 + 0.000481706 0.0078811 -0.000199536 + 0.000481706 0.0078811 -0.000199536 + 0.000481706 0.0078811 -0.000199536 + 0.000481706 0.0078811 -0.000199536 + 0.000481706 0.0078811 -0.000199536 + 0.000521396 0.0078811 0 + 0.000521396 0.0078811 0 + 0.000521396 0.0078811 0 + 0.000521396 0.0078811 0 + 0.000521396 0.0078811 0 + 0.000481706 0.0078811 0.000199523 + 0.000481706 0.0078811 0.000199523 + 0.000481706 0.0078811 0.000199523 + 0.000481706 0.0078811 0.000199523 + 0.000481706 0.0078811 0.000199523 + 0.000368682 0.0078811 0.000368675 + 0.000368682 0.0078811 0.000368675 + 0.000368682 0.0078811 0.000368675 + 0.000368682 0.0078811 0.000368675 + 0.000368682 0.0078811 0.000368675 + 0.000199529 0.0078811 0.000481701 + 0.000199529 0.0078811 0.000481701 + 0.000199529 0.0078811 0.000481701 + 0.000199529 0.0078811 0.000481701 + 0.000199529 0.0078811 0.000481701 + 0 0.0078811 0.000521388 + 0 0.0078811 0.000521388 + 0 0.0078811 0.000521388 + 0 0.0078811 0.000521388 + 0 0.0078811 0.000521388 + 0 0.0078811 0.000521388 + -0.00019953 0.0078811 0.000481701 + -0.00019953 0.0078811 0.000481701 + -0.00019953 0.0078811 0.000481701 + -0.00019953 0.0078811 0.000481701 + -0.00019953 0.0078811 0.000481701 + -0.000368683 0.0078811 0.000368675 + -0.000368683 0.0078811 0.000368675 + -0.000368683 0.0078811 0.000368675 + -0.000368683 0.0078811 0.000368675 + -0.000368683 0.0078811 0.000368675 + -0.000481707 0.0078811 0.000199523 + -0.000481707 0.0078811 0.000199523 + -0.000481707 0.0078811 0.000199523 + -0.000481707 0.0078811 0.000199523 + -0.000481707 0.0078811 0.000199523 + -0.000521396 0.0078811 0 + -0.000521396 0.0078811 0 + -0.000521396 0.0078811 0 + -0.000521396 0.0078811 0 + -0.000521396 0.0078811 0 + -0.000481707 0.0078811 -0.000199536 + -0.000481707 0.0078811 -0.000199536 + -0.000481707 0.0078811 -0.000199536 + -0.000481707 0.0078811 -0.000199536 + -0.000481707 0.0078811 -0.000199536 + -0.000368683 0.0078811 -0.000368689 + -0.000368683 0.0078811 -0.000368689 + -0.000368683 0.0078811 -0.000368689 + -0.000368683 0.0078811 -0.000368689 + -0.000368683 0.0078811 -0.000368689 + -0.00019953 0.0078811 -0.000481713 + -0.00019953 0.0078811 -0.000481713 + -0.00019953 0.0078811 -0.000481713 + -0.00019953 0.0078811 -0.000481713 + 0 0.00999188 0 + 0 0.00999188 0 + 0 0.00999188 0 + 0 0.00999188 0 + 0 0.00999188 0 + 0 0.00999188 0 + 0 0.00999188 0 + 0 0.00999188 0 + 0 0.00999188 0 + 0 0.00999188 0 + 0 0.00999188 0 + 0 0.00999188 0 + 0 0.00999188 0 + 0 0.00999188 0 + 0 0.00999188 0 + 0 0.00999188 0 + 0.000128021 0.00149989 0 + 0.000128021 0.00149989 0 + 0.000128021 0.00149989 0 + 0.000128021 0.00149989 0 + 0.000118276 0.00149989 -4.89919e-05 + 0.000118276 0.00149989 -4.89919e-05 + 0.000118276 0.00149989 -4.89919e-05 + 0.000118276 0.00149989 -4.89919e-05 + 0.000118276 0.00149989 -4.89919e-05 + 9.05246e-05 0.00149989 -9.05248e-05 + 9.05246e-05 0.00149989 -9.05248e-05 + 9.05246e-05 0.00149989 -9.05248e-05 + 9.05246e-05 0.00149989 -9.05248e-05 + 9.05246e-05 0.00149989 -9.05248e-05 + 4.89918e-05 0.00149989 -0.000118277 + 4.89918e-05 0.00149989 -0.000118277 + 4.89918e-05 0.00149989 -0.000118277 + 4.89918e-05 0.00149989 -0.000118277 + 4.89918e-05 0.00149989 -0.000118277 + 0 0.00149989 -0.000128021 + 0 0.00149989 -0.000128021 + 0 0.00149989 -0.000128021 + 0 0.00149989 -0.000128021 + 0 0.00149989 -0.000128021 + -4.89919e-05 0.00149989 -0.000118277 + -4.89919e-05 0.00149989 -0.000118277 + -4.89919e-05 0.00149989 -0.000118277 + -4.89919e-05 0.00149989 -0.000118277 + -4.89919e-05 0.00149989 -0.000118277 + -9.05247e-05 0.00149989 -9.05248e-05 + -9.05247e-05 0.00149989 -9.05248e-05 + -9.05247e-05 0.00149989 -9.05248e-05 + -9.05247e-05 0.00149989 -9.05248e-05 + -9.05247e-05 0.00149989 -9.05248e-05 + -0.000118277 0.00149989 -4.89919e-05 + -0.000118277 0.00149989 -4.89919e-05 + -0.000118277 0.00149989 -4.89919e-05 + -0.000118277 0.00149989 -4.89919e-05 + -0.000118277 0.00149989 -4.89919e-05 + -0.000128021 0.00149989 0 + -0.000128021 0.00149989 0 + -0.000128021 0.00149989 0 + -0.000128021 0.00149989 0 + -0.000128021 0.00149989 0 + -0.000118277 0.00149989 4.89918e-05 + -0.000118277 0.00149989 4.89918e-05 + -0.000118277 0.00149989 4.89918e-05 + -0.000118277 0.00149989 4.89918e-05 + -0.000118277 0.00149989 4.89918e-05 + -9.05247e-05 0.00149989 9.05245e-05 + -9.05247e-05 0.00149989 9.05245e-05 + -9.05247e-05 0.00149989 9.05245e-05 + -9.05247e-05 0.00149989 9.05245e-05 + -9.05247e-05 0.00149989 9.05245e-05 + -4.89919e-05 0.00149989 0.000118276 + -4.89919e-05 0.00149989 0.000118276 + -4.89919e-05 0.00149989 0.000118276 + -4.89919e-05 0.00149989 0.000118276 + -4.89919e-05 0.00149989 0.000118276 + 0 0.00149989 0.000128021 + 0 0.00149989 0.000128021 + 0 0.00149989 0.000128021 + 0 0.00149989 0.000128021 + 0 0.00149989 0.000128021 + 4.89918e-05 0.00149989 0.000118276 + 4.89918e-05 0.00149989 0.000118276 + 4.89918e-05 0.00149989 0.000118276 + 4.89918e-05 0.00149989 0.000118276 + 4.89918e-05 0.00149989 0.000118276 + 9.05246e-05 0.00149989 9.05245e-05 + 9.05246e-05 0.00149989 9.05245e-05 + 9.05246e-05 0.00149989 9.05245e-05 + 9.05246e-05 0.00149989 9.05245e-05 + 9.05246e-05 0.00149989 9.05245e-05 + 0.000118276 0.00149989 4.89918e-05 + 0.000118276 0.00149989 4.89918e-05 + 0.000118276 0.00149989 4.89918e-05 + 0.000118276 0.00149989 4.89918e-05 + 0.000118276 0.00149989 4.89918e-05 + 0.000118276 0.00149989 4.89918e-05 + 0.000118276 0.00789094 4.89917e-05 + 0.000118276 0.00789094 4.89917e-05 + 0.000118276 0.00789094 4.89917e-05 + 0.000118276 0.00789094 4.89917e-05 + 0.000118276 0.00789094 4.89917e-05 + 9.05244e-05 0.00789094 9.05244e-05 + 9.05244e-05 0.00789094 9.05244e-05 + 9.05244e-05 0.00789094 9.05244e-05 + 9.05244e-05 0.00789094 9.05244e-05 + 9.05244e-05 0.00789094 9.05244e-05 + 9.05244e-05 0.00789094 9.05244e-05 + 4.89916e-05 0.00789094 0.000118276 + 4.89916e-05 0.00789094 0.000118276 + 4.89916e-05 0.00789094 0.000118276 + 4.89916e-05 0.00789094 0.000118276 + 4.89916e-05 0.00789094 0.000118276 + 4.89916e-05 0.00789094 0.000118276 + 0 0.00789094 0.000128021 + 0 0.00789094 0.000128021 + 0 0.00789094 0.000128021 + 0 0.00789094 0.000128021 + 0 0.00789094 0.000128021 + -4.8992e-05 0.00789094 0.000118276 + -4.8992e-05 0.00789094 0.000118276 + -4.8992e-05 0.00789094 0.000118276 + -4.8992e-05 0.00789094 0.000118276 + -4.8992e-05 0.00789094 0.000118276 + -4.8992e-05 0.00789094 0.000118276 + -9.05249e-05 0.00789094 9.05244e-05 + -9.05249e-05 0.00789094 9.05244e-05 + -9.05249e-05 0.00789094 9.05244e-05 + -9.05249e-05 0.00789094 9.05244e-05 + -9.05249e-05 0.00789094 9.05244e-05 + -9.05249e-05 0.00789094 9.05244e-05 + -0.000118277 0.00789094 4.89917e-05 + -0.000118277 0.00789094 4.89917e-05 + -0.000118277 0.00789094 4.89917e-05 + -0.000118277 0.00789094 4.89917e-05 + -0.000118277 0.00789094 4.89917e-05 + -0.000118277 0.00789094 4.89917e-05 + -0.000128021 0.00789094 0 + -0.000128021 0.00789094 0 + -0.000128021 0.00789094 0 + -0.000128021 0.00789094 0 + -0.000128021 0.00789094 0 + -0.000128021 0.00789094 0 + -0.000118277 0.00789094 -4.8992e-05 + -0.000118277 0.00789094 -4.8992e-05 + -0.000118277 0.00789094 -4.8992e-05 + -0.000118277 0.00789094 -4.8992e-05 + -0.000118277 0.00789094 -4.8992e-05 + -0.000118277 0.00789094 -4.8992e-05 + -9.05249e-05 0.00789094 -9.05249e-05 + -9.05249e-05 0.00789094 -9.05249e-05 + -9.05249e-05 0.00789094 -9.05249e-05 + -9.05249e-05 0.00789094 -9.05249e-05 + -9.05249e-05 0.00789094 -9.05249e-05 + -9.05249e-05 0.00789094 -9.05249e-05 + -4.8992e-05 0.00789094 -0.000118277 + -4.8992e-05 0.00789094 -0.000118277 + -4.8992e-05 0.00789094 -0.000118277 + -4.8992e-05 0.00789094 -0.000118277 + -4.8992e-05 0.00789094 -0.000118277 + -4.8992e-05 0.00789094 -0.000118277 + -4.8992e-05 0.00789094 -0.000118277 + 0 0.00789094 -0.000128021 + 0 0.00789094 -0.000128021 + 0 0.00789094 -0.000128021 + 0 0.00789094 -0.000128021 + 0 0.00789094 -0.000128021 + 0 0.00789094 -0.000128021 + 4.89916e-05 0.00789094 -0.000118277 + 4.89916e-05 0.00789094 -0.000118277 + 4.89916e-05 0.00789094 -0.000118277 + 4.89916e-05 0.00789094 -0.000118277 + 4.89916e-05 0.00789094 -0.000118277 + 4.89916e-05 0.00789094 -0.000118277 + 9.05244e-05 0.00789094 -9.05249e-05 + 9.05244e-05 0.00789094 -9.05249e-05 + 9.05244e-05 0.00789094 -9.05249e-05 + 9.05244e-05 0.00789094 -9.05249e-05 + 9.05244e-05 0.00789094 -9.05249e-05 + 9.05244e-05 0.00789094 -9.05249e-05 + 0.000118276 0.00789094 -4.8992e-05 + 0.000118276 0.00789094 -4.8992e-05 + 0.000118276 0.00789094 -4.8992e-05 + 0.000118276 0.00789094 -4.8992e-05 + 0.000118276 0.00789094 -4.8992e-05 + 0.000118276 0.00789094 -4.8992e-05 + 0.000128021 0.00789094 0 + 0.000128021 0.00789094 0 + 0.000128021 0.00789094 0 + 0.000128021 0.00789094 0 + 0.000128021 0.00789094 0 + 0.000128021 0.00789094 0 + 0.000128021 0.00789094 0 + 0 0.00149989 0 + 0 0.00149989 0 + 0 0.00149989 0 + 0 0.00149989 0 + 0 0.00149989 0 + 0 0.00149989 0 + 0 0.00149989 0 + 0 0.00149989 0 + 0 0.00149989 0 + 0 0.00149989 0 + 0 0.00149989 0 + 0 0.00149989 0 + 0 0.00149989 0 + 0 0.00149989 0 + 0 0.00149989 0 + 0 0.00149989 0 + } + } + } + NormalArray TRUE { + osg::Vec3Array { + UniqueID 48 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 47 + } + } + Binding BIND_PER_VERTEX + vector 288 { + 3.59728e-07 -0.582045 -0.813157 + 3.59728e-07 -0.582045 -0.813157 + 3.59728e-07 -0.582045 -0.813157 + 3.59728e-07 -0.582045 -0.813157 + 3.59728e-07 -0.582045 -0.813157 + 0.311181 -0.582046 -0.751258 + 0.311181 -0.582046 -0.751258 + 0.311181 -0.582046 -0.751258 + 0.311181 -0.582046 -0.751258 + 0.311181 -0.582046 -0.751258 + 0.574989 -0.582046 -0.574987 + 0.574989 -0.582046 -0.574987 + 0.574989 -0.582046 -0.574987 + 0.574989 -0.582046 -0.574987 + 0.574989 -0.582046 -0.574987 + 0.751259 -0.582047 -0.311178 + 0.751259 -0.582047 -0.311178 + 0.751259 -0.582047 -0.311178 + 0.751259 -0.582047 -0.311178 + 0.751259 -0.582047 -0.311178 + 0.813156 -0.582045 4.86091e-06 + 0.813156 -0.582045 4.86091e-06 + 0.813156 -0.582045 4.86091e-06 + 0.813156 -0.582045 4.86091e-06 + 0.813156 -0.582045 4.86091e-06 + 0.751255 -0.582048 0.311184 + 0.751255 -0.582048 0.311184 + 0.751255 -0.582048 0.311184 + 0.751255 -0.582048 0.311184 + 0.751255 -0.582048 0.311184 + 0.574988 -0.582048 0.574986 + 0.574988 -0.582048 0.574986 + 0.574988 -0.582048 0.574986 + 0.574988 -0.582048 0.574986 + 0.574988 -0.582048 0.574986 + 0.311181 -0.582046 0.751258 + 0.311181 -0.582046 0.751258 + 0.311181 -0.582046 0.751258 + 0.311181 -0.582046 0.751258 + 0.311181 -0.582046 0.751258 + 3.76144e-07 -0.58205 0.813153 + 3.76144e-07 -0.58205 0.813153 + 3.76144e-07 -0.58205 0.813153 + 3.76144e-07 -0.58205 0.813153 + 3.76144e-07 -0.58205 0.813153 + 3.76144e-07 -0.58205 0.813153 + -0.31118 -0.582046 0.751258 + -0.31118 -0.582046 0.751258 + -0.31118 -0.582046 0.751258 + -0.31118 -0.582046 0.751258 + -0.31118 -0.582046 0.751258 + -0.574989 -0.582048 0.574984 + -0.574989 -0.582048 0.574984 + -0.574989 -0.582048 0.574984 + -0.574989 -0.582048 0.574984 + -0.574989 -0.582048 0.574984 + -0.751256 -0.582047 0.311184 + -0.751256 -0.582047 0.311184 + -0.751256 -0.582047 0.311184 + -0.751256 -0.582047 0.311184 + -0.751256 -0.582047 0.311184 + -0.813156 -0.582046 6.50548e-06 + -0.813156 -0.582046 6.50548e-06 + -0.813156 -0.582046 6.50548e-06 + -0.813156 -0.582046 6.50548e-06 + -0.813156 -0.582046 6.50548e-06 + -0.75126 -0.582045 -0.311178 + -0.75126 -0.582045 -0.311178 + -0.75126 -0.582045 -0.311178 + -0.75126 -0.582045 -0.311178 + -0.75126 -0.582045 -0.311178 + -0.574988 -0.582045 -0.574989 + -0.574988 -0.582045 -0.574989 + -0.574988 -0.582045 -0.574989 + -0.574988 -0.582045 -0.574989 + -0.574988 -0.582045 -0.574989 + -0.311181 -0.582045 -0.751259 + -0.311181 -0.582045 -0.751259 + -0.311181 -0.582045 -0.751259 + -0.311181 -0.582045 -0.751259 + -2.82067e-06 1 0 + -2.82067e-06 1 0 + -2.82067e-06 1 0 + -2.82067e-06 1 0 + -2.82067e-06 1 0 + -2.82067e-06 1 0 + -2.82067e-06 1 0 + -2.82067e-06 1 0 + -2.82067e-06 1 0 + -2.82067e-06 1 0 + -2.82067e-06 1 0 + -2.82067e-06 1 0 + -2.82067e-06 1 0 + -2.82067e-06 1 0 + -2.82067e-06 1 0 + -2.82067e-06 1 0 + 0.746202 -0.66572 1.44349e-07 + 0.746202 -0.66572 1.44349e-07 + 0.746202 -0.66572 1.44349e-07 + 0.746202 -0.66572 1.44349e-07 + 0.689401 -0.66572 -0.285559 + 0.689401 -0.66572 -0.285559 + 0.689401 -0.66572 -0.285559 + 0.689401 -0.66572 -0.285559 + 0.689401 -0.66572 -0.285559 + 0.527647 -0.665721 -0.52764 + 0.527647 -0.665721 -0.52764 + 0.527647 -0.665721 -0.52764 + 0.527647 -0.665721 -0.52764 + 0.527647 -0.665721 -0.52764 + 0.285558 -0.665716 -0.689405 + 0.285558 -0.665716 -0.689405 + 0.285558 -0.665716 -0.689405 + 0.285558 -0.665716 -0.689405 + 0.285558 -0.665716 -0.689405 + 0 -0.665724 -0.746198 + 0 -0.665724 -0.746198 + 0 -0.665724 -0.746198 + 0 -0.665724 -0.746198 + 0 -0.665724 -0.746198 + -0.285558 -0.665716 -0.689404 + -0.285558 -0.665716 -0.689404 + -0.285558 -0.665716 -0.689404 + -0.285558 -0.665716 -0.689404 + -0.285558 -0.665716 -0.689404 + -0.527642 -0.665723 -0.527643 + -0.527642 -0.665723 -0.527643 + -0.527642 -0.665723 -0.527643 + -0.527642 -0.665723 -0.527643 + -0.527642 -0.665723 -0.527643 + -0.689405 -0.665717 -0.285557 + -0.689405 -0.665717 -0.285557 + -0.689405 -0.665717 -0.285557 + -0.689405 -0.665717 -0.285557 + -0.689405 -0.665717 -0.285557 + -0.746198 -0.665724 3.08036e-07 + -0.746198 -0.665724 3.08036e-07 + -0.746198 -0.665724 3.08036e-07 + -0.746198 -0.665724 3.08036e-07 + -0.746198 -0.665724 3.08036e-07 + -0.689404 -0.665716 0.285558 + -0.689404 -0.665716 0.285558 + -0.689404 -0.665716 0.285558 + -0.689404 -0.665716 0.285558 + -0.689404 -0.665716 0.285558 + -0.527639 -0.665721 0.527648 + -0.527639 -0.665721 0.527648 + -0.527639 -0.665721 0.527648 + -0.527639 -0.665721 0.527648 + -0.527639 -0.665721 0.527648 + -0.28556 -0.66572 0.689401 + -0.28556 -0.66572 0.689401 + -0.28556 -0.66572 0.689401 + -0.28556 -0.66572 0.689401 + -0.28556 -0.66572 0.689401 + 3.06967e-07 -0.665721 0.746201 + 3.06967e-07 -0.665721 0.746201 + 3.06967e-07 -0.665721 0.746201 + 3.06967e-07 -0.665721 0.746201 + 3.06967e-07 -0.665721 0.746201 + 0.28556 -0.665719 0.689401 + 0.28556 -0.665719 0.689401 + 0.28556 -0.665719 0.689401 + 0.28556 -0.665719 0.689401 + 0.28556 -0.665719 0.689401 + 0.527644 -0.66572 0.527645 + 0.527644 -0.66572 0.527645 + 0.527644 -0.66572 0.527645 + 0.527644 -0.66572 0.527645 + 0.527644 -0.66572 0.527645 + 0.6894 -0.66572 0.28556 + 0.6894 -0.66572 0.28556 + 0.6894 -0.66572 0.28556 + 0.6894 -0.66572 0.28556 + 0.6894 -0.66572 0.28556 + 0.6894 -0.66572 0.28556 + 0.59717 -0.763023 0.247355 + 0.59717 -0.763023 0.247355 + 0.59717 -0.763023 0.247355 + 0.59717 -0.763023 0.247355 + 0.59717 -0.763023 0.247355 + 0.457055 -0.763022 0.457053 + 0.457055 -0.763022 0.457053 + 0.457055 -0.763022 0.457053 + 0.457055 -0.763022 0.457053 + 0.457055 -0.763022 0.457053 + 0.457055 -0.763022 0.457053 + 0.247356 -0.763023 0.597169 + 0.247356 -0.763023 0.597169 + 0.247356 -0.763023 0.597169 + 0.247356 -0.763023 0.597169 + 0.247356 -0.763023 0.597169 + 0.247356 -0.763023 0.597169 + 0 -0.763022 0.646372 + 0 -0.763022 0.646372 + 0 -0.763022 0.646372 + 0 -0.763022 0.646372 + 0 -0.763022 0.646372 + -0.247356 -0.763022 0.59717 + -0.247356 -0.763022 0.59717 + -0.247356 -0.763022 0.59717 + -0.247356 -0.763022 0.59717 + -0.247356 -0.763022 0.59717 + -0.247356 -0.763022 0.59717 + -0.457052 -0.763019 0.457061 + -0.457052 -0.763019 0.457061 + -0.457052 -0.763019 0.457061 + -0.457052 -0.763019 0.457061 + -0.457052 -0.763019 0.457061 + -0.457052 -0.763019 0.457061 + -0.597165 -0.763027 0.247351 + -0.597165 -0.763027 0.247351 + -0.597165 -0.763027 0.247351 + -0.597165 -0.763027 0.247351 + -0.597165 -0.763027 0.247351 + -0.597165 -0.763027 0.247351 + -0.646379 -0.763017 -8.12033e-06 + -0.646379 -0.763017 -8.12033e-06 + -0.646379 -0.763017 -8.12033e-06 + -0.646379 -0.763017 -8.12033e-06 + -0.646379 -0.763017 -8.12033e-06 + -0.646379 -0.763017 -8.12033e-06 + -0.597165 -0.763026 -0.247358 + -0.597165 -0.763026 -0.247358 + -0.597165 -0.763026 -0.247358 + -0.597165 -0.763026 -0.247358 + -0.597165 -0.763026 -0.247358 + -0.597165 -0.763026 -0.247358 + -0.457058 -0.76302 -0.457053 + -0.457058 -0.76302 -0.457053 + -0.457058 -0.76302 -0.457053 + -0.457058 -0.76302 -0.457053 + -0.457058 -0.76302 -0.457053 + -0.457058 -0.76302 -0.457053 + -0.247353 -0.763029 -0.597163 + -0.247353 -0.763029 -0.597163 + -0.247353 -0.763029 -0.597163 + -0.247353 -0.763029 -0.597163 + -0.247353 -0.763029 -0.597163 + -0.247353 -0.763029 -0.597163 + -0.247353 -0.763029 -0.597163 + 1.88868e-07 -0.763017 -0.646378 + 1.88868e-07 -0.763017 -0.646378 + 1.88868e-07 -0.763017 -0.646378 + 1.88868e-07 -0.763017 -0.646378 + 1.88868e-07 -0.763017 -0.646378 + 1.88868e-07 -0.763017 -0.646378 + 0.247352 -0.763026 -0.597167 + 0.247352 -0.763026 -0.597167 + 0.247352 -0.763026 -0.597167 + 0.247352 -0.763026 -0.597167 + 0.247352 -0.763026 -0.597167 + 0.247352 -0.763026 -0.597167 + 0.457057 -0.763017 -0.45706 + 0.457057 -0.763017 -0.45706 + 0.457057 -0.763017 -0.45706 + 0.457057 -0.763017 -0.45706 + 0.457057 -0.763017 -0.45706 + 0.457057 -0.763017 -0.45706 + 0.597169 -0.763021 -0.247361 + 0.597169 -0.763021 -0.247361 + 0.597169 -0.763021 -0.247361 + 0.597169 -0.763021 -0.247361 + 0.597169 -0.763021 -0.247361 + 0.597169 -0.763021 -0.247361 + 0.646372 -0.763022 -1.69961e-07 + 0.646372 -0.763022 -1.69961e-07 + 0.646372 -0.763022 -1.69961e-07 + 0.646372 -0.763022 -1.69961e-07 + 0.646372 -0.763022 -1.69961e-07 + 0.646372 -0.763022 -1.69961e-07 + 0.646372 -0.763022 -1.69961e-07 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + } + } + } + ColorArray TRUE { + osg::Vec4Array { + UniqueID 49 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 47 + } + } + Binding BIND_PER_VERTEX + vector 288 { + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + } + } + } + } + } + } + } + Matrix { + 253.52 0 0 0 + 0 253.52 0 0 + 0 0 253.52 0 + 0 0 0 1 + } + + } + osg::MatrixTransform { + UniqueID 50 + Name "Z_Wall" + UserDataContainer TRUE { + osg::DefaultUserDataContainer { + UniqueID 51 + UDC_UserObjects 1 { + osg::StringValueObject { + UniqueID 52 + Name "dae_node_id" + Value "Z_Wall" + } + } + } + } + StateSet TRUE { + osg::StateSet { + UniqueID 6 + } + } + Children 1 { + osg::Geode { + UniqueID 53 + Drawables 2 { + osg::Geometry { + UniqueID 54 + Name "blue-material" + DataVariance STATIC + StateSet TRUE { + osg::StateSet { + UniqueID 29 + } + } + PrimitiveSetList 1 { + osg::DrawElementsUInt { + UniqueID 55 + BufferObject TRUE { + osg::ElementBufferObject { + UniqueID 56 + Target 34963 + } + } + Mode TRIANGLES + vector 48 { + 12 5 19 16 + 8 2 13 3 + 0 9 20 6 + 29 36 43 32 + 40 26 37 27 + 41 33 44 46 + 14 1 7 17 + 22 10 15 18 + 4 11 23 21 + 30 24 38 34 + 47 42 39 25 + 28 35 31 45 + + } + } + } + VertexArray TRUE { + osg::Vec3Array { + UniqueID 57 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 58 + } + } + Binding BIND_PER_VERTEX + vector 48 { + 0.00450295 0.00450295 0 + 0.00450295 0.00450295 0 + 0.00450295 0.00550365 0 + 0.00450295 0.00550365 0 + 0.00450295 0.00550365 0 + 0.00550365 0.00450295 0 + 0.00550365 0.00450295 0 + 0.00550365 0.00450295 0 + 0.00550365 0.00550365 0 + 0.00550365 0.00550365 0 + 0.00550365 0.00550365 0 + 0.00550365 0.00550365 0 + 0.00461376 0.00461376 0 + 0.00461376 0.00461376 0 + 0.00461376 0.00461376 0 + 0.00461376 0.00461376 0 + 0.00461376 0.00539291 0 + 0.00461376 0.00539291 0 + 0.00461376 0.00539291 0 + 0.00539291 0.00461376 0 + 0.00539291 0.00461376 0 + 0.00539291 0.00461376 0 + 0.00539291 0.00539291 0 + 0.00539291 0.00539291 0 + 0.00450295 0.00450295 0 + 0.00450295 0.00450295 0 + 0.00450295 0.00550365 0 + 0.00450295 0.00550365 0 + 0.00450295 0.00550365 0 + 0.00550365 0.00450295 0 + 0.00550365 0.00450295 0 + 0.00550365 0.00450295 0 + 0.00550365 0.00550365 0 + 0.00550365 0.00550365 0 + 0.00550365 0.00550365 0 + 0.00550365 0.00550365 0 + 0.00461376 0.00461376 0 + 0.00461376 0.00461376 0 + 0.00461376 0.00461376 0 + 0.00461376 0.00461376 0 + 0.00461376 0.00539291 0 + 0.00461376 0.00539291 0 + 0.00461376 0.00539291 0 + 0.00539291 0.00461376 0 + 0.00539291 0.00461376 0 + 0.00539291 0.00461376 0 + 0.00539291 0.00539291 0 + 0.00539291 0.00539291 0 + } + } + } + NormalArray TRUE { + osg::Vec3Array { + UniqueID 59 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 58 + } + } + Binding BIND_PER_VERTEX + vector 48 { + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + } + } + } + ColorArray TRUE { + osg::Vec4Array { + UniqueID 60 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 58 + } + } + Binding BIND_PER_VERTEX + vector 48 { + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + } + } + } + } + osg::Geometry { + UniqueID 61 + Name "blue_alpha-material" + DataVariance STATIC + StateSet TRUE { + osg::StateSet { + UniqueID 62 + Name "blue_alpha" + DataVariance STATIC + ModeList 2 { + GL_CULL_FACE ON + GL_BLEND ON + } + AttributeList 3 { + osg::Material { + UniqueID 63 + Ambient TRUE Front 0.05127 0.38982 0.8 1 Back 0.05127 0.38982 0.8 1 + Diffuse TRUE Front 0 0 0 1 Back 0 0 0 1 + Specular TRUE Front 0 0 0 1 Back 0 0 0 1 + Emission TRUE Front 0.05127 0.38982 0.8 1 Back 0.05127 0.38982 0.8 1 + Shininess TRUE Front 0 Back 0 + } + Value OFF + osg::BlendFunc { + UniqueID 64 + SourceRGB CONSTANT_COLOR + SourceAlpha CONSTANT_COLOR + DestinationRGB ONE_MINUS_CONSTANT_COLOR + DestinationAlpha ONE_MINUS_CONSTANT_COLOR + } + Value OFF + osg::BlendColor { + UniqueID 65 + ConstantColor 0.5 0.5 0.5 0.5 + } + Value OFF + } + RenderingHint 2 + RenderBinMode USE_RENDERBIN_DETAILS + BinNumber 10 + BinName "DepthSortedBin" + } + } + PrimitiveSetList 1 { + osg::DrawElementsUInt { + UniqueID 66 + BufferObject TRUE { + osg::ElementBufferObject { + UniqueID 67 + Target 34963 + } + } + Mode TRIANGLES + vector 12 { + 3 1 0 7 + 9 6 4 5 + 2 8 11 10 + + } + } + } + VertexArray TRUE { + osg::Vec3Array { + UniqueID 68 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 69 + } + } + Binding BIND_PER_VERTEX + vector 12 { + 0.00461376 0.00461376 0 + 0.00461376 0.00539291 0 + 0.00461376 0.00539291 0 + 0.00539291 0.00461376 0 + 0.00539291 0.00461376 0 + 0.00539291 0.00539291 0 + 0.00461376 0.00461376 0 + 0.00461376 0.00539291 0 + 0.00461376 0.00539291 0 + 0.00539291 0.00461376 0 + 0.00539291 0.00461376 0 + 0.00539291 0.00539291 0 + } + } + } + NormalArray TRUE { + osg::Vec3Array { + UniqueID 70 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 69 + } + } + Binding BIND_PER_VERTEX + vector 12 { + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + } + } + } + ColorArray TRUE { + osg::Vec4Array { + UniqueID 71 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 69 + } + } + Binding BIND_PER_VERTEX + vector 12 { + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + } + } + } + } + } + } + } + Matrix { + 253.52 0 0 0 + 0 253.52 0 0 + 0 0 253.52 0 + 0 0 0 1 + } + + } + osg::MatrixTransform { + UniqueID 72 + Name "Y_Wall" + UserDataContainer TRUE { + osg::DefaultUserDataContainer { + UniqueID 73 + UDC_UserObjects 1 { + osg::StringValueObject { + UniqueID 74 + Name "dae_node_id" + Value "Y_Wall" + } + } + } + } + StateSet TRUE { + osg::StateSet { + UniqueID 6 + } + } + Children 1 { + osg::Geode { + UniqueID 75 + Drawables 2 { + osg::Geometry { + UniqueID 76 + Name "green_alpha-material" + DataVariance STATIC + StateSet TRUE { + osg::StateSet { + UniqueID 77 + Name "green_alpha" + DataVariance STATIC + ModeList 2 { + GL_CULL_FACE ON + GL_BLEND ON + } + AttributeList 3 { + osg::Material { + UniqueID 78 + Ambient TRUE Front 0.190456 0.8 0.229407 1 Back 0.190456 0.8 0.229407 1 + Diffuse TRUE Front 0 0 0 1 Back 0 0 0 1 + Specular TRUE Front 0 0 0 1 Back 0 0 0 1 + Emission TRUE Front 0.190456 0.8 0.229407 1 Back 0.190456 0.8 0.229407 1 + Shininess TRUE Front 0 Back 0 + } + Value OFF + osg::BlendFunc { + UniqueID 64 + } + Value OFF + osg::BlendColor { + UniqueID 65 + } + Value OFF + } + RenderingHint 2 + RenderBinMode USE_RENDERBIN_DETAILS + BinNumber 10 + BinName "DepthSortedBin" + } + } + PrimitiveSetList 1 { + osg::DrawElementsUInt { + UniqueID 79 + BufferObject TRUE { + osg::ElementBufferObject { + UniqueID 80 + Target 34963 + } + } + Mode TRIANGLES + vector 12 { + 3 1 0 7 + 9 6 4 5 + 2 8 11 10 + + } + } + } + VertexArray TRUE { + osg::Vec3Array { + UniqueID 81 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 82 + } + } + Binding BIND_PER_VERTEX + vector 12 { + 0.00461376 0 0.00539291 + 0.00461376 0 0.00461376 + 0.00461376 0 0.00461376 + 0.00539291 0 0.00539291 + 0.00539291 0 0.00539291 + 0.00539291 0 0.00461376 + 0.00461376 0 0.00539291 + 0.00461376 0 0.00461376 + 0.00461376 0 0.00461376 + 0.00539291 0 0.00539291 + 0.00539291 0 0.00539291 + 0.00539291 0 0.00461376 + } + } + } + NormalArray TRUE { + osg::Vec3Array { + UniqueID 83 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 82 + } + } + Binding BIND_PER_VERTEX + vector 12 { + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + } + } + } + ColorArray TRUE { + osg::Vec4Array { + UniqueID 84 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 82 + } + } + Binding BIND_PER_VERTEX + vector 12 { + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + } + } + } + } + osg::Geometry { + UniqueID 85 + Name "green-material" + DataVariance STATIC + StateSet TRUE { + osg::StateSet { + UniqueID 42 + } + } + PrimitiveSetList 1 { + osg::DrawElementsUInt { + UniqueID 86 + BufferObject TRUE { + osg::ElementBufferObject { + UniqueID 87 + Target 34963 + } + } + Mode TRIANGLES + vector 48 { + 15 9 3 16 + 0 12 21 5 + 10 13 6 19 + 33 39 27 24 + 40 36 29 45 + 34 30 37 43 + 17 22 11 18 + 4 1 23 20 + 7 14 2 8 + 35 46 41 25 + 28 42 31 44 + 47 32 26 38 + + } + } + } + VertexArray TRUE { + osg::Vec3Array { + UniqueID 88 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 89 + } + } + Binding BIND_PER_VERTEX + vector 48 { + 0.00450295 0 0.00550365 + 0.00450295 0 0.00550365 + 0.00450295 0 0.00550365 + 0.00450295 0 0.00450295 + 0.00450295 0 0.00450295 + 0.00550365 0 0.00550365 + 0.00550365 0 0.00550365 + 0.00550365 0 0.00550365 + 0.00550365 0 0.00550365 + 0.00550365 0 0.00450295 + 0.00550365 0 0.00450295 + 0.00550365 0 0.00450295 + 0.00461376 0 0.00539291 + 0.00461376 0 0.00539291 + 0.00461376 0 0.00539291 + 0.00461376 0 0.00461376 + 0.00461376 0 0.00461376 + 0.00461376 0 0.00461376 + 0.00461376 0 0.00461376 + 0.00539291 0 0.00539291 + 0.00539291 0 0.00539291 + 0.00539291 0 0.00461376 + 0.00539291 0 0.00461376 + 0.00539291 0 0.00461376 + 0.00450295 0 0.00550365 + 0.00450295 0 0.00550365 + 0.00450295 0 0.00550365 + 0.00450295 0 0.00450295 + 0.00450295 0 0.00450295 + 0.00550365 0 0.00550365 + 0.00550365 0 0.00550365 + 0.00550365 0 0.00550365 + 0.00550365 0 0.00550365 + 0.00550365 0 0.00450295 + 0.00550365 0 0.00450295 + 0.00550365 0 0.00450295 + 0.00461376 0 0.00539291 + 0.00461376 0 0.00539291 + 0.00461376 0 0.00539291 + 0.00461376 0 0.00461376 + 0.00461376 0 0.00461376 + 0.00461376 0 0.00461376 + 0.00461376 0 0.00461376 + 0.00539291 0 0.00539291 + 0.00539291 0 0.00539291 + 0.00539291 0 0.00461376 + 0.00539291 0 0.00461376 + 0.00539291 0 0.00461376 + } + } + } + NormalArray TRUE { + osg::Vec3Array { + UniqueID 90 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 89 + } + } + Binding BIND_PER_VERTEX + vector 48 { + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + } + } + } + ColorArray TRUE { + osg::Vec4Array { + UniqueID 91 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 89 + } + } + Binding BIND_PER_VERTEX + vector 48 { + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + } + } + } + } + } + } + } + Matrix { + 253.52 0 0 0 + 0 253.52 0 0 + 0 0 253.52 0 + 0 0 0 1 + } + + } + osg::MatrixTransform { + UniqueID 92 + Name "X_Wall" + UserDataContainer TRUE { + osg::DefaultUserDataContainer { + UniqueID 93 + UDC_UserObjects 1 { + osg::StringValueObject { + UniqueID 94 + Name "dae_node_id" + Value "X_Wall" + } + } + } + } + StateSet TRUE { + osg::StateSet { + UniqueID 6 + } + } + Children 1 { + osg::Geode { + UniqueID 95 + Drawables 2 { + osg::Geometry { + UniqueID 96 + Name "red-material" + DataVariance STATIC + StateSet TRUE { + osg::StateSet { + UniqueID 16 + } + } + PrimitiveSetList 1 { + osg::DrawElementsUInt { + UniqueID 97 + BufferObject TRUE { + osg::ElementBufferObject { + UniqueID 98 + Target 34963 + } + } + Mode TRIANGLES + vector 48 { + 17 0 7 9 + 18 8 21 3 + 15 12 4 1 + 24 41 31 33 + 42 45 27 46 + 39 36 28 40 + 19 13 2 10 + 22 20 23 11 + 5 14 16 6 + 25 37 43 34 + 32 44 29 35 + 47 38 26 30 + + } + } + } + VertexArray TRUE { + osg::Vec3Array { + UniqueID 99 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 100 + } + } + Binding BIND_PER_VERTEX + vector 48 { + 0 0.00450295 0.00550365 + 0 0.00450295 0.00550365 + 0 0.00450295 0.00550365 + 0 0.00550365 0.00550365 + 0 0.00550365 0.00550365 + 0 0.00550365 0.00550365 + 0 0.00550365 0.00550365 + 0 0.00450295 0.00450295 + 0 0.00450295 0.00450295 + 0 0.00550365 0.00450295 + 0 0.00550365 0.00450295 + 0 0.00550365 0.00450295 + 0 0.00461376 0.00539291 + 0 0.00461376 0.00539291 + 0 0.00461376 0.00539291 + 0 0.00539291 0.00539291 + 0 0.00539291 0.00539291 + 0 0.00461376 0.00461376 + 0 0.00461376 0.00461376 + 0 0.00461376 0.00461376 + 0 0.00461376 0.00461376 + 0 0.00539291 0.00461376 + 0 0.00539291 0.00461376 + 0 0.00539291 0.00461376 + 0 0.00450295 0.00550365 + 0 0.00450295 0.00550365 + 0 0.00450295 0.00550365 + 0 0.00550365 0.00550365 + 0 0.00550365 0.00550365 + 0 0.00550365 0.00550365 + 0 0.00550365 0.00550365 + 0 0.00450295 0.00450295 + 0 0.00450295 0.00450295 + 0 0.00550365 0.00450295 + 0 0.00550365 0.00450295 + 0 0.00550365 0.00450295 + 0 0.00461376 0.00539291 + 0 0.00461376 0.00539291 + 0 0.00461376 0.00539291 + 0 0.00539291 0.00539291 + 0 0.00539291 0.00539291 + 0 0.00461376 0.00461376 + 0 0.00461376 0.00461376 + 0 0.00461376 0.00461376 + 0 0.00461376 0.00461376 + 0 0.00539291 0.00461376 + 0 0.00539291 0.00461376 + 0 0.00539291 0.00461376 + } + } + } + NormalArray TRUE { + osg::Vec3Array { + UniqueID 101 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 100 + } + } + Binding BIND_PER_VERTEX + vector 48 { + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + } + } + } + ColorArray TRUE { + osg::Vec4Array { + UniqueID 102 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 100 + } + } + Binding BIND_PER_VERTEX + vector 48 { + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + } + } + } + } + osg::Geometry { + UniqueID 103 + Name "red_alpha-material" + DataVariance STATIC + StateSet TRUE { + osg::StateSet { + UniqueID 104 + Name "red_alpha" + DataVariance STATIC + ModeList 2 { + GL_CULL_FACE ON + GL_BLEND ON + } + AttributeList 3 { + osg::Material { + UniqueID 105 + Ambient TRUE Front 0.8 0.123281 0.11568 1 Back 0.8 0.123281 0.11568 1 + Diffuse TRUE Front 0 0 0 1 Back 0 0 0 1 + Specular TRUE Front 0 0 0 1 Back 0 0 0 1 + Emission TRUE Front 0.8 0.123281 0.11568 1 Back 0.8 0.123281 0.11568 1 + Shininess TRUE Front 0 Back 0 + } + Value OFF + osg::BlendFunc { + UniqueID 64 + } + Value OFF + osg::BlendColor { + UniqueID 65 + } + Value OFF + } + RenderingHint 2 + RenderBinMode USE_RENDERBIN_DETAILS + BinNumber 10 + BinName "DepthSortedBin" + } + } + PrimitiveSetList 1 { + osg::DrawElementsUInt { + UniqueID 106 + BufferObject TRUE { + osg::ElementBufferObject { + UniqueID 107 + Target 34963 + } + } + Mode TRIANGLES + vector 12 { + 3 1 0 7 + 9 6 4 5 + 2 8 11 10 + + } + } + } + VertexArray TRUE { + osg::Vec3Array { + UniqueID 108 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 109 + } + } + Binding BIND_PER_VERTEX + vector 12 { + 0 0.00461376 0.00539291 + 0 0.00539291 0.00539291 + 0 0.00539291 0.00539291 + 0 0.00461376 0.00461376 + 0 0.00461376 0.00461376 + 0 0.00539291 0.00461376 + 0 0.00461376 0.00539291 + 0 0.00539291 0.00539291 + 0 0.00539291 0.00539291 + 0 0.00461376 0.00461376 + 0 0.00461376 0.00461376 + 0 0.00539291 0.00461376 + } + } + } + NormalArray TRUE { + osg::Vec3Array { + UniqueID 110 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 109 + } + } + Binding BIND_PER_VERTEX + vector 12 { + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + } + } + } + ColorArray TRUE { + osg::Vec4Array { + UniqueID 111 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 109 + } + } + Binding BIND_PER_VERTEX + vector 12 { + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + } + } + } + } + } + } + } + Matrix { + 253.52 0 0 0 + 0 253.52 0 0 + 0 0 253.52 0 + 0 0 0 1 + } + + } + } + Matrix { + 0.00394446 0 0 0 + 0 0.00394446 0 0 + 0 0 0.00394446 0 + 0 0 0 1 + } + + } + osg::MatrixTransform { + UniqueID 112 + Name "scaleMarkers" + UserDataContainer TRUE { + osg::DefaultUserDataContainer { + UniqueID 113 + UDC_UserObjects 1 { + osg::StringValueObject { + UniqueID 114 + Name "dae_node_id" + Value "scaleMarkers" + } + } + } + } + StateSet TRUE { + osg::StateSet { + UniqueID 6 + } + } + Children 6 { + osg::MatrixTransform { + UniqueID 115 + Name "Z_Wall_Scale" + UserDataContainer TRUE { + osg::DefaultUserDataContainer { + UniqueID 116 + UDC_UserObjects 1 { + osg::StringValueObject { + UniqueID 117 + Name "dae_node_id" + Value "Z_Wall_Scale" + } + } + } + } + StateSet TRUE { + osg::StateSet { + UniqueID 6 + } + } + Children 1 { + osg::Geode { + UniqueID 118 + Drawables 2 { + osg::Geometry { + UniqueID 119 + Name "blue-material" + DataVariance STATIC + StateSet TRUE { + osg::StateSet { + UniqueID 29 + } + } + PrimitiveSetList 1 { + osg::DrawElementsUInt { + UniqueID 55 + } + } + VertexArray TRUE { + osg::Vec3Array { + UniqueID 120 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 58 + } + } + Binding BIND_PER_VERTEX + vector 48 { + 0.00450295 0.00450295 0 + 0.00450295 0.00450295 0 + 0.00450295 0.00550365 0 + 0.00450295 0.00550365 0 + 0.00450295 0.00550365 0 + 0.00550365 0.00450295 0 + 0.00550365 0.00450295 0 + 0.00550365 0.00450295 0 + 0.00550365 0.00550365 0 + 0.00550365 0.00550365 0 + 0.00550365 0.00550365 0 + 0.00550365 0.00550365 0 + 0.00461376 0.00461376 0 + 0.00461376 0.00461376 0 + 0.00461376 0.00461376 0 + 0.00461376 0.00461376 0 + 0.00461376 0.00539291 0 + 0.00461376 0.00539291 0 + 0.00461376 0.00539291 0 + 0.00539291 0.00461376 0 + 0.00539291 0.00461376 0 + 0.00539291 0.00461376 0 + 0.00539291 0.00539291 0 + 0.00539291 0.00539291 0 + 0.00450295 0.00450295 0 + 0.00450295 0.00450295 0 + 0.00450295 0.00550365 0 + 0.00450295 0.00550365 0 + 0.00450295 0.00550365 0 + 0.00550365 0.00450295 0 + 0.00550365 0.00450295 0 + 0.00550365 0.00450295 0 + 0.00550365 0.00550365 0 + 0.00550365 0.00550365 0 + 0.00550365 0.00550365 0 + 0.00550365 0.00550365 0 + 0.00461376 0.00461376 0 + 0.00461376 0.00461376 0 + 0.00461376 0.00461376 0 + 0.00461376 0.00461376 0 + 0.00461376 0.00539291 0 + 0.00461376 0.00539291 0 + 0.00461376 0.00539291 0 + 0.00539291 0.00461376 0 + 0.00539291 0.00461376 0 + 0.00539291 0.00461376 0 + 0.00539291 0.00539291 0 + 0.00539291 0.00539291 0 + } + } + } + NormalArray TRUE { + osg::Vec3Array { + UniqueID 121 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 58 + } + } + Binding BIND_PER_VERTEX + vector 48 { + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + } + } + } + ColorArray TRUE { + osg::Vec4Array { + UniqueID 60 + } + } + } + osg::Geometry { + UniqueID 122 + Name "blue_alpha-material" + DataVariance STATIC + StateSet TRUE { + osg::StateSet { + UniqueID 62 + } + } + PrimitiveSetList 1 { + osg::DrawElementsUInt { + UniqueID 66 + } + } + VertexArray TRUE { + osg::Vec3Array { + UniqueID 123 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 69 + } + } + Binding BIND_PER_VERTEX + vector 12 { + 0.00461376 0.00461376 0 + 0.00461376 0.00539291 0 + 0.00461376 0.00539291 0 + 0.00539291 0.00461376 0 + 0.00539291 0.00461376 0 + 0.00539291 0.00539291 0 + 0.00461376 0.00461376 0 + 0.00461376 0.00539291 0 + 0.00461376 0.00539291 0 + 0.00539291 0.00461376 0 + 0.00539291 0.00461376 0 + 0.00539291 0.00539291 0 + } + } + } + NormalArray TRUE { + osg::Vec3Array { + UniqueID 124 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 69 + } + } + Binding BIND_PER_VERTEX + vector 12 { + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + } + } + } + ColorArray TRUE { + osg::Vec4Array { + UniqueID 71 + } + } + } + } + } + } + Matrix { + 253.52 0 0 0 + 0 253.52 0 0 + 0 0 253.52 0 + 0 0 0 1 + } + + } + osg::MatrixTransform { + UniqueID 125 + Name "Y_Wall_Scale" + UserDataContainer TRUE { + osg::DefaultUserDataContainer { + UniqueID 126 + UDC_UserObjects 1 { + osg::StringValueObject { + UniqueID 127 + Name "dae_node_id" + Value "Y_Wall_Scale" + } + } + } + } + StateSet TRUE { + osg::StateSet { + UniqueID 6 + } + } + Children 1 { + osg::Geode { + UniqueID 128 + Drawables 2 { + osg::Geometry { + UniqueID 129 + Name "green_alpha-material" + DataVariance STATIC + StateSet TRUE { + osg::StateSet { + UniqueID 77 + } + } + PrimitiveSetList 1 { + osg::DrawElementsUInt { + UniqueID 79 + } + } + VertexArray TRUE { + osg::Vec3Array { + UniqueID 130 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 82 + } + } + Binding BIND_PER_VERTEX + vector 12 { + 0.00461376 0 0.00539291 + 0.00461376 0 0.00461376 + 0.00461376 0 0.00461376 + 0.00539291 0 0.00539291 + 0.00539291 0 0.00539291 + 0.00539291 0 0.00461376 + 0.00461376 0 0.00539291 + 0.00461376 0 0.00461376 + 0.00461376 0 0.00461376 + 0.00539291 0 0.00539291 + 0.00539291 0 0.00539291 + 0.00539291 0 0.00461376 + } + } + } + NormalArray TRUE { + osg::Vec3Array { + UniqueID 131 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 82 + } + } + Binding BIND_PER_VERTEX + vector 12 { + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + } + } + } + ColorArray TRUE { + osg::Vec4Array { + UniqueID 84 + } + } + } + osg::Geometry { + UniqueID 132 + Name "green-material" + DataVariance STATIC + StateSet TRUE { + osg::StateSet { + UniqueID 42 + } + } + PrimitiveSetList 1 { + osg::DrawElementsUInt { + UniqueID 86 + } + } + VertexArray TRUE { + osg::Vec3Array { + UniqueID 133 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 89 + } + } + Binding BIND_PER_VERTEX + vector 48 { + 0.00450295 0 0.00550365 + 0.00450295 0 0.00550365 + 0.00450295 0 0.00550365 + 0.00450295 0 0.00450295 + 0.00450295 0 0.00450295 + 0.00550365 0 0.00550365 + 0.00550365 0 0.00550365 + 0.00550365 0 0.00550365 + 0.00550365 0 0.00550365 + 0.00550365 0 0.00450295 + 0.00550365 0 0.00450295 + 0.00550365 0 0.00450295 + 0.00461376 0 0.00539291 + 0.00461376 0 0.00539291 + 0.00461376 0 0.00539291 + 0.00461376 0 0.00461376 + 0.00461376 0 0.00461376 + 0.00461376 0 0.00461376 + 0.00461376 0 0.00461376 + 0.00539291 0 0.00539291 + 0.00539291 0 0.00539291 + 0.00539291 0 0.00461376 + 0.00539291 0 0.00461376 + 0.00539291 0 0.00461376 + 0.00450295 0 0.00550365 + 0.00450295 0 0.00550365 + 0.00450295 0 0.00550365 + 0.00450295 0 0.00450295 + 0.00450295 0 0.00450295 + 0.00550365 0 0.00550365 + 0.00550365 0 0.00550365 + 0.00550365 0 0.00550365 + 0.00550365 0 0.00550365 + 0.00550365 0 0.00450295 + 0.00550365 0 0.00450295 + 0.00550365 0 0.00450295 + 0.00461376 0 0.00539291 + 0.00461376 0 0.00539291 + 0.00461376 0 0.00539291 + 0.00461376 0 0.00461376 + 0.00461376 0 0.00461376 + 0.00461376 0 0.00461376 + 0.00461376 0 0.00461376 + 0.00539291 0 0.00539291 + 0.00539291 0 0.00539291 + 0.00539291 0 0.00461376 + 0.00539291 0 0.00461376 + 0.00539291 0 0.00461376 + } + } + } + NormalArray TRUE { + osg::Vec3Array { + UniqueID 134 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 89 + } + } + Binding BIND_PER_VERTEX + vector 48 { + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + } + } + } + ColorArray TRUE { + osg::Vec4Array { + UniqueID 91 + } + } + } + } + } + } + Matrix { + 253.52 0 0 0 + 0 253.52 0 0 + 0 0 253.52 0 + 0 0 0 1 + } + + } + osg::MatrixTransform { + UniqueID 135 + Name "X_Wall_Scale" + UserDataContainer TRUE { + osg::DefaultUserDataContainer { + UniqueID 136 + UDC_UserObjects 1 { + osg::StringValueObject { + UniqueID 137 + Name "dae_node_id" + Value "X_Wall_Scale" + } + } + } + } + StateSet TRUE { + osg::StateSet { + UniqueID 6 + } + } + Children 1 { + osg::Geode { + UniqueID 138 + Drawables 2 { + osg::Geometry { + UniqueID 139 + Name "red-material" + DataVariance STATIC + StateSet TRUE { + osg::StateSet { + UniqueID 16 + } + } + PrimitiveSetList 1 { + osg::DrawElementsUInt { + UniqueID 97 + } + } + VertexArray TRUE { + osg::Vec3Array { + UniqueID 140 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 100 + } + } + Binding BIND_PER_VERTEX + vector 48 { + 0 0.00450295 0.00550365 + 0 0.00450295 0.00550365 + 0 0.00450295 0.00550365 + 0 0.00550365 0.00550365 + 0 0.00550365 0.00550365 + 0 0.00550365 0.00550365 + 0 0.00550365 0.00550365 + 0 0.00450295 0.00450295 + 0 0.00450295 0.00450295 + 0 0.00550365 0.00450295 + 0 0.00550365 0.00450295 + 0 0.00550365 0.00450295 + 0 0.00461376 0.00539291 + 0 0.00461376 0.00539291 + 0 0.00461376 0.00539291 + 0 0.00539291 0.00539291 + 0 0.00539291 0.00539291 + 0 0.00461376 0.00461376 + 0 0.00461376 0.00461376 + 0 0.00461376 0.00461376 + 0 0.00461376 0.00461376 + 0 0.00539291 0.00461376 + 0 0.00539291 0.00461376 + 0 0.00539291 0.00461376 + 0 0.00450295 0.00550365 + 0 0.00450295 0.00550365 + 0 0.00450295 0.00550365 + 0 0.00550365 0.00550365 + 0 0.00550365 0.00550365 + 0 0.00550365 0.00550365 + 0 0.00550365 0.00550365 + 0 0.00450295 0.00450295 + 0 0.00450295 0.00450295 + 0 0.00550365 0.00450295 + 0 0.00550365 0.00450295 + 0 0.00550365 0.00450295 + 0 0.00461376 0.00539291 + 0 0.00461376 0.00539291 + 0 0.00461376 0.00539291 + 0 0.00539291 0.00539291 + 0 0.00539291 0.00539291 + 0 0.00461376 0.00461376 + 0 0.00461376 0.00461376 + 0 0.00461376 0.00461376 + 0 0.00461376 0.00461376 + 0 0.00539291 0.00461376 + 0 0.00539291 0.00461376 + 0 0.00539291 0.00461376 + } + } + } + NormalArray TRUE { + osg::Vec3Array { + UniqueID 141 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 100 + } + } + Binding BIND_PER_VERTEX + vector 48 { + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + } + } + } + ColorArray TRUE { + osg::Vec4Array { + UniqueID 102 + } + } + } + osg::Geometry { + UniqueID 142 + Name "red_alpha-material" + DataVariance STATIC + StateSet TRUE { + osg::StateSet { + UniqueID 104 + } + } + PrimitiveSetList 1 { + osg::DrawElementsUInt { + UniqueID 106 + } + } + VertexArray TRUE { + osg::Vec3Array { + UniqueID 143 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 109 + } + } + Binding BIND_PER_VERTEX + vector 12 { + 0 0.00461376 0.00539291 + 0 0.00539291 0.00539291 + 0 0.00539291 0.00539291 + 0 0.00461376 0.00461376 + 0 0.00461376 0.00461376 + 0 0.00539291 0.00461376 + 0 0.00461376 0.00539291 + 0 0.00539291 0.00539291 + 0 0.00539291 0.00539291 + 0 0.00461376 0.00461376 + 0 0.00461376 0.00461376 + 0 0.00539291 0.00461376 + } + } + } + NormalArray TRUE { + osg::Vec3Array { + UniqueID 144 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 109 + } + } + Binding BIND_PER_VERTEX + vector 12 { + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + } + } + } + ColorArray TRUE { + osg::Vec4Array { + UniqueID 111 + } + } + } + } + } + } + Matrix { + 253.52 0 0 0 + 0 253.52 0 0 + 0 0 253.52 0 + 0 0 0 1 + } + + } + osg::MatrixTransform { + UniqueID 145 + Name "Z_Axis_Scale" + UserDataContainer TRUE { + osg::DefaultUserDataContainer { + UniqueID 146 + UDC_UserObjects 1 { + osg::StringValueObject { + UniqueID 147 + Name "dae_node_id" + Value "Z_Axis_Scale" + } + } + } + } + StateSet TRUE { + osg::StateSet { + UniqueID 6 + } + } + Children 1 { + osg::Geode { + UniqueID 148 + Drawables 1 { + osg::Geometry { + UniqueID 149 + Name "blue-material" + DataVariance STATIC + StateSet TRUE { + osg::StateSet { + UniqueID 29 + } + } + PrimitiveSetList 1 { + osg::DrawElementsUInt { + UniqueID 150 + BufferObject TRUE { + osg::ElementBufferObject { + UniqueID 151 + Target 34963 + } + } + Mode TRIANGLES + vector 180 { + 0 21 16 1 + 26 22 2 31 + 27 3 36 32 + 4 41 37 5 + 46 42 6 51 + 47 7 56 52 + 8 61 57 9 + 66 62 10 71 + 67 11 76 72 + 12 81 77 13 + 86 82 14 91 + 87 15 17 92 + 33 135 28 83 + 105 78 23 141 + 18 63 117 58 + 38 132 34 43 + 129 39 68 114 + 64 88 102 84 + 93 99 89 79 + 108 73 53 123 + 48 29 138 24 + 59 120 54 49 + 126 44 74 111 + 69 19 96 94 + 162 153 144 154 + 175 158 163 148 + 167 171 168 176 + 145 159 149 150 + 177 169 35 133 + 136 85 103 106 + 25 139 142 65 + 115 118 40 130 + 134 45 127 131 + 70 112 116 90 + 100 104 95 97 + 101 80 107 109 + 55 121 124 30 + 137 140 60 119 + 122 50 125 128 + 75 110 113 20 + 143 98 164 172 + 155 156 173 178 + 165 146 151 174 + 166 170 147 157 + 160 152 161 179 + + } + } + } + VertexArray TRUE { + osg::Vec3Array { + UniqueID 152 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 153 + } + } + Binding BIND_PER_VERTEX + vector 180 { + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 0 0.00149989 + 0 -0.000128021 0.00149989 + 0 -0.000128021 0.00149989 + 0 -0.000128021 0.00149989 + 0 -0.000128021 0.00149989 + 0 -0.000128021 0.00149989 + 4.89918e-05 -0.000118276 0.00149989 + 4.89918e-05 -0.000118276 0.00149989 + 4.89918e-05 -0.000118276 0.00149989 + 4.89918e-05 -0.000118276 0.00149989 + 4.89918e-05 -0.000118276 0.00149989 + 9.05247e-05 -9.05247e-05 0.00149989 + 9.05247e-05 -9.05247e-05 0.00149989 + 9.05247e-05 -9.05247e-05 0.00149989 + 9.05247e-05 -9.05247e-05 0.00149989 + 9.05247e-05 -9.05247e-05 0.00149989 + 0.000118276 -4.89918e-05 0.00149989 + 0.000118276 -4.89918e-05 0.00149989 + 0.000118276 -4.89918e-05 0.00149989 + 0.000118276 -4.89918e-05 0.00149989 + 0.000118276 -4.89918e-05 0.00149989 + 0.000128021 0 0.00149989 + 0.000128021 0 0.00149989 + 0.000128021 0 0.00149989 + 0.000128021 0 0.00149989 + 0.000128021 0 0.00149989 + 0.000118276 4.89918e-05 0.00149989 + 0.000118276 4.89918e-05 0.00149989 + 0.000118276 4.89918e-05 0.00149989 + 0.000118276 4.89918e-05 0.00149989 + 0.000118276 4.89918e-05 0.00149989 + 9.05247e-05 9.05247e-05 0.00149989 + 9.05247e-05 9.05247e-05 0.00149989 + 9.05247e-05 9.05247e-05 0.00149989 + 9.05247e-05 9.05247e-05 0.00149989 + 9.05247e-05 9.05247e-05 0.00149989 + 4.89918e-05 0.000118276 0.00149989 + 4.89918e-05 0.000118276 0.00149989 + 4.89918e-05 0.000118276 0.00149989 + 4.89918e-05 0.000118276 0.00149989 + 4.89918e-05 0.000118276 0.00149989 + 0 0.000128021 0.00149989 + 0 0.000128021 0.00149989 + 0 0.000128021 0.00149989 + 0 0.000128021 0.00149989 + 0 0.000128021 0.00149989 + -4.89918e-05 0.000118276 0.00149989 + -4.89918e-05 0.000118276 0.00149989 + -4.89918e-05 0.000118276 0.00149989 + -4.89918e-05 0.000118276 0.00149989 + -4.89918e-05 0.000118276 0.00149989 + -9.05247e-05 9.05247e-05 0.00149989 + -9.05247e-05 9.05247e-05 0.00149989 + -9.05247e-05 9.05247e-05 0.00149989 + -9.05247e-05 9.05247e-05 0.00149989 + -9.05247e-05 9.05247e-05 0.00149989 + -0.000118276 4.89918e-05 0.00149989 + -0.000118276 4.89918e-05 0.00149989 + -0.000118276 4.89918e-05 0.00149989 + -0.000118276 4.89918e-05 0.00149989 + -0.000118276 4.89918e-05 0.00149989 + -0.000128021 0 0.00149989 + -0.000128021 0 0.00149989 + -0.000128021 0 0.00149989 + -0.000128021 0 0.00149989 + -0.000128021 0 0.00149989 + -0.000118276 -4.89918e-05 0.00149989 + -0.000118276 -4.89918e-05 0.00149989 + -0.000118276 -4.89918e-05 0.00149989 + -0.000118276 -4.89918e-05 0.00149989 + -0.000118276 -4.89918e-05 0.00149989 + -9.05247e-05 -9.05247e-05 0.00149989 + -9.05247e-05 -9.05247e-05 0.00149989 + -9.05247e-05 -9.05247e-05 0.00149989 + -9.05247e-05 -9.05247e-05 0.00149989 + -9.05247e-05 -9.05247e-05 0.00149989 + -4.89918e-05 -0.000118276 0.00149989 + -4.89918e-05 -0.000118276 0.00149989 + -4.89918e-05 -0.000118276 0.00149989 + -4.89918e-05 -0.000118276 0.00149989 + -4.89918e-05 -0.000118276 0.00149989 + -4.89918e-05 -0.000118276 0.00789094 + -4.89918e-05 -0.000118276 0.00789094 + -4.89918e-05 -0.000118276 0.00789094 + -9.05247e-05 -9.05247e-05 0.00789094 + -9.05247e-05 -9.05247e-05 0.00789094 + -9.05247e-05 -9.05247e-05 0.00789094 + -0.000118276 -4.89918e-05 0.00789094 + -0.000118276 -4.89918e-05 0.00789094 + -0.000118276 -4.89918e-05 0.00789094 + -0.000128021 0 0.00789094 + -0.000128021 0 0.00789094 + -0.000128021 0 0.00789094 + -0.000118276 4.89918e-05 0.00789094 + -0.000118276 4.89918e-05 0.00789094 + -0.000118276 4.89918e-05 0.00789094 + -9.05247e-05 9.05247e-05 0.00789094 + -9.05247e-05 9.05247e-05 0.00789094 + -9.05247e-05 9.05247e-05 0.00789094 + -4.89918e-05 0.000118276 0.00789094 + -4.89918e-05 0.000118276 0.00789094 + -4.89918e-05 0.000118276 0.00789094 + 0 0.000128021 0.00789094 + 0 0.000128021 0.00789094 + 0 0.000128021 0.00789094 + 4.89918e-05 0.000118276 0.00789094 + 4.89918e-05 0.000118276 0.00789094 + 4.89918e-05 0.000118276 0.00789094 + 9.05247e-05 9.05247e-05 0.00789094 + 9.05247e-05 9.05247e-05 0.00789094 + 9.05247e-05 9.05247e-05 0.00789094 + 0.000118276 4.89918e-05 0.00789094 + 0.000118276 4.89918e-05 0.00789094 + 0.000118276 4.89918e-05 0.00789094 + 0.000128021 0 0.00789094 + 0.000128021 0 0.00789094 + 0.000128021 0 0.00789094 + 0.000118276 -4.89918e-05 0.00789094 + 0.000118276 -4.89918e-05 0.00789094 + 0.000118276 -4.89918e-05 0.00789094 + 9.05247e-05 -9.05247e-05 0.00789094 + 9.05247e-05 -9.05247e-05 0.00789094 + 9.05247e-05 -9.05247e-05 0.00789094 + 4.89918e-05 -0.000118276 0.00789094 + 4.89918e-05 -0.000118276 0.00789094 + 4.89918e-05 -0.000118276 0.00789094 + 0 -0.000128021 0.00789094 + 0 -0.000128021 0.00789094 + 0 -0.000128021 0.00789094 + 0.000464075 0.000464075 0.00881904 + 0.000464075 0.000464075 0.00881904 + 0.000464075 0.000464075 0.00881904 + 0.000464075 0.000464075 0.00881904 + 0.000464075 0.000464075 0.00789094 + 0.000464075 0.000464075 0.00789094 + 0.000464075 0.000464075 0.00789094 + 0.000464075 0.000464075 0.00789094 + 0.000464075 0.000464075 0.00789094 + 0.000464075 -0.000464075 0.00881904 + 0.000464075 -0.000464075 0.00881904 + 0.000464075 -0.000464075 0.00881904 + 0.000464075 -0.000464075 0.00881904 + 0.000464075 -0.000464075 0.00881904 + 0.000464075 -0.000464075 0.00789094 + 0.000464075 -0.000464075 0.00789094 + 0.000464075 -0.000464075 0.00789094 + 0.000464075 -0.000464075 0.00789094 + -0.000464075 0.000464075 0.00881904 + -0.000464075 0.000464075 0.00881904 + -0.000464075 0.000464075 0.00881904 + -0.000464075 0.000464075 0.00881904 + -0.000464075 0.000464075 0.00881904 + -0.000464075 0.000464075 0.00789094 + -0.000464075 0.000464075 0.00789094 + -0.000464075 0.000464075 0.00789094 + -0.000464075 0.000464075 0.00789094 + -0.000464075 -0.000464075 0.00881904 + -0.000464075 -0.000464075 0.00881904 + -0.000464075 -0.000464075 0.00881904 + -0.000464075 -0.000464075 0.00881904 + -0.000464075 -0.000464075 0.00789094 + -0.000464075 -0.000464075 0.00789094 + -0.000464075 -0.000464075 0.00789094 + -0.000464075 -0.000464075 0.00789094 + -0.000464075 -0.000464075 0.00789094 + } + } + } + NormalArray TRUE { + osg::Vec3Array { + UniqueID 154 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 153 + } + } + Binding BIND_PER_VERTEX + vector 180 { + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 1.47817e-07 -0.746202 -0.66572 + 1.47817e-07 -0.746202 -0.66572 + 1.47817e-07 -0.746202 -0.66572 + 1.47817e-07 -0.746202 -0.66572 + 1.47817e-07 -0.746202 -0.66572 + 0.285558 -0.689401 -0.665719 + 0.285558 -0.689401 -0.665719 + 0.285558 -0.689401 -0.665719 + 0.285558 -0.689401 -0.665719 + 0.285558 -0.689401 -0.665719 + 0.527646 -0.527645 -0.665719 + 0.527646 -0.527645 -0.665719 + 0.527646 -0.527645 -0.665719 + 0.527646 -0.527645 -0.665719 + 0.527646 -0.527645 -0.665719 + 0.689402 -0.285558 -0.665719 + 0.689402 -0.285558 -0.665719 + 0.689402 -0.285558 -0.665719 + 0.689402 -0.285558 -0.665719 + 0.689402 -0.285558 -0.665719 + 0.746202 2.91827e-07 -0.66572 + 0.746202 2.91827e-07 -0.66572 + 0.746202 2.91827e-07 -0.66572 + 0.746202 2.91827e-07 -0.66572 + 0.746202 2.91827e-07 -0.66572 + 0.689402 0.285558 -0.665719 + 0.689402 0.285558 -0.665719 + 0.689402 0.285558 -0.665719 + 0.689402 0.285558 -0.665719 + 0.689402 0.285558 -0.665719 + 0.527645 0.527645 -0.665719 + 0.527645 0.527645 -0.665719 + 0.527645 0.527645 -0.665719 + 0.527645 0.527645 -0.665719 + 0.527645 0.527645 -0.665719 + 0.285558 0.689402 -0.665719 + 0.285558 0.689402 -0.665719 + 0.285558 0.689402 -0.665719 + 0.285558 0.689402 -0.665719 + 0.285558 0.689402 -0.665719 + -1.76686e-07 0.746202 -0.66572 + -1.76686e-07 0.746202 -0.66572 + -1.76686e-07 0.746202 -0.66572 + -1.76686e-07 0.746202 -0.66572 + -1.76686e-07 0.746202 -0.66572 + -0.285558 0.689401 -0.665719 + -0.285558 0.689401 -0.665719 + -0.285558 0.689401 -0.665719 + -0.285558 0.689401 -0.665719 + -0.285558 0.689401 -0.665719 + -0.527646 0.527645 -0.665719 + -0.527646 0.527645 -0.665719 + -0.527646 0.527645 -0.665719 + -0.527646 0.527645 -0.665719 + -0.527646 0.527645 -0.665719 + -0.689402 0.285558 -0.665719 + -0.689402 0.285558 -0.665719 + -0.689402 0.285558 -0.665719 + -0.689402 0.285558 -0.665719 + -0.689402 0.285558 -0.665719 + -0.746202 -2.84638e-07 -0.66572 + -0.746202 -2.84638e-07 -0.66572 + -0.746202 -2.84638e-07 -0.66572 + -0.746202 -2.84638e-07 -0.66572 + -0.746202 -2.84638e-07 -0.66572 + -0.689402 -0.285558 -0.665719 + -0.689402 -0.285558 -0.665719 + -0.689402 -0.285558 -0.665719 + -0.689402 -0.285558 -0.665719 + -0.689402 -0.285558 -0.665719 + -0.527645 -0.527645 -0.665719 + -0.527645 -0.527645 -0.665719 + -0.527645 -0.527645 -0.665719 + -0.527645 -0.527645 -0.665719 + -0.527645 -0.527645 -0.665719 + -0.285558 -0.689402 -0.665719 + -0.285558 -0.689402 -0.665719 + -0.285558 -0.689402 -0.665719 + -0.285558 -0.689402 -0.665719 + -0.285558 -0.689402 -0.665719 + -0.382682 -0.92388 0 + -0.382682 -0.92388 0 + -0.382682 -0.92388 0 + -0.707107 -0.707107 0 + -0.707107 -0.707107 0 + -0.707107 -0.707107 0 + -0.92388 -0.382682 0 + -0.92388 -0.382682 0 + -0.92388 -0.382682 0 + -1 3.86889e-07 0 + -1 3.86889e-07 0 + -1 3.86889e-07 0 + -0.92388 0.382682 0 + -0.92388 0.382682 0 + -0.92388 0.382682 0 + -0.707107 0.707107 0 + -0.707107 0.707107 0 + -0.707107 0.707107 0 + -0.382682 0.92388 0 + -0.382682 0.92388 0 + -0.382682 0.92388 0 + 1.93445e-07 1 0 + 1.93445e-07 1 0 + 1.93445e-07 1 0 + 0.382682 0.92388 0 + 0.382682 0.92388 0 + 0.382682 0.92388 0 + 0.707107 0.707106 0 + 0.707107 0.707106 0 + 0.707107 0.707106 0 + 0.92388 0.382682 0 + 0.92388 0.382682 0 + 0.92388 0.382682 0 + 1 -3.77217e-07 0 + 1 -3.77217e-07 0 + 1 -3.77217e-07 0 + 0.92388 -0.382682 0 + 0.92388 -0.382682 0 + 0.92388 -0.382682 0 + 0.707107 -0.707107 0 + 0.707107 -0.707107 0 + 0.707107 -0.707107 0 + 0.382682 -0.92388 0 + 0.382682 -0.92388 0 + 0.382682 -0.92388 0 + -2.22461e-07 -1 0 + -2.22461e-07 -1 0 + -2.22461e-07 -1 0 + 0 0 1 + 1 0 0 + 0 1 0 + 1 0 0 + 0 1 0 + 1 0 0 + 0 0 -1 + 0 1 0 + 0 0 -1 + 0 0 1 + 0 -1 0 + 0 0 1 + 0 -1 0 + 1 0 0 + 0 -1 0 + 1 0 0 + 1 0 0 + 0 0 -1 + 0 0 1 + 0 1 0 + 0 0 1 + 0 1 0 + -1 0 0 + 0 1 0 + -1 0 0 + 0 0 -1 + -1 0 0 + -1 0 0 + 0 0 1 + 0 -1 0 + -1 0 0 + 0 -1 0 + -1 0 0 + 0 0 -1 + 0 -1 0 + 0 0 -1 + } + } + } + ColorArray TRUE { + osg::Vec4Array { + UniqueID 155 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 153 + } + } + Binding BIND_PER_VERTEX + vector 180 { + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + } + } + } + } + } + } + } + Matrix { + 253.52 0 0 0 + 0 253.52 0 0 + 0 0 253.52 0 + 0 0 0 1 + } + + } + osg::MatrixTransform { + UniqueID 156 + Name "Y_Axis_Scale" + UserDataContainer TRUE { + osg::DefaultUserDataContainer { + UniqueID 157 + UDC_UserObjects 1 { + osg::StringValueObject { + UniqueID 158 + Name "dae_node_id" + Value "Y_Axis_Scale" + } + } + } + } + StateSet TRUE { + osg::StateSet { + UniqueID 6 + } + } + Children 1 { + osg::Geode { + UniqueID 159 + Drawables 1 { + osg::Geometry { + UniqueID 160 + Name "green-material" + DataVariance STATIC + StateSet TRUE { + osg::StateSet { + UniqueID 42 + } + } + PrimitiveSetList 1 { + osg::DrawElementsUInt { + UniqueID 161 + BufferObject TRUE { + osg::ElementBufferObject { + UniqueID 162 + Target 34963 + } + } + Mode TRIANGLES + vector 180 { + 18 9 0 10 + 31 14 19 4 + 23 27 24 32 + 1 15 5 6 + 33 25 65 145 + 60 45 157 40 + 61 148 55 160 + 110 36 75 139 + 70 56 151 50 + 41 161 37 71 + 142 66 51 154 + 46 105 121 100 + 85 133 80 101 + 124 95 81 136 + 76 96 127 90 + 111 118 106 91 + 130 86 87 82 + 164 52 47 165 + 92 88 166 57 + 53 167 97 93 + 168 62 58 169 + 102 98 170 67 + 63 171 107 103 + 172 72 68 173 + 112 108 174 77 + 73 175 42 38 + 176 39 113 177 + 83 78 178 48 + 43 179 20 28 + 11 12 29 34 + 21 2 7 30 + 22 26 3 13 + 16 8 17 35 + 69 143 146 49 + 155 158 64 147 + 149 162 116 114 + 79 137 140 59 + 150 152 44 159 + 163 74 141 144 + 54 153 156 109 + 119 122 89 131 + 134 104 123 125 + 84 135 138 99 + 126 128 115 117 + 120 94 129 132 + + } + } + } + VertexArray TRUE { + osg::Vec3Array { + UniqueID 163 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 164 + } + } + Binding BIND_PER_VERTEX + vector 180 { + 0.000464075 0.000464075 0.00881904 + 0.000464075 0.000464075 0.00881904 + 0.000464075 0.000464075 0.00881904 + 0.000464075 0.000464075 0.00881904 + 0.000464075 0.000464075 0.00789094 + 0.000464075 0.000464075 0.00789094 + 0.000464075 0.000464075 0.00789094 + 0.000464075 0.000464075 0.00789094 + 0.000464075 0.000464075 0.00789094 + 0.000464075 -0.000464075 0.00881904 + 0.000464075 -0.000464075 0.00881904 + 0.000464075 -0.000464075 0.00881904 + 0.000464075 -0.000464075 0.00881904 + 0.000464075 -0.000464075 0.00881904 + 0.000464075 -0.000464075 0.00789094 + 0.000464075 -0.000464075 0.00789094 + 0.000464075 -0.000464075 0.00789094 + 0.000464075 -0.000464075 0.00789094 + -0.000464075 0.000464075 0.00881904 + -0.000464075 0.000464075 0.00881904 + -0.000464075 0.000464075 0.00881904 + -0.000464075 0.000464075 0.00881904 + -0.000464075 0.000464075 0.00881904 + -0.000464075 0.000464075 0.00789094 + -0.000464075 0.000464075 0.00789094 + -0.000464075 0.000464075 0.00789094 + -0.000464075 0.000464075 0.00789094 + -0.000464075 -0.000464075 0.00881904 + -0.000464075 -0.000464075 0.00881904 + -0.000464075 -0.000464075 0.00881904 + -0.000464075 -0.000464075 0.00881904 + -0.000464075 -0.000464075 0.00789094 + -0.000464075 -0.000464075 0.00789094 + -0.000464075 -0.000464075 0.00789094 + -0.000464075 -0.000464075 0.00789094 + -0.000464075 -0.000464075 0.00789094 + 0.000128021 0 0.00149989 + 0.000128021 0 0.00149989 + 0.000128021 0 0.00149989 + 0.000128021 0 0.00149989 + 0.000118276 4.89918e-05 0.00149989 + 0.000118276 4.89918e-05 0.00149989 + 0.000118276 4.89918e-05 0.00149989 + 0.000118276 4.89918e-05 0.00149989 + 0.000118276 4.89918e-05 0.00149989 + 9.05246e-05 9.05247e-05 0.00149989 + 9.05246e-05 9.05247e-05 0.00149989 + 9.05246e-05 9.05247e-05 0.00149989 + 9.05246e-05 9.05247e-05 0.00149989 + 9.05246e-05 9.05247e-05 0.00149989 + 4.89918e-05 0.000118277 0.00149989 + 4.89918e-05 0.000118277 0.00149989 + 4.89918e-05 0.000118277 0.00149989 + 4.89918e-05 0.000118277 0.00149989 + 4.89918e-05 0.000118277 0.00149989 + 0 0.000128021 0.00149989 + 0 0.000128021 0.00149989 + 0 0.000128021 0.00149989 + 0 0.000128021 0.00149989 + 0 0.000128021 0.00149989 + -4.89919e-05 0.000118277 0.00149989 + -4.89919e-05 0.000118277 0.00149989 + -4.89919e-05 0.000118277 0.00149989 + -4.89919e-05 0.000118277 0.00149989 + -4.89919e-05 0.000118277 0.00149989 + -9.05247e-05 9.05247e-05 0.00149989 + -9.05247e-05 9.05247e-05 0.00149989 + -9.05247e-05 9.05247e-05 0.00149989 + -9.05247e-05 9.05247e-05 0.00149989 + -9.05247e-05 9.05247e-05 0.00149989 + -0.000118277 4.89918e-05 0.00149989 + -0.000118277 4.89918e-05 0.00149989 + -0.000118277 4.89918e-05 0.00149989 + -0.000118277 4.89918e-05 0.00149989 + -0.000118277 4.89918e-05 0.00149989 + -0.000128021 0 0.00149989 + -0.000128021 0 0.00149989 + -0.000128021 0 0.00149989 + -0.000128021 0 0.00149989 + -0.000128021 0 0.00149989 + -0.000118277 -4.89919e-05 0.00149989 + -0.000118277 -4.89919e-05 0.00149989 + -0.000118277 -4.89919e-05 0.00149989 + -0.000118277 -4.89919e-05 0.00149989 + -0.000118277 -4.89919e-05 0.00149989 + -9.05247e-05 -9.05246e-05 0.00149989 + -9.05247e-05 -9.05246e-05 0.00149989 + -9.05247e-05 -9.05246e-05 0.00149989 + -9.05247e-05 -9.05246e-05 0.00149989 + -9.05247e-05 -9.05246e-05 0.00149989 + -4.89919e-05 -0.000118276 0.00149989 + -4.89919e-05 -0.000118276 0.00149989 + -4.89919e-05 -0.000118276 0.00149989 + -4.89919e-05 -0.000118276 0.00149989 + -4.89919e-05 -0.000118276 0.00149989 + 0 -0.000128021 0.00149989 + 0 -0.000128021 0.00149989 + 0 -0.000128021 0.00149989 + 0 -0.000128021 0.00149989 + 0 -0.000128021 0.00149989 + 4.89918e-05 -0.000118276 0.00149989 + 4.89918e-05 -0.000118276 0.00149989 + 4.89918e-05 -0.000118276 0.00149989 + 4.89918e-05 -0.000118276 0.00149989 + 4.89918e-05 -0.000118276 0.00149989 + 9.05246e-05 -9.05246e-05 0.00149989 + 9.05246e-05 -9.05246e-05 0.00149989 + 9.05246e-05 -9.05246e-05 0.00149989 + 9.05246e-05 -9.05246e-05 0.00149989 + 9.05246e-05 -9.05246e-05 0.00149989 + 0.000118276 -4.89919e-05 0.00149989 + 0.000118276 -4.89919e-05 0.00149989 + 0.000118276 -4.89919e-05 0.00149989 + 0.000118276 -4.89919e-05 0.00149989 + 0.000118276 -4.89919e-05 0.00149989 + 0.000118276 -4.89919e-05 0.00149989 + 0.000118276 -4.89921e-05 0.00789094 + 0.000118276 -4.89921e-05 0.00789094 + 9.05245e-05 -9.05248e-05 0.00789094 + 9.05245e-05 -9.05248e-05 0.00789094 + 9.05245e-05 -9.05248e-05 0.00789094 + 4.89917e-05 -0.000118276 0.00789094 + 4.89917e-05 -0.000118276 0.00789094 + 4.89917e-05 -0.000118276 0.00789094 + 0 -0.000128021 0.00789094 + 0 -0.000128021 0.00789094 + 0 -0.000128021 0.00789094 + -4.89921e-05 -0.000118276 0.00789094 + -4.89921e-05 -0.000118276 0.00789094 + -4.89921e-05 -0.000118276 0.00789094 + -9.05249e-05 -9.05248e-05 0.00789094 + -9.05249e-05 -9.05248e-05 0.00789094 + -9.05249e-05 -9.05248e-05 0.00789094 + -0.000118277 -4.89921e-05 0.00789094 + -0.000118277 -4.89921e-05 0.00789094 + -0.000118277 -4.89921e-05 0.00789094 + -0.000128021 0 0.00789094 + -0.000128021 0 0.00789094 + -0.000128021 0 0.00789094 + -0.000118277 4.89916e-05 0.00789094 + -0.000118277 4.89916e-05 0.00789094 + -0.000118277 4.89916e-05 0.00789094 + -9.05249e-05 9.05245e-05 0.00789094 + -9.05249e-05 9.05245e-05 0.00789094 + -9.05249e-05 9.05245e-05 0.00789094 + -4.89921e-05 0.000118277 0.00789094 + -4.89921e-05 0.000118277 0.00789094 + -4.89921e-05 0.000118277 0.00789094 + 0 0.000128021 0.00789094 + 0 0.000128021 0.00789094 + 0 0.000128021 0.00789094 + 4.89917e-05 0.000118277 0.00789094 + 4.89917e-05 0.000118277 0.00789094 + 4.89917e-05 0.000118277 0.00789094 + 9.05245e-05 9.05245e-05 0.00789094 + 9.05245e-05 9.05245e-05 0.00789094 + 9.05245e-05 9.05245e-05 0.00789094 + 0.000118276 4.89916e-05 0.00789094 + 0.000118276 4.89916e-05 0.00789094 + 0.000118276 4.89916e-05 0.00789094 + 0.000128021 0 0.00789094 + 0.000128021 0 0.00789094 + 0.000128021 0 0.00789094 + 0.000128021 0 0.00789094 + 0 0 0.00149995 + 0 0 0.00149995 + 0 0 0.00149995 + 0 0 0.00149995 + 0 0 0.00149995 + 0 0 0.00149995 + 0 0 0.00149995 + 0 0 0.00149995 + 0 0 0.00149995 + 0 0 0.00149995 + 0 0 0.00149995 + 0 0 0.00149995 + 0 0 0.00149995 + 0 0 0.00149995 + 0 0 0.00149995 + 0 0 0.00149995 + } + } + } + NormalArray TRUE { + osg::Vec3Array { + UniqueID 165 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 164 + } + } + Binding BIND_PER_VERTEX + vector 180 { + 0 0 1 + 1 0 0 + 0 1 0 + 1 0 0 + 0 1 0 + 1 0 0 + 0 0 -1 + 0 1 0 + 0 0 -1 + 0 0 1 + 0 -1 0 + 0 0 1 + 0 -1 0 + 1 0 0 + 0 -1 0 + 1 0 0 + 1 0 0 + 0 0 -1 + 0 0 1 + 0 1 0 + 0 0 1 + 0 1 0 + -1 0 0 + 0 1 0 + -1 0 0 + 0 0 -1 + -1 0 0 + -1 0 0 + 0 0 1 + 0 -1 0 + -1 0 0 + 0 -1 0 + -1 0 0 + 0 0 -1 + 0 -1 0 + 0 0 -1 + 0.746202 -1.44348e-07 -0.66572 + 0.746202 -1.44348e-07 -0.66572 + 0.746202 -1.44348e-07 -0.66572 + 0.746202 -1.44348e-07 -0.66572 + 0.689401 0.285559 -0.66572 + 0.689401 0.285559 -0.66572 + 0.689401 0.285559 -0.66572 + 0.689401 0.285559 -0.66572 + 0.689401 0.285559 -0.66572 + 0.527648 0.527639 -0.665721 + 0.527648 0.527639 -0.665721 + 0.527648 0.527639 -0.665721 + 0.527648 0.527639 -0.665721 + 0.527648 0.527639 -0.665721 + 0.285558 0.689404 -0.665716 + 0.285558 0.689404 -0.665716 + 0.285558 0.689404 -0.665716 + 0.285558 0.689404 -0.665716 + 0.285558 0.689404 -0.665716 + 0 0.746198 -0.665724 + 0 0.746198 -0.665724 + 0 0.746198 -0.665724 + 0 0.746198 -0.665724 + 0 0.746198 -0.665724 + -0.285558 0.689404 -0.665716 + -0.285558 0.689404 -0.665716 + -0.285558 0.689404 -0.665716 + -0.285558 0.689404 -0.665716 + -0.285558 0.689404 -0.665716 + -0.527643 0.527642 -0.665722 + -0.527643 0.527642 -0.665722 + -0.527643 0.527642 -0.665722 + -0.527643 0.527642 -0.665722 + -0.527643 0.527642 -0.665722 + -0.689404 0.285558 -0.665717 + -0.689404 0.285558 -0.665717 + -0.689404 0.285558 -0.665717 + -0.689404 0.285558 -0.665717 + -0.689404 0.285558 -0.665717 + -0.746198 -1.49761e-07 -0.665724 + -0.746198 -1.49761e-07 -0.665724 + -0.746198 -1.49761e-07 -0.665724 + -0.746198 -1.49761e-07 -0.665724 + -0.746198 -1.49761e-07 -0.665724 + -0.689404 -0.285559 -0.665716 + -0.689404 -0.285559 -0.665716 + -0.689404 -0.285559 -0.665716 + -0.689404 -0.285559 -0.665716 + -0.689404 -0.285559 -0.665716 + -0.527639 -0.527647 -0.665722 + -0.527639 -0.527647 -0.665722 + -0.527639 -0.527647 -0.665722 + -0.527639 -0.527647 -0.665722 + -0.527639 -0.527647 -0.665722 + -0.28556 -0.689401 -0.665719 + -0.28556 -0.689401 -0.665719 + -0.28556 -0.689401 -0.665719 + -0.28556 -0.689401 -0.665719 + -0.28556 -0.689401 -0.665719 + 3.00144e-07 -0.746202 -0.66572 + 3.00144e-07 -0.746202 -0.66572 + 3.00144e-07 -0.746202 -0.66572 + 3.00144e-07 -0.746202 -0.66572 + 3.00144e-07 -0.746202 -0.66572 + 0.28556 -0.6894 -0.66572 + 0.28556 -0.6894 -0.66572 + 0.28556 -0.6894 -0.66572 + 0.28556 -0.6894 -0.66572 + 0.28556 -0.6894 -0.66572 + 0.527645 -0.527644 -0.66572 + 0.527645 -0.527644 -0.66572 + 0.527645 -0.527644 -0.66572 + 0.527645 -0.527644 -0.66572 + 0.527645 -0.527644 -0.66572 + 0.6894 -0.285559 -0.66572 + 0.6894 -0.285559 -0.66572 + 0.6894 -0.285559 -0.66572 + 0.6894 -0.285559 -0.66572 + 0.6894 -0.285559 -0.66572 + 0.6894 -0.285559 -0.66572 + 0.923879 -0.382684 0 + 0.923879 -0.382684 0 + 0.707107 -0.707107 0 + 0.707107 -0.707107 0 + 0.707107 -0.707107 0 + 0.382684 -0.923879 0 + 0.382684 -0.923879 0 + 0.382684 -0.923879 0 + 0 -1 0 + 0 -1 0 + 0 -1 0 + -0.382684 -0.923879 0 + -0.382684 -0.923879 0 + -0.382684 -0.923879 0 + -0.707102 -0.707112 0 + -0.707102 -0.707112 0 + -0.707102 -0.707112 0 + -0.92388 -0.382681 0 + -0.92388 -0.382681 0 + -0.92388 -0.382681 0 + -1 -1.74099e-07 0 + -1 -1.74099e-07 0 + -1 -1.74099e-07 0 + -0.923881 0.382681 0 + -0.923881 0.382681 0 + -0.923881 0.382681 0 + -0.707106 0.707107 0 + -0.707106 0.707107 0 + -0.707106 0.707107 0 + -0.38268 0.923881 0 + -0.38268 0.923881 0 + -0.38268 0.923881 0 + 4.06232e-07 1 0 + 4.06232e-07 1 0 + 4.06232e-07 1 0 + 0.382681 0.923881 0 + 0.382681 0.923881 0 + 0.382681 0.923881 0 + 0.707112 0.707102 0 + 0.707112 0.707102 0 + 0.707112 0.707102 0 + 0.92388 0.382683 0 + 0.92388 0.382683 0 + 0.92388 0.382683 0 + 1 -1.93445e-07 0 + 1 -1.93445e-07 0 + 1 -1.93445e-07 0 + 1 -1.93445e-07 0 + 2.29181e-07 0 -1 + 2.29181e-07 0 -1 + 2.29181e-07 0 -1 + 2.29181e-07 0 -1 + 2.29181e-07 0 -1 + 2.29181e-07 0 -1 + 2.29181e-07 0 -1 + 2.29181e-07 0 -1 + 2.29181e-07 0 -1 + 2.29181e-07 0 -1 + 2.29181e-07 0 -1 + 2.29181e-07 0 -1 + 2.29181e-07 0 -1 + 2.29181e-07 0 -1 + 2.29181e-07 0 -1 + 2.29181e-07 0 -1 + } + } + } + ColorArray TRUE { + osg::Vec4Array { + UniqueID 166 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 164 + } + } + Binding BIND_PER_VERTEX + vector 180 { + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + } + } + } + } + } + } + } + Matrix { + 253.52 0 0 0 + 0 -1.10817e-05 -253.52 0 + 0 253.52 -1.10817e-05 0 + 0 0 0 1 + } + + } + osg::MatrixTransform { + UniqueID 167 + Name "X_Axis_Scale" + UserDataContainer TRUE { + osg::DefaultUserDataContainer { + UniqueID 168 + UDC_UserObjects 1 { + osg::StringValueObject { + UniqueID 169 + Name "dae_node_id" + Value "X_Axis_Scale" + } + } + } + } + StateSet TRUE { + osg::StateSet { + UniqueID 6 + } + } + Children 1 { + osg::Geode { + UniqueID 170 + Drawables 1 { + osg::Geometry { + UniqueID 171 + Name "red-material" + DataVariance STATIC + StateSet TRUE { + osg::StateSet { + UniqueID 16 + } + } + PrimitiveSetList 1 { + osg::DrawElementsUInt { + UniqueID 172 + BufferObject TRUE { + osg::ElementBufferObject { + UniqueID 173 + Target 34963 + } + } + Mode TRIANGLES + vector 180 { + 86 102 81 91 + 99 87 76 108 + 71 0 21 16 + 1 26 22 2 + 31 27 3 36 + 32 4 41 37 + 5 46 42 6 + 51 47 7 56 + 52 8 61 57 + 9 66 62 10 + 72 67 11 77 + 73 12 82 78 + 13 88 83 14 + 92 89 15 17 + 93 38 132 33 + 34 135 28 84 + 105 79 68 114 + 63 23 141 18 + 74 111 69 19 + 96 94 43 129 + 39 48 126 44 + 58 120 53 54 + 123 49 29 138 + 24 64 117 59 + 162 153 144 154 + 175 158 163 148 + 167 171 168 176 + 145 159 149 150 + 177 169 90 100 + 103 95 97 101 + 80 106 109 40 + 130 133 35 134 + 136 85 104 107 + 70 112 115 25 + 139 142 75 110 + 113 20 143 98 + 45 127 131 50 + 124 128 60 118 + 121 55 122 125 + 30 137 140 65 + 116 119 164 172 + 155 156 173 178 + 165 146 151 174 + 166 170 147 157 + 160 152 161 179 + + } + } + } + VertexArray TRUE { + osg::Vec3Array { + UniqueID 174 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 175 + } + } + Binding BIND_PER_VERTEX + vector 180 { + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 0 0 + 0.00149989 -0.000128021 0 + 0.00149989 -0.000128021 0 + 0.00149989 -0.000128021 0 + 0.00149989 -0.000128021 0 + 0.00149989 -0.000128021 0 + 0.00149989 -0.000118276 -4.89919e-05 + 0.00149989 -0.000118276 -4.89919e-05 + 0.00149989 -0.000118276 -4.89919e-05 + 0.00149989 -0.000118276 -4.89919e-05 + 0.00149989 -0.000118276 -4.89919e-05 + 0.00149989 -9.05247e-05 -9.05248e-05 + 0.00149989 -9.05247e-05 -9.05248e-05 + 0.00149989 -9.05247e-05 -9.05248e-05 + 0.00149989 -9.05247e-05 -9.05248e-05 + 0.00149989 -9.05247e-05 -9.05248e-05 + 0.00149989 -4.89918e-05 -0.000118277 + 0.00149989 -4.89918e-05 -0.000118277 + 0.00149989 -4.89918e-05 -0.000118277 + 0.00149989 -4.89918e-05 -0.000118277 + 0.00149989 -4.89918e-05 -0.000118277 + 0.00149989 0 -0.000128021 + 0.00149989 0 -0.000128021 + 0.00149989 0 -0.000128021 + 0.00149989 0 -0.000128021 + 0.00149989 0 -0.000128021 + 0.00149989 4.89918e-05 -0.000118277 + 0.00149989 4.89918e-05 -0.000118277 + 0.00149989 4.89918e-05 -0.000118277 + 0.00149989 4.89918e-05 -0.000118277 + 0.00149989 4.89918e-05 -0.000118277 + 0.00149989 9.05247e-05 -9.05248e-05 + 0.00149989 9.05247e-05 -9.05248e-05 + 0.00149989 9.05247e-05 -9.05248e-05 + 0.00149989 9.05247e-05 -9.05248e-05 + 0.00149989 9.05247e-05 -9.05248e-05 + 0.00149989 0.000118276 -4.89919e-05 + 0.00149989 0.000118276 -4.89919e-05 + 0.00149989 0.000118276 -4.89919e-05 + 0.00149989 0.000118276 -4.89919e-05 + 0.00149989 0.000118276 -4.89919e-05 + 0.00149989 0.000128021 0 + 0.00149989 0.000128021 0 + 0.00149989 0.000128021 0 + 0.00149989 0.000128021 0 + 0.00149989 0.000128021 0 + 0.00149989 0.000118276 4.89918e-05 + 0.00149989 0.000118276 4.89918e-05 + 0.00149989 0.000118276 4.89918e-05 + 0.00149989 0.000118276 4.89918e-05 + 0.00149989 0.000118276 4.89918e-05 + 0.00149989 9.05247e-05 9.05246e-05 + 0.00149989 9.05247e-05 9.05246e-05 + 0.00149989 9.05247e-05 9.05246e-05 + 0.00149989 9.05247e-05 9.05246e-05 + 0.00149989 9.05247e-05 9.05246e-05 + 0.00149989 4.89918e-05 0.000118276 + 0.00149989 4.89918e-05 0.000118276 + 0.00149989 4.89918e-05 0.000118276 + 0.00149989 4.89918e-05 0.000118276 + 0.00149989 4.89918e-05 0.000118276 + 0.00149989 0 0.000128021 + 0.00149989 0 0.000128021 + 0.00149989 0 0.000128021 + 0.00149989 0 0.000128021 + 0.00149989 0 0.000128021 + 0.00149989 -4.89918e-05 0.000118276 + 0.00149989 -4.89918e-05 0.000118276 + 0.00149989 -4.89918e-05 0.000118276 + 0.00149989 -4.89918e-05 0.000118276 + 0.00149989 -4.89918e-05 0.000118276 + 0.00149989 -9.05247e-05 9.05246e-05 + 0.00149989 -9.05247e-05 9.05246e-05 + 0.00149989 -9.05247e-05 9.05246e-05 + 0.00149989 -9.05247e-05 9.05246e-05 + 0.00149989 -9.05247e-05 9.05246e-05 + 0.00149989 -0.000118276 4.89918e-05 + 0.00149989 -0.000118276 4.89918e-05 + 0.00149989 -0.000118276 4.89918e-05 + 0.00149989 -0.000118276 4.89918e-05 + 0.00149989 -0.000118276 4.89918e-05 + 0.00789094 -0.000118276 4.89917e-05 + 0.00789094 -0.000118276 4.89917e-05 + 0.00789094 -0.000118276 4.89917e-05 + 0.00789094 -9.05247e-05 9.05245e-05 + 0.00789094 -9.05247e-05 9.05245e-05 + 0.00789094 -9.05247e-05 9.05245e-05 + 0.00789094 -4.89918e-05 0.000118276 + 0.00789094 -4.89918e-05 0.000118276 + 0.00789094 -4.89918e-05 0.000118276 + 0.00789094 0 0.000128021 + 0.00789094 0 0.000128021 + 0.00789094 0 0.000128021 + 0.00789094 4.89918e-05 0.000118276 + 0.00789094 4.89918e-05 0.000118276 + 0.00789094 4.89918e-05 0.000118276 + 0.00789094 9.05247e-05 9.05245e-05 + 0.00789094 9.05247e-05 9.05245e-05 + 0.00789094 9.05247e-05 9.05245e-05 + 0.00789094 0.000118276 4.89917e-05 + 0.00789094 0.000118276 4.89917e-05 + 0.00789094 0.000118276 4.89917e-05 + 0.00789094 0.000128021 0 + 0.00789094 0.000128021 0 + 0.00789094 0.000128021 0 + 0.00789094 0.000118276 -4.8992e-05 + 0.00789094 0.000118276 -4.8992e-05 + 0.00789094 0.000118276 -4.8992e-05 + 0.00789094 9.05247e-05 -9.05249e-05 + 0.00789094 9.05247e-05 -9.05249e-05 + 0.00789094 9.05247e-05 -9.05249e-05 + 0.00789094 4.89918e-05 -0.000118277 + 0.00789094 4.89918e-05 -0.000118277 + 0.00789094 4.89918e-05 -0.000118277 + 0.00789094 0 -0.000128021 + 0.00789094 0 -0.000128021 + 0.00789094 0 -0.000128021 + 0.00789094 -4.89918e-05 -0.000118277 + 0.00789094 -4.89918e-05 -0.000118277 + 0.00789094 -4.89918e-05 -0.000118277 + 0.00789094 -9.05247e-05 -9.05249e-05 + 0.00789094 -9.05247e-05 -9.05249e-05 + 0.00789094 -9.05247e-05 -9.05249e-05 + 0.00789094 -0.000118276 -4.8992e-05 + 0.00789094 -0.000118276 -4.8992e-05 + 0.00789094 -0.000118276 -4.8992e-05 + 0.00789094 -0.000128021 0 + 0.00789094 -0.000128021 0 + 0.00789094 -0.000128021 0 + 0.00881904 -0.000464076 -0.000464076 + 0.00881904 -0.000464076 -0.000464076 + 0.00881904 -0.000464076 -0.000464076 + 0.00881904 -0.000464076 -0.000464076 + 0.00789094 -0.000464076 -0.000464076 + 0.00789094 -0.000464076 -0.000464076 + 0.00789094 -0.000464076 -0.000464076 + 0.00789094 -0.000464076 -0.000464076 + 0.00789094 -0.000464076 -0.000464076 + 0.00881904 -0.000464076 0.000464075 + 0.00881904 -0.000464076 0.000464075 + 0.00881904 -0.000464076 0.000464075 + 0.00881904 -0.000464076 0.000464075 + 0.00881904 -0.000464076 0.000464075 + 0.00789094 -0.000464076 0.000464075 + 0.00789094 -0.000464076 0.000464075 + 0.00789094 -0.000464076 0.000464075 + 0.00789094 -0.000464076 0.000464075 + 0.00881904 0.000464075 -0.000464076 + 0.00881904 0.000464075 -0.000464076 + 0.00881904 0.000464075 -0.000464076 + 0.00881904 0.000464075 -0.000464076 + 0.00881904 0.000464075 -0.000464076 + 0.00789094 0.000464075 -0.000464076 + 0.00789094 0.000464075 -0.000464076 + 0.00789094 0.000464075 -0.000464076 + 0.00789094 0.000464075 -0.000464076 + 0.00881904 0.000464075 0.000464075 + 0.00881904 0.000464075 0.000464075 + 0.00881904 0.000464075 0.000464075 + 0.00881904 0.000464075 0.000464075 + 0.00789094 0.000464075 0.000464075 + 0.00789094 0.000464075 0.000464075 + 0.00789094 0.000464075 0.000464075 + 0.00789094 0.000464075 0.000464075 + 0.00789094 0.000464075 0.000464075 + } + } + } + NormalArray TRUE { + osg::Vec3Array { + UniqueID 176 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 175 + } + } + Binding BIND_PER_VERTEX + vector 180 { + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -0.66572 -0.746202 -1.33156e-07 + -0.66572 -0.746202 -1.33156e-07 + -0.66572 -0.746202 -1.33156e-07 + -0.66572 -0.746202 -1.33156e-07 + -0.66572 -0.746202 -1.33156e-07 + -0.665719 -0.689402 -0.285558 + -0.665719 -0.689402 -0.285558 + -0.665719 -0.689402 -0.285558 + -0.665719 -0.689402 -0.285558 + -0.665719 -0.689402 -0.285558 + -0.66572 -0.527648 -0.52764 + -0.66572 -0.527648 -0.52764 + -0.66572 -0.527648 -0.52764 + -0.66572 -0.527648 -0.52764 + -0.66572 -0.527648 -0.52764 + -0.665716 -0.285558 -0.689405 + -0.665716 -0.285558 -0.689405 + -0.665716 -0.285558 -0.689405 + -0.665716 -0.285558 -0.689405 + -0.665716 -0.285558 -0.689405 + -0.665724 1.55766e-07 -0.746199 + -0.665724 1.55766e-07 -0.746199 + -0.665724 1.55766e-07 -0.746199 + -0.665724 1.55766e-07 -0.746199 + -0.665724 1.55766e-07 -0.746199 + -0.665716 0.285558 -0.689405 + -0.665716 0.285558 -0.689405 + -0.665716 0.285558 -0.689405 + -0.665716 0.285558 -0.689405 + -0.665716 0.285558 -0.689405 + -0.66572 0.527649 -0.52764 + -0.66572 0.527649 -0.52764 + -0.66572 0.527649 -0.52764 + -0.66572 0.527649 -0.52764 + -0.66572 0.527649 -0.52764 + -0.665719 0.689402 -0.285558 + -0.665719 0.689402 -0.285558 + -0.665719 0.689402 -0.285558 + -0.665719 0.689402 -0.285558 + -0.665719 0.689402 -0.285558 + -0.66572 0.746202 4.29748e-07 + -0.66572 0.746202 4.29748e-07 + -0.66572 0.746202 4.29748e-07 + -0.66572 0.746202 4.29748e-07 + -0.66572 0.746202 4.29748e-07 + -0.665719 0.689401 0.285559 + -0.665719 0.689401 0.285559 + -0.665719 0.689401 0.285559 + -0.665719 0.689401 0.285559 + -0.665719 0.689401 0.285559 + -0.665719 0.527646 0.527645 + -0.665719 0.527646 0.527645 + -0.665719 0.527646 0.527645 + -0.665719 0.527646 0.527645 + -0.665719 0.527646 0.527645 + -0.665719 0.28556 0.689401 + -0.665719 0.28556 0.689401 + -0.665719 0.28556 0.689401 + -0.665719 0.28556 0.689401 + -0.665719 0.28556 0.689401 + -0.66572 -1.61998e-07 0.746202 + -0.66572 -1.61998e-07 0.746202 + -0.66572 -1.61998e-07 0.746202 + -0.66572 -1.61998e-07 0.746202 + -0.66572 -1.61998e-07 0.746202 + -0.665719 -0.28556 0.689401 + -0.665719 -0.28556 0.689401 + -0.665719 -0.28556 0.689401 + -0.665719 -0.28556 0.689401 + -0.665719 -0.28556 0.689401 + -0.665719 -0.527646 0.527644 + -0.665719 -0.527646 0.527644 + -0.665719 -0.527646 0.527644 + -0.665719 -0.527646 0.527644 + -0.665719 -0.527646 0.527644 + -0.665719 -0.689402 0.285558 + -0.665719 -0.689402 0.285558 + -0.665719 -0.689402 0.285558 + -0.665719 -0.689402 0.285558 + -0.665719 -0.689402 0.285558 + 0 -0.92388 0.382683 + 0 -0.92388 0.382683 + 0 -0.92388 0.382683 + 0 -0.707107 0.707107 + 0 -0.707107 0.707107 + 0 -0.707107 0.707107 + 0 -0.382683 0.92388 + 0 -0.382683 0.92388 + 0 -0.382683 0.92388 + 0 1.93445e-07 1 + 0 1.93445e-07 1 + 0 1.93445e-07 1 + 0 0.382683 0.92388 + 0 0.382683 0.92388 + 0 0.382683 0.92388 + 0 0.707107 0.707106 + 0 0.707107 0.707106 + 0 0.707107 0.707106 + 0 0.92388 0.382682 + 0 0.92388 0.382682 + 0 0.92388 0.382682 + 0 1 -1.741e-07 + 0 1 -1.741e-07 + 0 1 -1.741e-07 + 0 0.92388 -0.382682 + 0 0.92388 -0.382682 + 0 0.92388 -0.382682 + 0 0.707112 -0.707102 + 0 0.707112 -0.707102 + 0 0.707112 -0.707102 + 0 0.382679 -0.923881 + 0 0.382679 -0.923881 + 0 0.382679 -0.923881 + 0 -2.2246e-07 -1 + 0 -2.2246e-07 -1 + 0 -2.2246e-07 -1 + 0 -0.38268 -0.923881 + 0 -0.38268 -0.923881 + 0 -0.38268 -0.923881 + 0 -0.707112 -0.707101 + 0 -0.707112 -0.707101 + 0 -0.707112 -0.707101 + 0 -0.92388 -0.382681 + 0 -0.92388 -0.382681 + 0 -0.92388 -0.382681 + 0 -1 5.80334e-07 + 0 -1 5.80334e-07 + 0 -1 5.80334e-07 + 1 0 0 + 0 -1 0 + 0 0 -1 + 0 -1 0 + 0 0 -1 + 0 -1 0 + -1 0 0 + 0 0 -1 + -1 0 0 + 1 0 0 + 0 0 1 + 1 0 0 + 0 0 1 + 0 -1 0 + 0 0 1 + 0 -1 0 + 0 -1 0 + -1 0 0 + 1 0 0 + 0 0 -1 + 1 0 0 + 0 0 -1 + 0 1 0 + 0 0 -1 + 0 1 0 + -1 0 0 + 0 1 0 + 0 1 0 + 1 0 0 + 0 0 1 + 0 1 0 + 0 0 1 + 0 1 0 + -1 0 0 + 0 0 1 + -1 0 0 + } + } + } + ColorArray TRUE { + osg::Vec4Array { + UniqueID 177 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 175 + } + } + Binding BIND_PER_VERTEX + vector 180 { + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + 1 1 1 1 + } + } + } + } + } + } + } + Matrix { + 253.52 0 0 0 + 0 253.52 0 0 + 0 0 253.52 0 + 0 0 0 1 + } + + } + } + Matrix { + 0.00394446 0 0 0 + 0 0.00394446 0 0 + 0 0 0.00394446 0 + 0 0 0 1 + } + + } + osg::MatrixTransform { + UniqueID 178 + Name "rotateMarkers" + UserDataContainer TRUE { + osg::DefaultUserDataContainer { + UniqueID 179 + UDC_UserObjects 1 { + osg::StringValueObject { + UniqueID 180 + Name "dae_node_id" + Value "rotateMarkers" + } + } + } + } + StateSet TRUE { + osg::StateSet { + UniqueID 211 + } + } + Children 3 { + osg::MatrixTransform { + UniqueID 181 + Name "X_Axis_Rot" + UserDataContainer TRUE { + osg::DefaultUserDataContainer { + UniqueID 182 + UDC_UserObjects 1 { + osg::StringValueObject { + UniqueID 183 + Name "dae_node_id" + Value "X_Axis_Rot" + } + } + } + } + Children 1 { + osg::Geode { + UniqueID 184 + Drawables 1 { + osg::Geometry { + UniqueID 185 + Name "red-material" + DataVariance STATIC + StateSet TRUE { + osg::StateSet { + UniqueID 16 + } + } + PrimitiveSetList 1 { + osg::DrawElementsUInt { + UniqueID 186 + BufferObject TRUE { + osg::ElementBufferObject { + UniqueID 187 + Target 34963 + } + } + Mode TRIANGLES + vector 3456 { + 0 78 8 79 + 12 9 84 19 + 13 91 25 20 + 26 101 32 33 + 108 38 109 42 + 39 114 48 43 + 121 55 49 126 + 61 56 62 138 + 68 139 1 69 + 72 148 80 149 + 85 81 86 161 + 92 93 167 97 + 168 102 98 103 + 179 110 180 115 + 111 116 191 122 + 192 127 123 197 + 132 128 133 208 + 140 209 73 141 + 216 150 144 151 + 228 156 157 235 + 162 163 240 169 + 241 173 170 174 + 252 181 253 185 + 182 186 265 193 + 266 198 194 271 + 203 199 277 210 + 204 211 217 145 + 218 294 224 295 + 229 225 230 306 + 236 307 242 237 + 313 247 243 318 + 254 248 325 259 + 255 260 336 267 + 337 272 268 342 + 278 273 279 354 + 284 355 219 285 + 288 366 296 367 + 300 297 301 378 + 308 309 384 314 + 385 319 315 320 + 396 326 397 330 + 327 331 408 338 + 409 343 339 414 + 348 344 349 426 + 356 427 289 357 + 360 436 368 437 + 372 369 373 449 + 379 380 454 386 + 455 390 387 391 + 467 398 468 402 + 399 403 478 410 + 479 415 411 486 + 420 416 421 497 + 428 498 361 429 + 504 438 432 510 + 443 439 444 521 + 450 522 456 451 + 457 534 462 463 + 539 469 540 473 + 470 547 480 474 + 481 558 487 559 + 491 488 492 569 + 499 500 505 433 + 576 511 506 512 + 587 517 588 523 + 518 595 528 524 + 529 606 535 607 + 541 536 542 618 + 548 619 552 549 + 553 630 560 631 + 564 561 636 570 + 565 571 577 507 + 648 582 578 654 + 589 583 590 666 + 596 667 600 597 + 601 678 608 679 + 612 609 613 690 + 620 691 624 621 + 625 702 632 703 + 637 633 638 714 + 643 644 649 579 + 720 655 650 726 + 660 656 661 737 + 668 738 672 669 + 673 749 680 750 + 684 681 685 762 + 692 763 696 693 + 697 774 704 775 + 708 705 709 785 + 715 716 721 651 + 792 727 722 728 + 804 733 805 739 + 734 810 744 740 + 817 751 745 822 + 756 752 757 834 + 764 765 840 769 + 770 845 776 777 + 851 781 852 786 + 782 787 793 723 + 864 798 794 799 + 876 806 877 811 + 807 812 888 818 + 889 823 819 895 + 828 824 829 906 + 835 836 913 841 + 914 846 842 920 + 853 847 925 858 + 854 859 865 795 + 936 871 866 943 + 878 872 948 883 + 879 955 890 884 + 961 896 891 967 + 901 897 972 907 + 902 908 983 915 + 916 989 921 990 + 926 922 927 1002 + 932 1003 867 933 + 937 1014 944 1015 + 949 945 950 1025 + 956 957 1032 962 + 963 1037 968 1038 + 973 969 974 1050 + 979 1051 984 980 + 1057 991 985 1062 + 996 992 997 1073 + 1004 1074 938 1005 + 1008 1086 1016 1087 + 1020 1017 1093 1026 + 1021 1027 1104 1033 + 1105 1039 1034 1110 + 1044 1040 1045 1122 + 1052 1053 1127 1058 + 1128 1063 1059 1064 + 1140 1069 1141 1075 + 1070 1146 1009 1076 + 1080 1156 1088 1089 + 1162 1094 1163 1098 + 1095 1099 1175 1106 + 1176 1111 1107 1181 + 1116 1112 1117 1192 + 1123 1193 1129 1124 + 1200 1134 1130 1135 + 1211 1142 1212 1147 + 1143 1218 1081 1148 + 1224 1157 1152 1232 + 1164 1158 1237 1169 + 1165 1170 1248 1177 + 1249 1182 1178 1256 + 1187 1183 1262 1194 + 1188 1195 1272 1201 + 1273 1205 1202 1206 + 1284 1213 1214 1291 + 1219 1220 1225 1153 + 1226 1302 1233 1303 + 1238 1234 1239 1314 + 1244 1315 1250 1245 + 1251 1326 1257 1258 + 1331 1263 1332 1267 + 1264 1339 1274 1268 + 1275 1350 1280 1351 + 1285 1281 1286 1362 + 1292 1363 1227 1293 + 1296 1373 1304 1374 + 1308 1305 1309 1386 + 1316 1387 1320 1317 + 1321 1398 1327 1399 + 1333 1328 1334 1410 + 1340 1411 1344 1341 + 1345 1421 1352 1422 + 1356 1353 1357 1434 + 1364 1435 1297 1365 + 1440 1375 1368 1445 + 1380 1376 1381 1457 + 1388 1389 1462 1393 + 1394 1468 1400 1469 + 1404 1401 1405 1480 + 1412 1481 1416 1413 + 1488 1423 1417 1494 + 1428 1424 1429 1505 + 1436 1506 1369 1437 + 1512 1446 1441 1520 + 1451 1447 1452 1531 + 1458 1532 1463 1459 + 1537 1470 1464 1471 + 1549 1476 1550 1482 + 1477 1483 1561 1489 + 1490 1567 1495 1568 + 1499 1496 1500 1578 + 1507 1508 1513 1442 + 1514 1589 1521 1522 + 1596 1526 1527 1601 + 1533 1602 1538 1534 + 1608 1543 1539 1544 + 1620 1551 1621 1555 + 1552 1556 1632 1562 + 1563 1638 1569 1639 + 1573 1570 1645 1579 + 1574 1650 1515 1580 + 1656 1590 1584 1591 + 1667 1597 1668 1603 + 1598 1674 1609 1604 + 1680 1614 1610 1615 + 1690 1622 1691 1626 + 1623 1627 1702 1633 + 1634 1708 1640 1641 + 1714 1646 1715 1651 + 1647 1721 1585 1652 + 1728 1661 1657 1662 + 1740 1669 1670 1746 + 1675 1676 1752 1681 + 1753 1685 1682 1760 + 1692 1686 1765 1697 + 1693 1772 1703 1698 + 1777 1709 1704 1784 + 1716 1710 1790 1722 + 1717 1723 1729 1658 + 1730 1805 1736 1806 + 1741 1737 1812 1747 + 1742 1819 1754 1748 + 1755 1830 1761 1831 + 1766 1762 1767 1842 + 1773 1843 1778 1774 + 1779 1853 1785 1786 + 1859 1791 1792 1866 + 1796 1867 1731 1797 + 1872 1807 1800 1877 + 1813 1808 1814 1889 + 1820 1821 1894 1825 + 1826 1901 1832 1902 + 1836 1833 1837 1913 + 1844 1914 1848 1845 + 1919 1854 1849 1926 + 1860 1855 1861 1937 + 1868 1938 1801 1869 + 1944 1878 1873 1952 + 1883 1879 1884 1963 + 1890 1964 1895 1891 + 1896 1975 1903 1976 + 1907 1904 1908 1987 + 1915 1988 1920 1916 + 1921 1999 1927 2000 + 1931 1928 1932 2011 + 1939 1940 1945 1874 + 1946 2020 1953 2021 + 1957 1954 1958 2032 + 1965 2033 1969 1966 + 1970 2044 1977 2045 + 1981 1978 1982 2056 + 1989 2057 1993 1990 + 1994 2069 2001 2070 + 2005 2002 2006 2081 + 2012 2082 1947 2013 + 2088 2022 2016 2094 + 2027 2023 2101 2034 + 2028 2106 2039 2035 + 2113 2046 2040 2118 + 2051 2047 2125 2058 + 2052 2059 2136 2064 + 2065 2141 2071 2142 + 2075 2072 2076 2153 + 2083 2084 2089 2017 + 2160 2095 2090 2096 + 2172 2102 2173 2107 + 2103 2108 2184 2114 + 2185 2119 2115 2120 + 2195 2126 2196 2130 + 2127 2131 2207 2137 + 2208 2143 2138 2144 + 2220 2149 2221 2154 + 2150 2155 2161 2091 + 2232 2166 2162 2167 + 2244 2174 2245 2178 + 2175 2179 2255 2186 + 2256 2190 2187 2263 + 2197 2191 2198 2273 + 2203 2274 2209 2204 + 2280 2214 2210 2215 + 2292 2222 2293 2226 + 2223 2227 2233 2163 + 2304 2238 2234 2239 + 2315 2246 2316 2250 + 2247 2323 2257 2251 + 2258 2333 2264 2334 + 2268 2265 2341 2275 + 2269 2346 2281 2276 + 2282 2358 2287 2288 + 2363 2294 2364 2298 + 2295 2299 2305 2235 + 2376 2310 2306 2384 + 2317 2311 2318 2395 + 2324 2396 2328 2325 + 2401 2335 2329 2336 + 2412 2342 2413 2347 + 2343 2420 2352 2348 + 2353 2431 2359 2432 + 2365 2360 2366 2443 + 2371 2372 2377 2307 + 2378 2454 2385 2455 + 2389 2386 2390 2466 + 2397 2467 2402 2398 + 2403 2477 2408 2478 + 2414 2409 2415 2489 + 2421 2490 2425 2422 + 2426 2502 2433 2503 + 2437 2434 2438 2514 + 2444 2515 2379 2445 + 2448 2525 2456 2526 + 2460 2457 2461 2538 + 2468 2539 2472 2469 + 2545 2479 2473 2550 + 2484 2480 2557 2491 + 2485 2562 2496 2492 + 2497 2573 2504 2574 + 2508 2505 2509 2586 + 2516 2587 2449 2517 + 2592 2527 2520 2528 + 2603 2533 2534 2610 + 2540 2541 2615 2546 + 2616 2551 2547 2552 + 2627 2558 2628 2563 + 2559 2564 2639 2569 + 2640 2575 2570 2647 + 2580 2576 2581 2658 + 2588 2659 2521 2589 + 2593 2670 2599 2671 + 2604 2600 2605 2682 + 2611 2683 2617 2612 + 2688 2622 2618 2695 + 2629 2623 2700 2634 + 2630 2706 2641 2635 + 2642 2718 2648 2649 + 2723 2653 2654 2730 + 2660 2731 2594 2661 + 2664 2742 2672 2743 + 2676 2673 2677 2753 + 2684 2754 2689 2685 + 2690 2765 2696 2766 + 2701 2697 2773 2707 + 2702 2778 2712 2708 + 2713 2789 2719 2790 + 2724 2720 2725 2801 + 2732 2802 2665 2733 + 2736 2814 2744 2745 + 2820 2749 2821 2755 + 2750 2756 2832 2761 + 2833 2767 2762 2768 + 2844 2774 2845 2779 + 2775 2780 2856 2785 + 2857 2791 2786 2862 + 2796 2792 2869 2803 + 2797 2874 2737 2804 + 2808 2886 2815 2816 + 2891 2822 2892 2826 + 2823 2827 2904 2834 + 2905 2838 2835 2839 + 2916 2846 2917 2850 + 2847 2851 2928 2858 + 2929 2863 2859 2864 + 2940 2870 2941 2875 + 2871 2947 2809 2876 + 2880 2956 2887 2957 + 2893 2888 2964 2898 + 2894 2899 2975 2906 + 2976 2910 2907 2911 + 2987 2918 2988 2922 + 2919 2923 2999 2930 + 3000 2934 2931 2935 + 3011 2942 2943 3016 + 2948 3017 2881 2949 + 3024 2958 2952 2959 + 3036 2965 3037 2969 + 2966 2970 3047 2977 + 3048 2981 2978 2982 + 3059 2989 3060 2993 + 2990 2994 3071 3001 + 3072 3005 3002 3006 + 3084 3012 3085 3018 + 3013 3019 3025 2953 + 3096 3030 3026 3031 + 3108 3038 3109 3042 + 3039 3114 3049 3043 + 3050 3126 3055 3127 + 3061 3056 3062 3138 + 3067 3139 3073 3068 + 3074 3150 3079 3080 + 3156 3086 3157 3090 + 3087 3091 3097 3027 + 3168 3102 3098 3103 + 3180 3110 3181 3115 + 3111 3186 3120 3116 + 3121 3198 3128 3199 + 3132 3129 3133 3210 + 3140 3211 3144 3141 + 3145 3221 3151 3152 + 3228 3158 3229 3162 + 3159 3163 3169 3099 + 3240 3174 3170 3175 + 3252 3182 3253 3187 + 3183 3188 3264 3193 + 3194 3269 3200 3270 + 3204 3201 3205 3281 + 3212 3282 3216 3213 + 3289 3222 3217 3223 + 3300 3230 3301 3234 + 3231 3235 3241 3171 + 3312 3246 3242 3247 + 3324 3254 3325 3258 + 3255 3259 3336 3265 + 3337 3271 3266 3272 + 3347 3277 3348 3283 + 3278 3284 3359 3290 + 3360 3294 3291 3295 + 3372 3302 3373 3306 + 3303 3307 3313 3243 + 3384 3318 3314 3319 + 3396 3326 3397 3330 + 3327 3331 3407 3338 + 3408 3342 3339 3414 + 3349 3343 3350 3426 + 3355 3427 3361 3356 + 3433 3366 3362 3367 + 3443 3374 3444 3378 + 3375 3379 3385 3315 + 2 3390 3386 3391 + 14 3398 15 3402 + 3399 21 3409 3403 + 27 3415 3410 34 + 3420 3416 3421 44 + 3428 3429 50 3434 + 51 3438 3435 57 + 3445 3439 63 3450 + 3446 3451 3 3387 + 4 74 82 83 + 87 16 88 94 + 22 95 99 28 + 29 100 104 35 + 105 112 113 117 + 45 118 124 52 + 125 129 58 130 + 134 64 65 135 + 142 143 75 5 + 76 146 152 153 + 158 89 90 159 + 164 96 165 171 + 172 175 106 107 + 176 183 184 187 + 119 120 188 195 + 196 200 131 201 + 205 136 137 206 + 212 213 147 77 + 220 226 154 155 + 227 231 160 232 + 238 166 239 244 + 245 249 177 178 + 250 256 257 261 + 189 190 262 269 + 270 274 202 275 + 280 207 281 286 + 214 215 287 221 + 222 290 298 299 + 302 233 234 303 + 310 311 316 246 + 317 321 251 322 + 328 258 329 332 + 263 264 333 340 + 341 345 276 346 + 350 282 283 351 + 358 359 291 223 + 292 362 370 371 + 374 304 305 375 + 381 312 382 388 + 389 392 323 324 + 393 400 401 404 + 334 335 405 412 + 413 417 347 418 + 422 352 353 423 + 430 431 363 293 + 364 434 440 441 + 445 376 377 446 + 452 383 453 458 + 459 464 394 395 + 465 471 472 475 + 406 407 476 482 + 483 489 419 490 + 493 424 425 494 + 501 502 435 365 + 508 513 442 514 + 519 447 448 520 + 525 526 530 460 + 461 531 537 466 + 538 543 544 550 + 477 551 554 484 + 485 555 562 563 + 566 495 496 567 + 572 503 573 509 + 580 584 515 516 + 585 591 592 598 + 527 599 602 532 + 533 603 610 611 + 614 545 546 615 + 622 623 626 556 + 557 627 634 635 + 639 568 640 645 + 574 575 646 581 + 652 657 586 658 + 662 593 594 663 + 670 671 674 604 + 605 675 682 683 + 686 616 617 687 + 694 695 698 628 + 629 699 706 707 + 710 641 642 711 + 717 647 718 653 + 724 729 659 730 + 735 664 665 736 + 741 742 746 676 + 677 747 753 754 + 758 688 689 759 + 766 767 771 700 + 701 772 778 779 + 783 712 713 784 + 788 719 789 725 + 796 800 731 732 + 801 808 809 813 + 743 814 820 748 + 821 825 755 826 + 830 760 761 831 + 837 768 838 843 + 773 844 848 780 + 849 855 856 860 + 790 791 861 797 + 868 873 802 803 + 874 880 881 885 + 815 816 886 892 + 893 898 827 899 + 903 832 833 904 + 909 839 910 917 + 918 923 850 924 + 928 857 929 934 + 862 863 935 869 + 939 946 875 947 + 951 882 952 958 + 887 959 964 894 + 965 970 900 971 + 975 905 976 981 + 911 912 982 986 + 919 987 993 994 + 998 930 931 999 + 1006 1007 940 870 + 941 1010 1018 1019 + 1022 953 954 1023 + 1028 960 1029 1035 + 966 1036 1041 1042 + 1046 977 978 1047 + 1054 1055 1060 988 + 1061 1065 995 1066 + 1071 1000 1001 1072 + 1077 1078 1011 942 + 1012 1082 1090 1091 + 1096 1024 1097 1100 + 1030 1031 1101 1108 + 1109 1113 1043 1114 + 1118 1048 1049 1119 + 1125 1056 1126 1131 + 1132 1136 1067 1068 + 1137 1144 1145 1149 + 1079 1150 1083 1013 + 1084 1154 1159 1092 + 1160 1166 1167 1171 + 1102 1103 1172 1179 + 1180 1184 1115 1185 + 1189 1120 1121 1190 + 1196 1197 1203 1133 + 1204 1207 1138 1139 + 1208 1215 1216 1221 + 1151 1222 1155 1085 + 1228 1235 1161 1236 + 1240 1168 1241 1246 + 1173 1174 1247 1252 + 1253 1259 1186 1260 + 1265 1191 1266 1269 + 1198 1199 1270 1276 + 1277 1282 1209 1210 + 1283 1287 1217 1288 + 1294 1223 1295 1229 + 1230 1298 1306 1307 + 1310 1242 1243 1311 + 1318 1319 1322 1254 + 1255 1323 1329 1261 + 1330 1335 1336 1342 + 1271 1343 1346 1278 + 1279 1347 1354 1355 + 1358 1289 1290 1359 + 1366 1367 1299 1231 + 1300 1370 1377 1378 + 1382 1312 1313 1383 + 1390 1391 1395 1324 + 1325 1396 1402 1403 + 1406 1337 1338 1407 + 1414 1415 1418 1348 + 1349 1419 1425 1426 + 1430 1360 1361 1431 + 1438 1439 1371 1301 + 1443 1448 1379 1449 + 1453 1384 1385 1454 + 1460 1392 1461 1465 + 1397 1466 1472 1473 + 1478 1408 1409 1479 + 1484 1485 1491 1420 + 1492 1497 1427 1498 + 1501 1432 1433 1502 + 1509 1510 1444 1372 + 1516 1523 1450 1524 + 1528 1455 1456 1529 + 1535 1536 1540 1467 + 1541 1545 1474 1475 + 1546 1553 1554 1557 + 1486 1487 1558 1564 + 1493 1565 1571 1572 + 1575 1503 1504 1576 + 1581 1511 1582 1517 + 1518 1586 1592 1525 + 1593 1599 1530 1600 + 1605 1606 1611 1542 + 1612 1616 1547 1548 + 1617 1624 1625 1628 + 1559 1560 1629 1635 + 1566 1636 1642 1643 + 1648 1577 1649 1653 + 1583 1654 1587 1519 + 1659 1663 1594 1595 + 1664 1671 1672 1677 + 1607 1678 1683 1613 + 1684 1687 1618 1619 + 1688 1694 1695 1699 + 1630 1631 1700 1705 + 1637 1706 1711 1644 + 1712 1718 1719 1724 + 1655 1725 1660 1588 + 1732 1738 1665 1666 + 1739 1743 1673 1744 + 1749 1679 1750 1756 + 1757 1763 1689 1764 + 1768 1696 1769 1775 + 1701 1776 1780 1707 + 1781 1787 1713 1788 + 1793 1720 1794 1798 + 1726 1727 1799 1733 + 1734 1802 1809 1810 + 1815 1745 1816 1822 + 1751 1823 1827 1758 + 1759 1828 1834 1835 + 1838 1770 1771 1839 + 1846 1847 1850 1782 + 1783 1851 1856 1789 + 1857 1862 1795 1863 + 1870 1871 1803 1735 + 1875 1880 1811 1881 + 1885 1817 1818 1886 + 1892 1824 1893 1897 + 1829 1898 1905 1906 + 1909 1840 1841 1910 + 1917 1918 1922 1852 + 1923 1929 1858 1930 + 1933 1864 1865 1934 + 1941 1942 1876 1804 + 1948 1955 1882 1956 + 1959 1887 1888 1960 + 1967 1968 1971 1899 + 1900 1972 1979 1980 + 1983 1911 1912 1984 + 1991 1992 1995 1924 + 1925 1996 2003 2004 + 2007 1935 1936 2008 + 2014 1943 2015 1949 + 1950 2018 2024 2025 + 2029 1961 1962 2030 + 2036 2037 2041 1973 + 1974 2042 2048 2049 + 2053 1985 1986 2054 + 2060 2061 2066 1997 + 1998 2067 2073 2074 + 2077 2009 2010 2078 + 2085 2086 2019 1951 + 2092 2097 2026 2098 + 2104 2031 2105 2109 + 2038 2110 2116 2043 + 2117 2121 2050 2122 + 2128 2055 2129 2132 + 2062 2063 2133 2139 + 2068 2140 2145 2146 + 2151 2079 2080 2152 + 2156 2087 2157 2093 + 2164 2168 2099 2100 + 2169 2176 2177 2180 + 2111 2112 2181 2188 + 2189 2192 2123 2124 + 2193 2199 2200 2205 + 2134 2135 2206 2211 + 2212 2216 2147 2148 + 2217 2224 2225 2228 + 2158 2159 2229 2165 + 2236 2240 2170 2171 + 2241 2248 2249 2252 + 2182 2183 2253 2259 + 2260 2266 2194 2267 + 2270 2201 2202 2271 + 2277 2278 2283 2213 + 2284 2289 2218 2219 + 2290 2296 2297 2300 + 2230 2231 2301 2237 + 2308 2312 2242 2243 + 2313 2319 2320 2326 + 2254 2327 2330 2261 + 2262 2331 2337 2338 + 2344 2272 2345 2349 + 2279 2350 2354 2285 + 2286 2355 2361 2291 + 2362 2367 2368 2373 + 2302 2303 2374 2309 + 2380 2387 2314 2388 + 2391 2321 2322 2392 + 2399 2400 2404 2332 + 2405 2410 2339 2340 + 2411 2416 2417 2423 + 2351 2424 2427 2356 + 2357 2428 2435 2436 + 2439 2369 2370 2440 + 2446 2375 2447 2381 + 2382 2450 2458 2459 + 2462 2393 2394 2463 + 2470 2471 2474 2406 + 2407 2475 2481 2482 + 2486 2418 2419 2487 + 2493 2494 2498 2429 + 2430 2499 2506 2507 + 2510 2441 2442 2511 + 2518 2519 2451 2383 + 2452 2522 2529 2530 + 2535 2464 2465 2536 + 2542 2543 2548 2476 + 2549 2553 2483 2554 + 2560 2488 2561 2565 + 2495 2566 2571 2500 + 2501 2572 2577 2578 + 2582 2512 2513 2583 + 2590 2591 2523 2453 + 2595 2601 2531 2532 + 2602 2606 2537 2607 + 2613 2544 2614 2619 + 2620 2624 2555 2556 + 2625 2631 2632 2636 + 2567 2568 2637 2643 + 2644 2650 2579 2651 + 2655 2584 2585 2656 + 2662 2663 2596 2524 + 2597 2666 2674 2675 + 2678 2608 2609 2679 + 2686 2687 2691 2621 + 2692 2698 2626 2699 + 2703 2633 2704 2709 + 2638 2710 2714 2645 + 2646 2715 2721 2652 + 2722 2726 2657 2727 + 2734 2735 2667 2598 + 2668 2738 2746 2747 + 2751 2680 2681 2752 + 2757 2758 2763 2693 + 2694 2764 2769 2770 + 2776 2705 2777 2781 + 2711 2782 2787 2716 + 2717 2788 2793 2794 + 2798 2728 2729 2799 + 2805 2806 2739 2669 + 2740 2810 2817 2748 + 2818 2824 2825 2828 + 2759 2760 2829 2836 + 2837 2840 2771 2772 + 2841 2848 2849 2852 + 2783 2784 2853 2860 + 2861 2865 2795 2866 + 2872 2800 2873 2877 + 2807 2878 2811 2741 + 2812 2882 2889 2819 + 2890 2895 2896 2900 + 2830 2831 2901 2908 + 2909 2912 2842 2843 + 2913 2920 2921 2924 + 2854 2855 2925 2932 + 2933 2936 2867 2868 + 2937 2944 2945 2950 + 2879 2951 2883 2813 + 2884 2954 2960 2961 + 2967 2897 2968 2971 + 2902 2903 2972 2979 + 2980 2983 2914 2915 + 2984 2991 2992 2995 + 2926 2927 2996 3003 + 3004 3007 2938 2939 + 3008 3014 2946 3015 + 3020 3021 2955 2885 + 3028 3032 2962 2963 + 3033 3040 3041 3044 + 2973 2974 3045 3051 + 3052 3057 2985 2986 + 3058 3063 3064 3069 + 2997 2998 3070 3075 + 3076 3081 3009 3010 + 3082 3088 3089 3092 + 3022 3023 3093 3029 + 3100 3104 3034 3035 + 3105 3112 3113 3117 + 3046 3118 3122 3053 + 3054 3123 3130 3131 + 3134 3065 3066 3135 + 3142 3143 3146 3077 + 3078 3147 3153 3083 + 3154 3160 3161 3164 + 3094 3095 3165 3101 + 3172 3176 3106 3107 + 3177 3184 3185 3189 + 3119 3190 3195 3124 + 3125 3196 3202 3203 + 3206 3136 3137 3207 + 3214 3215 3218 3148 + 3149 3219 3224 3155 + 3225 3232 3233 3236 + 3166 3167 3237 3173 + 3244 3248 3178 3179 + 3249 3256 3257 3260 + 3191 3192 3261 3267 + 3197 3268 3273 3274 + 3279 3208 3209 3280 + 3285 3286 3292 3220 + 3293 3296 3226 3227 + 3297 3304 3305 3308 + 3238 3239 3309 3245 + 3316 3320 3250 3251 + 3321 3328 3329 3332 + 3262 3263 3333 3340 + 3341 3344 3275 3276 + 3345 3351 3352 3357 + 3287 3288 3358 3363 + 3364 3368 3298 3299 + 3369 3376 3377 3380 + 3310 3311 3381 3317 + 3388 3392 3322 3323 + 3393 3400 3401 3404 + 3334 3335 3405 3411 + 3412 3417 3346 3418 + 3422 3353 3354 3423 + 3430 3431 3436 3365 + 3437 3440 3370 3371 + 3441 3447 3448 3452 + 3382 3383 3453 3389 + 6 10 3394 3395 + 11 17 18 23 + 3406 24 30 3413 + 31 36 3419 37 + 40 3424 3425 41 + 46 3432 47 53 + 54 59 3442 60 + 66 3449 67 70 + 3454 3455 71 7 + + } + } + } + VertexArray TRUE { + osg::Vec3Array { + UniqueID 188 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 189 + } + } + Binding BIND_PER_VERTEX + vector 3456 { + -1.3113e-07 0 -1.998 + -1.3113e-07 0 -1.998 + -1.3113e-07 0 -1.998 + -1.3113e-07 0 -1.998 + -1.3113e-07 0 -1.998 + -1.3113e-07 0 -1.998 + -1.3113e-07 0 -1.998 + -1.3113e-07 0 -1.998 + 0.0245 0 -1.99144 + 0.0245 0 -1.99144 + 0.0245 0 -1.99144 + 0.0245 0 -1.99144 + 0.0424352 0 -1.9735 + 0.0424352 0 -1.9735 + 0.0424352 0 -1.9735 + 0.0424352 0 -1.9735 + 0.0424352 0 -1.9735 + 0.0424352 0 -1.9735 + 0.0424352 0 -1.9735 + 0.0489999 0 -1.949 + 0.0489999 0 -1.949 + 0.0489999 0 -1.949 + 0.0489999 0 -1.949 + 0.0489999 0 -1.949 + 0.0489999 0 -1.949 + 0.0424352 0 -1.9245 + 0.0424352 0 -1.9245 + 0.0424352 0 -1.9245 + 0.0424352 0 -1.9245 + 0.0424352 0 -1.9245 + 0.0424352 0 -1.9245 + 0.0424352 0 -1.9245 + 0.0245 0 -1.90656 + 0.0245 0 -1.90656 + 0.0245 0 -1.90656 + 0.0245 0 -1.90656 + 0.0245 0 -1.90656 + 0.0245 0 -1.90656 + -1.3113e-07 0 -1.9 + -1.3113e-07 0 -1.9 + -1.3113e-07 0 -1.9 + -1.3113e-07 0 -1.9 + -0.0245001 0 -1.90656 + -0.0245001 0 -1.90656 + -0.0245001 0 -1.90656 + -0.0245001 0 -1.90656 + -0.0245001 0 -1.90656 + -0.0245001 0 -1.90656 + -0.0424353 0 -1.9245 + -0.0424353 0 -1.9245 + -0.0424353 0 -1.9245 + -0.0424353 0 -1.9245 + -0.0424353 0 -1.9245 + -0.0424353 0 -1.9245 + -0.0424353 0 -1.9245 + -0.0490001 0 -1.949 + -0.0490001 0 -1.949 + -0.0490001 0 -1.949 + -0.0490001 0 -1.949 + -0.0490001 0 -1.949 + -0.0490001 0 -1.949 + -0.0424353 0 -1.9735 + -0.0424353 0 -1.9735 + -0.0424353 0 -1.9735 + -0.0424353 0 -1.9735 + -0.0424353 0 -1.9735 + -0.0424353 0 -1.9735 + -0.0424353 0 -1.9735 + -0.0245001 0 -1.99144 + -0.0245001 0 -1.99144 + -0.0245001 0 -1.99144 + -0.0245001 0 -1.99144 + -1.3113e-07 0.260791 -1.98091 + -1.3113e-07 0.260791 -1.98091 + -1.3113e-07 0.260791 -1.98091 + -1.3113e-07 0.260791 -1.98091 + -1.3113e-07 0.260791 -1.98091 + -1.3113e-07 0.260791 -1.98091 + 0.0245 0.259934 -1.9744 + 0.0245 0.259934 -1.9744 + 0.0245 0.259934 -1.9744 + 0.0245 0.259934 -1.9744 + 0.0245 0.259934 -1.9744 + 0.0245 0.259934 -1.9744 + 0.0424352 0.257593 -1.95662 + 0.0424352 0.257593 -1.95662 + 0.0424352 0.257593 -1.95662 + 0.0424352 0.257593 -1.95662 + 0.0424352 0.257593 -1.95662 + 0.0424352 0.257593 -1.95662 + 0.0424352 0.257593 -1.95662 + 0.0489999 0.254395 -1.93233 + 0.0489999 0.254395 -1.93233 + 0.0489999 0.254395 -1.93233 + 0.0489999 0.254395 -1.93233 + 0.0489999 0.254395 -1.93233 + 0.0489999 0.254395 -1.93233 + 0.0424352 0.251198 -1.90804 + 0.0424352 0.251198 -1.90804 + 0.0424352 0.251198 -1.90804 + 0.0424352 0.251198 -1.90804 + 0.0245 0.248856 -1.89025 + 0.0245 0.248856 -1.89025 + 0.0245 0.248856 -1.89025 + 0.0245 0.248856 -1.89025 + 0.0245 0.248856 -1.89025 + 0.0245 0.248856 -1.89025 + 0.0245 0.248856 -1.89025 + -1.3113e-07 0.248 -1.88374 + -1.3113e-07 0.248 -1.88374 + -1.3113e-07 0.248 -1.88374 + -1.3113e-07 0.248 -1.88374 + -1.3113e-07 0.248 -1.88374 + -1.3113e-07 0.248 -1.88374 + -0.0245001 0.248856 -1.89025 + -0.0245001 0.248856 -1.89025 + -0.0245001 0.248856 -1.89025 + -0.0245001 0.248856 -1.89025 + -0.0245001 0.248856 -1.89025 + -0.0245001 0.248856 -1.89025 + -0.0245001 0.248856 -1.89025 + -0.0424353 0.251198 -1.90804 + -0.0424353 0.251198 -1.90804 + -0.0424353 0.251198 -1.90804 + -0.0424353 0.251198 -1.90804 + -0.0424353 0.251198 -1.90804 + -0.0490001 0.254395 -1.93233 + -0.0490001 0.254395 -1.93233 + -0.0490001 0.254395 -1.93233 + -0.0490001 0.254395 -1.93233 + -0.0490001 0.254395 -1.93233 + -0.0490001 0.254395 -1.93233 + -0.0424353 0.257593 -1.95662 + -0.0424353 0.257593 -1.95662 + -0.0424353 0.257593 -1.95662 + -0.0424353 0.257593 -1.95662 + -0.0424353 0.257593 -1.95662 + -0.0424353 0.257593 -1.95662 + -0.0245001 0.259934 -1.9744 + -0.0245001 0.259934 -1.9744 + -0.0245001 0.259934 -1.9744 + -0.0245001 0.259934 -1.9744 + -0.0245001 0.259934 -1.9744 + -0.0245001 0.259934 -1.9744 + -1.3113e-07 0.51712 -1.92992 + -1.3113e-07 0.51712 -1.92992 + -1.3113e-07 0.51712 -1.92992 + -1.3113e-07 0.51712 -1.92992 + 0.0245 0.515421 -1.92358 + 0.0245 0.515421 -1.92358 + 0.0245 0.515421 -1.92358 + 0.0245 0.515421 -1.92358 + 0.0245 0.515421 -1.92358 + 0.0245 0.515421 -1.92358 + 0.0245 0.515421 -1.92358 + 0.0245 0.515421 -1.92358 + 0.0424352 0.510779 -1.90625 + 0.0424352 0.510779 -1.90625 + 0.0424352 0.510779 -1.90625 + 0.0424352 0.510779 -1.90625 + 0.0424352 0.510779 -1.90625 + 0.0489999 0.504438 -1.88259 + 0.0489999 0.504438 -1.88259 + 0.0489999 0.504438 -1.88259 + 0.0489999 0.504438 -1.88259 + 0.0489999 0.504438 -1.88259 + 0.0489999 0.504438 -1.88259 + 0.0424352 0.498097 -1.85892 + 0.0424352 0.498097 -1.85892 + 0.0424352 0.498097 -1.85892 + 0.0424352 0.498097 -1.85892 + 0.0424352 0.498097 -1.85892 + 0.0424352 0.498097 -1.85892 + 0.0245 0.493455 -1.8416 + 0.0245 0.493455 -1.8416 + 0.0245 0.493455 -1.8416 + 0.0245 0.493455 -1.8416 + 0.0245 0.493455 -1.8416 + 0.0245 0.493455 -1.8416 + -1.3113e-07 0.491756 -1.83526 + -1.3113e-07 0.491756 -1.83526 + -1.3113e-07 0.491756 -1.83526 + -1.3113e-07 0.491756 -1.83526 + -1.3113e-07 0.491756 -1.83526 + -1.3113e-07 0.491756 -1.83526 + -0.0245001 0.493455 -1.8416 + -0.0245001 0.493455 -1.8416 + -0.0245001 0.493455 -1.8416 + -0.0245001 0.493455 -1.8416 + -0.0245001 0.493455 -1.8416 + -0.0245001 0.493455 -1.8416 + -0.0424353 0.498097 -1.85892 + -0.0424353 0.498097 -1.85892 + -0.0424353 0.498097 -1.85892 + -0.0424353 0.498097 -1.85892 + -0.0424353 0.498097 -1.85892 + -0.0424353 0.498097 -1.85892 + -0.0490001 0.504438 -1.88259 + -0.0490001 0.504438 -1.88259 + -0.0490001 0.504438 -1.88259 + -0.0490001 0.504438 -1.88259 + -0.0490001 0.504438 -1.88259 + -0.0490001 0.504438 -1.88259 + -0.0424353 0.510779 -1.90625 + -0.0424353 0.510779 -1.90625 + -0.0424353 0.510779 -1.90625 + -0.0424353 0.510779 -1.90625 + -0.0424353 0.510779 -1.90625 + -0.0245001 0.515421 -1.92358 + -0.0245001 0.515421 -1.92358 + -0.0245001 0.515421 -1.92358 + -0.0245001 0.515421 -1.92358 + -0.0245001 0.515421 -1.92358 + -0.0245001 0.515421 -1.92358 + -0.0245001 0.515421 -1.92358 + -0.0245001 0.515421 -1.92358 + -1.3113e-07 0.764601 -1.84591 + -1.3113e-07 0.764601 -1.84591 + -1.3113e-07 0.764601 -1.84591 + -1.3113e-07 0.764601 -1.84591 + -1.3113e-07 0.764601 -1.84591 + -1.3113e-07 0.764601 -1.84591 + -1.3113e-07 0.764601 -1.84591 + -1.3113e-07 0.764601 -1.84591 + 0.0245 0.762089 -1.83985 + 0.0245 0.762089 -1.83985 + 0.0245 0.762089 -1.83985 + 0.0245 0.762089 -1.83985 + 0.0424352 0.755225 -1.82328 + 0.0424352 0.755225 -1.82328 + 0.0424352 0.755225 -1.82328 + 0.0424352 0.755225 -1.82328 + 0.0424352 0.755225 -1.82328 + 0.0424352 0.755225 -1.82328 + 0.0424352 0.755225 -1.82328 + 0.0489999 0.74585 -1.80064 + 0.0489999 0.74585 -1.80064 + 0.0489999 0.74585 -1.80064 + 0.0489999 0.74585 -1.80064 + 0.0489999 0.74585 -1.80064 + 0.0424352 0.736474 -1.77801 + 0.0424352 0.736474 -1.77801 + 0.0424352 0.736474 -1.77801 + 0.0424352 0.736474 -1.77801 + 0.0424352 0.736474 -1.77801 + 0.0424352 0.736474 -1.77801 + 0.0424352 0.736474 -1.77801 + 0.0245 0.729611 -1.76144 + 0.0245 0.729611 -1.76144 + 0.0245 0.729611 -1.76144 + 0.0245 0.729611 -1.76144 + 0.0245 0.729611 -1.76144 + -1.3113e-07 0.727098 -1.75537 + -1.3113e-07 0.727098 -1.75537 + -1.3113e-07 0.727098 -1.75537 + -1.3113e-07 0.727098 -1.75537 + -1.3113e-07 0.727098 -1.75537 + -1.3113e-07 0.727098 -1.75537 + -1.3113e-07 0.727098 -1.75537 + -0.0245001 0.729611 -1.76144 + -0.0245001 0.729611 -1.76144 + -0.0245001 0.729611 -1.76144 + -0.0245001 0.729611 -1.76144 + -0.0245001 0.729611 -1.76144 + -0.0245001 0.729611 -1.76144 + -0.0424353 0.736474 -1.77801 + -0.0424353 0.736474 -1.77801 + -0.0424353 0.736474 -1.77801 + -0.0424353 0.736474 -1.77801 + -0.0424353 0.736474 -1.77801 + -0.0424353 0.736474 -1.77801 + -0.0490001 0.74585 -1.80064 + -0.0490001 0.74585 -1.80064 + -0.0490001 0.74585 -1.80064 + -0.0490001 0.74585 -1.80064 + -0.0490001 0.74585 -1.80064 + -0.0490001 0.74585 -1.80064 + -0.0424353 0.755225 -1.82328 + -0.0424353 0.755225 -1.82328 + -0.0424353 0.755225 -1.82328 + -0.0424353 0.755225 -1.82328 + -0.0424353 0.755225 -1.82328 + -0.0424353 0.755225 -1.82328 + -0.0424353 0.755225 -1.82328 + -0.0245001 0.762089 -1.83985 + -0.0245001 0.762089 -1.83985 + -0.0245001 0.762089 -1.83985 + -0.0245001 0.762089 -1.83985 + -1.3113e-07 0.999 -1.73032 + -1.3113e-07 0.999 -1.73032 + -1.3113e-07 0.999 -1.73032 + -1.3113e-07 0.999 -1.73032 + -1.3113e-07 0.999 -1.73032 + -1.3113e-07 0.999 -1.73032 + 0.0245 0.995718 -1.72463 + 0.0245 0.995718 -1.72463 + 0.0245 0.995718 -1.72463 + 0.0245 0.995718 -1.72463 + 0.0245 0.995718 -1.72463 + 0.0245 0.995718 -1.72463 + 0.0424352 0.98675 -1.7091 + 0.0424352 0.98675 -1.7091 + 0.0424352 0.98675 -1.7091 + 0.0424352 0.98675 -1.7091 + 0.0424352 0.98675 -1.7091 + 0.0424352 0.98675 -1.7091 + 0.0489999 0.9745 -1.68788 + 0.0489999 0.9745 -1.68788 + 0.0489999 0.9745 -1.68788 + 0.0489999 0.9745 -1.68788 + 0.0489999 0.9745 -1.68788 + 0.0489999 0.9745 -1.68788 + 0.0489999 0.9745 -1.68788 + 0.0424352 0.96225 -1.66667 + 0.0424352 0.96225 -1.66667 + 0.0424352 0.96225 -1.66667 + 0.0424352 0.96225 -1.66667 + 0.0424352 0.96225 -1.66667 + 0.0245 0.953282 -1.65113 + 0.0245 0.953282 -1.65113 + 0.0245 0.953282 -1.65113 + 0.0245 0.953282 -1.65113 + 0.0245 0.953282 -1.65113 + 0.0245 0.953282 -1.65113 + 0.0245 0.953282 -1.65113 + -1.3113e-07 0.95 -1.64545 + -1.3113e-07 0.95 -1.64545 + -1.3113e-07 0.95 -1.64545 + -1.3113e-07 0.95 -1.64545 + -1.3113e-07 0.95 -1.64545 + -0.0245001 0.953282 -1.65113 + -0.0245001 0.953282 -1.65113 + -0.0245001 0.953282 -1.65113 + -0.0245001 0.953282 -1.65113 + -0.0245001 0.953282 -1.65113 + -0.0245001 0.953282 -1.65113 + -0.0424353 0.96225 -1.66667 + -0.0424353 0.96225 -1.66667 + -0.0424353 0.96225 -1.66667 + -0.0424353 0.96225 -1.66667 + -0.0424353 0.96225 -1.66667 + -0.0424353 0.96225 -1.66667 + -0.0490001 0.9745 -1.68788 + -0.0490001 0.9745 -1.68788 + -0.0490001 0.9745 -1.68788 + -0.0490001 0.9745 -1.68788 + -0.0490001 0.9745 -1.68788 + -0.0490001 0.9745 -1.68788 + -0.0424353 0.98675 -1.7091 + -0.0424353 0.98675 -1.7091 + -0.0424353 0.98675 -1.7091 + -0.0424353 0.98675 -1.7091 + -0.0424353 0.98675 -1.7091 + -0.0424353 0.98675 -1.7091 + -0.0245001 0.995718 -1.72463 + -0.0245001 0.995718 -1.72463 + -0.0245001 0.995718 -1.72463 + -0.0245001 0.995718 -1.72463 + -0.0245001 0.995718 -1.72463 + -0.0245001 0.995718 -1.72463 + -1.3113e-07 1.21631 -1.58512 + -1.3113e-07 1.21631 -1.58512 + -1.3113e-07 1.21631 -1.58512 + -1.3113e-07 1.21631 -1.58512 + -1.3113e-07 1.21631 -1.58512 + -1.3113e-07 1.21631 -1.58512 + 0.0245 1.21231 -1.57991 + 0.0245 1.21231 -1.57991 + 0.0245 1.21231 -1.57991 + 0.0245 1.21231 -1.57991 + 0.0245 1.21231 -1.57991 + 0.0245 1.21231 -1.57991 + 0.0424352 1.20139 -1.56568 + 0.0424352 1.20139 -1.56568 + 0.0424352 1.20139 -1.56568 + 0.0424352 1.20139 -1.56568 + 0.0424352 1.20139 -1.56568 + 0.0424352 1.20139 -1.56568 + 0.0489999 1.18648 -1.54625 + 0.0489999 1.18648 -1.54625 + 0.0489999 1.18648 -1.54625 + 0.0489999 1.18648 -1.54625 + 0.0489999 1.18648 -1.54625 + 0.0489999 1.18648 -1.54625 + 0.0424352 1.17156 -1.52681 + 0.0424352 1.17156 -1.52681 + 0.0424352 1.17156 -1.52681 + 0.0424352 1.17156 -1.52681 + 0.0424352 1.17156 -1.52681 + 0.0424352 1.17156 -1.52681 + 0.0245 1.16064 -1.51258 + 0.0245 1.16064 -1.51258 + 0.0245 1.16064 -1.51258 + 0.0245 1.16064 -1.51258 + 0.0245 1.16064 -1.51258 + 0.0245 1.16064 -1.51258 + -1.3113e-07 1.15665 -1.50737 + -1.3113e-07 1.15665 -1.50737 + -1.3113e-07 1.15665 -1.50737 + -1.3113e-07 1.15665 -1.50737 + -1.3113e-07 1.15665 -1.50737 + -1.3113e-07 1.15665 -1.50737 + -0.0245001 1.16064 -1.51258 + -0.0245001 1.16064 -1.51258 + -0.0245001 1.16064 -1.51258 + -0.0245001 1.16064 -1.51258 + -0.0245001 1.16064 -1.51258 + -0.0245001 1.16064 -1.51258 + -0.0424353 1.17156 -1.52681 + -0.0424353 1.17156 -1.52681 + -0.0424353 1.17156 -1.52681 + -0.0424353 1.17156 -1.52681 + -0.0424353 1.17156 -1.52681 + -0.0424353 1.17156 -1.52681 + -0.0490001 1.18648 -1.54625 + -0.0490001 1.18648 -1.54625 + -0.0490001 1.18648 -1.54625 + -0.0490001 1.18648 -1.54625 + -0.0490001 1.18648 -1.54625 + -0.0490001 1.18648 -1.54625 + -0.0424353 1.20139 -1.56568 + -0.0424353 1.20139 -1.56568 + -0.0424353 1.20139 -1.56568 + -0.0424353 1.20139 -1.56568 + -0.0424353 1.20139 -1.56568 + -0.0424353 1.20139 -1.56568 + -0.0245001 1.21231 -1.57991 + -0.0245001 1.21231 -1.57991 + -0.0245001 1.21231 -1.57991 + -0.0245001 1.21231 -1.57991 + -0.0245001 1.21231 -1.57991 + -0.0245001 1.21231 -1.57991 + 0 1.4128 -1.4128 + 0 1.4128 -1.4128 + 0 1.4128 -1.4128 + 0 1.4128 -1.4128 + 0.0245 1.40816 -1.40816 + 0.0245 1.40816 -1.40816 + 0.0245 1.40816 -1.40816 + 0.0245 1.40816 -1.40816 + 0.0245 1.40816 -1.40816 + 0.0245 1.40816 -1.40816 + 0.0245 1.40816 -1.40816 + 0.0424352 1.39548 -1.39548 + 0.0424352 1.39548 -1.39548 + 0.0424352 1.39548 -1.39548 + 0.0424352 1.39548 -1.39548 + 0.0424352 1.39548 -1.39548 + 0.0424352 1.39548 -1.39548 + 0.0489999 1.37815 -1.37815 + 0.0489999 1.37815 -1.37815 + 0.0489999 1.37815 -1.37815 + 0.0489999 1.37815 -1.37815 + 0.0489999 1.37815 -1.37815 + 0.0424352 1.36083 -1.36083 + 0.0424352 1.36083 -1.36083 + 0.0424352 1.36083 -1.36083 + 0.0424352 1.36083 -1.36083 + 0.0424352 1.36083 -1.36083 + 0.0424352 1.36083 -1.36083 + 0.0424352 1.36083 -1.36083 + 0.0424352 1.36083 -1.36083 + 0.0245 1.34815 -1.34815 + 0.0245 1.34815 -1.34815 + 0.0245 1.34815 -1.34815 + 0.0245 1.34815 -1.34815 + 0.0245 1.34815 -1.34815 + 0 1.3435 -1.3435 + 0 1.3435 -1.3435 + 0 1.3435 -1.3435 + 0 1.3435 -1.3435 + 0 1.3435 -1.3435 + 0 1.3435 -1.3435 + -0.0245001 1.34815 -1.34815 + -0.0245001 1.34815 -1.34815 + -0.0245001 1.34815 -1.34815 + -0.0245001 1.34815 -1.34815 + -0.0245001 1.34815 -1.34815 + -0.0424353 1.36083 -1.36083 + -0.0424353 1.36083 -1.36083 + -0.0424353 1.36083 -1.36083 + -0.0424353 1.36083 -1.36083 + -0.0424353 1.36083 -1.36083 + -0.0424353 1.36083 -1.36083 + -0.0424353 1.36083 -1.36083 + -0.0424353 1.36083 -1.36083 + -0.0490001 1.37815 -1.37815 + -0.0490001 1.37815 -1.37815 + -0.0490001 1.37815 -1.37815 + -0.0490001 1.37815 -1.37815 + -0.0490001 1.37815 -1.37815 + -0.0424353 1.39548 -1.39548 + -0.0424353 1.39548 -1.39548 + -0.0424353 1.39548 -1.39548 + -0.0424353 1.39548 -1.39548 + -0.0424353 1.39548 -1.39548 + -0.0424353 1.39548 -1.39548 + -0.0245001 1.40816 -1.40816 + -0.0245001 1.40816 -1.40816 + -0.0245001 1.40816 -1.40816 + -0.0245001 1.40816 -1.40816 + -0.0245001 1.40816 -1.40816 + -0.0245001 1.40816 -1.40816 + -0.0245001 1.40816 -1.40816 + 0 1.58512 -1.21631 + 0 1.58512 -1.21631 + 0 1.58512 -1.21631 + 0 1.58512 -1.21631 + 0 1.58512 -1.21631 + 0 1.58512 -1.21631 + 0.0245 1.57991 -1.21231 + 0.0245 1.57991 -1.21231 + 0.0245 1.57991 -1.21231 + 0.0245 1.57991 -1.21231 + 0.0245 1.57991 -1.21231 + 0.0245 1.57991 -1.21231 + 0.0245 1.57991 -1.21231 + 0.0424352 1.56568 -1.20139 + 0.0424352 1.56568 -1.20139 + 0.0424352 1.56568 -1.20139 + 0.0424352 1.56568 -1.20139 + 0.0489999 1.54624 -1.18648 + 0.0489999 1.54624 -1.18648 + 0.0489999 1.54624 -1.18648 + 0.0489999 1.54624 -1.18648 + 0.0489999 1.54624 -1.18648 + 0.0489999 1.54624 -1.18648 + 0.0489999 1.54624 -1.18648 + 0.0424352 1.52681 -1.17156 + 0.0424352 1.52681 -1.17156 + 0.0424352 1.52681 -1.17156 + 0.0424352 1.52681 -1.17156 + 0.0424352 1.52681 -1.17156 + 0.0424352 1.52681 -1.17156 + 0.0245 1.51258 -1.16064 + 0.0245 1.51258 -1.16064 + 0.0245 1.51258 -1.16064 + 0.0245 1.51258 -1.16064 + 0.0245 1.51258 -1.16064 + 0 1.50737 -1.15665 + 0 1.50737 -1.15665 + 0 1.50737 -1.15665 + 0 1.50737 -1.15665 + 0 1.50737 -1.15665 + 0 1.50737 -1.15665 + 0 1.50737 -1.15665 + 0 1.50737 -1.15665 + -0.0245001 1.51258 -1.16064 + -0.0245001 1.51258 -1.16064 + -0.0245001 1.51258 -1.16064 + -0.0245001 1.51258 -1.16064 + -0.0245001 1.51258 -1.16064 + -0.0424353 1.52681 -1.17156 + -0.0424353 1.52681 -1.17156 + -0.0424353 1.52681 -1.17156 + -0.0424353 1.52681 -1.17156 + -0.0424353 1.52681 -1.17156 + -0.0424353 1.52681 -1.17156 + -0.0490001 1.54624 -1.18648 + -0.0490001 1.54624 -1.18648 + -0.0490001 1.54624 -1.18648 + -0.0490001 1.54624 -1.18648 + -0.0490001 1.54624 -1.18648 + -0.0490001 1.54624 -1.18648 + -0.0424353 1.56568 -1.20139 + -0.0424353 1.56568 -1.20139 + -0.0424353 1.56568 -1.20139 + -0.0424353 1.56568 -1.20139 + -0.0424353 1.56568 -1.20139 + -0.0245001 1.57991 -1.21231 + -0.0245001 1.57991 -1.21231 + -0.0245001 1.57991 -1.21231 + -0.0245001 1.57991 -1.21231 + -0.0245001 1.57991 -1.21231 + -0.0245001 1.57991 -1.21231 + -0.0245001 1.57991 -1.21231 + 0 1.73032 -0.999 + 0 1.73032 -0.999 + 0 1.73032 -0.999 + 0 1.73032 -0.999 + 0 1.73032 -0.999 + 0 1.73032 -0.999 + 0.0245 1.72463 -0.995718 + 0.0245 1.72463 -0.995718 + 0.0245 1.72463 -0.995718 + 0.0245 1.72463 -0.995718 + 0.0245 1.72463 -0.995718 + 0.0424352 1.7091 -0.98675 + 0.0424352 1.7091 -0.98675 + 0.0424352 1.7091 -0.98675 + 0.0424352 1.7091 -0.98675 + 0.0424352 1.7091 -0.98675 + 0.0424352 1.7091 -0.98675 + 0.0424352 1.7091 -0.98675 + 0.0424352 1.7091 -0.98675 + 0.0489999 1.68788 -0.9745 + 0.0489999 1.68788 -0.9745 + 0.0489999 1.68788 -0.9745 + 0.0489999 1.68788 -0.9745 + 0.0489999 1.68788 -0.9745 + 0.0424352 1.66667 -0.96225 + 0.0424352 1.66667 -0.96225 + 0.0424352 1.66667 -0.96225 + 0.0424352 1.66667 -0.96225 + 0.0424352 1.66667 -0.96225 + 0.0424352 1.66667 -0.96225 + 0.0245 1.65113 -0.953282 + 0.0245 1.65113 -0.953282 + 0.0245 1.65113 -0.953282 + 0.0245 1.65113 -0.953282 + 0.0245 1.65113 -0.953282 + 0.0245 1.65113 -0.953282 + 0 1.64545 -0.95 + 0 1.64545 -0.95 + 0 1.64545 -0.95 + 0 1.64545 -0.95 + 0 1.64545 -0.95 + 0 1.64545 -0.95 + -0.0245 1.65113 -0.953282 + -0.0245 1.65113 -0.953282 + -0.0245 1.65113 -0.953282 + -0.0245 1.65113 -0.953282 + -0.0245 1.65113 -0.953282 + -0.0245 1.65113 -0.953282 + -0.0424353 1.66667 -0.96225 + -0.0424353 1.66667 -0.96225 + -0.0424353 1.66667 -0.96225 + -0.0424353 1.66667 -0.96225 + -0.0424353 1.66667 -0.96225 + -0.0424353 1.66667 -0.96225 + -0.049 1.68788 -0.9745 + -0.049 1.68788 -0.9745 + -0.049 1.68788 -0.9745 + -0.049 1.68788 -0.9745 + -0.049 1.68788 -0.9745 + -0.049 1.68788 -0.9745 + -0.0424353 1.7091 -0.98675 + -0.0424353 1.7091 -0.98675 + -0.0424353 1.7091 -0.98675 + -0.0424353 1.7091 -0.98675 + -0.0424353 1.7091 -0.98675 + -0.0424353 1.7091 -0.98675 + -0.0424353 1.7091 -0.98675 + -0.0245 1.72463 -0.995718 + -0.0245 1.72463 -0.995718 + -0.0245 1.72463 -0.995718 + -0.0245 1.72463 -0.995718 + -0.0245 1.72463 -0.995718 + 0 1.84591 -0.764602 + 0 1.84591 -0.764602 + 0 1.84591 -0.764602 + 0 1.84591 -0.764602 + 0 1.84591 -0.764602 + 0 1.84591 -0.764602 + 0.0245 1.83985 -0.76209 + 0.0245 1.83985 -0.76209 + 0.0245 1.83985 -0.76209 + 0.0245 1.83985 -0.76209 + 0.0245 1.83985 -0.76209 + 0.0245 1.83985 -0.76209 + 0.0424352 1.82328 -0.755226 + 0.0424352 1.82328 -0.755226 + 0.0424352 1.82328 -0.755226 + 0.0424352 1.82328 -0.755226 + 0.0424352 1.82328 -0.755226 + 0.0424352 1.82328 -0.755226 + 0.0489999 1.80064 -0.74585 + 0.0489999 1.80064 -0.74585 + 0.0489999 1.80064 -0.74585 + 0.0489999 1.80064 -0.74585 + 0.0489999 1.80064 -0.74585 + 0.0489999 1.80064 -0.74585 + 0.0424352 1.77801 -0.736475 + 0.0424352 1.77801 -0.736475 + 0.0424352 1.77801 -0.736475 + 0.0424352 1.77801 -0.736475 + 0.0424352 1.77801 -0.736475 + 0.0424352 1.77801 -0.736475 + 0.0245 1.76144 -0.729611 + 0.0245 1.76144 -0.729611 + 0.0245 1.76144 -0.729611 + 0.0245 1.76144 -0.729611 + 0.0245 1.76144 -0.729611 + 0.0245 1.76144 -0.729611 + 0 1.75537 -0.727099 + 0 1.75537 -0.727099 + 0 1.75537 -0.727099 + 0 1.75537 -0.727099 + 0 1.75537 -0.727099 + 0 1.75537 -0.727099 + -0.0245 1.76144 -0.729611 + -0.0245 1.76144 -0.729611 + -0.0245 1.76144 -0.729611 + -0.0245 1.76144 -0.729611 + -0.0245 1.76144 -0.729611 + -0.0245 1.76144 -0.729611 + -0.0424352 1.77801 -0.736475 + -0.0424352 1.77801 -0.736475 + -0.0424352 1.77801 -0.736475 + -0.0424352 1.77801 -0.736475 + -0.0424352 1.77801 -0.736475 + -0.0424352 1.77801 -0.736475 + -0.049 1.80064 -0.74585 + -0.049 1.80064 -0.74585 + -0.049 1.80064 -0.74585 + -0.049 1.80064 -0.74585 + -0.049 1.80064 -0.74585 + -0.049 1.80064 -0.74585 + -0.0424352 1.82328 -0.755226 + -0.0424352 1.82328 -0.755226 + -0.0424352 1.82328 -0.755226 + -0.0424352 1.82328 -0.755226 + -0.0424352 1.82328 -0.755226 + -0.0424352 1.82328 -0.755226 + -0.0245 1.83985 -0.76209 + -0.0245 1.83985 -0.76209 + -0.0245 1.83985 -0.76209 + -0.0245 1.83985 -0.76209 + -0.0245 1.83985 -0.76209 + -0.0245 1.83985 -0.76209 + 0 1.92992 -0.51712 + 0 1.92992 -0.51712 + 0 1.92992 -0.51712 + 0 1.92992 -0.51712 + 0 1.92992 -0.51712 + 0 1.92992 -0.51712 + 0.0245 1.92358 -0.515421 + 0.0245 1.92358 -0.515421 + 0.0245 1.92358 -0.515421 + 0.0245 1.92358 -0.515421 + 0.0245 1.92358 -0.515421 + 0.0245 1.92358 -0.515421 + 0.0245 1.92358 -0.515421 + 0.0424352 1.90625 -0.51078 + 0.0424352 1.90625 -0.51078 + 0.0424352 1.90625 -0.51078 + 0.0424352 1.90625 -0.51078 + 0.049 1.88259 -0.504438 + 0.049 1.88259 -0.504438 + 0.049 1.88259 -0.504438 + 0.049 1.88259 -0.504438 + 0.049 1.88259 -0.504438 + 0.049 1.88259 -0.504438 + 0.049 1.88259 -0.504438 + 0.0424352 1.85892 -0.498097 + 0.0424352 1.85892 -0.498097 + 0.0424352 1.85892 -0.498097 + 0.0424352 1.85892 -0.498097 + 0.0424352 1.85892 -0.498097 + 0.0245 1.8416 -0.493455 + 0.0245 1.8416 -0.493455 + 0.0245 1.8416 -0.493455 + 0.0245 1.8416 -0.493455 + 0.0245 1.8416 -0.493455 + 0.0245 1.8416 -0.493455 + 0.0245 1.8416 -0.493455 + 0 1.83526 -0.491756 + 0 1.83526 -0.491756 + 0 1.83526 -0.491756 + 0 1.83526 -0.491756 + 0 1.83526 -0.491756 + 0 1.83526 -0.491756 + -0.0245 1.8416 -0.493455 + -0.0245 1.8416 -0.493455 + -0.0245 1.8416 -0.493455 + -0.0245 1.8416 -0.493455 + -0.0245 1.8416 -0.493455 + -0.0245 1.8416 -0.493455 + -0.0245 1.8416 -0.493455 + -0.0424352 1.85892 -0.498097 + -0.0424352 1.85892 -0.498097 + -0.0424352 1.85892 -0.498097 + -0.0424352 1.85892 -0.498097 + -0.0424352 1.85892 -0.498097 + -0.049 1.88259 -0.504438 + -0.049 1.88259 -0.504438 + -0.049 1.88259 -0.504438 + -0.049 1.88259 -0.504438 + -0.049 1.88259 -0.504438 + -0.049 1.88259 -0.504438 + -0.049 1.88259 -0.504438 + -0.0424352 1.90625 -0.51078 + -0.0424352 1.90625 -0.51078 + -0.0424352 1.90625 -0.51078 + -0.0424352 1.90625 -0.51078 + -0.0245 1.92358 -0.515421 + -0.0245 1.92358 -0.515421 + -0.0245 1.92358 -0.515421 + -0.0245 1.92358 -0.515421 + -0.0245 1.92358 -0.515421 + -0.0245 1.92358 -0.515421 + -0.0245 1.92358 -0.515421 + 0 1.98091 -0.260791 + 0 1.98091 -0.260791 + 0 1.98091 -0.260791 + 0 1.98091 -0.260791 + 0 1.98091 -0.260791 + 0 1.98091 -0.260791 + 0.0245 1.9744 -0.259934 + 0.0245 1.9744 -0.259934 + 0.0245 1.9744 -0.259934 + 0.0245 1.9744 -0.259934 + 0.0245 1.9744 -0.259934 + 0.0245 1.9744 -0.259934 + 0.0424352 1.95662 -0.257593 + 0.0424352 1.95662 -0.257593 + 0.0424352 1.95662 -0.257593 + 0.0424352 1.95662 -0.257593 + 0.0424352 1.95662 -0.257593 + 0.0424352 1.95662 -0.257593 + 0.049 1.93233 -0.254395 + 0.049 1.93233 -0.254395 + 0.049 1.93233 -0.254395 + 0.049 1.93233 -0.254395 + 0.049 1.93233 -0.254395 + 0.049 1.93233 -0.254395 + 0.049 1.93233 -0.254395 + 0.0424352 1.90804 -0.251197 + 0.0424352 1.90804 -0.251197 + 0.0424352 1.90804 -0.251197 + 0.0424352 1.90804 -0.251197 + 0.0424352 1.90804 -0.251197 + 0.0245 1.89025 -0.248856 + 0.0245 1.89025 -0.248856 + 0.0245 1.89025 -0.248856 + 0.0245 1.89025 -0.248856 + 0.0245 1.89025 -0.248856 + 0.0245 1.89025 -0.248856 + 0 1.88374 -0.247999 + 0 1.88374 -0.247999 + 0 1.88374 -0.247999 + 0 1.88374 -0.247999 + 0 1.88374 -0.247999 + 0 1.88374 -0.247999 + -0.0245 1.89025 -0.248856 + -0.0245 1.89025 -0.248856 + -0.0245 1.89025 -0.248856 + -0.0245 1.89025 -0.248856 + -0.0245 1.89025 -0.248856 + -0.0245 1.89025 -0.248856 + -0.0424352 1.90804 -0.251197 + -0.0424352 1.90804 -0.251197 + -0.0424352 1.90804 -0.251197 + -0.0424352 1.90804 -0.251197 + -0.0424352 1.90804 -0.251197 + -0.049 1.93233 -0.254395 + -0.049 1.93233 -0.254395 + -0.049 1.93233 -0.254395 + -0.049 1.93233 -0.254395 + -0.049 1.93233 -0.254395 + -0.049 1.93233 -0.254395 + -0.0424352 1.95662 -0.257593 + -0.0424352 1.95662 -0.257593 + -0.0424352 1.95662 -0.257593 + -0.0424352 1.95662 -0.257593 + -0.0424352 1.95662 -0.257593 + -0.0424352 1.95662 -0.257593 + -0.0424352 1.95662 -0.257593 + -0.0245 1.9744 -0.259934 + -0.0245 1.9744 -0.259934 + -0.0245 1.9744 -0.259934 + -0.0245 1.9744 -0.259934 + -0.0245 1.9744 -0.259934 + -0.0245 1.9744 -0.259934 + 0 1.998 -1.50845e-07 + 0 1.998 -1.50845e-07 + 0 1.998 -1.50845e-07 + 0 1.998 -1.50845e-07 + 0 1.998 -1.50845e-07 + 0 1.998 -1.50845e-07 + 0 1.998 -1.50845e-07 + 0.0245 1.99144 -1.51619e-07 + 0.0245 1.99144 -1.51619e-07 + 0.0245 1.99144 -1.51619e-07 + 0.0245 1.99144 -1.51619e-07 + 0.0245 1.99144 -1.51619e-07 + 0.0424352 1.9735 -1.51619e-07 + 0.0424352 1.9735 -1.51619e-07 + 0.0424352 1.9735 -1.51619e-07 + 0.0424352 1.9735 -1.51619e-07 + 0.0424352 1.9735 -1.51619e-07 + 0.0424352 1.9735 -1.51619e-07 + 0.0424352 1.9735 -1.51619e-07 + 0.049 1.949 -1.47522e-07 + 0.049 1.949 -1.47522e-07 + 0.049 1.949 -1.47522e-07 + 0.049 1.949 -1.47522e-07 + 0.049 1.949 -1.47522e-07 + 0.0424352 1.9245 -1.47522e-07 + 0.0424352 1.9245 -1.47522e-07 + 0.0424352 1.9245 -1.47522e-07 + 0.0424352 1.9245 -1.47522e-07 + 0.0424352 1.9245 -1.47522e-07 + 0.0424352 1.9245 -1.47522e-07 + 0.0424352 1.9245 -1.47522e-07 + 0.0245 1.90656 -1.45473e-07 + 0.0245 1.90656 -1.45473e-07 + 0.0245 1.90656 -1.45473e-07 + 0.0245 1.90656 -1.45473e-07 + 0.0245 1.90656 -1.45473e-07 + 0.0245 1.90656 -1.45473e-07 + 0 1.9 -1.43446e-07 + 0 1.9 -1.43446e-07 + 0 1.9 -1.43446e-07 + 0 1.9 -1.43446e-07 + 0 1.9 -1.43446e-07 + -0.0245 1.90656 -1.43424e-07 + -0.0245 1.90656 -1.43424e-07 + -0.0245 1.90656 -1.43424e-07 + -0.0245 1.90656 -1.43424e-07 + -0.0245 1.90656 -1.43424e-07 + -0.0245 1.90656 -1.43424e-07 + -0.0245 1.90656 -1.43424e-07 + -0.0424352 1.9245 -1.43424e-07 + -0.0424352 1.9245 -1.43424e-07 + -0.0424352 1.9245 -1.43424e-07 + -0.0424352 1.9245 -1.43424e-07 + -0.0424352 1.9245 -1.43424e-07 + -0.0424352 1.9245 -1.43424e-07 + -0.0424352 1.9245 -1.43424e-07 + -0.049 1.949 -1.43424e-07 + -0.049 1.949 -1.43424e-07 + -0.049 1.949 -1.43424e-07 + -0.049 1.949 -1.43424e-07 + -0.049 1.949 -1.43424e-07 + -0.0424352 1.9735 -1.47522e-07 + -0.0424352 1.9735 -1.47522e-07 + -0.0424352 1.9735 -1.47522e-07 + -0.0424352 1.9735 -1.47522e-07 + -0.0424352 1.9735 -1.47522e-07 + -0.0424352 1.9735 -1.47522e-07 + -0.0424352 1.9735 -1.47522e-07 + -0.0245 1.99144 -1.4957e-07 + -0.0245 1.99144 -1.4957e-07 + -0.0245 1.99144 -1.4957e-07 + -0.0245 1.99144 -1.4957e-07 + 0 1.98091 0.260792 + 0 1.98091 0.260792 + 0 1.98091 0.260792 + 0 1.98091 0.260792 + 0 1.98091 0.260792 + 0 1.98091 0.260792 + 0 1.98091 0.260792 + 0.0245 1.9744 0.259935 + 0.0245 1.9744 0.259935 + 0.0245 1.9744 0.259935 + 0.0245 1.9744 0.259935 + 0.0245 1.9744 0.259935 + 0.0424352 1.95662 0.257594 + 0.0424352 1.95662 0.257594 + 0.0424352 1.95662 0.257594 + 0.0424352 1.95662 0.257594 + 0.0424352 1.95662 0.257594 + 0.0424352 1.95662 0.257594 + 0.0424352 1.95662 0.257594 + 0.049 1.93233 0.254396 + 0.049 1.93233 0.254396 + 0.049 1.93233 0.254396 + 0.049 1.93233 0.254396 + 0.049 1.93233 0.254396 + 0.049 1.93233 0.254396 + 0.0424352 1.90804 0.251198 + 0.0424352 1.90804 0.251198 + 0.0424352 1.90804 0.251198 + 0.0424352 1.90804 0.251198 + 0.0424352 1.90804 0.251198 + 0.0424352 1.90804 0.251198 + 0.0245 1.89025 0.248857 + 0.0245 1.89025 0.248857 + 0.0245 1.89025 0.248857 + 0.0245 1.89025 0.248857 + 0.0245 1.89025 0.248857 + 0 1.88374 0.248 + 0 1.88374 0.248 + 0 1.88374 0.248 + 0 1.88374 0.248 + 0 1.88374 0.248 + 0 1.88374 0.248 + 0 1.88374 0.248 + -0.0245 1.89025 0.248857 + -0.0245 1.89025 0.248857 + -0.0245 1.89025 0.248857 + -0.0245 1.89025 0.248857 + -0.0424352 1.90804 0.251198 + -0.0424352 1.90804 0.251198 + -0.0424352 1.90804 0.251198 + -0.0424352 1.90804 0.251198 + -0.0424352 1.90804 0.251198 + -0.0424352 1.90804 0.251198 + -0.049 1.93233 0.254396 + -0.049 1.93233 0.254396 + -0.049 1.93233 0.254396 + -0.049 1.93233 0.254396 + -0.049 1.93233 0.254396 + -0.049 1.93233 0.254396 + -0.049 1.93233 0.254396 + -0.0424352 1.95662 0.257594 + -0.0424352 1.95662 0.257594 + -0.0424352 1.95662 0.257594 + -0.0424352 1.95662 0.257594 + -0.0424352 1.95662 0.257594 + -0.0424352 1.95662 0.257594 + -0.0245 1.9744 0.259935 + -0.0245 1.9744 0.259935 + -0.0245 1.9744 0.259935 + -0.0245 1.9744 0.259935 + -0.0245 1.9744 0.259935 + -0.0245 1.9744 0.259935 + 0 1.92992 0.51712 + 0 1.92992 0.51712 + 0 1.92992 0.51712 + 0 1.92992 0.51712 + 0 1.92992 0.51712 + 0 1.92992 0.51712 + 0.0245 1.92358 0.515421 + 0.0245 1.92358 0.515421 + 0.0245 1.92358 0.515421 + 0.0245 1.92358 0.515421 + 0.0245 1.92358 0.515421 + 0.0245 1.92358 0.515421 + 0.0424352 1.90625 0.510779 + 0.0424352 1.90625 0.510779 + 0.0424352 1.90625 0.510779 + 0.0424352 1.90625 0.510779 + 0.0424352 1.90625 0.510779 + 0.049 1.88259 0.504438 + 0.049 1.88259 0.504438 + 0.049 1.88259 0.504438 + 0.049 1.88259 0.504438 + 0.049 1.88259 0.504438 + 0.049 1.88259 0.504438 + 0.049 1.88259 0.504438 + 0.0424352 1.85892 0.498097 + 0.0424352 1.85892 0.498097 + 0.0424352 1.85892 0.498097 + 0.0424352 1.85892 0.498097 + 0.0424352 1.85892 0.498097 + 0.0245 1.8416 0.493455 + 0.0245 1.8416 0.493455 + 0.0245 1.8416 0.493455 + 0.0245 1.8416 0.493455 + 0.0245 1.8416 0.493455 + 0.0245 1.8416 0.493455 + 0.0245 1.8416 0.493455 + 0 1.83526 0.491756 + 0 1.83526 0.491756 + 0 1.83526 0.491756 + 0 1.83526 0.491756 + 0 1.83526 0.491756 + 0 1.83526 0.491756 + -0.0245 1.8416 0.493455 + -0.0245 1.8416 0.493455 + -0.0245 1.8416 0.493455 + -0.0245 1.8416 0.493455 + -0.0245 1.8416 0.493455 + -0.0245 1.8416 0.493455 + -0.0245 1.8416 0.493455 + -0.0424352 1.85892 0.498097 + -0.0424352 1.85892 0.498097 + -0.0424352 1.85892 0.498097 + -0.0424352 1.85892 0.498097 + -0.0424352 1.85892 0.498097 + -0.049 1.88259 0.504438 + -0.049 1.88259 0.504438 + -0.049 1.88259 0.504438 + -0.049 1.88259 0.504438 + -0.049 1.88259 0.504438 + -0.049 1.88259 0.504438 + -0.049 1.88259 0.504438 + -0.0424352 1.90625 0.510779 + -0.0424352 1.90625 0.510779 + -0.0424352 1.90625 0.510779 + -0.0424352 1.90625 0.510779 + -0.0245 1.92358 0.515421 + -0.0245 1.92358 0.515421 + -0.0245 1.92358 0.515421 + -0.0245 1.92358 0.515421 + -0.0245 1.92358 0.515421 + -0.0245 1.92358 0.515421 + -0.0245 1.92358 0.515421 + 0 1.84591 0.764602 + 0 1.84591 0.764602 + 0 1.84591 0.764602 + 0 1.84591 0.764602 + 0 1.84591 0.764602 + 0 1.84591 0.764602 + 0.0245 1.83985 0.762089 + 0.0245 1.83985 0.762089 + 0.0245 1.83985 0.762089 + 0.0245 1.83985 0.762089 + 0.0245 1.83985 0.762089 + 0.0245 1.83985 0.762089 + 0.0245 1.83985 0.762089 + 0.0424352 1.82328 0.755226 + 0.0424352 1.82328 0.755226 + 0.0424352 1.82328 0.755226 + 0.0424352 1.82328 0.755226 + 0.0424352 1.82328 0.755226 + 0.049 1.80064 0.74585 + 0.049 1.80064 0.74585 + 0.049 1.80064 0.74585 + 0.049 1.80064 0.74585 + 0.049 1.80064 0.74585 + 0.049 1.80064 0.74585 + 0.0424352 1.77801 0.736474 + 0.0424352 1.77801 0.736474 + 0.0424352 1.77801 0.736474 + 0.0424352 1.77801 0.736474 + 0.0424352 1.77801 0.736474 + 0.0424352 1.77801 0.736474 + 0.0245 1.76144 0.729611 + 0.0245 1.76144 0.729611 + 0.0245 1.76144 0.729611 + 0.0245 1.76144 0.729611 + 0.0245 1.76144 0.729611 + 0.0245 1.76144 0.729611 + 0 1.75537 0.727099 + 0 1.75537 0.727099 + 0 1.75537 0.727099 + 0 1.75537 0.727099 + 0 1.75537 0.727099 + 0 1.75537 0.727099 + -0.0245 1.76144 0.729611 + -0.0245 1.76144 0.729611 + -0.0245 1.76144 0.729611 + -0.0245 1.76144 0.729611 + -0.0245 1.76144 0.729611 + -0.0424352 1.77801 0.736474 + -0.0424352 1.77801 0.736474 + -0.0424352 1.77801 0.736474 + -0.0424352 1.77801 0.736474 + -0.0424352 1.77801 0.736474 + -0.0424352 1.77801 0.736474 + -0.0424352 1.77801 0.736474 + -0.0489999 1.80064 0.74585 + -0.0489999 1.80064 0.74585 + -0.0489999 1.80064 0.74585 + -0.0489999 1.80064 0.74585 + -0.0489999 1.80064 0.74585 + -0.0489999 1.80064 0.74585 + -0.0424352 1.82328 0.755226 + -0.0424352 1.82328 0.755226 + -0.0424352 1.82328 0.755226 + -0.0424352 1.82328 0.755226 + -0.0424352 1.82328 0.755226 + -0.0424352 1.82328 0.755226 + -0.0245 1.83985 0.762089 + -0.0245 1.83985 0.762089 + -0.0245 1.83985 0.762089 + -0.0245 1.83985 0.762089 + -0.0245 1.83985 0.762089 + -0.0245 1.83985 0.762089 + 0 1.73032 0.999 + 0 1.73032 0.999 + 0 1.73032 0.999 + 0 1.73032 0.999 + 0.0245 1.72463 0.995717 + 0.0245 1.72463 0.995717 + 0.0245 1.72463 0.995717 + 0.0245 1.72463 0.995717 + 0.0245 1.72463 0.995717 + 0.0245 1.72463 0.995717 + 0.0424353 1.7091 0.98675 + 0.0424353 1.7091 0.98675 + 0.0424353 1.7091 0.98675 + 0.0424353 1.7091 0.98675 + 0.0424353 1.7091 0.98675 + 0.0424353 1.7091 0.98675 + 0.0424353 1.7091 0.98675 + 0.049 1.68788 0.9745 + 0.049 1.68788 0.9745 + 0.049 1.68788 0.9745 + 0.049 1.68788 0.9745 + 0.049 1.68788 0.9745 + 0.049 1.68788 0.9745 + 0.0424353 1.66667 0.96225 + 0.0424353 1.66667 0.96225 + 0.0424353 1.66667 0.96225 + 0.0424353 1.66667 0.96225 + 0.0424353 1.66667 0.96225 + 0.0424353 1.66667 0.96225 + 0.0245 1.65113 0.953282 + 0.0245 1.65113 0.953282 + 0.0245 1.65113 0.953282 + 0.0245 1.65113 0.953282 + 0.0245 1.65113 0.953282 + 0.0245 1.65113 0.953282 + 0 1.64545 0.95 + 0 1.64545 0.95 + 0 1.64545 0.95 + 0 1.64545 0.95 + 0 1.64545 0.95 + -0.0245 1.65113 0.953282 + -0.0245 1.65113 0.953282 + -0.0245 1.65113 0.953282 + -0.0245 1.65113 0.953282 + -0.0245 1.65113 0.953282 + -0.0245 1.65113 0.953282 + -0.0245 1.65113 0.953282 + -0.0245 1.65113 0.953282 + -0.0424352 1.66667 0.96225 + -0.0424352 1.66667 0.96225 + -0.0424352 1.66667 0.96225 + -0.0424352 1.66667 0.96225 + -0.0424352 1.66667 0.96225 + -0.0489999 1.68788 0.9745 + -0.0489999 1.68788 0.9745 + -0.0489999 1.68788 0.9745 + -0.0489999 1.68788 0.9745 + -0.0489999 1.68788 0.9745 + -0.0489999 1.68788 0.9745 + -0.0424352 1.7091 0.98675 + -0.0424352 1.7091 0.98675 + -0.0424352 1.7091 0.98675 + -0.0424352 1.7091 0.98675 + -0.0424352 1.7091 0.98675 + -0.0424352 1.7091 0.98675 + -0.0424352 1.7091 0.98675 + -0.0245 1.72463 0.995717 + -0.0245 1.72463 0.995717 + -0.0245 1.72463 0.995717 + -0.0245 1.72463 0.995717 + -0.0245 1.72463 0.995717 + -0.0245 1.72463 0.995717 + 0 1.58512 1.21631 + 0 1.58512 1.21631 + 0 1.58512 1.21631 + 0 1.58512 1.21631 + 0 1.58512 1.21631 + 0 1.58512 1.21631 + 0 1.58512 1.21631 + 0 1.58512 1.21631 + 0.0245001 1.57991 1.21231 + 0.0245001 1.57991 1.21231 + 0.0245001 1.57991 1.21231 + 0.0245001 1.57991 1.21231 + 0.0245001 1.57991 1.21231 + 0.0424353 1.56568 1.20139 + 0.0424353 1.56568 1.20139 + 0.0424353 1.56568 1.20139 + 0.0424353 1.56568 1.20139 + 0.0424353 1.56568 1.20139 + 0.0424353 1.56568 1.20139 + 0.0424353 1.56568 1.20139 + 0.0490001 1.54624 1.18648 + 0.0490001 1.54624 1.18648 + 0.0490001 1.54624 1.18648 + 0.0490001 1.54624 1.18648 + 0.0424353 1.52681 1.17156 + 0.0424353 1.52681 1.17156 + 0.0424353 1.52681 1.17156 + 0.0424353 1.52681 1.17156 + 0.0424353 1.52681 1.17156 + 0.0424353 1.52681 1.17156 + 0.0424353 1.52681 1.17156 + 0.0424353 1.52681 1.17156 + 0.0245001 1.51258 1.16064 + 0.0245001 1.51258 1.16064 + 0.0245001 1.51258 1.16064 + 0.0245001 1.51258 1.16064 + 0.0245001 1.51258 1.16064 + 0.0245001 1.51258 1.16064 + 0 1.50737 1.15665 + 0 1.50737 1.15665 + 0 1.50737 1.15665 + 0 1.50737 1.15665 + 0 1.50737 1.15665 + -0.0245 1.51258 1.16064 + -0.0245 1.51258 1.16064 + -0.0245 1.51258 1.16064 + -0.0245 1.51258 1.16064 + -0.0245 1.51258 1.16064 + -0.0424352 1.52681 1.17156 + -0.0424352 1.52681 1.17156 + -0.0424352 1.52681 1.17156 + -0.0424352 1.52681 1.17156 + -0.0424352 1.52681 1.17156 + -0.0424352 1.52681 1.17156 + -0.0424352 1.52681 1.17156 + -0.0424352 1.52681 1.17156 + -0.0489999 1.54624 1.18648 + -0.0489999 1.54624 1.18648 + -0.0489999 1.54624 1.18648 + -0.0489999 1.54624 1.18648 + -0.0424352 1.56568 1.20139 + -0.0424352 1.56568 1.20139 + -0.0424352 1.56568 1.20139 + -0.0424352 1.56568 1.20139 + -0.0424352 1.56568 1.20139 + -0.0424352 1.56568 1.20139 + -0.0424352 1.56568 1.20139 + -0.0245 1.57991 1.21231 + -0.0245 1.57991 1.21231 + -0.0245 1.57991 1.21231 + -0.0245 1.57991 1.21231 + -0.0245 1.57991 1.21231 + 0 1.4128 1.4128 + 0 1.4128 1.4128 + 0 1.4128 1.4128 + 0 1.4128 1.4128 + 0 1.4128 1.4128 + 0 1.4128 1.4128 + 0.0245001 1.40816 1.40816 + 0.0245001 1.40816 1.40816 + 0.0245001 1.40816 1.40816 + 0.0245001 1.40816 1.40816 + 0.0245001 1.40816 1.40816 + 0.0245001 1.40816 1.40816 + 0.0424353 1.39548 1.39548 + 0.0424353 1.39548 1.39548 + 0.0424353 1.39548 1.39548 + 0.0424353 1.39548 1.39548 + 0.0424353 1.39548 1.39548 + 0.0424353 1.39548 1.39548 + 0.0490001 1.37815 1.37815 + 0.0490001 1.37815 1.37815 + 0.0490001 1.37815 1.37815 + 0.0490001 1.37815 1.37815 + 0.0490001 1.37815 1.37815 + 0.0490001 1.37815 1.37815 + 0.0424353 1.36083 1.36083 + 0.0424353 1.36083 1.36083 + 0.0424353 1.36083 1.36083 + 0.0424353 1.36083 1.36083 + 0.0424353 1.36083 1.36083 + 0.0424353 1.36083 1.36083 + 0.0245001 1.34814 1.34815 + 0.0245001 1.34814 1.34815 + 0.0245001 1.34814 1.34815 + 0.0245001 1.34814 1.34815 + 0.0245001 1.34814 1.34815 + 0 1.3435 1.3435 + 0 1.3435 1.3435 + 0 1.3435 1.3435 + 0 1.3435 1.3435 + 0 1.3435 1.3435 + 0 1.3435 1.3435 + 0 1.3435 1.3435 + 0 1.3435 1.3435 + -0.0245 1.34814 1.34815 + -0.0245 1.34814 1.34815 + -0.0245 1.34814 1.34815 + -0.0245 1.34814 1.34815 + -0.0245 1.34814 1.34815 + -0.0424352 1.36083 1.36083 + -0.0424352 1.36083 1.36083 + -0.0424352 1.36083 1.36083 + -0.0424352 1.36083 1.36083 + -0.0424352 1.36083 1.36083 + -0.0424352 1.36083 1.36083 + -0.0489999 1.37815 1.37815 + -0.0489999 1.37815 1.37815 + -0.0489999 1.37815 1.37815 + -0.0489999 1.37815 1.37815 + -0.0489999 1.37815 1.37815 + -0.0489999 1.37815 1.37815 + -0.0424352 1.39548 1.39548 + -0.0424352 1.39548 1.39548 + -0.0424352 1.39548 1.39548 + -0.0424352 1.39548 1.39548 + -0.0424352 1.39548 1.39548 + -0.0424352 1.39548 1.39548 + -0.0245 1.40816 1.40816 + -0.0245 1.40816 1.40816 + -0.0245 1.40816 1.40816 + -0.0245 1.40816 1.40816 + -0.0245 1.40816 1.40816 + -0.0245 1.40816 1.40816 + 1.3113e-07 1.21631 1.58512 + 1.3113e-07 1.21631 1.58512 + 1.3113e-07 1.21631 1.58512 + 1.3113e-07 1.21631 1.58512 + 1.3113e-07 1.21631 1.58512 + 0.0245001 1.21231 1.57991 + 0.0245001 1.21231 1.57991 + 0.0245001 1.21231 1.57991 + 0.0245001 1.21231 1.57991 + 0.0245001 1.21231 1.57991 + 0.0245001 1.21231 1.57991 + 0.0245001 1.21231 1.57991 + 0.0424353 1.20139 1.56568 + 0.0424353 1.20139 1.56568 + 0.0424353 1.20139 1.56568 + 0.0424353 1.20139 1.56568 + 0.0424353 1.20139 1.56568 + 0.0424353 1.20139 1.56568 + 0.0490001 1.18648 1.54625 + 0.0490001 1.18648 1.54625 + 0.0490001 1.18648 1.54625 + 0.0490001 1.18648 1.54625 + 0.0490001 1.18648 1.54625 + 0.0490001 1.18648 1.54625 + 0.0490001 1.18648 1.54625 + 0.0424353 1.17156 1.52681 + 0.0424353 1.17156 1.52681 + 0.0424353 1.17156 1.52681 + 0.0424353 1.17156 1.52681 + 0.0424353 1.17156 1.52681 + 0.0245001 1.16064 1.51258 + 0.0245001 1.16064 1.51258 + 0.0245001 1.16064 1.51258 + 0.0245001 1.16064 1.51258 + 0.0245001 1.16064 1.51258 + 0.0245001 1.16064 1.51258 + 1.3113e-07 1.15665 1.50737 + 1.3113e-07 1.15665 1.50737 + 1.3113e-07 1.15665 1.50737 + 1.3113e-07 1.15665 1.50737 + 1.3113e-07 1.15665 1.50737 + 1.3113e-07 1.15665 1.50737 + -0.0245 1.16064 1.51258 + -0.0245 1.16064 1.51258 + -0.0245 1.16064 1.51258 + -0.0245 1.16064 1.51258 + -0.0245 1.16064 1.51258 + -0.0245 1.16064 1.51258 + -0.0424352 1.17156 1.52681 + -0.0424352 1.17156 1.52681 + -0.0424352 1.17156 1.52681 + -0.0424352 1.17156 1.52681 + -0.0424352 1.17156 1.52681 + -0.0489999 1.18648 1.54625 + -0.0489999 1.18648 1.54625 + -0.0489999 1.18648 1.54625 + -0.0489999 1.18648 1.54625 + -0.0489999 1.18648 1.54625 + -0.0489999 1.18648 1.54625 + -0.0489999 1.18648 1.54625 + -0.0424352 1.20139 1.56568 + -0.0424352 1.20139 1.56568 + -0.0424352 1.20139 1.56568 + -0.0424352 1.20139 1.56568 + -0.0424352 1.20139 1.56568 + -0.0424352 1.20139 1.56568 + -0.0245 1.21231 1.57991 + -0.0245 1.21231 1.57991 + -0.0245 1.21231 1.57991 + -0.0245 1.21231 1.57991 + -0.0245 1.21231 1.57991 + -0.0245 1.21231 1.57991 + 1.3113e-07 0.999 1.73032 + 1.3113e-07 0.999 1.73032 + 1.3113e-07 0.999 1.73032 + 1.3113e-07 0.999 1.73032 + 1.3113e-07 0.999 1.73032 + 0.0245001 0.995718 1.72463 + 0.0245001 0.995718 1.72463 + 0.0245001 0.995718 1.72463 + 0.0245001 0.995718 1.72463 + 0.0245001 0.995718 1.72463 + 0.0245001 0.995718 1.72463 + 0.0424353 0.98675 1.7091 + 0.0424353 0.98675 1.7091 + 0.0424353 0.98675 1.7091 + 0.0424353 0.98675 1.7091 + 0.0424353 0.98675 1.7091 + 0.0424353 0.98675 1.7091 + 0.0490001 0.9745 1.68788 + 0.0490001 0.9745 1.68788 + 0.0490001 0.9745 1.68788 + 0.0490001 0.9745 1.68788 + 0.0490001 0.9745 1.68788 + 0.0424353 0.96225 1.66667 + 0.0424353 0.96225 1.66667 + 0.0424353 0.96225 1.66667 + 0.0424353 0.96225 1.66667 + 0.0424353 0.96225 1.66667 + 0.0424353 0.96225 1.66667 + 0.0245001 0.953283 1.65113 + 0.0245001 0.953283 1.65113 + 0.0245001 0.953283 1.65113 + 0.0245001 0.953283 1.65113 + 0.0245001 0.953283 1.65113 + 0.0245001 0.953283 1.65113 + 0.0245001 0.953283 1.65113 + 0.0245001 0.953283 1.65113 + 1.3113e-07 0.95 1.64545 + 1.3113e-07 0.95 1.64545 + 1.3113e-07 0.95 1.64545 + 1.3113e-07 0.95 1.64545 + -0.0245 0.953283 1.65113 + -0.0245 0.953283 1.65113 + -0.0245 0.953283 1.65113 + -0.0245 0.953283 1.65113 + -0.0245 0.953283 1.65113 + -0.0245 0.953283 1.65113 + -0.0245 0.953283 1.65113 + -0.0245 0.953283 1.65113 + -0.0424352 0.96225 1.66667 + -0.0424352 0.96225 1.66667 + -0.0424352 0.96225 1.66667 + -0.0424352 0.96225 1.66667 + -0.0424352 0.96225 1.66667 + -0.0424352 0.96225 1.66667 + -0.0489999 0.9745 1.68788 + -0.0489999 0.9745 1.68788 + -0.0489999 0.9745 1.68788 + -0.0489999 0.9745 1.68788 + -0.0489999 0.9745 1.68788 + -0.0424352 0.98675 1.7091 + -0.0424352 0.98675 1.7091 + -0.0424352 0.98675 1.7091 + -0.0424352 0.98675 1.7091 + -0.0424352 0.98675 1.7091 + -0.0424352 0.98675 1.7091 + -0.0245 0.995718 1.72463 + -0.0245 0.995718 1.72463 + -0.0245 0.995718 1.72463 + -0.0245 0.995718 1.72463 + -0.0245 0.995718 1.72463 + -0.0245 0.995718 1.72463 + -0.0245 0.995718 1.72463 + 1.3113e-07 0.764602 1.84591 + 1.3113e-07 0.764602 1.84591 + 1.3113e-07 0.764602 1.84591 + 1.3113e-07 0.764602 1.84591 + 1.3113e-07 0.764602 1.84591 + 1.3113e-07 0.764602 1.84591 + 1.3113e-07 0.764602 1.84591 + 1.3113e-07 0.764602 1.84591 + 0.0245001 0.762089 1.83985 + 0.0245001 0.762089 1.83985 + 0.0245001 0.762089 1.83985 + 0.0245001 0.762089 1.83985 + 0.0245001 0.762089 1.83985 + 0.0245001 0.762089 1.83985 + 0.0424353 0.755226 1.82328 + 0.0424353 0.755226 1.82328 + 0.0424353 0.755226 1.82328 + 0.0424353 0.755226 1.82328 + 0.0424353 0.755226 1.82328 + 0.0490001 0.74585 1.80064 + 0.0490001 0.74585 1.80064 + 0.0490001 0.74585 1.80064 + 0.0490001 0.74585 1.80064 + 0.0490001 0.74585 1.80064 + 0.0490001 0.74585 1.80064 + 0.0424353 0.736474 1.77801 + 0.0424353 0.736474 1.77801 + 0.0424353 0.736474 1.77801 + 0.0424353 0.736474 1.77801 + 0.0424353 0.736474 1.77801 + 0.0424353 0.736474 1.77801 + 0.0245001 0.729611 1.76144 + 0.0245001 0.729611 1.76144 + 0.0245001 0.729611 1.76144 + 0.0245001 0.729611 1.76144 + 0.0245001 0.729611 1.76144 + 0.0245001 0.729611 1.76144 + 1.3113e-07 0.727099 1.75537 + 1.3113e-07 0.727099 1.75537 + 1.3113e-07 0.727099 1.75537 + 1.3113e-07 0.727099 1.75537 + 1.3113e-07 0.727099 1.75537 + 1.3113e-07 0.727099 1.75537 + -0.0245 0.729611 1.76144 + -0.0245 0.729611 1.76144 + -0.0245 0.729611 1.76144 + -0.0245 0.729611 1.76144 + -0.0245 0.729611 1.76144 + -0.0245 0.729611 1.76144 + -0.0424352 0.736474 1.77801 + -0.0424352 0.736474 1.77801 + -0.0424352 0.736474 1.77801 + -0.0424352 0.736474 1.77801 + -0.0424352 0.736474 1.77801 + -0.0424352 0.736474 1.77801 + -0.0489999 0.74585 1.80064 + -0.0489999 0.74585 1.80064 + -0.0489999 0.74585 1.80064 + -0.0489999 0.74585 1.80064 + -0.0489999 0.74585 1.80064 + -0.0489999 0.74585 1.80064 + -0.0424352 0.755226 1.82328 + -0.0424352 0.755226 1.82328 + -0.0424352 0.755226 1.82328 + -0.0424352 0.755226 1.82328 + -0.0424352 0.755226 1.82328 + -0.0245 0.762089 1.83985 + -0.0245 0.762089 1.83985 + -0.0245 0.762089 1.83985 + -0.0245 0.762089 1.83985 + -0.0245 0.762089 1.83985 + -0.0245 0.762089 1.83985 + 1.3113e-07 0.51712 1.92992 + 1.3113e-07 0.51712 1.92992 + 1.3113e-07 0.51712 1.92992 + 1.3113e-07 0.51712 1.92992 + 1.3113e-07 0.51712 1.92992 + 0.0245001 0.515421 1.92358 + 0.0245001 0.515421 1.92358 + 0.0245001 0.515421 1.92358 + 0.0245001 0.515421 1.92358 + 0.0245001 0.515421 1.92358 + 0.0245001 0.515421 1.92358 + 0.0245001 0.515421 1.92358 + 0.0424353 0.510779 1.90626 + 0.0424353 0.510779 1.90626 + 0.0424353 0.510779 1.90626 + 0.0424353 0.510779 1.90626 + 0.0424353 0.510779 1.90626 + 0.0490001 0.504438 1.88259 + 0.0490001 0.504438 1.88259 + 0.0490001 0.504438 1.88259 + 0.0490001 0.504438 1.88259 + 0.0490001 0.504438 1.88259 + 0.0490001 0.504438 1.88259 + 0.0490001 0.504438 1.88259 + 0.0424353 0.498097 1.85892 + 0.0424353 0.498097 1.85892 + 0.0424353 0.498097 1.85892 + 0.0424353 0.498097 1.85892 + 0.0424353 0.498097 1.85892 + 0.0424353 0.498097 1.85892 + 0.0245001 0.493455 1.8416 + 0.0245001 0.493455 1.8416 + 0.0245001 0.493455 1.8416 + 0.0245001 0.493455 1.8416 + 0.0245001 0.493455 1.8416 + 0.0245001 0.493455 1.8416 + 1.3113e-07 0.491756 1.83526 + 1.3113e-07 0.491756 1.83526 + 1.3113e-07 0.491756 1.83526 + 1.3113e-07 0.491756 1.83526 + 1.3113e-07 0.491756 1.83526 + 1.3113e-07 0.491756 1.83526 + -0.0245 0.493455 1.8416 + -0.0245 0.493455 1.8416 + -0.0245 0.493455 1.8416 + -0.0245 0.493455 1.8416 + -0.0245 0.493455 1.8416 + -0.0245 0.493455 1.8416 + -0.0424352 0.498097 1.85892 + -0.0424352 0.498097 1.85892 + -0.0424352 0.498097 1.85892 + -0.0424352 0.498097 1.85892 + -0.0424352 0.498097 1.85892 + -0.0424352 0.498097 1.85892 + -0.0489999 0.504438 1.88259 + -0.0489999 0.504438 1.88259 + -0.0489999 0.504438 1.88259 + -0.0489999 0.504438 1.88259 + -0.0489999 0.504438 1.88259 + -0.0489999 0.504438 1.88259 + -0.0489999 0.504438 1.88259 + -0.0424352 0.510779 1.90626 + -0.0424352 0.510779 1.90626 + -0.0424352 0.510779 1.90626 + -0.0424352 0.510779 1.90626 + -0.0424352 0.510779 1.90626 + -0.0245 0.515421 1.92358 + -0.0245 0.515421 1.92358 + -0.0245 0.515421 1.92358 + -0.0245 0.515421 1.92358 + -0.0245 0.515421 1.92358 + -0.0245 0.515421 1.92358 + 1.3113e-07 0.260792 1.98091 + 1.3113e-07 0.260792 1.98091 + 1.3113e-07 0.260792 1.98091 + 1.3113e-07 0.260792 1.98091 + 1.3113e-07 0.260792 1.98091 + 0.0245001 0.259935 1.9744 + 0.0245001 0.259935 1.9744 + 0.0245001 0.259935 1.9744 + 0.0245001 0.259935 1.9744 + 0.0245001 0.259935 1.9744 + 0.0245001 0.259935 1.9744 + 0.0424353 0.257594 1.95662 + 0.0424353 0.257594 1.95662 + 0.0424353 0.257594 1.95662 + 0.0424353 0.257594 1.95662 + 0.0424353 0.257594 1.95662 + 0.0424353 0.257594 1.95662 + 0.0424353 0.257594 1.95662 + 0.0490001 0.254396 1.93233 + 0.0490001 0.254396 1.93233 + 0.0490001 0.254396 1.93233 + 0.0490001 0.254396 1.93233 + 0.0490001 0.254396 1.93233 + 0.0490001 0.254396 1.93233 + 0.0424353 0.251198 1.90804 + 0.0424353 0.251198 1.90804 + 0.0424353 0.251198 1.90804 + 0.0424353 0.251198 1.90804 + 0.0424353 0.251198 1.90804 + 0.0245001 0.248857 1.89025 + 0.0245001 0.248857 1.89025 + 0.0245001 0.248857 1.89025 + 0.0245001 0.248857 1.89025 + 0.0245001 0.248857 1.89025 + 1.3113e-07 0.248 1.88374 + 1.3113e-07 0.248 1.88374 + 1.3113e-07 0.248 1.88374 + 1.3113e-07 0.248 1.88374 + 1.3113e-07 0.248 1.88374 + 1.3113e-07 0.248 1.88374 + 1.3113e-07 0.248 1.88374 + -0.0245 0.248857 1.89025 + -0.0245 0.248857 1.89025 + -0.0245 0.248857 1.89025 + -0.0245 0.248857 1.89025 + -0.0245 0.248857 1.89025 + -0.0424352 0.251198 1.90804 + -0.0424352 0.251198 1.90804 + -0.0424352 0.251198 1.90804 + -0.0424352 0.251198 1.90804 + -0.0424352 0.251198 1.90804 + -0.0424352 0.251198 1.90804 + -0.0489999 0.254396 1.93233 + -0.0489999 0.254396 1.93233 + -0.0489999 0.254396 1.93233 + -0.0489999 0.254396 1.93233 + -0.0489999 0.254396 1.93233 + -0.0489999 0.254396 1.93233 + -0.0424352 0.257594 1.95662 + -0.0424352 0.257594 1.95662 + -0.0424352 0.257594 1.95662 + -0.0424352 0.257594 1.95662 + -0.0424352 0.257594 1.95662 + -0.0424352 0.257594 1.95662 + -0.0424352 0.257594 1.95662 + -0.0245 0.259935 1.9744 + -0.0245 0.259935 1.9744 + -0.0245 0.259935 1.9744 + -0.0245 0.259935 1.9744 + -0.0245 0.259935 1.9744 + -0.0245 0.259935 1.9744 + -0.0245 0.259935 1.9744 + 1.3113e-07 1.74671e-07 1.998 + 1.3113e-07 1.74671e-07 1.998 + 1.3113e-07 1.74671e-07 1.998 + 1.3113e-07 1.74671e-07 1.998 + 1.3113e-07 1.74671e-07 1.998 + 1.3113e-07 1.74671e-07 1.998 + 1.3113e-07 1.74671e-07 1.998 + 1.3113e-07 1.74671e-07 1.998 + 0.0245001 1.74097e-07 1.99144 + 0.0245001 1.74097e-07 1.99144 + 0.0245001 1.74097e-07 1.99144 + 0.0245001 1.74097e-07 1.99144 + 0.0424353 1.72529e-07 1.9735 + 0.0424353 1.72529e-07 1.9735 + 0.0424353 1.72529e-07 1.9735 + 0.0424353 1.72529e-07 1.9735 + 0.0424353 1.72529e-07 1.9735 + 0.0424353 1.72529e-07 1.9735 + 0.0490001 1.70387e-07 1.949 + 0.0490001 1.70387e-07 1.949 + 0.0490001 1.70387e-07 1.949 + 0.0490001 1.70387e-07 1.949 + 0.0490001 1.70387e-07 1.949 + 0.0490001 1.70387e-07 1.949 + 0.0424353 1.68245e-07 1.9245 + 0.0424353 1.68245e-07 1.9245 + 0.0424353 1.68245e-07 1.9245 + 0.0424353 1.68245e-07 1.9245 + 0.0424353 1.68245e-07 1.9245 + 0.0424353 1.68245e-07 1.9245 + 0.0424353 1.68245e-07 1.9245 + 0.0424353 1.68245e-07 1.9245 + 0.0245001 1.66677e-07 1.90656 + 0.0245001 1.66677e-07 1.90656 + 0.0245001 1.66677e-07 1.90656 + 0.0245001 1.66677e-07 1.90656 + 0.0245001 1.66677e-07 1.90656 + 1.3113e-07 1.66103e-07 1.9 + 1.3113e-07 1.66103e-07 1.9 + 1.3113e-07 1.66103e-07 1.9 + 1.3113e-07 1.66103e-07 1.9 + 1.3113e-07 1.66103e-07 1.9 + 1.3113e-07 1.66103e-07 1.9 + 1.3113e-07 1.66103e-07 1.9 + -0.0245 1.66677e-07 1.90656 + -0.0245 1.66677e-07 1.90656 + -0.0245 1.66677e-07 1.90656 + -0.0245 1.66677e-07 1.90656 + -0.0245 1.66677e-07 1.90656 + -0.0424352 1.68245e-07 1.9245 + -0.0424352 1.68245e-07 1.9245 + -0.0424352 1.68245e-07 1.9245 + -0.0424352 1.68245e-07 1.9245 + -0.0424352 1.68245e-07 1.9245 + -0.0424352 1.68245e-07 1.9245 + -0.0424352 1.68245e-07 1.9245 + -0.0489999 1.70387e-07 1.949 + -0.0489999 1.70387e-07 1.949 + -0.0489999 1.70387e-07 1.949 + -0.0489999 1.70387e-07 1.949 + -0.0489999 1.70387e-07 1.949 + -0.0489999 1.70387e-07 1.949 + -0.0424352 1.72529e-07 1.9735 + -0.0424352 1.72529e-07 1.9735 + -0.0424352 1.72529e-07 1.9735 + -0.0424352 1.72529e-07 1.9735 + -0.0424352 1.72529e-07 1.9735 + -0.0424352 1.72529e-07 1.9735 + -0.0245 1.74097e-07 1.99144 + -0.0245 1.74097e-07 1.99144 + -0.0245 1.74097e-07 1.99144 + -0.0245 1.74097e-07 1.99144 + 1.3113e-07 -0.260792 1.98091 + 1.3113e-07 -0.260792 1.98091 + 1.3113e-07 -0.260792 1.98091 + 1.3113e-07 -0.260792 1.98091 + 1.3113e-07 -0.260792 1.98091 + 0.0245001 -0.259935 1.9744 + 0.0245001 -0.259935 1.9744 + 0.0245001 -0.259935 1.9744 + 0.0245001 -0.259935 1.9744 + 0.0245001 -0.259935 1.9744 + 0.0245001 -0.259935 1.9744 + 0.0245001 -0.259935 1.9744 + 0.0424353 -0.257594 1.95662 + 0.0424353 -0.257594 1.95662 + 0.0424353 -0.257594 1.95662 + 0.0424353 -0.257594 1.95662 + 0.0424353 -0.257594 1.95662 + 0.0424353 -0.257594 1.95662 + 0.0424353 -0.257594 1.95662 + 0.0490001 -0.254396 1.93233 + 0.0490001 -0.254396 1.93233 + 0.0490001 -0.254396 1.93233 + 0.0490001 -0.254396 1.93233 + 0.0490001 -0.254396 1.93233 + 0.0490001 -0.254396 1.93233 + 0.0424353 -0.251198 1.90804 + 0.0424353 -0.251198 1.90804 + 0.0424353 -0.251198 1.90804 + 0.0424353 -0.251198 1.90804 + 0.0424353 -0.251198 1.90804 + 0.0245001 -0.248857 1.89025 + 0.0245001 -0.248857 1.89025 + 0.0245001 -0.248857 1.89025 + 0.0245001 -0.248857 1.89025 + 0.0245001 -0.248857 1.89025 + 0.0245001 -0.248857 1.89025 + 1.3113e-07 -0.248 1.88374 + 1.3113e-07 -0.248 1.88374 + 1.3113e-07 -0.248 1.88374 + 1.3113e-07 -0.248 1.88374 + 1.3113e-07 -0.248 1.88374 + 1.3113e-07 -0.248 1.88374 + -0.0245 -0.248857 1.89025 + -0.0245 -0.248857 1.89025 + -0.0245 -0.248857 1.89025 + -0.0245 -0.248857 1.89025 + -0.0245 -0.248857 1.89025 + -0.0245 -0.248857 1.89025 + -0.0424352 -0.251198 1.90804 + -0.0424352 -0.251198 1.90804 + -0.0424352 -0.251198 1.90804 + -0.0424352 -0.251198 1.90804 + -0.0424352 -0.251198 1.90804 + -0.0489999 -0.254396 1.93233 + -0.0489999 -0.254396 1.93233 + -0.0489999 -0.254396 1.93233 + -0.0489999 -0.254396 1.93233 + -0.0489999 -0.254396 1.93233 + -0.0489999 -0.254396 1.93233 + -0.0424352 -0.257594 1.95662 + -0.0424352 -0.257594 1.95662 + -0.0424352 -0.257594 1.95662 + -0.0424352 -0.257594 1.95662 + -0.0424352 -0.257594 1.95662 + -0.0424352 -0.257594 1.95662 + -0.0424352 -0.257594 1.95662 + -0.0245 -0.259935 1.9744 + -0.0245 -0.259935 1.9744 + -0.0245 -0.259935 1.9744 + -0.0245 -0.259935 1.9744 + -0.0245 -0.259935 1.9744 + -0.0245 -0.259935 1.9744 + 1.3113e-07 -0.51712 1.92992 + 1.3113e-07 -0.51712 1.92992 + 1.3113e-07 -0.51712 1.92992 + 1.3113e-07 -0.51712 1.92992 + 1.3113e-07 -0.51712 1.92992 + 0.0245001 -0.515421 1.92358 + 0.0245001 -0.515421 1.92358 + 0.0245001 -0.515421 1.92358 + 0.0245001 -0.515421 1.92358 + 0.0245001 -0.515421 1.92358 + 0.0245001 -0.515421 1.92358 + 0.0424353 -0.510779 1.90626 + 0.0424353 -0.510779 1.90626 + 0.0424353 -0.510779 1.90626 + 0.0424353 -0.510779 1.90626 + 0.0424353 -0.510779 1.90626 + 0.0424353 -0.510779 1.90626 + 0.0490001 -0.504438 1.88259 + 0.0490001 -0.504438 1.88259 + 0.0490001 -0.504438 1.88259 + 0.0490001 -0.504438 1.88259 + 0.0490001 -0.504438 1.88259 + 0.0424353 -0.498097 1.85892 + 0.0424353 -0.498097 1.85892 + 0.0424353 -0.498097 1.85892 + 0.0424353 -0.498097 1.85892 + 0.0424353 -0.498097 1.85892 + 0.0424353 -0.498097 1.85892 + 0.0424353 -0.498097 1.85892 + 0.0245001 -0.493455 1.8416 + 0.0245001 -0.493455 1.8416 + 0.0245001 -0.493455 1.8416 + 0.0245001 -0.493455 1.8416 + 0.0245001 -0.493455 1.8416 + 0.0245001 -0.493455 1.8416 + 1.3113e-07 -0.491756 1.83526 + 1.3113e-07 -0.491756 1.83526 + 1.3113e-07 -0.491756 1.83526 + 1.3113e-07 -0.491756 1.83526 + 1.3113e-07 -0.491756 1.83526 + 1.3113e-07 -0.491756 1.83526 + -0.0245 -0.493455 1.8416 + -0.0245 -0.493455 1.8416 + -0.0245 -0.493455 1.8416 + -0.0245 -0.493455 1.8416 + -0.0245 -0.493455 1.8416 + -0.0245 -0.493455 1.8416 + -0.0424352 -0.498097 1.85892 + -0.0424352 -0.498097 1.85892 + -0.0424352 -0.498097 1.85892 + -0.0424352 -0.498097 1.85892 + -0.0424352 -0.498097 1.85892 + -0.0424352 -0.498097 1.85892 + -0.0424352 -0.498097 1.85892 + -0.0489999 -0.504438 1.88259 + -0.0489999 -0.504438 1.88259 + -0.0489999 -0.504438 1.88259 + -0.0489999 -0.504438 1.88259 + -0.0489999 -0.504438 1.88259 + -0.0424352 -0.510779 1.90626 + -0.0424352 -0.510779 1.90626 + -0.0424352 -0.510779 1.90626 + -0.0424352 -0.510779 1.90626 + -0.0424352 -0.510779 1.90626 + -0.0424352 -0.510779 1.90626 + -0.0245 -0.515421 1.92358 + -0.0245 -0.515421 1.92358 + -0.0245 -0.515421 1.92358 + -0.0245 -0.515421 1.92358 + -0.0245 -0.515421 1.92358 + -0.0245 -0.515421 1.92358 + -0.0245 -0.515421 1.92358 + 1.3113e-07 -0.764601 1.84591 + 1.3113e-07 -0.764601 1.84591 + 1.3113e-07 -0.764601 1.84591 + 1.3113e-07 -0.764601 1.84591 + 1.3113e-07 -0.764601 1.84591 + 1.3113e-07 -0.764601 1.84591 + 1.3113e-07 -0.764601 1.84591 + 1.3113e-07 -0.764601 1.84591 + 0.0245001 -0.762088 1.83985 + 0.0245001 -0.762088 1.83985 + 0.0245001 -0.762088 1.83985 + 0.0245001 -0.762088 1.83985 + 0.0245001 -0.762088 1.83985 + 0.0424353 -0.755225 1.82328 + 0.0424353 -0.755225 1.82328 + 0.0424353 -0.755225 1.82328 + 0.0424353 -0.755225 1.82328 + 0.0424353 -0.755225 1.82328 + 0.0424353 -0.755225 1.82328 + 0.0490001 -0.745849 1.80064 + 0.0490001 -0.745849 1.80064 + 0.0490001 -0.745849 1.80064 + 0.0490001 -0.745849 1.80064 + 0.0490001 -0.745849 1.80064 + 0.0490001 -0.745849 1.80064 + 0.0424353 -0.736474 1.77801 + 0.0424353 -0.736474 1.77801 + 0.0424353 -0.736474 1.77801 + 0.0424353 -0.736474 1.77801 + 0.0424353 -0.736474 1.77801 + 0.0424353 -0.736474 1.77801 + 0.0245001 -0.72961 1.76144 + 0.0245001 -0.72961 1.76144 + 0.0245001 -0.72961 1.76144 + 0.0245001 -0.72961 1.76144 + 0.0245001 -0.72961 1.76144 + 0.0245001 -0.72961 1.76144 + 1.3113e-07 -0.727098 1.75537 + 1.3113e-07 -0.727098 1.75537 + 1.3113e-07 -0.727098 1.75537 + 1.3113e-07 -0.727098 1.75537 + 1.3113e-07 -0.727098 1.75537 + 1.3113e-07 -0.727098 1.75537 + -0.0245 -0.72961 1.76144 + -0.0245 -0.72961 1.76144 + -0.0245 -0.72961 1.76144 + -0.0245 -0.72961 1.76144 + -0.0245 -0.72961 1.76144 + -0.0245 -0.72961 1.76144 + -0.0424352 -0.736474 1.77801 + -0.0424352 -0.736474 1.77801 + -0.0424352 -0.736474 1.77801 + -0.0424352 -0.736474 1.77801 + -0.0424352 -0.736474 1.77801 + -0.0424352 -0.736474 1.77801 + -0.0489999 -0.745849 1.80064 + -0.0489999 -0.745849 1.80064 + -0.0489999 -0.745849 1.80064 + -0.0489999 -0.745849 1.80064 + -0.0489999 -0.745849 1.80064 + -0.0489999 -0.745849 1.80064 + -0.0424352 -0.755225 1.82328 + -0.0424352 -0.755225 1.82328 + -0.0424352 -0.755225 1.82328 + -0.0424352 -0.755225 1.82328 + -0.0424352 -0.755225 1.82328 + -0.0424352 -0.755225 1.82328 + -0.0245 -0.762088 1.83985 + -0.0245 -0.762088 1.83985 + -0.0245 -0.762088 1.83985 + -0.0245 -0.762088 1.83985 + -0.0245 -0.762088 1.83985 + 1.3113e-07 -0.998999 1.73032 + 1.3113e-07 -0.998999 1.73032 + 1.3113e-07 -0.998999 1.73032 + 1.3113e-07 -0.998999 1.73032 + 0.0245001 -0.995717 1.72463 + 0.0245001 -0.995717 1.72463 + 0.0245001 -0.995717 1.72463 + 0.0245001 -0.995717 1.72463 + 0.0245001 -0.995717 1.72463 + 0.0245001 -0.995717 1.72463 + 0.0245001 -0.995717 1.72463 + 0.0424353 -0.986749 1.7091 + 0.0424353 -0.986749 1.7091 + 0.0424353 -0.986749 1.7091 + 0.0424353 -0.986749 1.7091 + 0.0424353 -0.986749 1.7091 + 0.0490001 -0.974499 1.68788 + 0.0490001 -0.974499 1.68788 + 0.0490001 -0.974499 1.68788 + 0.0490001 -0.974499 1.68788 + 0.0490001 -0.974499 1.68788 + 0.0490001 -0.974499 1.68788 + 0.0490001 -0.974499 1.68788 + 0.0424353 -0.96225 1.66667 + 0.0424353 -0.96225 1.66667 + 0.0424353 -0.96225 1.66667 + 0.0424353 -0.96225 1.66667 + 0.0424353 -0.96225 1.66667 + 0.0245001 -0.953282 1.65113 + 0.0245001 -0.953282 1.65113 + 0.0245001 -0.953282 1.65113 + 0.0245001 -0.953282 1.65113 + 0.0245001 -0.953282 1.65113 + 0.0245001 -0.953282 1.65113 + 0.0245001 -0.953282 1.65113 + 1.3113e-07 -0.95 1.64545 + 1.3113e-07 -0.95 1.64545 + 1.3113e-07 -0.95 1.64545 + 1.3113e-07 -0.95 1.64545 + 1.3113e-07 -0.95 1.64545 + -0.0245 -0.953282 1.65113 + -0.0245 -0.953282 1.65113 + -0.0245 -0.953282 1.65113 + -0.0245 -0.953282 1.65113 + -0.0245 -0.953282 1.65113 + -0.0245 -0.953282 1.65113 + -0.0245 -0.953282 1.65113 + -0.0245 -0.953282 1.65113 + -0.0424352 -0.96225 1.66667 + -0.0424352 -0.96225 1.66667 + -0.0424352 -0.96225 1.66667 + -0.0424352 -0.96225 1.66667 + -0.0424352 -0.96225 1.66667 + -0.0489999 -0.974499 1.68788 + -0.0489999 -0.974499 1.68788 + -0.0489999 -0.974499 1.68788 + -0.0489999 -0.974499 1.68788 + -0.0489999 -0.974499 1.68788 + -0.0489999 -0.974499 1.68788 + -0.0424352 -0.986749 1.7091 + -0.0424352 -0.986749 1.7091 + -0.0424352 -0.986749 1.7091 + -0.0424352 -0.986749 1.7091 + -0.0424352 -0.986749 1.7091 + -0.0424352 -0.986749 1.7091 + -0.0245 -0.995717 1.72463 + -0.0245 -0.995717 1.72463 + -0.0245 -0.995717 1.72463 + -0.0245 -0.995717 1.72463 + -0.0245 -0.995717 1.72463 + -0.0245 -0.995717 1.72463 + -0.0245 -0.995717 1.72463 + 1.3113e-07 -1.21631 1.58512 + 1.3113e-07 -1.21631 1.58512 + 1.3113e-07 -1.21631 1.58512 + 1.3113e-07 -1.21631 1.58512 + 1.3113e-07 -1.21631 1.58512 + 1.3113e-07 -1.21631 1.58512 + 0.0245001 -1.21231 1.57991 + 0.0245001 -1.21231 1.57991 + 0.0245001 -1.21231 1.57991 + 0.0245001 -1.21231 1.57991 + 0.0245001 -1.21231 1.57991 + 0.0245001 -1.21231 1.57991 + 0.0245001 -1.21231 1.57991 + 0.0424353 -1.20139 1.56568 + 0.0424353 -1.20139 1.56568 + 0.0424353 -1.20139 1.56568 + 0.0424353 -1.20139 1.56568 + 0.0424353 -1.20139 1.56568 + 0.0490001 -1.18648 1.54625 + 0.0490001 -1.18648 1.54625 + 0.0490001 -1.18648 1.54625 + 0.0490001 -1.18648 1.54625 + 0.0490001 -1.18648 1.54625 + 0.0490001 -1.18648 1.54625 + 0.0490001 -1.18648 1.54625 + 0.0424353 -1.17156 1.52681 + 0.0424353 -1.17156 1.52681 + 0.0424353 -1.17156 1.52681 + 0.0424353 -1.17156 1.52681 + 0.0424353 -1.17156 1.52681 + 0.0245001 -1.16064 1.51258 + 0.0245001 -1.16064 1.51258 + 0.0245001 -1.16064 1.51258 + 0.0245001 -1.16064 1.51258 + 0.0245001 -1.16064 1.51258 + 0.0245001 -1.16064 1.51258 + 0.0245001 -1.16064 1.51258 + 1.3113e-07 -1.15665 1.50737 + 1.3113e-07 -1.15665 1.50737 + 1.3113e-07 -1.15665 1.50737 + 1.3113e-07 -1.15665 1.50737 + 1.3113e-07 -1.15665 1.50737 + -0.0245 -1.16064 1.51258 + -0.0245 -1.16064 1.51258 + -0.0245 -1.16064 1.51258 + -0.0245 -1.16064 1.51258 + -0.0245 -1.16064 1.51258 + -0.0245 -1.16064 1.51258 + -0.0424352 -1.17156 1.52681 + -0.0424352 -1.17156 1.52681 + -0.0424352 -1.17156 1.52681 + -0.0424352 -1.17156 1.52681 + -0.0424352 -1.17156 1.52681 + -0.0489999 -1.18648 1.54625 + -0.0489999 -1.18648 1.54625 + -0.0489999 -1.18648 1.54625 + -0.0489999 -1.18648 1.54625 + -0.0489999 -1.18648 1.54625 + -0.0489999 -1.18648 1.54625 + -0.0489999 -1.18648 1.54625 + -0.0489999 -1.18648 1.54625 + -0.0424352 -1.20139 1.56568 + -0.0424352 -1.20139 1.56568 + -0.0424352 -1.20139 1.56568 + -0.0424352 -1.20139 1.56568 + -0.0245 -1.21231 1.57991 + -0.0245 -1.21231 1.57991 + -0.0245 -1.21231 1.57991 + -0.0245 -1.21231 1.57991 + -0.0245 -1.21231 1.57991 + -0.0245 -1.21231 1.57991 + -0.0245 -1.21231 1.57991 + 0 -1.4128 1.4128 + 0 -1.4128 1.4128 + 0 -1.4128 1.4128 + 0 -1.4128 1.4128 + 0 -1.4128 1.4128 + 0 -1.4128 1.4128 + 0.0245001 -1.40816 1.40816 + 0.0245001 -1.40816 1.40816 + 0.0245001 -1.40816 1.40816 + 0.0245001 -1.40816 1.40816 + 0.0245001 -1.40816 1.40816 + 0.0245001 -1.40816 1.40816 + 0.0424353 -1.39548 1.39548 + 0.0424353 -1.39548 1.39548 + 0.0424353 -1.39548 1.39548 + 0.0424353 -1.39548 1.39548 + 0.0424353 -1.39548 1.39548 + 0.0424353 -1.39548 1.39548 + 0.0490001 -1.37815 1.37815 + 0.0490001 -1.37815 1.37815 + 0.0490001 -1.37815 1.37815 + 0.0490001 -1.37815 1.37815 + 0.0490001 -1.37815 1.37815 + 0.0490001 -1.37815 1.37815 + 0.0424353 -1.36083 1.36083 + 0.0424353 -1.36083 1.36083 + 0.0424353 -1.36083 1.36083 + 0.0424353 -1.36083 1.36083 + 0.0424353 -1.36083 1.36083 + 0.0424353 -1.36083 1.36083 + 0.0245001 -1.34814 1.34815 + 0.0245001 -1.34814 1.34815 + 0.0245001 -1.34814 1.34815 + 0.0245001 -1.34814 1.34815 + 0.0245001 -1.34814 1.34815 + 0 -1.3435 1.3435 + 0 -1.3435 1.3435 + 0 -1.3435 1.3435 + 0 -1.3435 1.3435 + 0 -1.3435 1.3435 + 0 -1.3435 1.3435 + 0 -1.3435 1.3435 + 0 -1.3435 1.3435 + -0.0245 -1.34814 1.34815 + -0.0245 -1.34814 1.34815 + -0.0245 -1.34814 1.34815 + -0.0245 -1.34814 1.34815 + -0.0424352 -1.36083 1.36083 + -0.0424352 -1.36083 1.36083 + -0.0424352 -1.36083 1.36083 + -0.0424352 -1.36083 1.36083 + -0.0424352 -1.36083 1.36083 + -0.0424352 -1.36083 1.36083 + -0.0424352 -1.36083 1.36083 + -0.0489999 -1.37815 1.37815 + -0.0489999 -1.37815 1.37815 + -0.0489999 -1.37815 1.37815 + -0.0489999 -1.37815 1.37815 + -0.0489999 -1.37815 1.37815 + -0.0489999 -1.37815 1.37815 + -0.0424352 -1.39548 1.39548 + -0.0424352 -1.39548 1.39548 + -0.0424352 -1.39548 1.39548 + -0.0424352 -1.39548 1.39548 + -0.0424352 -1.39548 1.39548 + -0.0424352 -1.39548 1.39548 + -0.0245 -1.40816 1.40816 + -0.0245 -1.40816 1.40816 + -0.0245 -1.40816 1.40816 + -0.0245 -1.40816 1.40816 + -0.0245 -1.40816 1.40816 + -0.0245 -1.40816 1.40816 + 0 -1.58512 1.21631 + 0 -1.58512 1.21631 + 0 -1.58512 1.21631 + 0 -1.58512 1.21631 + 0 -1.58512 1.21631 + 0 -1.58512 1.21631 + 0.0245001 -1.57991 1.21231 + 0.0245001 -1.57991 1.21231 + 0.0245001 -1.57991 1.21231 + 0.0245001 -1.57991 1.21231 + 0.0245001 -1.57991 1.21231 + 0.0245001 -1.57991 1.21231 + 0.0424353 -1.56568 1.20139 + 0.0424353 -1.56568 1.20139 + 0.0424353 -1.56568 1.20139 + 0.0424353 -1.56568 1.20139 + 0.0424353 -1.56568 1.20139 + 0.0424353 -1.56568 1.20139 + 0.0490001 -1.54624 1.18648 + 0.0490001 -1.54624 1.18648 + 0.0490001 -1.54624 1.18648 + 0.0490001 -1.54624 1.18648 + 0.0490001 -1.54624 1.18648 + 0.0424353 -1.52681 1.17156 + 0.0424353 -1.52681 1.17156 + 0.0424353 -1.52681 1.17156 + 0.0424353 -1.52681 1.17156 + 0.0424353 -1.52681 1.17156 + 0.0424353 -1.52681 1.17156 + 0.0424353 -1.52681 1.17156 + 0.0424353 -1.52681 1.17156 + 0.0245001 -1.51258 1.16064 + 0.0245001 -1.51258 1.16064 + 0.0245001 -1.51258 1.16064 + 0.0245001 -1.51258 1.16064 + 0.0245001 -1.51258 1.16064 + 0 -1.50737 1.15665 + 0 -1.50737 1.15665 + 0 -1.50737 1.15665 + 0 -1.50737 1.15665 + 0 -1.50737 1.15665 + -0.0245 -1.51258 1.16064 + -0.0245 -1.51258 1.16064 + -0.0245 -1.51258 1.16064 + -0.0245 -1.51258 1.16064 + -0.0245 -1.51258 1.16064 + -0.0245 -1.51258 1.16064 + -0.0245 -1.51258 1.16064 + -0.0424352 -1.52681 1.17156 + -0.0424352 -1.52681 1.17156 + -0.0424352 -1.52681 1.17156 + -0.0424352 -1.52681 1.17156 + -0.0424352 -1.52681 1.17156 + -0.0424352 -1.52681 1.17156 + -0.0424352 -1.52681 1.17156 + -0.0489999 -1.54624 1.18648 + -0.0489999 -1.54624 1.18648 + -0.0489999 -1.54624 1.18648 + -0.0489999 -1.54624 1.18648 + -0.0489999 -1.54624 1.18648 + -0.0424352 -1.56568 1.20139 + -0.0424352 -1.56568 1.20139 + -0.0424352 -1.56568 1.20139 + -0.0424352 -1.56568 1.20139 + -0.0424352 -1.56568 1.20139 + -0.0424352 -1.56568 1.20139 + -0.0245 -1.57991 1.21231 + -0.0245 -1.57991 1.21231 + -0.0245 -1.57991 1.21231 + -0.0245 -1.57991 1.21231 + -0.0245 -1.57991 1.21231 + -0.0245 -1.57991 1.21231 + 0 -1.73032 0.999 + 0 -1.73032 0.999 + 0 -1.73032 0.999 + 0 -1.73032 0.999 + 0 -1.73032 0.999 + 0 -1.73032 0.999 + 0.0245 -1.72463 0.995717 + 0.0245 -1.72463 0.995717 + 0.0245 -1.72463 0.995717 + 0.0245 -1.72463 0.995717 + 0.0245 -1.72463 0.995717 + 0.0424353 -1.7091 0.98675 + 0.0424353 -1.7091 0.98675 + 0.0424353 -1.7091 0.98675 + 0.0424353 -1.7091 0.98675 + 0.0424353 -1.7091 0.98675 + 0.0424353 -1.7091 0.98675 + 0.0424353 -1.7091 0.98675 + 0.0424353 -1.7091 0.98675 + 0.049 -1.68788 0.9745 + 0.049 -1.68788 0.9745 + 0.049 -1.68788 0.9745 + 0.049 -1.68788 0.9745 + 0.049 -1.68788 0.9745 + 0.0424353 -1.66667 0.96225 + 0.0424353 -1.66667 0.96225 + 0.0424353 -1.66667 0.96225 + 0.0424353 -1.66667 0.96225 + 0.0424353 -1.66667 0.96225 + 0.0245 -1.65113 0.953282 + 0.0245 -1.65113 0.953282 + 0.0245 -1.65113 0.953282 + 0.0245 -1.65113 0.953282 + 0.0245 -1.65113 0.953282 + 0.0245 -1.65113 0.953282 + 0.0245 -1.65113 0.953282 + 0.0245 -1.65113 0.953282 + 0 -1.64545 0.95 + 0 -1.64545 0.95 + 0 -1.64545 0.95 + 0 -1.64545 0.95 + 0 -1.64545 0.95 + -0.0245 -1.65113 0.953282 + -0.0245 -1.65113 0.953282 + -0.0245 -1.65113 0.953282 + -0.0245 -1.65113 0.953282 + -0.0245 -1.65113 0.953282 + -0.0245 -1.65113 0.953282 + -0.0424352 -1.66667 0.96225 + -0.0424352 -1.66667 0.96225 + -0.0424352 -1.66667 0.96225 + -0.0424352 -1.66667 0.96225 + -0.0424352 -1.66667 0.96225 + -0.0424352 -1.66667 0.96225 + -0.0489999 -1.68788 0.9745 + -0.0489999 -1.68788 0.9745 + -0.0489999 -1.68788 0.9745 + -0.0489999 -1.68788 0.9745 + -0.0489999 -1.68788 0.9745 + -0.0424352 -1.7091 0.98675 + -0.0424352 -1.7091 0.98675 + -0.0424352 -1.7091 0.98675 + -0.0424352 -1.7091 0.98675 + -0.0424352 -1.7091 0.98675 + -0.0424352 -1.7091 0.98675 + -0.0424352 -1.7091 0.98675 + -0.0424352 -1.7091 0.98675 + -0.0245 -1.72463 0.995717 + -0.0245 -1.72463 0.995717 + -0.0245 -1.72463 0.995717 + -0.0245 -1.72463 0.995717 + -0.0245 -1.72463 0.995717 + 0 -1.84591 0.764602 + 0 -1.84591 0.764602 + 0 -1.84591 0.764602 + 0 -1.84591 0.764602 + 0 -1.84591 0.764602 + 0 -1.84591 0.764602 + 0 -1.84591 0.764602 + 0 -1.84591 0.764602 + 0.0245 -1.83985 0.762089 + 0.0245 -1.83985 0.762089 + 0.0245 -1.83985 0.762089 + 0.0245 -1.83985 0.762089 + 0.0245 -1.83985 0.762089 + 0.0424352 -1.82328 0.755226 + 0.0424352 -1.82328 0.755226 + 0.0424352 -1.82328 0.755226 + 0.0424352 -1.82328 0.755226 + 0.0424352 -1.82328 0.755226 + 0.0424352 -1.82328 0.755226 + 0.049 -1.80064 0.74585 + 0.049 -1.80064 0.74585 + 0.049 -1.80064 0.74585 + 0.049 -1.80064 0.74585 + 0.049 -1.80064 0.74585 + 0.049 -1.80064 0.74585 + 0.0424352 -1.77801 0.736474 + 0.0424352 -1.77801 0.736474 + 0.0424352 -1.77801 0.736474 + 0.0424352 -1.77801 0.736474 + 0.0424352 -1.77801 0.736474 + 0.0424352 -1.77801 0.736474 + 0.0424352 -1.77801 0.736474 + 0.0245 -1.76144 0.729611 + 0.0245 -1.76144 0.729611 + 0.0245 -1.76144 0.729611 + 0.0245 -1.76144 0.729611 + 0 -1.75537 0.727099 + 0 -1.75537 0.727099 + 0 -1.75537 0.727099 + 0 -1.75537 0.727099 + 0 -1.75537 0.727099 + 0 -1.75537 0.727099 + 0 -1.75537 0.727099 + 0 -1.75537 0.727099 + -0.0245 -1.76144 0.729611 + -0.0245 -1.76144 0.729611 + -0.0245 -1.76144 0.729611 + -0.0245 -1.76144 0.729611 + -0.0245 -1.76144 0.729611 + -0.0424352 -1.77801 0.736474 + -0.0424352 -1.77801 0.736474 + -0.0424352 -1.77801 0.736474 + -0.0424352 -1.77801 0.736474 + -0.0424352 -1.77801 0.736474 + -0.0424352 -1.77801 0.736474 + -0.0489999 -1.80064 0.74585 + -0.0489999 -1.80064 0.74585 + -0.0489999 -1.80064 0.74585 + -0.0489999 -1.80064 0.74585 + -0.0489999 -1.80064 0.74585 + -0.0489999 -1.80064 0.74585 + -0.0424352 -1.82328 0.755226 + -0.0424352 -1.82328 0.755226 + -0.0424352 -1.82328 0.755226 + -0.0424352 -1.82328 0.755226 + -0.0424352 -1.82328 0.755226 + -0.0424352 -1.82328 0.755226 + -0.0245 -1.83985 0.762089 + -0.0245 -1.83985 0.762089 + -0.0245 -1.83985 0.762089 + -0.0245 -1.83985 0.762089 + -0.0245 -1.83985 0.762089 + 0 -1.92992 0.517121 + 0 -1.92992 0.517121 + 0 -1.92992 0.517121 + 0 -1.92992 0.517121 + 0 -1.92992 0.517121 + 0 -1.92992 0.517121 + 0.0245 -1.92358 0.515422 + 0.0245 -1.92358 0.515422 + 0.0245 -1.92358 0.515422 + 0.0245 -1.92358 0.515422 + 0.0245 -1.92358 0.515422 + 0.0245 -1.92358 0.515422 + 0.0424352 -1.90625 0.51078 + 0.0424352 -1.90625 0.51078 + 0.0424352 -1.90625 0.51078 + 0.0424352 -1.90625 0.51078 + 0.0424352 -1.90625 0.51078 + 0.0424352 -1.90625 0.51078 + 0.049 -1.88259 0.504439 + 0.049 -1.88259 0.504439 + 0.049 -1.88259 0.504439 + 0.049 -1.88259 0.504439 + 0.049 -1.88259 0.504439 + 0.049 -1.88259 0.504439 + 0.0424352 -1.85892 0.498098 + 0.0424352 -1.85892 0.498098 + 0.0424352 -1.85892 0.498098 + 0.0424352 -1.85892 0.498098 + 0.0424352 -1.85892 0.498098 + 0.0245 -1.8416 0.493456 + 0.0245 -1.8416 0.493456 + 0.0245 -1.8416 0.493456 + 0.0245 -1.8416 0.493456 + 0.0245 -1.8416 0.493456 + 0.0245 -1.8416 0.493456 + 0.0245 -1.8416 0.493456 + 0 -1.83526 0.491757 + 0 -1.83526 0.491757 + 0 -1.83526 0.491757 + 0 -1.83526 0.491757 + 0 -1.83526 0.491757 + -0.0245 -1.8416 0.493456 + -0.0245 -1.8416 0.493456 + -0.0245 -1.8416 0.493456 + -0.0245 -1.8416 0.493456 + -0.0245 -1.8416 0.493456 + -0.0245 -1.8416 0.493456 + -0.0245 -1.8416 0.493456 + -0.0424352 -1.85892 0.498098 + -0.0424352 -1.85892 0.498098 + -0.0424352 -1.85892 0.498098 + -0.0424352 -1.85892 0.498098 + -0.0424352 -1.85892 0.498098 + -0.0424352 -1.85892 0.498098 + -0.049 -1.88259 0.504439 + -0.049 -1.88259 0.504439 + -0.049 -1.88259 0.504439 + -0.049 -1.88259 0.504439 + -0.049 -1.88259 0.504439 + -0.049 -1.88259 0.504439 + -0.0424352 -1.90625 0.51078 + -0.0424352 -1.90625 0.51078 + -0.0424352 -1.90625 0.51078 + -0.0424352 -1.90625 0.51078 + -0.0424352 -1.90625 0.51078 + -0.0424352 -1.90625 0.51078 + -0.0245 -1.92358 0.515422 + -0.0245 -1.92358 0.515422 + -0.0245 -1.92358 0.515422 + -0.0245 -1.92358 0.515422 + -0.0245 -1.92358 0.515422 + -0.0245 -1.92358 0.515422 + 0 -1.98091 0.260792 + 0 -1.98091 0.260792 + 0 -1.98091 0.260792 + 0 -1.98091 0.260792 + 0 -1.98091 0.260792 + 0.0245 -1.9744 0.259936 + 0.0245 -1.9744 0.259936 + 0.0245 -1.9744 0.259936 + 0.0245 -1.9744 0.259936 + 0.0245 -1.9744 0.259936 + 0.0245 -1.9744 0.259936 + 0.0245 -1.9744 0.259936 + 0.0245 -1.9744 0.259936 + 0.0424352 -1.95662 0.257595 + 0.0424352 -1.95662 0.257595 + 0.0424352 -1.95662 0.257595 + 0.0424352 -1.95662 0.257595 + 0.0424352 -1.95662 0.257595 + 0.049 -1.93233 0.254397 + 0.049 -1.93233 0.254397 + 0.049 -1.93233 0.254397 + 0.049 -1.93233 0.254397 + 0.049 -1.93233 0.254397 + 0.049 -1.93233 0.254397 + 0.049 -1.93233 0.254397 + 0.0424352 -1.90804 0.251199 + 0.0424352 -1.90804 0.251199 + 0.0424352 -1.90804 0.251199 + 0.0424352 -1.90804 0.251199 + 0.0424352 -1.90804 0.251199 + 0.0245 -1.89025 0.248858 + 0.0245 -1.89025 0.248858 + 0.0245 -1.89025 0.248858 + 0.0245 -1.89025 0.248858 + 0.0245 -1.89025 0.248858 + 0.0245 -1.89025 0.248858 + 0.0245 -1.89025 0.248858 + 0 -1.88374 0.248001 + 0 -1.88374 0.248001 + 0 -1.88374 0.248001 + 0 -1.88374 0.248001 + 0 -1.88374 0.248001 + -0.0245 -1.89025 0.248858 + -0.0245 -1.89025 0.248858 + -0.0245 -1.89025 0.248858 + -0.0245 -1.89025 0.248858 + -0.0245 -1.89025 0.248858 + -0.0245 -1.89025 0.248858 + -0.0245 -1.89025 0.248858 + -0.0424352 -1.90804 0.251199 + -0.0424352 -1.90804 0.251199 + -0.0424352 -1.90804 0.251199 + -0.0424352 -1.90804 0.251199 + -0.049 -1.93233 0.254397 + -0.049 -1.93233 0.254397 + -0.049 -1.93233 0.254397 + -0.049 -1.93233 0.254397 + -0.049 -1.93233 0.254397 + -0.049 -1.93233 0.254397 + -0.049 -1.93233 0.254397 + -0.0424352 -1.95662 0.257595 + -0.0424352 -1.95662 0.257595 + -0.0424352 -1.95662 0.257595 + -0.0424352 -1.95662 0.257595 + -0.0424352 -1.95662 0.257595 + -0.0424352 -1.95662 0.257595 + -0.0245 -1.9744 0.259936 + -0.0245 -1.9744 0.259936 + -0.0245 -1.9744 0.259936 + -0.0245 -1.9744 0.259936 + -0.0245 -1.9744 0.259936 + -0.0245 -1.9744 0.259936 + 0 -1.998 -1.50845e-07 + 0 -1.998 -1.50845e-07 + 0 -1.998 -1.50845e-07 + 0 -1.998 -1.50845e-07 + 0 -1.998 -1.50845e-07 + 0 -1.998 -1.50845e-07 + 0 -1.998 -1.50845e-07 + 0.0245 -1.99144 -1.51619e-07 + 0.0245 -1.99144 -1.51619e-07 + 0.0245 -1.99144 -1.51619e-07 + 0.0245 -1.99144 -1.51619e-07 + 0.0424352 -1.9735 -1.51619e-07 + 0.0424352 -1.9735 -1.51619e-07 + 0.0424352 -1.9735 -1.51619e-07 + 0.0424352 -1.9735 -1.51619e-07 + 0.0424352 -1.9735 -1.51619e-07 + 0.0424352 -1.9735 -1.51619e-07 + 0.0424352 -1.9735 -1.51619e-07 + 0.049 -1.949 -1.47522e-07 + 0.049 -1.949 -1.47522e-07 + 0.049 -1.949 -1.47522e-07 + 0.049 -1.949 -1.47522e-07 + 0.049 -1.949 -1.47522e-07 + 0.0424352 -1.9245 -1.47522e-07 + 0.0424352 -1.9245 -1.47522e-07 + 0.0424352 -1.9245 -1.47522e-07 + 0.0424352 -1.9245 -1.47522e-07 + 0.0424352 -1.9245 -1.47522e-07 + 0.0424352 -1.9245 -1.47522e-07 + 0.0424352 -1.9245 -1.47522e-07 + 0.0245 -1.90656 -1.45473e-07 + 0.0245 -1.90656 -1.45473e-07 + 0.0245 -1.90656 -1.45473e-07 + 0.0245 -1.90656 -1.45473e-07 + 0.0245 -1.90656 -1.45473e-07 + 0 -1.9 -1.43446e-07 + 0 -1.9 -1.43446e-07 + 0 -1.9 -1.43446e-07 + 0 -1.9 -1.43446e-07 + 0 -1.9 -1.43446e-07 + 0 -1.9 -1.43446e-07 + 0 -1.9 -1.43446e-07 + -0.0245 -1.90656 -1.43424e-07 + -0.0245 -1.90656 -1.43424e-07 + -0.0245 -1.90656 -1.43424e-07 + -0.0245 -1.90656 -1.43424e-07 + -0.0245 -1.90656 -1.43424e-07 + -0.0424352 -1.9245 -1.43424e-07 + -0.0424352 -1.9245 -1.43424e-07 + -0.0424352 -1.9245 -1.43424e-07 + -0.0424352 -1.9245 -1.43424e-07 + -0.0424352 -1.9245 -1.43424e-07 + -0.0424352 -1.9245 -1.43424e-07 + -0.0424352 -1.9245 -1.43424e-07 + -0.0424352 -1.9245 -1.43424e-07 + -0.049 -1.949 -1.43424e-07 + -0.049 -1.949 -1.43424e-07 + -0.049 -1.949 -1.43424e-07 + -0.049 -1.949 -1.43424e-07 + -0.049 -1.949 -1.43424e-07 + -0.049 -1.949 -1.43424e-07 + -0.0424352 -1.9735 -1.47522e-07 + -0.0424352 -1.9735 -1.47522e-07 + -0.0424352 -1.9735 -1.47522e-07 + -0.0424352 -1.9735 -1.47522e-07 + -0.0424352 -1.9735 -1.47522e-07 + -0.0245 -1.99144 -1.4957e-07 + -0.0245 -1.99144 -1.4957e-07 + -0.0245 -1.99144 -1.4957e-07 + -0.0245 -1.99144 -1.4957e-07 + -0.0245 -1.99144 -1.4957e-07 + -0.0245 -1.99144 -1.4957e-07 + 0 -1.98091 -0.260791 + 0 -1.98091 -0.260791 + 0 -1.98091 -0.260791 + 0 -1.98091 -0.260791 + 0 -1.98091 -0.260791 + 0 -1.98091 -0.260791 + 0.0245 -1.9744 -0.259934 + 0.0245 -1.9744 -0.259934 + 0.0245 -1.9744 -0.259934 + 0.0245 -1.9744 -0.259934 + 0.0245 -1.9744 -0.259934 + 0.0245 -1.9744 -0.259934 + 0.0424352 -1.95662 -0.257593 + 0.0424352 -1.95662 -0.257593 + 0.0424352 -1.95662 -0.257593 + 0.0424352 -1.95662 -0.257593 + 0.0424352 -1.95662 -0.257593 + 0.0424352 -1.95662 -0.257593 + 0.049 -1.93233 -0.254395 + 0.049 -1.93233 -0.254395 + 0.049 -1.93233 -0.254395 + 0.049 -1.93233 -0.254395 + 0.049 -1.93233 -0.254395 + 0.049 -1.93233 -0.254395 + 0.0424352 -1.90804 -0.251197 + 0.0424352 -1.90804 -0.251197 + 0.0424352 -1.90804 -0.251197 + 0.0424352 -1.90804 -0.251197 + 0.0424352 -1.90804 -0.251197 + 0.0424352 -1.90804 -0.251197 + 0.0424352 -1.90804 -0.251197 + 0.0245 -1.89025 -0.248856 + 0.0245 -1.89025 -0.248856 + 0.0245 -1.89025 -0.248856 + 0.0245 -1.89025 -0.248856 + 0.0245 -1.89025 -0.248856 + 0 -1.88374 -0.247999 + 0 -1.88374 -0.247999 + 0 -1.88374 -0.247999 + 0 -1.88374 -0.247999 + 0 -1.88374 -0.247999 + 0 -1.88374 -0.247999 + -0.0245 -1.89025 -0.248856 + -0.0245 -1.89025 -0.248856 + -0.0245 -1.89025 -0.248856 + -0.0245 -1.89025 -0.248856 + -0.0245 -1.89025 -0.248856 + -0.0245 -1.89025 -0.248856 + -0.0424352 -1.90804 -0.251197 + -0.0424352 -1.90804 -0.251197 + -0.0424352 -1.90804 -0.251197 + -0.0424352 -1.90804 -0.251197 + -0.0424352 -1.90804 -0.251197 + -0.0424352 -1.90804 -0.251197 + -0.049 -1.93233 -0.254395 + -0.049 -1.93233 -0.254395 + -0.049 -1.93233 -0.254395 + -0.049 -1.93233 -0.254395 + -0.049 -1.93233 -0.254395 + -0.0424352 -1.95662 -0.257593 + -0.0424352 -1.95662 -0.257593 + -0.0424352 -1.95662 -0.257593 + -0.0424352 -1.95662 -0.257593 + -0.0424352 -1.95662 -0.257593 + -0.0424352 -1.95662 -0.257593 + -0.0424352 -1.95662 -0.257593 + -0.0245 -1.9744 -0.259934 + -0.0245 -1.9744 -0.259934 + -0.0245 -1.9744 -0.259934 + -0.0245 -1.9744 -0.259934 + -0.0245 -1.9744 -0.259934 + -0.0245 -1.9744 -0.259934 + 0 -1.92992 -0.51712 + 0 -1.92992 -0.51712 + 0 -1.92992 -0.51712 + 0 -1.92992 -0.51712 + 0 -1.92992 -0.51712 + 0 -1.92992 -0.51712 + 0.0245 -1.92358 -0.51542 + 0.0245 -1.92358 -0.51542 + 0.0245 -1.92358 -0.51542 + 0.0245 -1.92358 -0.51542 + 0.0245 -1.92358 -0.51542 + 0.0245 -1.92358 -0.51542 + 0.0245 -1.92358 -0.51542 + 0.0424352 -1.90625 -0.510778 + 0.0424352 -1.90625 -0.510778 + 0.0424352 -1.90625 -0.510778 + 0.0424352 -1.90625 -0.510778 + 0.049 -1.88259 -0.504437 + 0.049 -1.88259 -0.504437 + 0.049 -1.88259 -0.504437 + 0.049 -1.88259 -0.504437 + 0.049 -1.88259 -0.504437 + 0.049 -1.88259 -0.504437 + 0.049 -1.88259 -0.504437 + 0.049 -1.88259 -0.504437 + 0.0424352 -1.85892 -0.498096 + 0.0424352 -1.85892 -0.498096 + 0.0424352 -1.85892 -0.498096 + 0.0424352 -1.85892 -0.498096 + 0.0245 -1.8416 -0.493454 + 0.0245 -1.8416 -0.493454 + 0.0245 -1.8416 -0.493454 + 0.0245 -1.8416 -0.493454 + 0.0245 -1.8416 -0.493454 + 0.0245 -1.8416 -0.493454 + 0.0245 -1.8416 -0.493454 + 0.0245 -1.8416 -0.493454 + 0 -1.83526 -0.491755 + 0 -1.83526 -0.491755 + 0 -1.83526 -0.491755 + 0 -1.83526 -0.491755 + 0 -1.83526 -0.491755 + -0.0245 -1.8416 -0.493454 + -0.0245 -1.8416 -0.493454 + -0.0245 -1.8416 -0.493454 + -0.0245 -1.8416 -0.493454 + -0.0245 -1.8416 -0.493454 + -0.0245 -1.8416 -0.493454 + -0.0245 -1.8416 -0.493454 + -0.0424352 -1.85892 -0.498096 + -0.0424352 -1.85892 -0.498096 + -0.0424352 -1.85892 -0.498096 + -0.0424352 -1.85892 -0.498096 + -0.049 -1.88259 -0.504437 + -0.049 -1.88259 -0.504437 + -0.049 -1.88259 -0.504437 + -0.049 -1.88259 -0.504437 + -0.049 -1.88259 -0.504437 + -0.049 -1.88259 -0.504437 + -0.049 -1.88259 -0.504437 + -0.0424352 -1.90625 -0.510778 + -0.0424352 -1.90625 -0.510778 + -0.0424352 -1.90625 -0.510778 + -0.0424352 -1.90625 -0.510778 + -0.0424352 -1.90625 -0.510778 + -0.0245 -1.92358 -0.51542 + -0.0245 -1.92358 -0.51542 + -0.0245 -1.92358 -0.51542 + -0.0245 -1.92358 -0.51542 + -0.0245 -1.92358 -0.51542 + -0.0245 -1.92358 -0.51542 + -0.0245 -1.92358 -0.51542 + 0 -1.84591 -0.764602 + 0 -1.84591 -0.764602 + 0 -1.84591 -0.764602 + 0 -1.84591 -0.764602 + 0 -1.84591 -0.764602 + 0 -1.84591 -0.764602 + 0.0245 -1.83985 -0.76209 + 0.0245 -1.83985 -0.76209 + 0.0245 -1.83985 -0.76209 + 0.0245 -1.83985 -0.76209 + 0.0245 -1.83985 -0.76209 + 0.0245 -1.83985 -0.76209 + 0.0424352 -1.82328 -0.755226 + 0.0424352 -1.82328 -0.755226 + 0.0424352 -1.82328 -0.755226 + 0.0424352 -1.82328 -0.755226 + 0.0424352 -1.82328 -0.755226 + 0.0424352 -1.82328 -0.755226 + 0.0489999 -1.80064 -0.74585 + 0.0489999 -1.80064 -0.74585 + 0.0489999 -1.80064 -0.74585 + 0.0489999 -1.80064 -0.74585 + 0.0489999 -1.80064 -0.74585 + 0.0489999 -1.80064 -0.74585 + 0.0424352 -1.77801 -0.736475 + 0.0424352 -1.77801 -0.736475 + 0.0424352 -1.77801 -0.736475 + 0.0424352 -1.77801 -0.736475 + 0.0424352 -1.77801 -0.736475 + 0.0424352 -1.77801 -0.736475 + 0.0245 -1.76144 -0.729611 + 0.0245 -1.76144 -0.729611 + 0.0245 -1.76144 -0.729611 + 0.0245 -1.76144 -0.729611 + 0.0245 -1.76144 -0.729611 + 0.0245 -1.76144 -0.729611 + 0 -1.75537 -0.727099 + 0 -1.75537 -0.727099 + 0 -1.75537 -0.727099 + 0 -1.75537 -0.727099 + 0 -1.75537 -0.727099 + 0 -1.75537 -0.727099 + -0.0245 -1.76144 -0.729611 + -0.0245 -1.76144 -0.729611 + -0.0245 -1.76144 -0.729611 + -0.0245 -1.76144 -0.729611 + -0.0245 -1.76144 -0.729611 + -0.0245 -1.76144 -0.729611 + -0.0424352 -1.77801 -0.736475 + -0.0424352 -1.77801 -0.736475 + -0.0424352 -1.77801 -0.736475 + -0.0424352 -1.77801 -0.736475 + -0.0424352 -1.77801 -0.736475 + -0.0424352 -1.77801 -0.736475 + -0.049 -1.80064 -0.74585 + -0.049 -1.80064 -0.74585 + -0.049 -1.80064 -0.74585 + -0.049 -1.80064 -0.74585 + -0.049 -1.80064 -0.74585 + -0.049 -1.80064 -0.74585 + -0.049 -1.80064 -0.74585 + -0.0424352 -1.82328 -0.755226 + -0.0424352 -1.82328 -0.755226 + -0.0424352 -1.82328 -0.755226 + -0.0424352 -1.82328 -0.755226 + -0.0424352 -1.82328 -0.755226 + -0.0245 -1.83985 -0.76209 + -0.0245 -1.83985 -0.76209 + -0.0245 -1.83985 -0.76209 + -0.0245 -1.83985 -0.76209 + -0.0245 -1.83985 -0.76209 + -0.0245 -1.83985 -0.76209 + 0 -1.73032 -0.999 + 0 -1.73032 -0.999 + 0 -1.73032 -0.999 + 0 -1.73032 -0.999 + 0 -1.73032 -0.999 + 0 -1.73032 -0.999 + 0.0245 -1.72463 -0.995718 + 0.0245 -1.72463 -0.995718 + 0.0245 -1.72463 -0.995718 + 0.0245 -1.72463 -0.995718 + 0.0245 -1.72463 -0.995718 + 0.0424352 -1.7091 -0.98675 + 0.0424352 -1.7091 -0.98675 + 0.0424352 -1.7091 -0.98675 + 0.0424352 -1.7091 -0.98675 + 0.0424352 -1.7091 -0.98675 + 0.0424352 -1.7091 -0.98675 + 0.0424352 -1.7091 -0.98675 + 0.0489999 -1.68788 -0.9745 + 0.0489999 -1.68788 -0.9745 + 0.0489999 -1.68788 -0.9745 + 0.0489999 -1.68788 -0.9745 + 0.0489999 -1.68788 -0.9745 + 0.0489999 -1.68788 -0.9745 + 0.0424352 -1.66667 -0.96225 + 0.0424352 -1.66667 -0.96225 + 0.0424352 -1.66667 -0.96225 + 0.0424352 -1.66667 -0.96225 + 0.0424352 -1.66667 -0.96225 + 0.0424352 -1.66667 -0.96225 + 0.0245 -1.65113 -0.953282 + 0.0245 -1.65113 -0.953282 + 0.0245 -1.65113 -0.953282 + 0.0245 -1.65113 -0.953282 + 0.0245 -1.65113 -0.953282 + 0.0245 -1.65113 -0.953282 + 0 -1.64545 -0.95 + 0 -1.64545 -0.95 + 0 -1.64545 -0.95 + 0 -1.64545 -0.95 + 0 -1.64545 -0.95 + 0 -1.64545 -0.95 + -0.0245 -1.65113 -0.953282 + -0.0245 -1.65113 -0.953282 + -0.0245 -1.65113 -0.953282 + -0.0245 -1.65113 -0.953282 + -0.0245 -1.65113 -0.953282 + -0.0245 -1.65113 -0.953282 + -0.0424353 -1.66667 -0.96225 + -0.0424353 -1.66667 -0.96225 + -0.0424353 -1.66667 -0.96225 + -0.0424353 -1.66667 -0.96225 + -0.0424353 -1.66667 -0.96225 + -0.0424353 -1.66667 -0.96225 + -0.049 -1.68788 -0.9745 + -0.049 -1.68788 -0.9745 + -0.049 -1.68788 -0.9745 + -0.049 -1.68788 -0.9745 + -0.049 -1.68788 -0.9745 + -0.049 -1.68788 -0.9745 + -0.0424353 -1.7091 -0.98675 + -0.0424353 -1.7091 -0.98675 + -0.0424353 -1.7091 -0.98675 + -0.0424353 -1.7091 -0.98675 + -0.0424353 -1.7091 -0.98675 + -0.0424353 -1.7091 -0.98675 + -0.0424353 -1.7091 -0.98675 + -0.0245 -1.72463 -0.995718 + -0.0245 -1.72463 -0.995718 + -0.0245 -1.72463 -0.995718 + -0.0245 -1.72463 -0.995718 + -0.0245 -1.72463 -0.995718 + 0 -1.58512 -1.21631 + 0 -1.58512 -1.21631 + 0 -1.58512 -1.21631 + 0 -1.58512 -1.21631 + 0.0245 -1.57991 -1.21231 + 0.0245 -1.57991 -1.21231 + 0.0245 -1.57991 -1.21231 + 0.0245 -1.57991 -1.21231 + 0.0245 -1.57991 -1.21231 + 0.0245 -1.57991 -1.21231 + 0.0245 -1.57991 -1.21231 + 0.0245 -1.57991 -1.21231 + 0.0424352 -1.56568 -1.20139 + 0.0424352 -1.56568 -1.20139 + 0.0424352 -1.56568 -1.20139 + 0.0424352 -1.56568 -1.20139 + 0.0424352 -1.56568 -1.20139 + 0.0489999 -1.54625 -1.18648 + 0.0489999 -1.54625 -1.18648 + 0.0489999 -1.54625 -1.18648 + 0.0489999 -1.54625 -1.18648 + 0.0489999 -1.54625 -1.18648 + 0.0489999 -1.54625 -1.18648 + 0.0424352 -1.52681 -1.17156 + 0.0424352 -1.52681 -1.17156 + 0.0424352 -1.52681 -1.17156 + 0.0424352 -1.52681 -1.17156 + 0.0424352 -1.52681 -1.17156 + 0.0424352 -1.52681 -1.17156 + 0.0245 -1.51258 -1.16064 + 0.0245 -1.51258 -1.16064 + 0.0245 -1.51258 -1.16064 + 0.0245 -1.51258 -1.16064 + 0.0245 -1.51258 -1.16064 + 0.0245 -1.51258 -1.16064 + 0 -1.50737 -1.15665 + 0 -1.50737 -1.15665 + 0 -1.50737 -1.15665 + 0 -1.50737 -1.15665 + 0 -1.50737 -1.15665 + 0 -1.50737 -1.15665 + -0.0245001 -1.51258 -1.16064 + -0.0245001 -1.51258 -1.16064 + -0.0245001 -1.51258 -1.16064 + -0.0245001 -1.51258 -1.16064 + -0.0245001 -1.51258 -1.16064 + -0.0245001 -1.51258 -1.16064 + -0.0424353 -1.52681 -1.17156 + -0.0424353 -1.52681 -1.17156 + -0.0424353 -1.52681 -1.17156 + -0.0424353 -1.52681 -1.17156 + -0.0424353 -1.52681 -1.17156 + -0.0424353 -1.52681 -1.17156 + -0.0490001 -1.54625 -1.18648 + -0.0490001 -1.54625 -1.18648 + -0.0490001 -1.54625 -1.18648 + -0.0490001 -1.54625 -1.18648 + -0.0490001 -1.54625 -1.18648 + -0.0490001 -1.54625 -1.18648 + -0.0424353 -1.56568 -1.20139 + -0.0424353 -1.56568 -1.20139 + -0.0424353 -1.56568 -1.20139 + -0.0424353 -1.56568 -1.20139 + -0.0424353 -1.56568 -1.20139 + -0.0245001 -1.57991 -1.21231 + -0.0245001 -1.57991 -1.21231 + -0.0245001 -1.57991 -1.21231 + -0.0245001 -1.57991 -1.21231 + -0.0245001 -1.57991 -1.21231 + -0.0245001 -1.57991 -1.21231 + -0.0245001 -1.57991 -1.21231 + -0.0245001 -1.57991 -1.21231 + 0 -1.4128 -1.4128 + 0 -1.4128 -1.4128 + 0 -1.4128 -1.4128 + 0 -1.4128 -1.4128 + 0 -1.4128 -1.4128 + 0 -1.4128 -1.4128 + 0.0245 -1.40816 -1.40816 + 0.0245 -1.40816 -1.40816 + 0.0245 -1.40816 -1.40816 + 0.0245 -1.40816 -1.40816 + 0.0245 -1.40816 -1.40816 + 0.0245 -1.40816 -1.40816 + 0.0424352 -1.39548 -1.39547 + 0.0424352 -1.39548 -1.39547 + 0.0424352 -1.39548 -1.39547 + 0.0424352 -1.39548 -1.39547 + 0.0424352 -1.39548 -1.39547 + 0.0424352 -1.39548 -1.39547 + 0.0489999 -1.37815 -1.37815 + 0.0489999 -1.37815 -1.37815 + 0.0489999 -1.37815 -1.37815 + 0.0489999 -1.37815 -1.37815 + 0.0489999 -1.37815 -1.37815 + 0.0424352 -1.36083 -1.36083 + 0.0424352 -1.36083 -1.36083 + 0.0424352 -1.36083 -1.36083 + 0.0424352 -1.36083 -1.36083 + 0.0424352 -1.36083 -1.36083 + 0.0424352 -1.36083 -1.36083 + 0.0424352 -1.36083 -1.36083 + 0.0424352 -1.36083 -1.36083 + 0.0245 -1.34815 -1.34814 + 0.0245 -1.34815 -1.34814 + 0.0245 -1.34815 -1.34814 + 0.0245 -1.34815 -1.34814 + 0 -1.3435 -1.3435 + 0 -1.3435 -1.3435 + 0 -1.3435 -1.3435 + 0 -1.3435 -1.3435 + 0 -1.3435 -1.3435 + 0 -1.3435 -1.3435 + 0 -1.3435 -1.3435 + 0 -1.3435 -1.3435 + -0.0245001 -1.34815 -1.34814 + -0.0245001 -1.34815 -1.34814 + -0.0245001 -1.34815 -1.34814 + -0.0245001 -1.34815 -1.34814 + -0.0424353 -1.36083 -1.36083 + -0.0424353 -1.36083 -1.36083 + -0.0424353 -1.36083 -1.36083 + -0.0424353 -1.36083 -1.36083 + -0.0424353 -1.36083 -1.36083 + -0.0424353 -1.36083 -1.36083 + -0.0424353 -1.36083 -1.36083 + -0.0424353 -1.36083 -1.36083 + -0.0490001 -1.37815 -1.37815 + -0.0490001 -1.37815 -1.37815 + -0.0490001 -1.37815 -1.37815 + -0.0490001 -1.37815 -1.37815 + -0.0490001 -1.37815 -1.37815 + -0.0424353 -1.39548 -1.39547 + -0.0424353 -1.39548 -1.39547 + -0.0424353 -1.39548 -1.39547 + -0.0424353 -1.39548 -1.39547 + -0.0424353 -1.39548 -1.39547 + -0.0424353 -1.39548 -1.39547 + -0.0245001 -1.40816 -1.40816 + -0.0245001 -1.40816 -1.40816 + -0.0245001 -1.40816 -1.40816 + -0.0245001 -1.40816 -1.40816 + -0.0245001 -1.40816 -1.40816 + -0.0245001 -1.40816 -1.40816 + -1.3113e-07 -1.21631 -1.58512 + -1.3113e-07 -1.21631 -1.58512 + -1.3113e-07 -1.21631 -1.58512 + -1.3113e-07 -1.21631 -1.58512 + -1.3113e-07 -1.21631 -1.58512 + -1.3113e-07 -1.21631 -1.58512 + 0.0245 -1.21231 -1.57991 + 0.0245 -1.21231 -1.57991 + 0.0245 -1.21231 -1.57991 + 0.0245 -1.21231 -1.57991 + 0.0245 -1.21231 -1.57991 + 0.0245 -1.21231 -1.57991 + 0.0424352 -1.20139 -1.56568 + 0.0424352 -1.20139 -1.56568 + 0.0424352 -1.20139 -1.56568 + 0.0424352 -1.20139 -1.56568 + 0.0424352 -1.20139 -1.56568 + 0.0424352 -1.20139 -1.56568 + 0.0489999 -1.18648 -1.54625 + 0.0489999 -1.18648 -1.54625 + 0.0489999 -1.18648 -1.54625 + 0.0489999 -1.18648 -1.54625 + 0.0489999 -1.18648 -1.54625 + 0.0489999 -1.18648 -1.54625 + 0.0424352 -1.17156 -1.52681 + 0.0424352 -1.17156 -1.52681 + 0.0424352 -1.17156 -1.52681 + 0.0424352 -1.17156 -1.52681 + 0.0424352 -1.17156 -1.52681 + 0.0424352 -1.17156 -1.52681 + 0.0245 -1.16064 -1.51258 + 0.0245 -1.16064 -1.51258 + 0.0245 -1.16064 -1.51258 + 0.0245 -1.16064 -1.51258 + 0.0245 -1.16064 -1.51258 + 0.0245 -1.16064 -1.51258 + -1.3113e-07 -1.15665 -1.50737 + -1.3113e-07 -1.15665 -1.50737 + -1.3113e-07 -1.15665 -1.50737 + -1.3113e-07 -1.15665 -1.50737 + -1.3113e-07 -1.15665 -1.50737 + -1.3113e-07 -1.15665 -1.50737 + -0.0245001 -1.16064 -1.51258 + -0.0245001 -1.16064 -1.51258 + -0.0245001 -1.16064 -1.51258 + -0.0245001 -1.16064 -1.51258 + -0.0245001 -1.16064 -1.51258 + -0.0245001 -1.16064 -1.51258 + -0.0424353 -1.17156 -1.52681 + -0.0424353 -1.17156 -1.52681 + -0.0424353 -1.17156 -1.52681 + -0.0424353 -1.17156 -1.52681 + -0.0424353 -1.17156 -1.52681 + -0.0424353 -1.17156 -1.52681 + -0.0490001 -1.18648 -1.54625 + -0.0490001 -1.18648 -1.54625 + -0.0490001 -1.18648 -1.54625 + -0.0490001 -1.18648 -1.54625 + -0.0490001 -1.18648 -1.54625 + -0.0490001 -1.18648 -1.54625 + -0.0424353 -1.20139 -1.56568 + -0.0424353 -1.20139 -1.56568 + -0.0424353 -1.20139 -1.56568 + -0.0424353 -1.20139 -1.56568 + -0.0424353 -1.20139 -1.56568 + -0.0424353 -1.20139 -1.56568 + -0.0245001 -1.21231 -1.57991 + -0.0245001 -1.21231 -1.57991 + -0.0245001 -1.21231 -1.57991 + -0.0245001 -1.21231 -1.57991 + -0.0245001 -1.21231 -1.57991 + -0.0245001 -1.21231 -1.57991 + -1.3113e-07 -0.999 -1.73032 + -1.3113e-07 -0.999 -1.73032 + -1.3113e-07 -0.999 -1.73032 + -1.3113e-07 -0.999 -1.73032 + -1.3113e-07 -0.999 -1.73032 + -1.3113e-07 -0.999 -1.73032 + 0.0245 -0.995718 -1.72463 + 0.0245 -0.995718 -1.72463 + 0.0245 -0.995718 -1.72463 + 0.0245 -0.995718 -1.72463 + 0.0245 -0.995718 -1.72463 + 0.0245 -0.995718 -1.72463 + 0.0424352 -0.98675 -1.7091 + 0.0424352 -0.98675 -1.7091 + 0.0424352 -0.98675 -1.7091 + 0.0424352 -0.98675 -1.7091 + 0.0424352 -0.98675 -1.7091 + 0.0424352 -0.98675 -1.7091 + 0.0489999 -0.9745 -1.68788 + 0.0489999 -0.9745 -1.68788 + 0.0489999 -0.9745 -1.68788 + 0.0489999 -0.9745 -1.68788 + 0.0489999 -0.9745 -1.68788 + 0.0489999 -0.9745 -1.68788 + 0.0489999 -0.9745 -1.68788 + 0.0424352 -0.96225 -1.66667 + 0.0424352 -0.96225 -1.66667 + 0.0424352 -0.96225 -1.66667 + 0.0424352 -0.96225 -1.66667 + 0.0424352 -0.96225 -1.66667 + 0.0245 -0.953282 -1.65113 + 0.0245 -0.953282 -1.65113 + 0.0245 -0.953282 -1.65113 + 0.0245 -0.953282 -1.65113 + 0.0245 -0.953282 -1.65113 + 0.0245 -0.953282 -1.65113 + -1.3113e-07 -0.95 -1.64545 + -1.3113e-07 -0.95 -1.64545 + -1.3113e-07 -0.95 -1.64545 + -1.3113e-07 -0.95 -1.64545 + -1.3113e-07 -0.95 -1.64545 + -1.3113e-07 -0.95 -1.64545 + -0.0245001 -0.953282 -1.65113 + -0.0245001 -0.953282 -1.65113 + -0.0245001 -0.953282 -1.65113 + -0.0245001 -0.953282 -1.65113 + -0.0245001 -0.953282 -1.65113 + -0.0245001 -0.953282 -1.65113 + -0.0424353 -0.96225 -1.66667 + -0.0424353 -0.96225 -1.66667 + -0.0424353 -0.96225 -1.66667 + -0.0424353 -0.96225 -1.66667 + -0.0424353 -0.96225 -1.66667 + -0.0490001 -0.9745 -1.68788 + -0.0490001 -0.9745 -1.68788 + -0.0490001 -0.9745 -1.68788 + -0.0490001 -0.9745 -1.68788 + -0.0490001 -0.9745 -1.68788 + -0.0490001 -0.9745 -1.68788 + -0.0490001 -0.9745 -1.68788 + -0.0424353 -0.98675 -1.7091 + -0.0424353 -0.98675 -1.7091 + -0.0424353 -0.98675 -1.7091 + -0.0424353 -0.98675 -1.7091 + -0.0424353 -0.98675 -1.7091 + -0.0424353 -0.98675 -1.7091 + -0.0245001 -0.995718 -1.72463 + -0.0245001 -0.995718 -1.72463 + -0.0245001 -0.995718 -1.72463 + -0.0245001 -0.995718 -1.72463 + -0.0245001 -0.995718 -1.72463 + -0.0245001 -0.995718 -1.72463 + -1.3113e-07 -0.764602 -1.84591 + -1.3113e-07 -0.764602 -1.84591 + -1.3113e-07 -0.764602 -1.84591 + -1.3113e-07 -0.764602 -1.84591 + -1.3113e-07 -0.764602 -1.84591 + -1.3113e-07 -0.764602 -1.84591 + 0.0245 -0.76209 -1.83985 + 0.0245 -0.76209 -1.83985 + 0.0245 -0.76209 -1.83985 + 0.0245 -0.76209 -1.83985 + 0.0245 -0.76209 -1.83985 + 0.0245 -0.76209 -1.83985 + 0.0424352 -0.755226 -1.82328 + 0.0424352 -0.755226 -1.82328 + 0.0424352 -0.755226 -1.82328 + 0.0424352 -0.755226 -1.82328 + 0.0424352 -0.755226 -1.82328 + 0.0424352 -0.755226 -1.82328 + 0.0489999 -0.745851 -1.80064 + 0.0489999 -0.745851 -1.80064 + 0.0489999 -0.745851 -1.80064 + 0.0489999 -0.745851 -1.80064 + 0.0489999 -0.745851 -1.80064 + 0.0489999 -0.745851 -1.80064 + 0.0424352 -0.736475 -1.77801 + 0.0424352 -0.736475 -1.77801 + 0.0424352 -0.736475 -1.77801 + 0.0424352 -0.736475 -1.77801 + 0.0424352 -0.736475 -1.77801 + 0.0245 -0.729611 -1.76144 + 0.0245 -0.729611 -1.76144 + 0.0245 -0.729611 -1.76144 + 0.0245 -0.729611 -1.76144 + 0.0245 -0.729611 -1.76144 + 0.0245 -0.729611 -1.76144 + 0.0245 -0.729611 -1.76144 + 0.0245 -0.729611 -1.76144 + -1.3113e-07 -0.727099 -1.75537 + -1.3113e-07 -0.727099 -1.75537 + -1.3113e-07 -0.727099 -1.75537 + -1.3113e-07 -0.727099 -1.75537 + -0.0245001 -0.729611 -1.76144 + -0.0245001 -0.729611 -1.76144 + -0.0245001 -0.729611 -1.76144 + -0.0245001 -0.729611 -1.76144 + -0.0245001 -0.729611 -1.76144 + -0.0245001 -0.729611 -1.76144 + -0.0245001 -0.729611 -1.76144 + -0.0245001 -0.729611 -1.76144 + -0.0424353 -0.736475 -1.77801 + -0.0424353 -0.736475 -1.77801 + -0.0424353 -0.736475 -1.77801 + -0.0424353 -0.736475 -1.77801 + -0.0424353 -0.736475 -1.77801 + -0.0490001 -0.745851 -1.80064 + -0.0490001 -0.745851 -1.80064 + -0.0490001 -0.745851 -1.80064 + -0.0490001 -0.745851 -1.80064 + -0.0490001 -0.745851 -1.80064 + -0.0490001 -0.745851 -1.80064 + -0.0424353 -0.755226 -1.82328 + -0.0424353 -0.755226 -1.82328 + -0.0424353 -0.755226 -1.82328 + -0.0424353 -0.755226 -1.82328 + -0.0424353 -0.755226 -1.82328 + -0.0424353 -0.755226 -1.82328 + -0.0245001 -0.76209 -1.83985 + -0.0245001 -0.76209 -1.83985 + -0.0245001 -0.76209 -1.83985 + -0.0245001 -0.76209 -1.83985 + -0.0245001 -0.76209 -1.83985 + -0.0245001 -0.76209 -1.83985 + -1.3113e-07 -0.51712 -1.92992 + -1.3113e-07 -0.51712 -1.92992 + -1.3113e-07 -0.51712 -1.92992 + -1.3113e-07 -0.51712 -1.92992 + -1.3113e-07 -0.51712 -1.92992 + -1.3113e-07 -0.51712 -1.92992 + 0.0245 -0.515421 -1.92358 + 0.0245 -0.515421 -1.92358 + 0.0245 -0.515421 -1.92358 + 0.0245 -0.515421 -1.92358 + 0.0245 -0.515421 -1.92358 + 0.0245 -0.515421 -1.92358 + 0.0424352 -0.510779 -1.90626 + 0.0424352 -0.510779 -1.90626 + 0.0424352 -0.510779 -1.90626 + 0.0424352 -0.510779 -1.90626 + 0.0424352 -0.510779 -1.90626 + 0.0424352 -0.510779 -1.90626 + 0.0489999 -0.504438 -1.88259 + 0.0489999 -0.504438 -1.88259 + 0.0489999 -0.504438 -1.88259 + 0.0489999 -0.504438 -1.88259 + 0.0489999 -0.504438 -1.88259 + 0.0489999 -0.504438 -1.88259 + 0.0424352 -0.498097 -1.85892 + 0.0424352 -0.498097 -1.85892 + 0.0424352 -0.498097 -1.85892 + 0.0424352 -0.498097 -1.85892 + 0.0424352 -0.498097 -1.85892 + 0.0424352 -0.498097 -1.85892 + 0.0245 -0.493455 -1.8416 + 0.0245 -0.493455 -1.8416 + 0.0245 -0.493455 -1.8416 + 0.0245 -0.493455 -1.8416 + 0.0245 -0.493455 -1.8416 + -1.3113e-07 -0.491756 -1.83526 + -1.3113e-07 -0.491756 -1.83526 + -1.3113e-07 -0.491756 -1.83526 + -1.3113e-07 -0.491756 -1.83526 + -1.3113e-07 -0.491756 -1.83526 + -1.3113e-07 -0.491756 -1.83526 + -1.3113e-07 -0.491756 -1.83526 + -1.3113e-07 -0.491756 -1.83526 + -0.0245001 -0.493455 -1.8416 + -0.0245001 -0.493455 -1.8416 + -0.0245001 -0.493455 -1.8416 + -0.0245001 -0.493455 -1.8416 + -0.0424353 -0.498097 -1.85892 + -0.0424353 -0.498097 -1.85892 + -0.0424353 -0.498097 -1.85892 + -0.0424353 -0.498097 -1.85892 + -0.0424353 -0.498097 -1.85892 + -0.0424353 -0.498097 -1.85892 + -0.0424353 -0.498097 -1.85892 + -0.0490001 -0.504438 -1.88259 + -0.0490001 -0.504438 -1.88259 + -0.0490001 -0.504438 -1.88259 + -0.0490001 -0.504438 -1.88259 + -0.0490001 -0.504438 -1.88259 + -0.0490001 -0.504438 -1.88259 + -0.0424353 -0.510779 -1.90626 + -0.0424353 -0.510779 -1.90626 + -0.0424353 -0.510779 -1.90626 + -0.0424353 -0.510779 -1.90626 + -0.0424353 -0.510779 -1.90626 + -0.0424353 -0.510779 -1.90626 + -0.0245001 -0.515421 -1.92358 + -0.0245001 -0.515421 -1.92358 + -0.0245001 -0.515421 -1.92358 + -0.0245001 -0.515421 -1.92358 + -0.0245001 -0.515421 -1.92358 + -0.0245001 -0.515421 -1.92358 + -1.3113e-07 -0.260791 -1.98091 + -1.3113e-07 -0.260791 -1.98091 + -1.3113e-07 -0.260791 -1.98091 + -1.3113e-07 -0.260791 -1.98091 + -1.3113e-07 -0.260791 -1.98091 + -1.3113e-07 -0.260791 -1.98091 + 0.0245 -0.259934 -1.9744 + 0.0245 -0.259934 -1.9744 + 0.0245 -0.259934 -1.9744 + 0.0245 -0.259934 -1.9744 + 0.0245 -0.259934 -1.9744 + 0.0245 -0.259934 -1.9744 + 0.0424352 -0.257593 -1.95662 + 0.0424352 -0.257593 -1.95662 + 0.0424352 -0.257593 -1.95662 + 0.0424352 -0.257593 -1.95662 + 0.0424352 -0.257593 -1.95662 + 0.0424352 -0.257593 -1.95662 + 0.0489999 -0.254395 -1.93233 + 0.0489999 -0.254395 -1.93233 + 0.0489999 -0.254395 -1.93233 + 0.0489999 -0.254395 -1.93233 + 0.0489999 -0.254395 -1.93233 + 0.0424352 -0.251198 -1.90804 + 0.0424352 -0.251198 -1.90804 + 0.0424352 -0.251198 -1.90804 + 0.0424352 -0.251198 -1.90804 + 0.0424352 -0.251198 -1.90804 + 0.0424352 -0.251198 -1.90804 + 0.0424352 -0.251198 -1.90804 + 0.0245 -0.248856 -1.89025 + 0.0245 -0.248856 -1.89025 + 0.0245 -0.248856 -1.89025 + 0.0245 -0.248856 -1.89025 + 0.0245 -0.248856 -1.89025 + 0.0245 -0.248856 -1.89025 + -1.3113e-07 -0.248 -1.88374 + -1.3113e-07 -0.248 -1.88374 + -1.3113e-07 -0.248 -1.88374 + -1.3113e-07 -0.248 -1.88374 + -1.3113e-07 -0.248 -1.88374 + -1.3113e-07 -0.248 -1.88374 + -0.0245001 -0.248856 -1.89025 + -0.0245001 -0.248856 -1.89025 + -0.0245001 -0.248856 -1.89025 + -0.0245001 -0.248856 -1.89025 + -0.0245001 -0.248856 -1.89025 + -0.0245001 -0.248856 -1.89025 + -0.0245001 -0.248856 -1.89025 + -0.0424353 -0.251198 -1.90804 + -0.0424353 -0.251198 -1.90804 + -0.0424353 -0.251198 -1.90804 + -0.0424353 -0.251198 -1.90804 + -0.0424353 -0.251198 -1.90804 + -0.0490001 -0.254395 -1.93233 + -0.0490001 -0.254395 -1.93233 + -0.0490001 -0.254395 -1.93233 + -0.0490001 -0.254395 -1.93233 + -0.0490001 -0.254395 -1.93233 + -0.0424353 -0.257593 -1.95662 + -0.0424353 -0.257593 -1.95662 + -0.0424353 -0.257593 -1.95662 + -0.0424353 -0.257593 -1.95662 + -0.0424353 -0.257593 -1.95662 + -0.0424353 -0.257593 -1.95662 + -0.0424353 -0.257593 -1.95662 + -0.0245001 -0.259934 -1.9744 + -0.0245001 -0.259934 -1.9744 + -0.0245001 -0.259934 -1.9744 + -0.0245001 -0.259934 -1.9744 + -0.0245001 -0.259934 -1.9744 + -0.0245001 -0.259934 -1.9744 + } + } + } + NormalArray TRUE { + osg::Vec3Array { + UniqueID 190 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 189 + } + } + Binding BIND_PER_VERTEX + vector 3456 { + -5.62054e-07 0 -1 + -5.62054e-07 0 -1 + -5.62054e-07 0 -1 + -5.62054e-07 0 -1 + -5.62054e-07 0 -1 + -5.62054e-07 0 -1 + -5.62054e-07 0 -1 + -5.62054e-07 0 -1 + 0.495383 0 -0.868675 + 0.495383 0 -0.868675 + 0.495383 0 -0.868675 + 0.495383 0 -0.868675 + 0.861355 0 -0.508004 + 0.861355 0 -0.508004 + 0.861355 0 -0.508004 + 0.861355 0 -0.508004 + 0.861355 0 -0.508004 + 0.861355 0 -0.508004 + 0.861355 0 -0.508004 + 0.999942 -1.4211e-07 -0.0107847 + 0.999942 -1.4211e-07 -0.0107847 + 0.999942 -1.4211e-07 -0.0107847 + 0.999942 -1.4211e-07 -0.0107847 + 0.999942 -1.4211e-07 -0.0107847 + 0.999942 -1.4211e-07 -0.0107847 + 0.870694 0 0.491826 + 0.870694 0 0.491826 + 0.870694 0 0.491826 + 0.870694 0 0.491826 + 0.870694 0 0.491826 + 0.870694 0 0.491826 + 0.870694 0 0.491826 + 0.504724 0 0.863281 + 0.504724 0 0.863281 + 0.504724 0 0.863281 + 0.504724 0 0.863281 + 0.504724 0 0.863281 + 0.504724 0 0.863281 + -6.91238e-07 0 1 + -6.91238e-07 0 1 + -6.91238e-07 0 1 + -6.91238e-07 0 1 + -0.504725 0 0.86328 + -0.504725 0 0.86328 + -0.504725 0 0.86328 + -0.504725 0 0.86328 + -0.504725 0 0.86328 + -0.504725 0 0.86328 + -0.870694 0 0.491826 + -0.870694 0 0.491826 + -0.870694 0 0.491826 + -0.870694 0 0.491826 + -0.870694 0 0.491826 + -0.870694 0 0.491826 + -0.870694 0 0.491826 + -0.999942 1.31367e-07 -0.0107847 + -0.999942 1.31367e-07 -0.0107847 + -0.999942 1.31367e-07 -0.0107847 + -0.999942 1.31367e-07 -0.0107847 + -0.999942 1.31367e-07 -0.0107847 + -0.999942 1.31367e-07 -0.0107847 + -0.861355 0 -0.508004 + -0.861355 0 -0.508004 + -0.861355 0 -0.508004 + -0.861355 0 -0.508004 + -0.861355 0 -0.508004 + -0.861355 0 -0.508004 + -0.861355 0 -0.508004 + -0.495384 0 -0.868674 + -0.495384 0 -0.868674 + -0.495384 0 -0.868674 + -0.495384 0 -0.868674 + -4.95218e-07 0.130526 -0.991445 + -4.95218e-07 0.130526 -0.991445 + -4.95218e-07 0.130526 -0.991445 + -4.95218e-07 0.130526 -0.991445 + -4.95218e-07 0.130526 -0.991445 + -4.95218e-07 0.130526 -0.991445 + 0.495391 0.113385 -0.861239 + 0.495391 0.113385 -0.861239 + 0.495391 0.113385 -0.861239 + 0.495391 0.113385 -0.861239 + 0.495391 0.113385 -0.861239 + 0.495391 0.113385 -0.861239 + 0.861357 0.0663076 -0.503654 + 0.861357 0.0663076 -0.503654 + 0.861357 0.0663076 -0.503654 + 0.861357 0.0663076 -0.503654 + 0.861357 0.0663076 -0.503654 + 0.861357 0.0663076 -0.503654 + 0.861357 0.0663076 -0.503654 + 0.999942 0.00140756 -0.0106912 + 0.999942 0.00140756 -0.0106912 + 0.999942 0.00140756 -0.0106912 + 0.999942 0.00140756 -0.0106912 + 0.999942 0.00140756 -0.0106912 + 0.999942 0.00140756 -0.0106912 + 0.870692 -0.0641963 0.487621 + 0.870692 -0.0641963 0.487621 + 0.870692 -0.0641963 0.487621 + 0.870692 -0.0641963 0.487621 + 0.504719 -0.112681 0.855898 + 0.504719 -0.112681 0.855898 + 0.504719 -0.112681 0.855898 + 0.504719 -0.112681 0.855898 + 0.504719 -0.112681 0.855898 + 0.504719 -0.112681 0.855898 + 0.504719 -0.112681 0.855898 + -4.13769e-07 -0.130526 0.991445 + -4.13769e-07 -0.130526 0.991445 + -4.13769e-07 -0.130526 0.991445 + -4.13769e-07 -0.130526 0.991445 + -4.13769e-07 -0.130526 0.991445 + -4.13769e-07 -0.130526 0.991445 + -0.50472 -0.112681 0.855898 + -0.50472 -0.112681 0.855898 + -0.50472 -0.112681 0.855898 + -0.50472 -0.112681 0.855898 + -0.50472 -0.112681 0.855898 + -0.50472 -0.112681 0.855898 + -0.50472 -0.112681 0.855898 + -0.870692 -0.0641964 0.487621 + -0.870692 -0.0641964 0.487621 + -0.870692 -0.0641964 0.487621 + -0.870692 -0.0641964 0.487621 + -0.870692 -0.0641964 0.487621 + -0.999942 0.00140744 -0.0106899 + -0.999942 0.00140744 -0.0106899 + -0.999942 0.00140744 -0.0106899 + -0.999942 0.00140744 -0.0106899 + -0.999942 0.00140744 -0.0106899 + -0.999942 0.00140744 -0.0106899 + -0.861358 0.0663075 -0.503653 + -0.861358 0.0663075 -0.503653 + -0.861358 0.0663075 -0.503653 + -0.861358 0.0663075 -0.503653 + -0.861358 0.0663075 -0.503653 + -0.861358 0.0663075 -0.503653 + -0.495391 0.113384 -0.861238 + -0.495391 0.113384 -0.861238 + -0.495391 0.113384 -0.861238 + -0.495391 0.113384 -0.861238 + -0.495391 0.113384 -0.861238 + -0.495391 0.113384 -0.861238 + -2.8451e-06 0.258819 -0.965926 + -2.8451e-06 0.258819 -0.965926 + -2.8451e-06 0.258819 -0.965926 + -2.8451e-06 0.258819 -0.965926 + 0.49539 0.224828 -0.839071 + 0.49539 0.224828 -0.839071 + 0.49539 0.224828 -0.839071 + 0.49539 0.224828 -0.839071 + 0.49539 0.224828 -0.839071 + 0.49539 0.224828 -0.839071 + 0.49539 0.224828 -0.839071 + 0.49539 0.224828 -0.839071 + 0.861358 0.13148 -0.490689 + 0.861358 0.13148 -0.490689 + 0.861358 0.13148 -0.490689 + 0.861358 0.13148 -0.490689 + 0.861358 0.13148 -0.490689 + 0.999942 0.00279063 -0.010415 + 0.999942 0.00279063 -0.010415 + 0.999942 0.00279063 -0.010415 + 0.999942 0.00279063 -0.010415 + 0.999942 0.00279063 -0.010415 + 0.999942 0.00279063 -0.010415 + 0.870694 -0.127294 0.475066 + 0.870694 -0.127294 0.475066 + 0.870694 -0.127294 0.475066 + 0.870694 -0.127294 0.475066 + 0.870694 -0.127294 0.475066 + 0.870694 -0.127294 0.475066 + 0.504727 -0.223433 0.833864 + 0.504727 -0.223433 0.833864 + 0.504727 -0.223433 0.833864 + 0.504727 -0.223433 0.833864 + 0.504727 -0.223433 0.833864 + 0.504727 -0.223433 0.833864 + -2.26843e-06 -0.258819 0.965926 + -2.26843e-06 -0.258819 0.965926 + -2.26843e-06 -0.258819 0.965926 + -2.26843e-06 -0.258819 0.965926 + -2.26843e-06 -0.258819 0.965926 + -2.26843e-06 -0.258819 0.965926 + -0.504729 -0.223433 0.833863 + -0.504729 -0.223433 0.833863 + -0.504729 -0.223433 0.833863 + -0.504729 -0.223433 0.833863 + -0.504729 -0.223433 0.833863 + -0.504729 -0.223433 0.833863 + -0.870694 -0.127294 0.475066 + -0.870694 -0.127294 0.475066 + -0.870694 -0.127294 0.475066 + -0.870694 -0.127294 0.475066 + -0.870694 -0.127294 0.475066 + -0.870694 -0.127294 0.475066 + -0.999942 0.00279051 -0.0104149 + -0.999942 0.00279051 -0.0104149 + -0.999942 0.00279051 -0.0104149 + -0.999942 0.00279051 -0.0104149 + -0.999942 0.00279051 -0.0104149 + -0.999942 0.00279051 -0.0104149 + -0.861358 0.13148 -0.490689 + -0.861358 0.13148 -0.490689 + -0.861358 0.13148 -0.490689 + -0.861358 0.13148 -0.490689 + -0.861358 0.13148 -0.490689 + -0.495393 0.224828 -0.83907 + -0.495393 0.224828 -0.83907 + -0.495393 0.224828 -0.83907 + -0.495393 0.224828 -0.83907 + -0.495393 0.224828 -0.83907 + -0.495393 0.224828 -0.83907 + -0.495393 0.224828 -0.83907 + -0.495393 0.224828 -0.83907 + -7.72205e-07 0.382683 -0.92388 + -7.72205e-07 0.382683 -0.92388 + -7.72205e-07 0.382683 -0.92388 + -7.72205e-07 0.382683 -0.92388 + -7.72205e-07 0.382683 -0.92388 + -7.72205e-07 0.382683 -0.92388 + -7.72205e-07 0.382683 -0.92388 + -7.72205e-07 0.382683 -0.92388 + 0.495389 0.332426 -0.802548 + 0.495389 0.332426 -0.802548 + 0.495389 0.332426 -0.802548 + 0.495389 0.332426 -0.802548 + 0.861356 0.194404 -0.469332 + 0.861356 0.194404 -0.469332 + 0.861356 0.194404 -0.469332 + 0.861356 0.194404 -0.469332 + 0.861356 0.194404 -0.469332 + 0.861356 0.194404 -0.469332 + 0.861356 0.194404 -0.469332 + 0.999942 0.00412673 -0.0099628 + 0.999942 0.00412673 -0.0099628 + 0.999942 0.00412673 -0.0099628 + 0.999942 0.00412673 -0.0099628 + 0.999942 0.00412673 -0.0099628 + 0.870693 -0.188214 0.454389 + 0.870693 -0.188214 0.454389 + 0.870693 -0.188214 0.454389 + 0.870693 -0.188214 0.454389 + 0.870693 -0.188214 0.454389 + 0.870693 -0.188214 0.454389 + 0.870693 -0.188214 0.454389 + 0.504722 -0.330364 0.797569 + 0.504722 -0.330364 0.797569 + 0.504722 -0.330364 0.797569 + 0.504722 -0.330364 0.797569 + 0.504722 -0.330364 0.797569 + -4.66921e-06 -0.382683 0.92388 + -4.66921e-06 -0.382683 0.92388 + -4.66921e-06 -0.382683 0.92388 + -4.66921e-06 -0.382683 0.92388 + -4.66921e-06 -0.382683 0.92388 + -4.66921e-06 -0.382683 0.92388 + -4.66921e-06 -0.382683 0.92388 + -0.504726 -0.330363 0.797566 + -0.504726 -0.330363 0.797566 + -0.504726 -0.330363 0.797566 + -0.504726 -0.330363 0.797566 + -0.504726 -0.330363 0.797566 + -0.504726 -0.330363 0.797566 + -0.870693 -0.188214 0.454389 + -0.870693 -0.188214 0.454389 + -0.870693 -0.188214 0.454389 + -0.870693 -0.188214 0.454389 + -0.870693 -0.188214 0.454389 + -0.870693 -0.188214 0.454389 + -0.999942 0.00412673 -0.0099628 + -0.999942 0.00412673 -0.0099628 + -0.999942 0.00412673 -0.0099628 + -0.999942 0.00412673 -0.0099628 + -0.999942 0.00412673 -0.0099628 + -0.999942 0.00412673 -0.0099628 + -0.861356 0.194404 -0.469333 + -0.861356 0.194404 -0.469333 + -0.861356 0.194404 -0.469333 + -0.861356 0.194404 -0.469333 + -0.861356 0.194404 -0.469333 + -0.861356 0.194404 -0.469333 + -0.861356 0.194404 -0.469333 + -0.49539 0.332426 -0.802547 + -0.49539 0.332426 -0.802547 + -0.49539 0.332426 -0.802547 + -0.49539 0.332426 -0.802547 + -1.45798e-06 0.5 -0.866025 + -1.45798e-06 0.5 -0.866025 + -1.45798e-06 0.5 -0.866025 + -1.45798e-06 0.5 -0.866025 + -1.45798e-06 0.5 -0.866025 + -1.45798e-06 0.5 -0.866025 + 0.495385 0.434337 -0.752294 + 0.495385 0.434337 -0.752294 + 0.495385 0.434337 -0.752294 + 0.495385 0.434337 -0.752294 + 0.495385 0.434337 -0.752294 + 0.495385 0.434337 -0.752294 + 0.861358 0.254 -0.43994 + 0.861358 0.254 -0.43994 + 0.861358 0.254 -0.43994 + 0.861358 0.254 -0.43994 + 0.861358 0.254 -0.43994 + 0.861358 0.254 -0.43994 + 0.999942 0.0053913 -0.00933802 + 0.999942 0.0053913 -0.00933802 + 0.999942 0.0053913 -0.00933802 + 0.999942 0.0053913 -0.00933802 + 0.999942 0.0053913 -0.00933802 + 0.999942 0.0053913 -0.00933802 + 0.999942 0.0053913 -0.00933802 + 0.870694 -0.245913 0.425934 + 0.870694 -0.245913 0.425934 + 0.870694 -0.245913 0.425934 + 0.870694 -0.245913 0.425934 + 0.870694 -0.245913 0.425934 + 0.504725 -0.43164 0.747622 + 0.504725 -0.43164 0.747622 + 0.504725 -0.43164 0.747622 + 0.504725 -0.43164 0.747622 + 0.504725 -0.43164 0.747622 + 0.504725 -0.43164 0.747622 + 0.504725 -0.43164 0.747622 + 1.2267e-06 -0.5 0.866025 + 1.2267e-06 -0.5 0.866025 + 1.2267e-06 -0.5 0.866025 + 1.2267e-06 -0.5 0.866025 + 1.2267e-06 -0.5 0.866025 + -0.504723 -0.431641 0.747623 + -0.504723 -0.431641 0.747623 + -0.504723 -0.431641 0.747623 + -0.504723 -0.431641 0.747623 + -0.504723 -0.431641 0.747623 + -0.504723 -0.431641 0.747623 + -0.870694 -0.245913 0.425934 + -0.870694 -0.245913 0.425934 + -0.870694 -0.245913 0.425934 + -0.870694 -0.245913 0.425934 + -0.870694 -0.245913 0.425934 + -0.870694 -0.245913 0.425934 + -0.999942 0.0053916 -0.0093385 + -0.999942 0.0053916 -0.0093385 + -0.999942 0.0053916 -0.0093385 + -0.999942 0.0053916 -0.0093385 + -0.999942 0.0053916 -0.0093385 + -0.999942 0.0053916 -0.0093385 + -0.861358 0.254 -0.43994 + -0.861358 0.254 -0.43994 + -0.861358 0.254 -0.43994 + -0.861358 0.254 -0.43994 + -0.861358 0.254 -0.43994 + -0.861358 0.254 -0.43994 + -0.495386 0.434336 -0.752293 + -0.495386 0.434336 -0.752293 + -0.495386 0.434336 -0.752293 + -0.495386 0.434336 -0.752293 + -0.495386 0.434336 -0.752293 + -0.495386 0.434336 -0.752293 + -9.0246e-07 0.608761 -0.793354 + -9.0246e-07 0.608761 -0.793354 + -9.0246e-07 0.608761 -0.793354 + -9.0246e-07 0.608761 -0.793354 + -9.0246e-07 0.608761 -0.793354 + -9.0246e-07 0.608761 -0.793354 + 0.495391 0.528813 -0.689163 + 0.495391 0.528813 -0.689163 + 0.495391 0.528813 -0.689163 + 0.495391 0.528813 -0.689163 + 0.495391 0.528813 -0.689163 + 0.495391 0.528813 -0.689163 + 0.861357 0.309251 -0.403023 + 0.861357 0.309251 -0.403023 + 0.861357 0.309251 -0.403023 + 0.861357 0.309251 -0.403023 + 0.861357 0.309251 -0.403023 + 0.861357 0.309251 -0.403023 + 0.999942 0.00656474 -0.00855535 + 0.999942 0.00656474 -0.00855535 + 0.999942 0.00656474 -0.00855535 + 0.999942 0.00656474 -0.00855535 + 0.999942 0.00656474 -0.00855535 + 0.999942 0.00656474 -0.00855535 + 0.870695 -0.299404 0.390191 + 0.870695 -0.299404 0.390191 + 0.870695 -0.299404 0.390191 + 0.870695 -0.299404 0.390191 + 0.870695 -0.299404 0.390191 + 0.870695 -0.299404 0.390191 + 0.504726 -0.525532 0.684885 + 0.504726 -0.525532 0.684885 + 0.504726 -0.525532 0.684885 + 0.504726 -0.525532 0.684885 + 0.504726 -0.525532 0.684885 + 0.504726 -0.525532 0.684885 + 5.5007e-07 -0.608762 0.793353 + 5.5007e-07 -0.608762 0.793353 + 5.5007e-07 -0.608762 0.793353 + 5.5007e-07 -0.608762 0.793353 + 5.5007e-07 -0.608762 0.793353 + 5.5007e-07 -0.608762 0.793353 + -0.504726 -0.525532 0.684886 + -0.504726 -0.525532 0.684886 + -0.504726 -0.525532 0.684886 + -0.504726 -0.525532 0.684886 + -0.504726 -0.525532 0.684886 + -0.504726 -0.525532 0.684886 + -0.870694 -0.299404 0.390191 + -0.870694 -0.299404 0.390191 + -0.870694 -0.299404 0.390191 + -0.870694 -0.299404 0.390191 + -0.870694 -0.299404 0.390191 + -0.870694 -0.299404 0.390191 + -0.999942 0.00656432 -0.008555 + -0.999942 0.00656432 -0.008555 + -0.999942 0.00656432 -0.008555 + -0.999942 0.00656432 -0.008555 + -0.999942 0.00656432 -0.008555 + -0.999942 0.00656432 -0.008555 + -0.861357 0.309251 -0.403023 + -0.861357 0.309251 -0.403023 + -0.861357 0.309251 -0.403023 + -0.861357 0.309251 -0.403023 + -0.861357 0.309251 -0.403023 + -0.861357 0.309251 -0.403023 + -0.495391 0.528813 -0.689162 + -0.495391 0.528813 -0.689162 + -0.495391 0.528813 -0.689162 + -0.495391 0.528813 -0.689162 + -0.495391 0.528813 -0.689162 + -0.495391 0.528813 -0.689162 + 6.71482e-07 0.707107 -0.707106 + 6.71482e-07 0.707107 -0.707106 + 6.71482e-07 0.707107 -0.707106 + 6.71482e-07 0.707107 -0.707106 + 0.495389 0.614243 -0.614244 + 0.495389 0.614243 -0.614244 + 0.495389 0.614243 -0.614244 + 0.495389 0.614243 -0.614244 + 0.495389 0.614243 -0.614244 + 0.495389 0.614243 -0.614244 + 0.495389 0.614243 -0.614244 + 0.861356 0.359211 -0.359211 + 0.861356 0.359211 -0.359211 + 0.861356 0.359211 -0.359211 + 0.861356 0.359211 -0.359211 + 0.861356 0.359211 -0.359211 + 0.861356 0.359211 -0.359211 + 0.999942 0.00762552 -0.00762558 + 0.999942 0.00762552 -0.00762558 + 0.999942 0.00762552 -0.00762558 + 0.999942 0.00762552 -0.00762558 + 0.999942 0.00762552 -0.00762558 + 0.870694 -0.347773 0.347773 + 0.870694 -0.347773 0.347773 + 0.870694 -0.347773 0.347773 + 0.870694 -0.347773 0.347773 + 0.870694 -0.347773 0.347773 + 0.870694 -0.347773 0.347773 + 0.870694 -0.347773 0.347773 + 0.870694 -0.347773 0.347773 + 0.504729 -0.61043 0.61043 + 0.504729 -0.61043 0.61043 + 0.504729 -0.61043 0.61043 + 0.504729 -0.61043 0.61043 + 0.504729 -0.61043 0.61043 + -2.92073e-07 -0.707106 0.707107 + -2.92073e-07 -0.707106 0.707107 + -2.92073e-07 -0.707106 0.707107 + -2.92073e-07 -0.707106 0.707107 + -2.92073e-07 -0.707106 0.707107 + -2.92073e-07 -0.707106 0.707107 + -0.504728 -0.61043 0.61043 + -0.504728 -0.61043 0.61043 + -0.504728 -0.61043 0.61043 + -0.504728 -0.61043 0.61043 + -0.504728 -0.61043 0.61043 + -0.870694 -0.347773 0.347773 + -0.870694 -0.347773 0.347773 + -0.870694 -0.347773 0.347773 + -0.870694 -0.347773 0.347773 + -0.870694 -0.347773 0.347773 + -0.870694 -0.347773 0.347773 + -0.870694 -0.347773 0.347773 + -0.870694 -0.347773 0.347773 + -0.999942 0.0076257 -0.00762558 + -0.999942 0.0076257 -0.00762558 + -0.999942 0.0076257 -0.00762558 + -0.999942 0.0076257 -0.00762558 + -0.999942 0.0076257 -0.00762558 + -0.861357 0.359211 -0.359211 + -0.861357 0.359211 -0.359211 + -0.861357 0.359211 -0.359211 + -0.861357 0.359211 -0.359211 + -0.861357 0.359211 -0.359211 + -0.861357 0.359211 -0.359211 + -0.495389 0.614244 -0.614243 + -0.495389 0.614244 -0.614243 + -0.495389 0.614244 -0.614243 + -0.495389 0.614244 -0.614243 + -0.495389 0.614244 -0.614243 + -0.495389 0.614244 -0.614243 + -0.495389 0.614244 -0.614243 + 1.19872e-06 0.793353 -0.608762 + 1.19872e-06 0.793353 -0.608762 + 1.19872e-06 0.793353 -0.608762 + 1.19872e-06 0.793353 -0.608762 + 1.19872e-06 0.793353 -0.608762 + 1.19872e-06 0.793353 -0.608762 + 0.495388 0.689164 -0.528814 + 0.495388 0.689164 -0.528814 + 0.495388 0.689164 -0.528814 + 0.495388 0.689164 -0.528814 + 0.495388 0.689164 -0.528814 + 0.495388 0.689164 -0.528814 + 0.495388 0.689164 -0.528814 + 0.861357 0.403024 -0.309251 + 0.861357 0.403024 -0.309251 + 0.861357 0.403024 -0.309251 + 0.861357 0.403024 -0.309251 + 0.999942 0.00855511 -0.0065645 + 0.999942 0.00855511 -0.0065645 + 0.999942 0.00855511 -0.0065645 + 0.999942 0.00855511 -0.0065645 + 0.999942 0.00855511 -0.0065645 + 0.999942 0.00855511 -0.0065645 + 0.999942 0.00855511 -0.0065645 + 0.870693 -0.390193 0.299405 + 0.870693 -0.390193 0.299405 + 0.870693 -0.390193 0.299405 + 0.870693 -0.390193 0.299405 + 0.870693 -0.390193 0.299405 + 0.870693 -0.390193 0.299405 + 0.504726 -0.684886 0.525531 + 0.504726 -0.684886 0.525531 + 0.504726 -0.684886 0.525531 + 0.504726 -0.684886 0.525531 + 0.504726 -0.684886 0.525531 + 6.87284e-07 -0.793353 0.608761 + 6.87284e-07 -0.793353 0.608761 + 6.87284e-07 -0.793353 0.608761 + 6.87284e-07 -0.793353 0.608761 + 6.87284e-07 -0.793353 0.608761 + 6.87284e-07 -0.793353 0.608761 + 6.87284e-07 -0.793353 0.608761 + 6.87284e-07 -0.793353 0.608761 + -0.504725 -0.684886 0.525532 + -0.504725 -0.684886 0.525532 + -0.504725 -0.684886 0.525532 + -0.504725 -0.684886 0.525532 + -0.504725 -0.684886 0.525532 + -0.870692 -0.390193 0.299406 + -0.870692 -0.390193 0.299406 + -0.870692 -0.390193 0.299406 + -0.870692 -0.390193 0.299406 + -0.870692 -0.390193 0.299406 + -0.870692 -0.390193 0.299406 + -0.999942 0.00855559 -0.00656468 + -0.999942 0.00855559 -0.00656468 + -0.999942 0.00855559 -0.00656468 + -0.999942 0.00855559 -0.00656468 + -0.999942 0.00855559 -0.00656468 + -0.999942 0.00855559 -0.00656468 + -0.861356 0.403024 -0.309251 + -0.861356 0.403024 -0.309251 + -0.861356 0.403024 -0.309251 + -0.861356 0.403024 -0.309251 + -0.861356 0.403024 -0.309251 + -0.495387 0.689164 -0.528814 + -0.495387 0.689164 -0.528814 + -0.495387 0.689164 -0.528814 + -0.495387 0.689164 -0.528814 + -0.495387 0.689164 -0.528814 + -0.495387 0.689164 -0.528814 + -0.495387 0.689164 -0.528814 + -2.7854e-07 0.866025 -0.5 + -2.7854e-07 0.866025 -0.5 + -2.7854e-07 0.866025 -0.5 + -2.7854e-07 0.866025 -0.5 + -2.7854e-07 0.866025 -0.5 + -2.7854e-07 0.866025 -0.5 + 0.495388 0.752292 -0.434336 + 0.495388 0.752292 -0.434336 + 0.495388 0.752292 -0.434336 + 0.495388 0.752292 -0.434336 + 0.495388 0.752292 -0.434336 + 0.861358 0.439941 -0.254 + 0.861358 0.439941 -0.254 + 0.861358 0.439941 -0.254 + 0.861358 0.439941 -0.254 + 0.861358 0.439941 -0.254 + 0.861358 0.439941 -0.254 + 0.861358 0.439941 -0.254 + 0.861358 0.439941 -0.254 + 0.999942 0.00933743 -0.00539082 + 0.999942 0.00933743 -0.00539082 + 0.999942 0.00933743 -0.00539082 + 0.999942 0.00933743 -0.00539082 + 0.999942 0.00933743 -0.00539082 + 0.870693 -0.425934 0.245913 + 0.870693 -0.425934 0.245913 + 0.870693 -0.425934 0.245913 + 0.870693 -0.425934 0.245913 + 0.870693 -0.425934 0.245913 + 0.870693 -0.425934 0.245913 + 0.504724 -0.747623 0.43164 + 0.504724 -0.747623 0.43164 + 0.504724 -0.747623 0.43164 + 0.504724 -0.747623 0.43164 + 0.504724 -0.747623 0.43164 + 0.504724 -0.747623 0.43164 + -1.60336e-07 -0.866025 0.5 + -1.60336e-07 -0.866025 0.5 + -1.60336e-07 -0.866025 0.5 + -1.60336e-07 -0.866025 0.5 + -1.60336e-07 -0.866025 0.5 + -1.60336e-07 -0.866025 0.5 + -0.504724 -0.747623 0.431641 + -0.504724 -0.747623 0.431641 + -0.504724 -0.747623 0.431641 + -0.504724 -0.747623 0.431641 + -0.504724 -0.747623 0.431641 + -0.504724 -0.747623 0.431641 + -0.870694 -0.425934 0.245913 + -0.870694 -0.425934 0.245913 + -0.870694 -0.425934 0.245913 + -0.870694 -0.425934 0.245913 + -0.870694 -0.425934 0.245913 + -0.870694 -0.425934 0.245913 + -0.999942 0.00933731 -0.00539076 + -0.999942 0.00933731 -0.00539076 + -0.999942 0.00933731 -0.00539076 + -0.999942 0.00933731 -0.00539076 + -0.999942 0.00933731 -0.00539076 + -0.999942 0.00933731 -0.00539076 + -0.861358 0.43994 -0.253999 + -0.861358 0.43994 -0.253999 + -0.861358 0.43994 -0.253999 + -0.861358 0.43994 -0.253999 + -0.861358 0.43994 -0.253999 + -0.861358 0.43994 -0.253999 + -0.861358 0.43994 -0.253999 + -0.495388 0.752292 -0.434336 + -0.495388 0.752292 -0.434336 + -0.495388 0.752292 -0.434336 + -0.495388 0.752292 -0.434336 + -0.495388 0.752292 -0.434336 + -6.11794e-07 0.92388 -0.382684 + -6.11794e-07 0.92388 -0.382684 + -6.11794e-07 0.92388 -0.382684 + -6.11794e-07 0.92388 -0.382684 + -6.11794e-07 0.92388 -0.382684 + -6.11794e-07 0.92388 -0.382684 + 0.495387 0.802549 -0.332427 + 0.495387 0.802549 -0.332427 + 0.495387 0.802549 -0.332427 + 0.495387 0.802549 -0.332427 + 0.495387 0.802549 -0.332427 + 0.495387 0.802549 -0.332427 + 0.861357 0.469331 -0.194403 + 0.861357 0.469331 -0.194403 + 0.861357 0.469331 -0.194403 + 0.861357 0.469331 -0.194403 + 0.861357 0.469331 -0.194403 + 0.861357 0.469331 -0.194403 + 0.999942 0.00996113 -0.00412613 + 0.999942 0.00996113 -0.00412613 + 0.999942 0.00996113 -0.00412613 + 0.999942 0.00996113 -0.00412613 + 0.999942 0.00996113 -0.00412613 + 0.999942 0.00996113 -0.00412613 + 0.870694 -0.454388 0.188213 + 0.870694 -0.454388 0.188213 + 0.870694 -0.454388 0.188213 + 0.870694 -0.454388 0.188213 + 0.870694 -0.454388 0.188213 + 0.870694 -0.454388 0.188213 + 0.504727 -0.797566 0.330363 + 0.504727 -0.797566 0.330363 + 0.504727 -0.797566 0.330363 + 0.504727 -0.797566 0.330363 + 0.504727 -0.797566 0.330363 + 0.504727 -0.797566 0.330363 + 6.24914e-07 -0.92388 0.382683 + 6.24914e-07 -0.92388 0.382683 + 6.24914e-07 -0.92388 0.382683 + 6.24914e-07 -0.92388 0.382683 + 6.24914e-07 -0.92388 0.382683 + 6.24914e-07 -0.92388 0.382683 + -0.504726 -0.797566 0.330363 + -0.504726 -0.797566 0.330363 + -0.504726 -0.797566 0.330363 + -0.504726 -0.797566 0.330363 + -0.504726 -0.797566 0.330363 + -0.504726 -0.797566 0.330363 + -0.870694 -0.454388 0.188214 + -0.870694 -0.454388 0.188214 + -0.870694 -0.454388 0.188214 + -0.870694 -0.454388 0.188214 + -0.870694 -0.454388 0.188214 + -0.870694 -0.454388 0.188214 + -0.999942 0.00996119 -0.00412613 + -0.999942 0.00996119 -0.00412613 + -0.999942 0.00996119 -0.00412613 + -0.999942 0.00996119 -0.00412613 + -0.999942 0.00996119 -0.00412613 + -0.999942 0.00996119 -0.00412613 + -0.861357 0.469331 -0.194403 + -0.861357 0.469331 -0.194403 + -0.861357 0.469331 -0.194403 + -0.861357 0.469331 -0.194403 + -0.861357 0.469331 -0.194403 + -0.861357 0.469331 -0.194403 + -0.495388 0.802548 -0.332427 + -0.495388 0.802548 -0.332427 + -0.495388 0.802548 -0.332427 + -0.495388 0.802548 -0.332427 + -0.495388 0.802548 -0.332427 + -0.495388 0.802548 -0.332427 + -3.08384e-07 0.965926 -0.258819 + -3.08384e-07 0.965926 -0.258819 + -3.08384e-07 0.965926 -0.258819 + -3.08384e-07 0.965926 -0.258819 + -3.08384e-07 0.965926 -0.258819 + -3.08384e-07 0.965926 -0.258819 + 0.495389 0.839072 -0.224829 + 0.495389 0.839072 -0.224829 + 0.495389 0.839072 -0.224829 + 0.495389 0.839072 -0.224829 + 0.495389 0.839072 -0.224829 + 0.495389 0.839072 -0.224829 + 0.495389 0.839072 -0.224829 + 0.861357 0.49069 -0.13148 + 0.861357 0.49069 -0.13148 + 0.861357 0.49069 -0.13148 + 0.861357 0.49069 -0.13148 + 0.999942 0.0104151 -0.00279075 + 0.999942 0.0104151 -0.00279075 + 0.999942 0.0104151 -0.00279075 + 0.999942 0.0104151 -0.00279075 + 0.999942 0.0104151 -0.00279075 + 0.999942 0.0104151 -0.00279075 + 0.999942 0.0104151 -0.00279075 + 0.870693 -0.475069 0.127294 + 0.870693 -0.475069 0.127294 + 0.870693 -0.475069 0.127294 + 0.870693 -0.475069 0.127294 + 0.870693 -0.475069 0.127294 + 0.504724 -0.833865 0.223434 + 0.504724 -0.833865 0.223434 + 0.504724 -0.833865 0.223434 + 0.504724 -0.833865 0.223434 + 0.504724 -0.833865 0.223434 + 0.504724 -0.833865 0.223434 + 0.504724 -0.833865 0.223434 + -1.85892e-07 -0.965926 0.25882 + -1.85892e-07 -0.965926 0.25882 + -1.85892e-07 -0.965926 0.25882 + -1.85892e-07 -0.965926 0.25882 + -1.85892e-07 -0.965926 0.25882 + -1.85892e-07 -0.965926 0.25882 + -0.504724 -0.833865 0.223434 + -0.504724 -0.833865 0.223434 + -0.504724 -0.833865 0.223434 + -0.504724 -0.833865 0.223434 + -0.504724 -0.833865 0.223434 + -0.504724 -0.833865 0.223434 + -0.504724 -0.833865 0.223434 + -0.870693 -0.475069 0.127294 + -0.870693 -0.475069 0.127294 + -0.870693 -0.475069 0.127294 + -0.870693 -0.475069 0.127294 + -0.870693 -0.475069 0.127294 + -0.999942 0.0104157 -0.00279081 + -0.999942 0.0104157 -0.00279081 + -0.999942 0.0104157 -0.00279081 + -0.999942 0.0104157 -0.00279081 + -0.999942 0.0104157 -0.00279081 + -0.999942 0.0104157 -0.00279081 + -0.999942 0.0104157 -0.00279081 + -0.861357 0.490691 -0.13148 + -0.861357 0.490691 -0.13148 + -0.861357 0.490691 -0.13148 + -0.861357 0.490691 -0.13148 + -0.495389 0.839072 -0.224828 + -0.495389 0.839072 -0.224828 + -0.495389 0.839072 -0.224828 + -0.495389 0.839072 -0.224828 + -0.495389 0.839072 -0.224828 + -0.495389 0.839072 -0.224828 + -0.495389 0.839072 -0.224828 + -1.19374e-07 0.991445 -0.130526 + -1.19374e-07 0.991445 -0.130526 + -1.19374e-07 0.991445 -0.130526 + -1.19374e-07 0.991445 -0.130526 + -1.19374e-07 0.991445 -0.130526 + -1.19374e-07 0.991445 -0.130526 + 0.495389 0.86124 -0.113385 + 0.495389 0.86124 -0.113385 + 0.495389 0.86124 -0.113385 + 0.495389 0.86124 -0.113385 + 0.495389 0.86124 -0.113385 + 0.495389 0.86124 -0.113385 + 0.861358 0.503653 -0.0663072 + 0.861358 0.503653 -0.0663072 + 0.861358 0.503653 -0.0663072 + 0.861358 0.503653 -0.0663072 + 0.861358 0.503653 -0.0663072 + 0.861358 0.503653 -0.0663072 + 0.999942 0.0106906 -0.00140744 + 0.999942 0.0106906 -0.00140744 + 0.999942 0.0106906 -0.00140744 + 0.999942 0.0106906 -0.00140744 + 0.999942 0.0106906 -0.00140744 + 0.999942 0.0106906 -0.00140744 + 0.999942 0.0106906 -0.00140744 + 0.870692 -0.48762 0.0641965 + 0.870692 -0.48762 0.0641965 + 0.870692 -0.48762 0.0641965 + 0.870692 -0.48762 0.0641965 + 0.870692 -0.48762 0.0641965 + 0.504722 -0.855897 0.112681 + 0.504722 -0.855897 0.112681 + 0.504722 -0.855897 0.112681 + 0.504722 -0.855897 0.112681 + 0.504722 -0.855897 0.112681 + 0.504722 -0.855897 0.112681 + 0 -0.991445 0.130527 + 0 -0.991445 0.130527 + 0 -0.991445 0.130527 + 0 -0.991445 0.130527 + 0 -0.991445 0.130527 + 0 -0.991445 0.130527 + -0.504722 -0.855896 0.112682 + -0.504722 -0.855896 0.112682 + -0.504722 -0.855896 0.112682 + -0.504722 -0.855896 0.112682 + -0.504722 -0.855896 0.112682 + -0.504722 -0.855896 0.112682 + -0.870692 -0.48762 0.0641966 + -0.870692 -0.48762 0.0641966 + -0.870692 -0.48762 0.0641966 + -0.870692 -0.48762 0.0641966 + -0.870692 -0.48762 0.0641966 + -0.999942 0.0106907 -0.00140744 + -0.999942 0.0106907 -0.00140744 + -0.999942 0.0106907 -0.00140744 + -0.999942 0.0106907 -0.00140744 + -0.999942 0.0106907 -0.00140744 + -0.999942 0.0106907 -0.00140744 + -0.861358 0.503653 -0.0663072 + -0.861358 0.503653 -0.0663072 + -0.861358 0.503653 -0.0663072 + -0.861358 0.503653 -0.0663072 + -0.861358 0.503653 -0.0663072 + -0.861358 0.503653 -0.0663072 + -0.861358 0.503653 -0.0663072 + -0.495389 0.86124 -0.113385 + -0.495389 0.86124 -0.113385 + -0.495389 0.86124 -0.113385 + -0.495389 0.86124 -0.113385 + -0.495389 0.86124 -0.113385 + -0.495389 0.86124 -0.113385 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0.495387 0.868672 0 + 0.495387 0.868672 0 + 0.495387 0.868672 0 + 0.495387 0.868672 0 + 0.495387 0.868672 0 + 0.861357 0.508001 1.55688e-07 + 0.861357 0.508001 1.55688e-07 + 0.861357 0.508001 1.55688e-07 + 0.861357 0.508001 1.55688e-07 + 0.861357 0.508001 1.55688e-07 + 0.861357 0.508001 1.55688e-07 + 0.861357 0.508001 1.55688e-07 + 0.999942 0.0107837 -1.75297e-07 + 0.999942 0.0107837 -1.75297e-07 + 0.999942 0.0107837 -1.75297e-07 + 0.999942 0.0107837 -1.75297e-07 + 0.999942 0.0107837 -1.75297e-07 + 0.870692 -0.491828 0 + 0.870692 -0.491828 0 + 0.870692 -0.491828 0 + 0.870692 -0.491828 0 + 0.870692 -0.491828 0 + 0.870692 -0.491828 0 + 0.870692 -0.491828 0 + 0.504725 -0.86328 -7.18609e-07 + 0.504725 -0.86328 -7.18609e-07 + 0.504725 -0.86328 -7.18609e-07 + 0.504725 -0.86328 -7.18609e-07 + 0.504725 -0.86328 -7.18609e-07 + 0.504725 -0.86328 -7.18609e-07 + 0 -1 -1.07185e-06 + 0 -1 -1.07185e-06 + 0 -1 -1.07185e-06 + 0 -1 -1.07185e-06 + 0 -1 -1.07185e-06 + -0.504725 -0.86328 -4.6174e-07 + -0.504725 -0.86328 -4.6174e-07 + -0.504725 -0.86328 -4.6174e-07 + -0.504725 -0.86328 -4.6174e-07 + -0.504725 -0.86328 -4.6174e-07 + -0.504725 -0.86328 -4.6174e-07 + -0.504725 -0.86328 -4.6174e-07 + -0.870692 -0.491828 -1.93392e-07 + -0.870692 -0.491828 -1.93392e-07 + -0.870692 -0.491828 -1.93392e-07 + -0.870692 -0.491828 -1.93392e-07 + -0.870692 -0.491828 -1.93392e-07 + -0.870692 -0.491828 -1.93392e-07 + -0.870692 -0.491828 -1.93392e-07 + -0.999942 0.0107838 0 + -0.999942 0.0107838 0 + -0.999942 0.0107838 0 + -0.999942 0.0107838 0 + -0.999942 0.0107838 0 + -0.861357 0.508001 2.9725e-07 + -0.861357 0.508001 2.9725e-07 + -0.861357 0.508001 2.9725e-07 + -0.861357 0.508001 2.9725e-07 + -0.861357 0.508001 2.9725e-07 + -0.861357 0.508001 2.9725e-07 + -0.861357 0.508001 2.9725e-07 + -0.495387 0.868672 4.55483e-07 + -0.495387 0.868672 4.55483e-07 + -0.495387 0.868672 4.55483e-07 + -0.495387 0.868672 4.55483e-07 + 0 0.991445 0.130526 + 0 0.991445 0.130526 + 0 0.991445 0.130526 + 0 0.991445 0.130526 + 0 0.991445 0.130526 + 0 0.991445 0.130526 + 0 0.991445 0.130526 + 0.495391 0.861238 0.113384 + 0.495391 0.861238 0.113384 + 0.495391 0.861238 0.113384 + 0.495391 0.861238 0.113384 + 0.495391 0.861238 0.113384 + 0.861358 0.503653 0.066307 + 0.861358 0.503653 0.066307 + 0.861358 0.503653 0.066307 + 0.861358 0.503653 0.066307 + 0.861358 0.503653 0.066307 + 0.861358 0.503653 0.066307 + 0.861358 0.503653 0.066307 + 0.999942 0.0106907 0.00140744 + 0.999942 0.0106907 0.00140744 + 0.999942 0.0106907 0.00140744 + 0.999942 0.0106907 0.00140744 + 0.999942 0.0106907 0.00140744 + 0.999942 0.0106907 0.00140744 + 0.870692 -0.487621 -0.0641967 + 0.870692 -0.487621 -0.0641967 + 0.870692 -0.487621 -0.0641967 + 0.870692 -0.487621 -0.0641967 + 0.870692 -0.487621 -0.0641967 + 0.870692 -0.487621 -0.0641967 + 0.504724 -0.855896 -0.112681 + 0.504724 -0.855896 -0.112681 + 0.504724 -0.855896 -0.112681 + 0.504724 -0.855896 -0.112681 + 0.504724 -0.855896 -0.112681 + 0 -0.991445 -0.130525 + 0 -0.991445 -0.130525 + 0 -0.991445 -0.130525 + 0 -0.991445 -0.130525 + 0 -0.991445 -0.130525 + 0 -0.991445 -0.130525 + 0 -0.991445 -0.130525 + -0.504723 -0.855896 -0.112681 + -0.504723 -0.855896 -0.112681 + -0.504723 -0.855896 -0.112681 + -0.504723 -0.855896 -0.112681 + -0.870692 -0.48762 -0.0641966 + -0.870692 -0.48762 -0.0641966 + -0.870692 -0.48762 -0.0641966 + -0.870692 -0.48762 -0.0641966 + -0.870692 -0.48762 -0.0641966 + -0.870692 -0.48762 -0.0641966 + -0.999942 0.0106904 0.00140738 + -0.999942 0.0106904 0.00140738 + -0.999942 0.0106904 0.00140738 + -0.999942 0.0106904 0.00140738 + -0.999942 0.0106904 0.00140738 + -0.999942 0.0106904 0.00140738 + -0.999942 0.0106904 0.00140738 + -0.861358 0.503653 0.0663069 + -0.861358 0.503653 0.0663069 + -0.861358 0.503653 0.0663069 + -0.861358 0.503653 0.0663069 + -0.861358 0.503653 0.0663069 + -0.861358 0.503653 0.0663069 + -0.495391 0.861239 0.113384 + -0.495391 0.861239 0.113384 + -0.495391 0.861239 0.113384 + -0.495391 0.861239 0.113384 + -0.495391 0.861239 0.113384 + -0.495391 0.861239 0.113384 + 1.33053e-07 0.965926 0.258819 + 1.33053e-07 0.965926 0.258819 + 1.33053e-07 0.965926 0.258819 + 1.33053e-07 0.965926 0.258819 + 1.33053e-07 0.965926 0.258819 + 1.33053e-07 0.965926 0.258819 + 0.495388 0.839072 0.224829 + 0.495388 0.839072 0.224829 + 0.495388 0.839072 0.224829 + 0.495388 0.839072 0.224829 + 0.495388 0.839072 0.224829 + 0.495388 0.839072 0.224829 + 0.861357 0.49069 0.13148 + 0.861357 0.49069 0.13148 + 0.861357 0.49069 0.13148 + 0.861357 0.49069 0.13148 + 0.861357 0.49069 0.13148 + 0.999942 0.0104149 0.00279069 + 0.999942 0.0104149 0.00279069 + 0.999942 0.0104149 0.00279069 + 0.999942 0.0104149 0.00279069 + 0.999942 0.0104149 0.00279069 + 0.999942 0.0104149 0.00279069 + 0.999942 0.0104149 0.00279069 + 0.870692 -0.475069 -0.127294 + 0.870692 -0.475069 -0.127294 + 0.870692 -0.475069 -0.127294 + 0.870692 -0.475069 -0.127294 + 0.870692 -0.475069 -0.127294 + 0.504725 -0.833865 -0.223433 + 0.504725 -0.833865 -0.223433 + 0.504725 -0.833865 -0.223433 + 0.504725 -0.833865 -0.223433 + 0.504725 -0.833865 -0.223433 + 0.504725 -0.833865 -0.223433 + 0.504725 -0.833865 -0.223433 + 0 -0.965926 -0.258819 + 0 -0.965926 -0.258819 + 0 -0.965926 -0.258819 + 0 -0.965926 -0.258819 + 0 -0.965926 -0.258819 + 0 -0.965926 -0.258819 + -0.504725 -0.833865 -0.223433 + -0.504725 -0.833865 -0.223433 + -0.504725 -0.833865 -0.223433 + -0.504725 -0.833865 -0.223433 + -0.504725 -0.833865 -0.223433 + -0.504725 -0.833865 -0.223433 + -0.504725 -0.833865 -0.223433 + -0.870692 -0.475069 -0.127294 + -0.870692 -0.475069 -0.127294 + -0.870692 -0.475069 -0.127294 + -0.870692 -0.475069 -0.127294 + -0.870692 -0.475069 -0.127294 + -0.999942 0.0104156 0.00279105 + -0.999942 0.0104156 0.00279105 + -0.999942 0.0104156 0.00279105 + -0.999942 0.0104156 0.00279105 + -0.999942 0.0104156 0.00279105 + -0.999942 0.0104156 0.00279105 + -0.999942 0.0104156 0.00279105 + -0.861357 0.49069 0.13148 + -0.861357 0.49069 0.13148 + -0.861357 0.49069 0.13148 + -0.861357 0.49069 0.13148 + -0.495389 0.839072 0.224829 + -0.495389 0.839072 0.224829 + -0.495389 0.839072 0.224829 + -0.495389 0.839072 0.224829 + -0.495389 0.839072 0.224829 + -0.495389 0.839072 0.224829 + -0.495389 0.839072 0.224829 + 2.74189e-07 0.92388 0.382683 + 2.74189e-07 0.92388 0.382683 + 2.74189e-07 0.92388 0.382683 + 2.74189e-07 0.92388 0.382683 + 2.74189e-07 0.92388 0.382683 + 2.74189e-07 0.92388 0.382683 + 0.495388 0.802549 0.332426 + 0.495388 0.802549 0.332426 + 0.495388 0.802549 0.332426 + 0.495388 0.802549 0.332426 + 0.495388 0.802549 0.332426 + 0.495388 0.802549 0.332426 + 0.495388 0.802549 0.332426 + 0.861356 0.469333 0.194403 + 0.861356 0.469333 0.194403 + 0.861356 0.469333 0.194403 + 0.861356 0.469333 0.194403 + 0.861356 0.469333 0.194403 + 0.999942 0.00996137 0.00412595 + 0.999942 0.00996137 0.00412595 + 0.999942 0.00996137 0.00412595 + 0.999942 0.00996137 0.00412595 + 0.999942 0.00996137 0.00412595 + 0.999942 0.00996137 0.00412595 + 0.870694 -0.454388 -0.188214 + 0.870694 -0.454388 -0.188214 + 0.870694 -0.454388 -0.188214 + 0.870694 -0.454388 -0.188214 + 0.870694 -0.454388 -0.188214 + 0.870694 -0.454388 -0.188214 + 0.504726 -0.797567 -0.330363 + 0.504726 -0.797567 -0.330363 + 0.504726 -0.797567 -0.330363 + 0.504726 -0.797567 -0.330363 + 0.504726 -0.797567 -0.330363 + 0.504726 -0.797567 -0.330363 + -4.00383e-07 -0.92388 -0.382684 + -4.00383e-07 -0.92388 -0.382684 + -4.00383e-07 -0.92388 -0.382684 + -4.00383e-07 -0.92388 -0.382684 + -4.00383e-07 -0.92388 -0.382684 + -4.00383e-07 -0.92388 -0.382684 + -0.504726 -0.797566 -0.330363 + -0.504726 -0.797566 -0.330363 + -0.504726 -0.797566 -0.330363 + -0.504726 -0.797566 -0.330363 + -0.504726 -0.797566 -0.330363 + -0.870694 -0.454388 -0.188214 + -0.870694 -0.454388 -0.188214 + -0.870694 -0.454388 -0.188214 + -0.870694 -0.454388 -0.188214 + -0.870694 -0.454388 -0.188214 + -0.870694 -0.454388 -0.188214 + -0.870694 -0.454388 -0.188214 + -0.999942 0.00996125 0.00412613 + -0.999942 0.00996125 0.00412613 + -0.999942 0.00996125 0.00412613 + -0.999942 0.00996125 0.00412613 + -0.999942 0.00996125 0.00412613 + -0.999942 0.00996125 0.00412613 + -0.861356 0.469333 0.194404 + -0.861356 0.469333 0.194404 + -0.861356 0.469333 0.194404 + -0.861356 0.469333 0.194404 + -0.861356 0.469333 0.194404 + -0.861356 0.469333 0.194404 + -0.495387 0.802549 0.332427 + -0.495387 0.802549 0.332427 + -0.495387 0.802549 0.332427 + -0.495387 0.802549 0.332427 + -0.495387 0.802549 0.332427 + -0.495387 0.802549 0.332427 + 3.58124e-07 0.866026 0.499999 + 3.58124e-07 0.866026 0.499999 + 3.58124e-07 0.866026 0.499999 + 3.58124e-07 0.866026 0.499999 + 0.495391 0.752291 0.434335 + 0.495391 0.752291 0.434335 + 0.495391 0.752291 0.434335 + 0.495391 0.752291 0.434335 + 0.495391 0.752291 0.434335 + 0.495391 0.752291 0.434335 + 0.861358 0.43994 0.253999 + 0.861358 0.43994 0.253999 + 0.861358 0.43994 0.253999 + 0.861358 0.43994 0.253999 + 0.861358 0.43994 0.253999 + 0.861358 0.43994 0.253999 + 0.861358 0.43994 0.253999 + 0.999942 0.0093376 0.00539106 + 0.999942 0.0093376 0.00539106 + 0.999942 0.0093376 0.00539106 + 0.999942 0.0093376 0.00539106 + 0.999942 0.0093376 0.00539106 + 0.999942 0.0093376 0.00539106 + 0.870694 -0.425933 -0.245913 + 0.870694 -0.425933 -0.245913 + 0.870694 -0.425933 -0.245913 + 0.870694 -0.425933 -0.245913 + 0.870694 -0.425933 -0.245913 + 0.870694 -0.425933 -0.245913 + 0.504726 -0.747622 -0.43164 + 0.504726 -0.747622 -0.43164 + 0.504726 -0.747622 -0.43164 + 0.504726 -0.747622 -0.43164 + 0.504726 -0.747622 -0.43164 + 0.504726 -0.747622 -0.43164 + 4.87092e-07 -0.866026 -0.5 + 4.87092e-07 -0.866026 -0.5 + 4.87092e-07 -0.866026 -0.5 + 4.87092e-07 -0.866026 -0.5 + 4.87092e-07 -0.866026 -0.5 + -0.504727 -0.747622 -0.43164 + -0.504727 -0.747622 -0.43164 + -0.504727 -0.747622 -0.43164 + -0.504727 -0.747622 -0.43164 + -0.504727 -0.747622 -0.43164 + -0.504727 -0.747622 -0.43164 + -0.504727 -0.747622 -0.43164 + -0.504727 -0.747622 -0.43164 + -0.870694 -0.425934 -0.245913 + -0.870694 -0.425934 -0.245913 + -0.870694 -0.425934 -0.245913 + -0.870694 -0.425934 -0.245913 + -0.870694 -0.425934 -0.245913 + -0.999942 0.00933772 0.00539112 + -0.999942 0.00933772 0.00539112 + -0.999942 0.00933772 0.00539112 + -0.999942 0.00933772 0.00539112 + -0.999942 0.00933772 0.00539112 + -0.999942 0.00933772 0.00539112 + -0.861358 0.43994 0.253999 + -0.861358 0.43994 0.253999 + -0.861358 0.43994 0.253999 + -0.861358 0.43994 0.253999 + -0.861358 0.43994 0.253999 + -0.861358 0.43994 0.253999 + -0.861358 0.43994 0.253999 + -0.495391 0.752291 0.434335 + -0.495391 0.752291 0.434335 + -0.495391 0.752291 0.434335 + -0.495391 0.752291 0.434335 + -0.495391 0.752291 0.434335 + -0.495391 0.752291 0.434335 + -6.65885e-07 0.793353 0.608761 + -6.65885e-07 0.793353 0.608761 + -6.65885e-07 0.793353 0.608761 + -6.65885e-07 0.793353 0.608761 + -6.65885e-07 0.793353 0.608761 + -6.65885e-07 0.793353 0.608761 + -6.65885e-07 0.793353 0.608761 + -6.65885e-07 0.793353 0.608761 + 0.495387 0.689164 0.528814 + 0.495387 0.689164 0.528814 + 0.495387 0.689164 0.528814 + 0.495387 0.689164 0.528814 + 0.495387 0.689164 0.528814 + 0.861357 0.403023 0.309251 + 0.861357 0.403023 0.309251 + 0.861357 0.403023 0.309251 + 0.861357 0.403023 0.309251 + 0.861357 0.403023 0.309251 + 0.861357 0.403023 0.309251 + 0.861357 0.403023 0.309251 + 0.999942 0.00855523 0.00656426 + 0.999942 0.00855523 0.00656426 + 0.999942 0.00855523 0.00656426 + 0.999942 0.00855523 0.00656426 + 0.870692 -0.390193 -0.299406 + 0.870692 -0.390193 -0.299406 + 0.870692 -0.390193 -0.299406 + 0.870692 -0.390193 -0.299406 + 0.870692 -0.390193 -0.299406 + 0.870692 -0.390193 -0.299406 + 0.870692 -0.390193 -0.299406 + 0.870692 -0.390193 -0.299406 + 0.504723 -0.684887 -0.525532 + 0.504723 -0.684887 -0.525532 + 0.504723 -0.684887 -0.525532 + 0.504723 -0.684887 -0.525532 + 0.504723 -0.684887 -0.525532 + 0.504723 -0.684887 -0.525532 + -7.00974e-07 -0.793354 -0.608761 + -7.00974e-07 -0.793354 -0.608761 + -7.00974e-07 -0.793354 -0.608761 + -7.00974e-07 -0.793354 -0.608761 + -7.00974e-07 -0.793354 -0.608761 + -0.504724 -0.684887 -0.525532 + -0.504724 -0.684887 -0.525532 + -0.504724 -0.684887 -0.525532 + -0.504724 -0.684887 -0.525532 + -0.504724 -0.684887 -0.525532 + -0.870692 -0.390193 -0.299406 + -0.870692 -0.390193 -0.299406 + -0.870692 -0.390193 -0.299406 + -0.870692 -0.390193 -0.299406 + -0.870692 -0.390193 -0.299406 + -0.870692 -0.390193 -0.299406 + -0.870692 -0.390193 -0.299406 + -0.870692 -0.390193 -0.299406 + -0.999942 0.008555 0.00656444 + -0.999942 0.008555 0.00656444 + -0.999942 0.008555 0.00656444 + -0.999942 0.008555 0.00656444 + -0.861357 0.403023 0.309251 + -0.861357 0.403023 0.309251 + -0.861357 0.403023 0.309251 + -0.861357 0.403023 0.309251 + -0.861357 0.403023 0.309251 + -0.861357 0.403023 0.309251 + -0.861357 0.403023 0.309251 + -0.495388 0.689164 0.528814 + -0.495388 0.689164 0.528814 + -0.495388 0.689164 0.528814 + -0.495388 0.689164 0.528814 + -0.495388 0.689164 0.528814 + -1.66378e-06 0.707107 0.707107 + -1.66378e-06 0.707107 0.707107 + -1.66378e-06 0.707107 0.707107 + -1.66378e-06 0.707107 0.707107 + -1.66378e-06 0.707107 0.707107 + -1.66378e-06 0.707107 0.707107 + 0.495387 0.614244 0.614244 + 0.495387 0.614244 0.614244 + 0.495387 0.614244 0.614244 + 0.495387 0.614244 0.614244 + 0.495387 0.614244 0.614244 + 0.495387 0.614244 0.614244 + 0.861356 0.359211 0.359211 + 0.861356 0.359211 0.359211 + 0.861356 0.359211 0.359211 + 0.861356 0.359211 0.359211 + 0.861356 0.359211 0.359211 + 0.861356 0.359211 0.359211 + 0.999942 0.00762576 0.00762588 + 0.999942 0.00762576 0.00762588 + 0.999942 0.00762576 0.00762588 + 0.999942 0.00762576 0.00762588 + 0.999942 0.00762576 0.00762588 + 0.999942 0.00762576 0.00762588 + 0.870692 -0.347775 -0.347775 + 0.870692 -0.347775 -0.347775 + 0.870692 -0.347775 -0.347775 + 0.870692 -0.347775 -0.347775 + 0.870692 -0.347775 -0.347775 + 0.870692 -0.347775 -0.347775 + 0.504724 -0.610431 -0.610432 + 0.504724 -0.610431 -0.610432 + 0.504724 -0.610431 -0.610432 + 0.504724 -0.610431 -0.610432 + 0.504724 -0.610431 -0.610432 + 4.8405e-07 -0.707107 -0.707107 + 4.8405e-07 -0.707107 -0.707107 + 4.8405e-07 -0.707107 -0.707107 + 4.8405e-07 -0.707107 -0.707107 + 4.8405e-07 -0.707107 -0.707107 + 4.8405e-07 -0.707107 -0.707107 + 4.8405e-07 -0.707107 -0.707107 + 4.8405e-07 -0.707107 -0.707107 + -0.504724 -0.610431 -0.610432 + -0.504724 -0.610431 -0.610432 + -0.504724 -0.610431 -0.610432 + -0.504724 -0.610431 -0.610432 + -0.504724 -0.610431 -0.610432 + -0.870692 -0.347775 -0.347775 + -0.870692 -0.347775 -0.347775 + -0.870692 -0.347775 -0.347775 + -0.870692 -0.347775 -0.347775 + -0.870692 -0.347775 -0.347775 + -0.870692 -0.347775 -0.347775 + -0.999942 0.00762564 0.0076257 + -0.999942 0.00762564 0.0076257 + -0.999942 0.00762564 0.0076257 + -0.999942 0.00762564 0.0076257 + -0.999942 0.00762564 0.0076257 + -0.999942 0.00762564 0.0076257 + -0.861356 0.359211 0.359211 + -0.861356 0.359211 0.359211 + -0.861356 0.359211 0.359211 + -0.861356 0.359211 0.359211 + -0.861356 0.359211 0.359211 + -0.861356 0.359211 0.359211 + -0.495388 0.614244 0.614244 + -0.495388 0.614244 0.614244 + -0.495388 0.614244 0.614244 + -0.495388 0.614244 0.614244 + -0.495388 0.614244 0.614244 + -0.495388 0.614244 0.614244 + 3.32695e-06 0.608761 0.793354 + 3.32695e-06 0.608761 0.793354 + 3.32695e-06 0.608761 0.793354 + 3.32695e-06 0.608761 0.793354 + 3.32695e-06 0.608761 0.793354 + 0.495391 0.528813 0.689162 + 0.495391 0.528813 0.689162 + 0.495391 0.528813 0.689162 + 0.495391 0.528813 0.689162 + 0.495391 0.528813 0.689162 + 0.495391 0.528813 0.689162 + 0.495391 0.528813 0.689162 + 0.861357 0.309251 0.403024 + 0.861357 0.309251 0.403024 + 0.861357 0.309251 0.403024 + 0.861357 0.309251 0.403024 + 0.861357 0.309251 0.403024 + 0.861357 0.309251 0.403024 + 0.999942 0.00656462 0.00855553 + 0.999942 0.00656462 0.00855553 + 0.999942 0.00656462 0.00855553 + 0.999942 0.00656462 0.00855553 + 0.999942 0.00656462 0.00855553 + 0.999942 0.00656462 0.00855553 + 0.999942 0.00656462 0.00855553 + 0.870693 -0.299405 -0.390192 + 0.870693 -0.299405 -0.390192 + 0.870693 -0.299405 -0.390192 + 0.870693 -0.299405 -0.390192 + 0.870693 -0.299405 -0.390192 + 0.504724 -0.525532 -0.684886 + 0.504724 -0.525532 -0.684886 + 0.504724 -0.525532 -0.684886 + 0.504724 -0.525532 -0.684886 + 0.504724 -0.525532 -0.684886 + 0.504724 -0.525532 -0.684886 + 2.21397e-06 -0.608761 -0.793353 + 2.21397e-06 -0.608761 -0.793353 + 2.21397e-06 -0.608761 -0.793353 + 2.21397e-06 -0.608761 -0.793353 + 2.21397e-06 -0.608761 -0.793353 + 2.21397e-06 -0.608761 -0.793353 + -0.504723 -0.525533 -0.684887 + -0.504723 -0.525533 -0.684887 + -0.504723 -0.525533 -0.684887 + -0.504723 -0.525533 -0.684887 + -0.504723 -0.525533 -0.684887 + -0.504723 -0.525533 -0.684887 + -0.870693 -0.299405 -0.390192 + -0.870693 -0.299405 -0.390192 + -0.870693 -0.299405 -0.390192 + -0.870693 -0.299405 -0.390192 + -0.870693 -0.299405 -0.390192 + -0.999942 0.0065648 0.00855559 + -0.999942 0.0065648 0.00855559 + -0.999942 0.0065648 0.00855559 + -0.999942 0.0065648 0.00855559 + -0.999942 0.0065648 0.00855559 + -0.999942 0.0065648 0.00855559 + -0.999942 0.0065648 0.00855559 + -0.861357 0.309251 0.403024 + -0.861357 0.309251 0.403024 + -0.861357 0.309251 0.403024 + -0.861357 0.309251 0.403024 + -0.861357 0.309251 0.403024 + -0.861357 0.309251 0.403024 + -0.495389 0.528814 0.689164 + -0.495389 0.528814 0.689164 + -0.495389 0.528814 0.689164 + -0.495389 0.528814 0.689164 + -0.495389 0.528814 0.689164 + -0.495389 0.528814 0.689164 + -2.20843e-06 0.5 0.866025 + -2.20843e-06 0.5 0.866025 + -2.20843e-06 0.5 0.866025 + -2.20843e-06 0.5 0.866025 + -2.20843e-06 0.5 0.866025 + 0.495389 0.434336 0.752292 + 0.495389 0.434336 0.752292 + 0.495389 0.434336 0.752292 + 0.495389 0.434336 0.752292 + 0.495389 0.434336 0.752292 + 0.495389 0.434336 0.752292 + 0.861358 0.253999 0.439939 + 0.861358 0.253999 0.439939 + 0.861358 0.253999 0.439939 + 0.861358 0.253999 0.439939 + 0.861358 0.253999 0.439939 + 0.861358 0.253999 0.439939 + 0.999942 0.00539088 0.00933701 + 0.999942 0.00539088 0.00933701 + 0.999942 0.00539088 0.00933701 + 0.999942 0.00539088 0.00933701 + 0.999942 0.00539088 0.00933701 + 0.870694 -0.245913 -0.425933 + 0.870694 -0.245913 -0.425933 + 0.870694 -0.245913 -0.425933 + 0.870694 -0.245913 -0.425933 + 0.870694 -0.245913 -0.425933 + 0.870694 -0.245913 -0.425933 + 0.504725 -0.431641 -0.747623 + 0.504725 -0.431641 -0.747623 + 0.504725 -0.431641 -0.747623 + 0.504725 -0.431641 -0.747623 + 0.504725 -0.431641 -0.747623 + 0.504725 -0.431641 -0.747623 + 0.504725 -0.431641 -0.747623 + 0.504725 -0.431641 -0.747623 + 6.66898e-07 -0.5 -0.866025 + 6.66898e-07 -0.5 -0.866025 + 6.66898e-07 -0.5 -0.866025 + 6.66898e-07 -0.5 -0.866025 + -0.504724 -0.431641 -0.747623 + -0.504724 -0.431641 -0.747623 + -0.504724 -0.431641 -0.747623 + -0.504724 -0.431641 -0.747623 + -0.504724 -0.431641 -0.747623 + -0.504724 -0.431641 -0.747623 + -0.504724 -0.431641 -0.747623 + -0.504724 -0.431641 -0.747623 + -0.870694 -0.245913 -0.425934 + -0.870694 -0.245913 -0.425934 + -0.870694 -0.245913 -0.425934 + -0.870694 -0.245913 -0.425934 + -0.870694 -0.245913 -0.425934 + -0.870694 -0.245913 -0.425934 + -0.999942 0.00539082 0.00933719 + -0.999942 0.00539082 0.00933719 + -0.999942 0.00539082 0.00933719 + -0.999942 0.00539082 0.00933719 + -0.999942 0.00539082 0.00933719 + -0.861358 0.254 0.43994 + -0.861358 0.254 0.43994 + -0.861358 0.254 0.43994 + -0.861358 0.254 0.43994 + -0.861358 0.254 0.43994 + -0.861358 0.254 0.43994 + -0.495389 0.434336 0.752291 + -0.495389 0.434336 0.752291 + -0.495389 0.434336 0.752291 + -0.495389 0.434336 0.752291 + -0.495389 0.434336 0.752291 + -0.495389 0.434336 0.752291 + -0.495389 0.434336 0.752291 + 7.23396e-07 0.382683 0.92388 + 7.23396e-07 0.382683 0.92388 + 7.23396e-07 0.382683 0.92388 + 7.23396e-07 0.382683 0.92388 + 7.23396e-07 0.382683 0.92388 + 7.23396e-07 0.382683 0.92388 + 7.23396e-07 0.382683 0.92388 + 7.23396e-07 0.382683 0.92388 + 0.495386 0.332427 0.802549 + 0.495386 0.332427 0.802549 + 0.495386 0.332427 0.802549 + 0.495386 0.332427 0.802549 + 0.495386 0.332427 0.802549 + 0.495386 0.332427 0.802549 + 0.861356 0.194404 0.469333 + 0.861356 0.194404 0.469333 + 0.861356 0.194404 0.469333 + 0.861356 0.194404 0.469333 + 0.861356 0.194404 0.469333 + 0.999942 0.00412685 0.00996298 + 0.999942 0.00412685 0.00996298 + 0.999942 0.00412685 0.00996298 + 0.999942 0.00412685 0.00996298 + 0.999942 0.00412685 0.00996298 + 0.999942 0.00412685 0.00996298 + 0.870693 -0.188214 -0.45439 + 0.870693 -0.188214 -0.45439 + 0.870693 -0.188214 -0.45439 + 0.870693 -0.188214 -0.45439 + 0.870693 -0.188214 -0.45439 + 0.870693 -0.188214 -0.45439 + 0.504727 -0.330363 -0.797566 + 0.504727 -0.330363 -0.797566 + 0.504727 -0.330363 -0.797566 + 0.504727 -0.330363 -0.797566 + 0.504727 -0.330363 -0.797566 + 0.504727 -0.330363 -0.797566 + 2.35119e-06 -0.382684 -0.923879 + 2.35119e-06 -0.382684 -0.923879 + 2.35119e-06 -0.382684 -0.923879 + 2.35119e-06 -0.382684 -0.923879 + 2.35119e-06 -0.382684 -0.923879 + 2.35119e-06 -0.382684 -0.923879 + -0.504726 -0.330363 -0.797566 + -0.504726 -0.330363 -0.797566 + -0.504726 -0.330363 -0.797566 + -0.504726 -0.330363 -0.797566 + -0.504726 -0.330363 -0.797566 + -0.504726 -0.330363 -0.797566 + -0.870693 -0.188214 -0.454389 + -0.870693 -0.188214 -0.454389 + -0.870693 -0.188214 -0.454389 + -0.870693 -0.188214 -0.454389 + -0.870693 -0.188214 -0.454389 + -0.870693 -0.188214 -0.454389 + -0.999942 0.00412649 0.00996208 + -0.999942 0.00412649 0.00996208 + -0.999942 0.00412649 0.00996208 + -0.999942 0.00412649 0.00996208 + -0.999942 0.00412649 0.00996208 + -0.999942 0.00412649 0.00996208 + -0.861356 0.194404 0.469333 + -0.861356 0.194404 0.469333 + -0.861356 0.194404 0.469333 + -0.861356 0.194404 0.469333 + -0.861356 0.194404 0.469333 + -0.495385 0.332427 0.80255 + -0.495385 0.332427 0.80255 + -0.495385 0.332427 0.80255 + -0.495385 0.332427 0.80255 + -0.495385 0.332427 0.80255 + -0.495385 0.332427 0.80255 + 1.58918e-06 0.258819 0.965926 + 1.58918e-06 0.258819 0.965926 + 1.58918e-06 0.258819 0.965926 + 1.58918e-06 0.258819 0.965926 + 1.58918e-06 0.258819 0.965926 + 0.495393 0.224828 0.83907 + 0.495393 0.224828 0.83907 + 0.495393 0.224828 0.83907 + 0.495393 0.224828 0.83907 + 0.495393 0.224828 0.83907 + 0.495393 0.224828 0.83907 + 0.495393 0.224828 0.83907 + 0.861358 0.13148 0.490689 + 0.861358 0.13148 0.490689 + 0.861358 0.13148 0.490689 + 0.861358 0.13148 0.490689 + 0.861358 0.13148 0.490689 + 0.999942 0.00279099 0.0104166 + 0.999942 0.00279099 0.0104166 + 0.999942 0.00279099 0.0104166 + 0.999942 0.00279099 0.0104166 + 0.999942 0.00279099 0.0104166 + 0.999942 0.00279099 0.0104166 + 0.999942 0.00279099 0.0104166 + 0.870694 -0.127294 -0.475067 + 0.870694 -0.127294 -0.475067 + 0.870694 -0.127294 -0.475067 + 0.870694 -0.127294 -0.475067 + 0.870694 -0.127294 -0.475067 + 0.870694 -0.127294 -0.475067 + 0.504723 -0.223433 -0.833866 + 0.504723 -0.223433 -0.833866 + 0.504723 -0.223433 -0.833866 + 0.504723 -0.223433 -0.833866 + 0.504723 -0.223433 -0.833866 + 0.504723 -0.223433 -0.833866 + -5.40334e-07 -0.258819 -0.965926 + -5.40334e-07 -0.258819 -0.965926 + -5.40334e-07 -0.258819 -0.965926 + -5.40334e-07 -0.258819 -0.965926 + -5.40334e-07 -0.258819 -0.965926 + -5.40334e-07 -0.258819 -0.965926 + -0.504723 -0.223433 -0.833866 + -0.504723 -0.223433 -0.833866 + -0.504723 -0.223433 -0.833866 + -0.504723 -0.223433 -0.833866 + -0.504723 -0.223433 -0.833866 + -0.504723 -0.223433 -0.833866 + -0.870694 -0.127294 -0.475068 + -0.870694 -0.127294 -0.475068 + -0.870694 -0.127294 -0.475068 + -0.870694 -0.127294 -0.475068 + -0.870694 -0.127294 -0.475068 + -0.870694 -0.127294 -0.475068 + -0.999942 0.00279093 0.0104163 + -0.999942 0.00279093 0.0104163 + -0.999942 0.00279093 0.0104163 + -0.999942 0.00279093 0.0104163 + -0.999942 0.00279093 0.0104163 + -0.999942 0.00279093 0.0104163 + -0.999942 0.00279093 0.0104163 + -0.861359 0.131479 0.490688 + -0.861359 0.131479 0.490688 + -0.861359 0.131479 0.490688 + -0.861359 0.131479 0.490688 + -0.861359 0.131479 0.490688 + -0.495393 0.224828 0.83907 + -0.495393 0.224828 0.83907 + -0.495393 0.224828 0.83907 + -0.495393 0.224828 0.83907 + -0.495393 0.224828 0.83907 + -0.495393 0.224828 0.83907 + -1.40763e-06 0.130526 0.991445 + -1.40763e-06 0.130526 0.991445 + -1.40763e-06 0.130526 0.991445 + -1.40763e-06 0.130526 0.991445 + -1.40763e-06 0.130526 0.991445 + 0.495393 0.113384 0.861237 + 0.495393 0.113384 0.861237 + 0.495393 0.113384 0.861237 + 0.495393 0.113384 0.861237 + 0.495393 0.113384 0.861237 + 0.495393 0.113384 0.861237 + 0.861358 0.0663073 0.503653 + 0.861358 0.0663073 0.503653 + 0.861358 0.0663073 0.503653 + 0.861358 0.0663073 0.503653 + 0.861358 0.0663073 0.503653 + 0.861358 0.0663073 0.503653 + 0.861358 0.0663073 0.503653 + 0.999942 0.00140744 0.0106914 + 0.999942 0.00140744 0.0106914 + 0.999942 0.00140744 0.0106914 + 0.999942 0.00140744 0.0106914 + 0.999942 0.00140744 0.0106914 + 0.999942 0.00140744 0.0106914 + 0.870692 -0.0641964 -0.48762 + 0.870692 -0.0641964 -0.48762 + 0.870692 -0.0641964 -0.48762 + 0.870692 -0.0641964 -0.48762 + 0.870692 -0.0641964 -0.48762 + 0.504722 -0.112681 -0.855897 + 0.504722 -0.112681 -0.855897 + 0.504722 -0.112681 -0.855897 + 0.504722 -0.112681 -0.855897 + 0.504722 -0.112681 -0.855897 + 0 -0.130526 -0.991445 + 0 -0.130526 -0.991445 + 0 -0.130526 -0.991445 + 0 -0.130526 -0.991445 + 0 -0.130526 -0.991445 + 0 -0.130526 -0.991445 + 0 -0.130526 -0.991445 + -0.504722 -0.112681 -0.855896 + -0.504722 -0.112681 -0.855896 + -0.504722 -0.112681 -0.855896 + -0.504722 -0.112681 -0.855896 + -0.504722 -0.112681 -0.855896 + -0.870692 -0.0641965 -0.487621 + -0.870692 -0.0641965 -0.487621 + -0.870692 -0.0641965 -0.487621 + -0.870692 -0.0641965 -0.487621 + -0.870692 -0.0641965 -0.487621 + -0.870692 -0.0641965 -0.487621 + -0.999942 0.0014075 0.0106914 + -0.999942 0.0014075 0.0106914 + -0.999942 0.0014075 0.0106914 + -0.999942 0.0014075 0.0106914 + -0.999942 0.0014075 0.0106914 + -0.999942 0.0014075 0.0106914 + -0.861358 0.0663073 0.503653 + -0.861358 0.0663073 0.503653 + -0.861358 0.0663073 0.503653 + -0.861358 0.0663073 0.503653 + -0.861358 0.0663073 0.503653 + -0.861358 0.0663073 0.503653 + -0.861358 0.0663073 0.503653 + -0.495394 0.113384 0.861237 + -0.495394 0.113384 0.861237 + -0.495394 0.113384 0.861237 + -0.495394 0.113384 0.861237 + -0.495394 0.113384 0.861237 + -0.495394 0.113384 0.861237 + -0.495394 0.113384 0.861237 + 7.68784e-07 0 1 + 7.68784e-07 0 1 + 7.68784e-07 0 1 + 7.68784e-07 0 1 + 7.68784e-07 0 1 + 7.68784e-07 0 1 + 7.68784e-07 0 1 + 7.68784e-07 0 1 + 0.495389 0 0.868671 + 0.495389 0 0.868671 + 0.495389 0 0.868671 + 0.495389 0 0.868671 + 0.861358 0 0.507998 + 0.861358 0 0.507998 + 0.861358 0 0.507998 + 0.861358 0 0.507998 + 0.861358 0 0.507998 + 0.861358 0 0.507998 + 0.999942 0 0.0107843 + 0.999942 0 0.0107843 + 0.999942 0 0.0107843 + 0.999942 0 0.0107843 + 0.999942 0 0.0107843 + 0.999942 0 0.0107843 + 0.870692 0 -0.491828 + 0.870692 0 -0.491828 + 0.870692 0 -0.491828 + 0.870692 0 -0.491828 + 0.870692 0 -0.491828 + 0.870692 0 -0.491828 + 0.870692 0 -0.491828 + 0.870692 0 -0.491828 + 0.504724 0 -0.863281 + 0.504724 0 -0.863281 + 0.504724 0 -0.863281 + 0.504724 0 -0.863281 + 0.504724 0 -0.863281 + 1.60306e-06 0 -1 + 1.60306e-06 0 -1 + 1.60306e-06 0 -1 + 1.60306e-06 0 -1 + 1.60306e-06 0 -1 + 1.60306e-06 0 -1 + 1.60306e-06 0 -1 + -0.504722 0 -0.863282 + -0.504722 0 -0.863282 + -0.504722 0 -0.863282 + -0.504722 0 -0.863282 + -0.504722 0 -0.863282 + -0.870692 0 -0.491829 + -0.870692 0 -0.491829 + -0.870692 0 -0.491829 + -0.870692 0 -0.491829 + -0.870692 0 -0.491829 + -0.870692 0 -0.491829 + -0.870692 0 -0.491829 + -0.999942 0 0.0107843 + -0.999942 0 0.0107843 + -0.999942 0 0.0107843 + -0.999942 0 0.0107843 + -0.999942 0 0.0107843 + -0.999942 0 0.0107843 + -0.861358 0 0.507999 + -0.861358 0 0.507999 + -0.861358 0 0.507999 + -0.861358 0 0.507999 + -0.861358 0 0.507999 + -0.861358 0 0.507999 + -0.495388 0 0.868672 + -0.495388 0 0.868672 + -0.495388 0 0.868672 + -0.495388 0 0.868672 + 3.03441e-06 -0.130526 0.991445 + 3.03441e-06 -0.130526 0.991445 + 3.03441e-06 -0.130526 0.991445 + 3.03441e-06 -0.130526 0.991445 + 3.03441e-06 -0.130526 0.991445 + 0.495391 -0.113384 0.861238 + 0.495391 -0.113384 0.861238 + 0.495391 -0.113384 0.861238 + 0.495391 -0.113384 0.861238 + 0.495391 -0.113384 0.861238 + 0.495391 -0.113384 0.861238 + 0.495391 -0.113384 0.861238 + 0.861358 -0.0663073 0.503653 + 0.861358 -0.0663073 0.503653 + 0.861358 -0.0663073 0.503653 + 0.861358 -0.0663073 0.503653 + 0.861358 -0.0663073 0.503653 + 0.861358 -0.0663073 0.503653 + 0.861358 -0.0663073 0.503653 + 0.999942 -0.00140744 0.0106914 + 0.999942 -0.00140744 0.0106914 + 0.999942 -0.00140744 0.0106914 + 0.999942 -0.00140744 0.0106914 + 0.999942 -0.00140744 0.0106914 + 0.999942 -0.00140744 0.0106914 + 0.870694 0.0641962 -0.487618 + 0.870694 0.0641962 -0.487618 + 0.870694 0.0641962 -0.487618 + 0.870694 0.0641962 -0.487618 + 0.870694 0.0641962 -0.487618 + 0.504725 0.112681 -0.855895 + 0.504725 0.112681 -0.855895 + 0.504725 0.112681 -0.855895 + 0.504725 0.112681 -0.855895 + 0.504725 0.112681 -0.855895 + 0.504725 0.112681 -0.855895 + 8.85953e-07 0.130526 -0.991445 + 8.85953e-07 0.130526 -0.991445 + 8.85953e-07 0.130526 -0.991445 + 8.85953e-07 0.130526 -0.991445 + 8.85953e-07 0.130526 -0.991445 + 8.85953e-07 0.130526 -0.991445 + -0.504723 0.112681 -0.855896 + -0.504723 0.112681 -0.855896 + -0.504723 0.112681 -0.855896 + -0.504723 0.112681 -0.855896 + -0.504723 0.112681 -0.855896 + -0.504723 0.112681 -0.855896 + -0.870693 0.0641963 -0.487619 + -0.870693 0.0641963 -0.487619 + -0.870693 0.0641963 -0.487619 + -0.870693 0.0641963 -0.487619 + -0.870693 0.0641963 -0.487619 + -0.999942 -0.0014075 0.0106914 + -0.999942 -0.0014075 0.0106914 + -0.999942 -0.0014075 0.0106914 + -0.999942 -0.0014075 0.0106914 + -0.999942 -0.0014075 0.0106914 + -0.999942 -0.0014075 0.0106914 + -0.861358 -0.0663073 0.503653 + -0.861358 -0.0663073 0.503653 + -0.861358 -0.0663073 0.503653 + -0.861358 -0.0663073 0.503653 + -0.861358 -0.0663073 0.503653 + -0.861358 -0.0663073 0.503653 + -0.861358 -0.0663073 0.503653 + -0.495389 -0.113384 0.86124 + -0.495389 -0.113384 0.86124 + -0.495389 -0.113384 0.86124 + -0.495389 -0.113384 0.86124 + -0.495389 -0.113384 0.86124 + -0.495389 -0.113384 0.86124 + -1.03955e-06 -0.258819 0.965926 + -1.03955e-06 -0.258819 0.965926 + -1.03955e-06 -0.258819 0.965926 + -1.03955e-06 -0.258819 0.965926 + -1.03955e-06 -0.258819 0.965926 + 0.495392 -0.224828 0.83907 + 0.495392 -0.224828 0.83907 + 0.495392 -0.224828 0.83907 + 0.495392 -0.224828 0.83907 + 0.495392 -0.224828 0.83907 + 0.495392 -0.224828 0.83907 + 0.861358 -0.131479 0.490689 + 0.861358 -0.131479 0.490689 + 0.861358 -0.131479 0.490689 + 0.861358 -0.131479 0.490689 + 0.861358 -0.131479 0.490689 + 0.861358 -0.131479 0.490689 + 0.999942 -0.00279117 0.0104169 + 0.999942 -0.00279117 0.0104169 + 0.999942 -0.00279117 0.0104169 + 0.999942 -0.00279117 0.0104169 + 0.999942 -0.00279117 0.0104169 + 0.870694 0.127294 -0.475067 + 0.870694 0.127294 -0.475067 + 0.870694 0.127294 -0.475067 + 0.870694 0.127294 -0.475067 + 0.870694 0.127294 -0.475067 + 0.870694 0.127294 -0.475067 + 0.870694 0.127294 -0.475067 + 0.504722 0.223434 -0.833867 + 0.504722 0.223434 -0.833867 + 0.504722 0.223434 -0.833867 + 0.504722 0.223434 -0.833867 + 0.504722 0.223434 -0.833867 + 0.504722 0.223434 -0.833867 + -6.90629e-07 0.258819 -0.965926 + -6.90629e-07 0.258819 -0.965926 + -6.90629e-07 0.258819 -0.965926 + -6.90629e-07 0.258819 -0.965926 + -6.90629e-07 0.258819 -0.965926 + -6.90629e-07 0.258819 -0.965926 + -0.504722 0.223433 -0.833866 + -0.504722 0.223433 -0.833866 + -0.504722 0.223433 -0.833866 + -0.504722 0.223433 -0.833866 + -0.504722 0.223433 -0.833866 + -0.504722 0.223433 -0.833866 + -0.870694 0.127294 -0.475067 + -0.870694 0.127294 -0.475067 + -0.870694 0.127294 -0.475067 + -0.870694 0.127294 -0.475067 + -0.870694 0.127294 -0.475067 + -0.870694 0.127294 -0.475067 + -0.870694 0.127294 -0.475067 + -0.999942 -0.00279122 0.010417 + -0.999942 -0.00279122 0.010417 + -0.999942 -0.00279122 0.010417 + -0.999942 -0.00279122 0.010417 + -0.999942 -0.00279122 0.010417 + -0.861359 -0.131479 0.490688 + -0.861359 -0.131479 0.490688 + -0.861359 -0.131479 0.490688 + -0.861359 -0.131479 0.490688 + -0.861359 -0.131479 0.490688 + -0.861359 -0.131479 0.490688 + -0.495394 -0.224828 0.839069 + -0.495394 -0.224828 0.839069 + -0.495394 -0.224828 0.839069 + -0.495394 -0.224828 0.839069 + -0.495394 -0.224828 0.839069 + -0.495394 -0.224828 0.839069 + -0.495394 -0.224828 0.839069 + 6.47544e-07 -0.382683 0.92388 + 6.47544e-07 -0.382683 0.92388 + 6.47544e-07 -0.382683 0.92388 + 6.47544e-07 -0.382683 0.92388 + 6.47544e-07 -0.382683 0.92388 + 6.47544e-07 -0.382683 0.92388 + 6.47544e-07 -0.382683 0.92388 + 6.47544e-07 -0.382683 0.92388 + 0.495388 -0.332426 0.802548 + 0.495388 -0.332426 0.802548 + 0.495388 -0.332426 0.802548 + 0.495388 -0.332426 0.802548 + 0.495388 -0.332426 0.802548 + 0.861357 -0.194403 0.469331 + 0.861357 -0.194403 0.469331 + 0.861357 -0.194403 0.469331 + 0.861357 -0.194403 0.469331 + 0.861357 -0.194403 0.469331 + 0.861357 -0.194403 0.469331 + 0.999942 -0.00412667 0.00996262 + 0.999942 -0.00412667 0.00996262 + 0.999942 -0.00412667 0.00996262 + 0.999942 -0.00412667 0.00996262 + 0.999942 -0.00412667 0.00996262 + 0.999942 -0.00412667 0.00996262 + 0.870692 0.188215 -0.45439 + 0.870692 0.188215 -0.45439 + 0.870692 0.188215 -0.45439 + 0.870692 0.188215 -0.45439 + 0.870692 0.188215 -0.45439 + 0.870692 0.188215 -0.45439 + 0.504728 0.330362 -0.797566 + 0.504728 0.330362 -0.797566 + 0.504728 0.330362 -0.797566 + 0.504728 0.330362 -0.797566 + 0.504728 0.330362 -0.797566 + 0.504728 0.330362 -0.797566 + 2.63475e-07 0.382683 -0.92388 + 2.63475e-07 0.382683 -0.92388 + 2.63475e-07 0.382683 -0.92388 + 2.63475e-07 0.382683 -0.92388 + 2.63475e-07 0.382683 -0.92388 + 2.63475e-07 0.382683 -0.92388 + -0.504727 0.330362 -0.797566 + -0.504727 0.330362 -0.797566 + -0.504727 0.330362 -0.797566 + -0.504727 0.330362 -0.797566 + -0.504727 0.330362 -0.797566 + -0.504727 0.330362 -0.797566 + -0.870692 0.188215 -0.454391 + -0.870692 0.188215 -0.454391 + -0.870692 0.188215 -0.454391 + -0.870692 0.188215 -0.454391 + -0.870692 0.188215 -0.454391 + -0.870692 0.188215 -0.454391 + -0.999942 -0.00412673 0.00996292 + -0.999942 -0.00412673 0.00996292 + -0.999942 -0.00412673 0.00996292 + -0.999942 -0.00412673 0.00996292 + -0.999942 -0.00412673 0.00996292 + -0.999942 -0.00412673 0.00996292 + -0.861357 -0.194403 0.469331 + -0.861357 -0.194403 0.469331 + -0.861357 -0.194403 0.469331 + -0.861357 -0.194403 0.469331 + -0.861357 -0.194403 0.469331 + -0.861357 -0.194403 0.469331 + -0.495388 -0.332426 0.802548 + -0.495388 -0.332426 0.802548 + -0.495388 -0.332426 0.802548 + -0.495388 -0.332426 0.802548 + -0.495388 -0.332426 0.802548 + 6.31691e-07 -0.5 0.866025 + 6.31691e-07 -0.5 0.866025 + 6.31691e-07 -0.5 0.866025 + 6.31691e-07 -0.5 0.866025 + 0.495391 -0.434335 0.75229 + 0.495391 -0.434335 0.75229 + 0.495391 -0.434335 0.75229 + 0.495391 -0.434335 0.75229 + 0.495391 -0.434335 0.75229 + 0.495391 -0.434335 0.75229 + 0.495391 -0.434335 0.75229 + 0.861358 -0.254 0.43994 + 0.861358 -0.254 0.43994 + 0.861358 -0.254 0.43994 + 0.861358 -0.254 0.43994 + 0.861358 -0.254 0.43994 + 0.999942 -0.00539112 0.00933754 + 0.999942 -0.00539112 0.00933754 + 0.999942 -0.00539112 0.00933754 + 0.999942 -0.00539112 0.00933754 + 0.999942 -0.00539112 0.00933754 + 0.999942 -0.00539112 0.00933754 + 0.999942 -0.00539112 0.00933754 + 0.870694 0.245913 -0.425933 + 0.870694 0.245913 -0.425933 + 0.870694 0.245913 -0.425933 + 0.870694 0.245913 -0.425933 + 0.870694 0.245913 -0.425933 + 0.504729 0.431639 -0.747621 + 0.504729 0.431639 -0.747621 + 0.504729 0.431639 -0.747621 + 0.504729 0.431639 -0.747621 + 0.504729 0.431639 -0.747621 + 0.504729 0.431639 -0.747621 + 0.504729 0.431639 -0.747621 + 2.11053e-06 0.5 -0.866025 + 2.11053e-06 0.5 -0.866025 + 2.11053e-06 0.5 -0.866025 + 2.11053e-06 0.5 -0.866025 + 2.11053e-06 0.5 -0.866025 + -0.504727 0.431639 -0.747622 + -0.504727 0.431639 -0.747622 + -0.504727 0.431639 -0.747622 + -0.504727 0.431639 -0.747622 + -0.504727 0.431639 -0.747622 + -0.504727 0.431639 -0.747622 + -0.504727 0.431639 -0.747622 + -0.504727 0.431639 -0.747622 + -0.870694 0.245913 -0.425933 + -0.870694 0.245913 -0.425933 + -0.870694 0.245913 -0.425933 + -0.870694 0.245913 -0.425933 + -0.870694 0.245913 -0.425933 + -0.999942 -0.00539088 0.00933725 + -0.999942 -0.00539088 0.00933725 + -0.999942 -0.00539088 0.00933725 + -0.999942 -0.00539088 0.00933725 + -0.999942 -0.00539088 0.00933725 + -0.999942 -0.00539088 0.00933725 + -0.861358 -0.253999 0.43994 + -0.861358 -0.253999 0.43994 + -0.861358 -0.253999 0.43994 + -0.861358 -0.253999 0.43994 + -0.861358 -0.253999 0.43994 + -0.861358 -0.253999 0.43994 + -0.495391 -0.434335 0.75229 + -0.495391 -0.434335 0.75229 + -0.495391 -0.434335 0.75229 + -0.495391 -0.434335 0.75229 + -0.495391 -0.434335 0.75229 + -0.495391 -0.434335 0.75229 + -0.495391 -0.434335 0.75229 + -5.27238e-07 -0.608761 0.793354 + -5.27238e-07 -0.608761 0.793354 + -5.27238e-07 -0.608761 0.793354 + -5.27238e-07 -0.608761 0.793354 + -5.27238e-07 -0.608761 0.793354 + -5.27238e-07 -0.608761 0.793354 + 0.495389 -0.528814 0.689164 + 0.495389 -0.528814 0.689164 + 0.495389 -0.528814 0.689164 + 0.495389 -0.528814 0.689164 + 0.495389 -0.528814 0.689164 + 0.495389 -0.528814 0.689164 + 0.495389 -0.528814 0.689164 + 0.861356 -0.309252 0.403025 + 0.861356 -0.309252 0.403025 + 0.861356 -0.309252 0.403025 + 0.861356 -0.309252 0.403025 + 0.861356 -0.309252 0.403025 + 0.999942 -0.00656462 0.00855547 + 0.999942 -0.00656462 0.00855547 + 0.999942 -0.00656462 0.00855547 + 0.999942 -0.00656462 0.00855547 + 0.999942 -0.00656462 0.00855547 + 0.999942 -0.00656462 0.00855547 + 0.999942 -0.00656462 0.00855547 + 0.870693 0.299405 -0.390192 + 0.870693 0.299405 -0.390192 + 0.870693 0.299405 -0.390192 + 0.870693 0.299405 -0.390192 + 0.870693 0.299405 -0.390192 + 0.504722 0.525533 -0.684888 + 0.504722 0.525533 -0.684888 + 0.504722 0.525533 -0.684888 + 0.504722 0.525533 -0.684888 + 0.504722 0.525533 -0.684888 + 0.504722 0.525533 -0.684888 + 0.504722 0.525533 -0.684888 + 0 0.608761 -0.793353 + 0 0.608761 -0.793353 + 0 0.608761 -0.793353 + 0 0.608761 -0.793353 + 0 0.608761 -0.793353 + -0.504722 0.525533 -0.684888 + -0.504722 0.525533 -0.684888 + -0.504722 0.525533 -0.684888 + -0.504722 0.525533 -0.684888 + -0.504722 0.525533 -0.684888 + -0.504722 0.525533 -0.684888 + -0.870694 0.299405 -0.390192 + -0.870694 0.299405 -0.390192 + -0.870694 0.299405 -0.390192 + -0.870694 0.299405 -0.390192 + -0.870694 0.299405 -0.390192 + -0.999942 -0.00656486 0.00855559 + -0.999942 -0.00656486 0.00855559 + -0.999942 -0.00656486 0.00855559 + -0.999942 -0.00656486 0.00855559 + -0.999942 -0.00656486 0.00855559 + -0.999942 -0.00656486 0.00855559 + -0.999942 -0.00656486 0.00855559 + -0.999942 -0.00656486 0.00855559 + -0.861356 -0.309252 0.403025 + -0.861356 -0.309252 0.403025 + -0.861356 -0.309252 0.403025 + -0.861356 -0.309252 0.403025 + -0.495389 -0.528814 0.689163 + -0.495389 -0.528814 0.689163 + -0.495389 -0.528814 0.689163 + -0.495389 -0.528814 0.689163 + -0.495389 -0.528814 0.689163 + -0.495389 -0.528814 0.689163 + -0.495389 -0.528814 0.689163 + -1.66129e-06 -0.707106 0.707107 + -1.66129e-06 -0.707106 0.707107 + -1.66129e-06 -0.707106 0.707107 + -1.66129e-06 -0.707106 0.707107 + -1.66129e-06 -0.707106 0.707107 + -1.66129e-06 -0.707106 0.707107 + 0.495386 -0.614245 0.614245 + 0.495386 -0.614245 0.614245 + 0.495386 -0.614245 0.614245 + 0.495386 -0.614245 0.614245 + 0.495386 -0.614245 0.614245 + 0.495386 -0.614245 0.614245 + 0.861356 -0.359211 0.359211 + 0.861356 -0.359211 0.359211 + 0.861356 -0.359211 0.359211 + 0.861356 -0.359211 0.359211 + 0.861356 -0.359211 0.359211 + 0.861356 -0.359211 0.359211 + 0.999942 -0.00762516 0.00762522 + 0.999942 -0.00762516 0.00762522 + 0.999942 -0.00762516 0.00762522 + 0.999942 -0.00762516 0.00762522 + 0.999942 -0.00762516 0.00762522 + 0.999942 -0.00762516 0.00762522 + 0.870691 0.347776 -0.347777 + 0.870691 0.347776 -0.347777 + 0.870691 0.347776 -0.347777 + 0.870691 0.347776 -0.347777 + 0.870691 0.347776 -0.347777 + 0.870691 0.347776 -0.347777 + 0.504723 0.610432 -0.610432 + 0.504723 0.610432 -0.610432 + 0.504723 0.610432 -0.610432 + 0.504723 0.610432 -0.610432 + 0.504723 0.610432 -0.610432 + 3.73306e-07 0.707106 -0.707107 + 3.73306e-07 0.707106 -0.707107 + 3.73306e-07 0.707106 -0.707107 + 3.73306e-07 0.707106 -0.707107 + 3.73306e-07 0.707106 -0.707107 + 3.73306e-07 0.707106 -0.707107 + 3.73306e-07 0.707106 -0.707107 + 3.73306e-07 0.707106 -0.707107 + -0.504723 0.610432 -0.610433 + -0.504723 0.610432 -0.610433 + -0.504723 0.610432 -0.610433 + -0.504723 0.610432 -0.610433 + -0.870691 0.347776 -0.347776 + -0.870691 0.347776 -0.347776 + -0.870691 0.347776 -0.347776 + -0.870691 0.347776 -0.347776 + -0.870691 0.347776 -0.347776 + -0.870691 0.347776 -0.347776 + -0.870691 0.347776 -0.347776 + -0.999942 -0.00762504 0.00762516 + -0.999942 -0.00762504 0.00762516 + -0.999942 -0.00762504 0.00762516 + -0.999942 -0.00762504 0.00762516 + -0.999942 -0.00762504 0.00762516 + -0.999942 -0.00762504 0.00762516 + -0.861356 -0.359211 0.359212 + -0.861356 -0.359211 0.359212 + -0.861356 -0.359211 0.359212 + -0.861356 -0.359211 0.359212 + -0.861356 -0.359211 0.359212 + -0.861356 -0.359211 0.359212 + -0.495387 -0.614244 0.614244 + -0.495387 -0.614244 0.614244 + -0.495387 -0.614244 0.614244 + -0.495387 -0.614244 0.614244 + -0.495387 -0.614244 0.614244 + -0.495387 -0.614244 0.614244 + -3.7802e-07 -0.793353 0.608762 + -3.7802e-07 -0.793353 0.608762 + -3.7802e-07 -0.793353 0.608762 + -3.7802e-07 -0.793353 0.608762 + -3.7802e-07 -0.793353 0.608762 + -3.7802e-07 -0.793353 0.608762 + 0.495391 -0.689163 0.528813 + 0.495391 -0.689163 0.528813 + 0.495391 -0.689163 0.528813 + 0.495391 -0.689163 0.528813 + 0.495391 -0.689163 0.528813 + 0.495391 -0.689163 0.528813 + 0.861356 -0.403025 0.309252 + 0.861356 -0.403025 0.309252 + 0.861356 -0.403025 0.309252 + 0.861356 -0.403025 0.309252 + 0.861356 -0.403025 0.309252 + 0.861356 -0.403025 0.309252 + 0.999942 -0.00855631 0.00656551 + 0.999942 -0.00855631 0.00656551 + 0.999942 -0.00855631 0.00656551 + 0.999942 -0.00855631 0.00656551 + 0.999942 -0.00855631 0.00656551 + 0.870694 0.390192 -0.299405 + 0.870694 0.390192 -0.299405 + 0.870694 0.390192 -0.299405 + 0.870694 0.390192 -0.299405 + 0.870694 0.390192 -0.299405 + 0.870694 0.390192 -0.299405 + 0.870694 0.390192 -0.299405 + 0.870694 0.390192 -0.299405 + 0.504723 0.684887 -0.525532 + 0.504723 0.684887 -0.525532 + 0.504723 0.684887 -0.525532 + 0.504723 0.684887 -0.525532 + 0.504723 0.684887 -0.525532 + -9.44063e-07 0.793353 -0.608762 + -9.44063e-07 0.793353 -0.608762 + -9.44063e-07 0.793353 -0.608762 + -9.44063e-07 0.793353 -0.608762 + -9.44063e-07 0.793353 -0.608762 + -0.504724 0.684887 -0.525532 + -0.504724 0.684887 -0.525532 + -0.504724 0.684887 -0.525532 + -0.504724 0.684887 -0.525532 + -0.504724 0.684887 -0.525532 + -0.504724 0.684887 -0.525532 + -0.504724 0.684887 -0.525532 + -0.870694 0.390192 -0.299405 + -0.870694 0.390192 -0.299405 + -0.870694 0.390192 -0.299405 + -0.870694 0.390192 -0.299405 + -0.870694 0.390192 -0.299405 + -0.870694 0.390192 -0.299405 + -0.870694 0.390192 -0.299405 + -0.999942 -0.00855642 0.00656569 + -0.999942 -0.00855642 0.00656569 + -0.999942 -0.00855642 0.00656569 + -0.999942 -0.00855642 0.00656569 + -0.999942 -0.00855642 0.00656569 + -0.861356 -0.403025 0.309253 + -0.861356 -0.403025 0.309253 + -0.861356 -0.403025 0.309253 + -0.861356 -0.403025 0.309253 + -0.861356 -0.403025 0.309253 + -0.861356 -0.403025 0.309253 + -0.495391 -0.689163 0.528813 + -0.495391 -0.689163 0.528813 + -0.495391 -0.689163 0.528813 + -0.495391 -0.689163 0.528813 + -0.495391 -0.689163 0.528813 + -0.495391 -0.689163 0.528813 + 6.31691e-07 -0.866026 0.5 + 6.31691e-07 -0.866026 0.5 + 6.31691e-07 -0.866026 0.5 + 6.31691e-07 -0.866026 0.5 + 6.31691e-07 -0.866026 0.5 + 6.31691e-07 -0.866026 0.5 + 0.495389 -0.752291 0.434336 + 0.495389 -0.752291 0.434336 + 0.495389 -0.752291 0.434336 + 0.495389 -0.752291 0.434336 + 0.495389 -0.752291 0.434336 + 0.861358 -0.43994 0.253999 + 0.861358 -0.43994 0.253999 + 0.861358 -0.43994 0.253999 + 0.861358 -0.43994 0.253999 + 0.861358 -0.43994 0.253999 + 0.861358 -0.43994 0.253999 + 0.861358 -0.43994 0.253999 + 0.861358 -0.43994 0.253999 + 0.999942 -0.00933719 0.00539076 + 0.999942 -0.00933719 0.00539076 + 0.999942 -0.00933719 0.00539076 + 0.999942 -0.00933719 0.00539076 + 0.999942 -0.00933719 0.00539076 + 0.870693 0.425934 -0.245913 + 0.870693 0.425934 -0.245913 + 0.870693 0.425934 -0.245913 + 0.870693 0.425934 -0.245913 + 0.870693 0.425934 -0.245913 + 0.504725 0.747623 -0.43164 + 0.504725 0.747623 -0.43164 + 0.504725 0.747623 -0.43164 + 0.504725 0.747623 -0.43164 + 0.504725 0.747623 -0.43164 + 0.504725 0.747623 -0.43164 + 0.504725 0.747623 -0.43164 + 0.504725 0.747623 -0.43164 + 0 0.866026 -0.5 + 0 0.866026 -0.5 + 0 0.866026 -0.5 + 0 0.866026 -0.5 + 0 0.866026 -0.5 + -0.504726 0.747622 -0.43164 + -0.504726 0.747622 -0.43164 + -0.504726 0.747622 -0.43164 + -0.504726 0.747622 -0.43164 + -0.504726 0.747622 -0.43164 + -0.504726 0.747622 -0.43164 + -0.870693 0.425934 -0.245913 + -0.870693 0.425934 -0.245913 + -0.870693 0.425934 -0.245913 + -0.870693 0.425934 -0.245913 + -0.870693 0.425934 -0.245913 + -0.870693 0.425934 -0.245913 + -0.999942 -0.00933725 0.00539076 + -0.999942 -0.00933725 0.00539076 + -0.999942 -0.00933725 0.00539076 + -0.999942 -0.00933725 0.00539076 + -0.999942 -0.00933725 0.00539076 + -0.861358 -0.43994 0.254 + -0.861358 -0.43994 0.254 + -0.861358 -0.43994 0.254 + -0.861358 -0.43994 0.254 + -0.861358 -0.43994 0.254 + -0.861358 -0.43994 0.254 + -0.861358 -0.43994 0.254 + -0.861358 -0.43994 0.254 + -0.495389 -0.752291 0.434336 + -0.495389 -0.752291 0.434336 + -0.495389 -0.752291 0.434336 + -0.495389 -0.752291 0.434336 + -0.495389 -0.752291 0.434336 + 0 -0.92388 0.382683 + 0 -0.92388 0.382683 + 0 -0.92388 0.382683 + 0 -0.92388 0.382683 + 0 -0.92388 0.382683 + 0 -0.92388 0.382683 + 0 -0.92388 0.382683 + 0 -0.92388 0.382683 + 0.495387 -0.802549 0.332426 + 0.495387 -0.802549 0.332426 + 0.495387 -0.802549 0.332426 + 0.495387 -0.802549 0.332426 + 0.495387 -0.802549 0.332426 + 0.861356 -0.469333 0.194404 + 0.861356 -0.469333 0.194404 + 0.861356 -0.469333 0.194404 + 0.861356 -0.469333 0.194404 + 0.861356 -0.469333 0.194404 + 0.861356 -0.469333 0.194404 + 0.999942 -0.00996119 0.00412595 + 0.999942 -0.00996119 0.00412595 + 0.999942 -0.00996119 0.00412595 + 0.999942 -0.00996119 0.00412595 + 0.999942 -0.00996119 0.00412595 + 0.999942 -0.00996119 0.00412595 + 0.870693 0.454388 -0.188214 + 0.870693 0.454388 -0.188214 + 0.870693 0.454388 -0.188214 + 0.870693 0.454388 -0.188214 + 0.870693 0.454388 -0.188214 + 0.870693 0.454388 -0.188214 + 0.870693 0.454388 -0.188214 + 0.504726 0.797567 -0.330363 + 0.504726 0.797567 -0.330363 + 0.504726 0.797567 -0.330363 + 0.504726 0.797567 -0.330363 + -2.74427e-07 0.92388 -0.382683 + -2.74427e-07 0.92388 -0.382683 + -2.74427e-07 0.92388 -0.382683 + -2.74427e-07 0.92388 -0.382683 + -2.74427e-07 0.92388 -0.382683 + -2.74427e-07 0.92388 -0.382683 + -2.74427e-07 0.92388 -0.382683 + -2.74427e-07 0.92388 -0.382683 + -0.504726 0.797567 -0.330363 + -0.504726 0.797567 -0.330363 + -0.504726 0.797567 -0.330363 + -0.504726 0.797567 -0.330363 + -0.504726 0.797567 -0.330363 + -0.870693 0.454388 -0.188213 + -0.870693 0.454388 -0.188213 + -0.870693 0.454388 -0.188213 + -0.870693 0.454388 -0.188213 + -0.870693 0.454388 -0.188213 + -0.870693 0.454388 -0.188213 + -0.999942 -0.00996113 0.00412613 + -0.999942 -0.00996113 0.00412613 + -0.999942 -0.00996113 0.00412613 + -0.999942 -0.00996113 0.00412613 + -0.999942 -0.00996113 0.00412613 + -0.999942 -0.00996113 0.00412613 + -0.861356 -0.469333 0.194404 + -0.861356 -0.469333 0.194404 + -0.861356 -0.469333 0.194404 + -0.861356 -0.469333 0.194404 + -0.861356 -0.469333 0.194404 + -0.861356 -0.469333 0.194404 + -0.495387 -0.802549 0.332426 + -0.495387 -0.802549 0.332426 + -0.495387 -0.802549 0.332426 + -0.495387 -0.802549 0.332426 + -0.495387 -0.802549 0.332426 + 2.11704e-07 -0.965926 0.258819 + 2.11704e-07 -0.965926 0.258819 + 2.11704e-07 -0.965926 0.258819 + 2.11704e-07 -0.965926 0.258819 + 2.11704e-07 -0.965926 0.258819 + 2.11704e-07 -0.965926 0.258819 + 0.495389 -0.839072 0.224829 + 0.495389 -0.839072 0.224829 + 0.495389 -0.839072 0.224829 + 0.495389 -0.839072 0.224829 + 0.495389 -0.839072 0.224829 + 0.495389 -0.839072 0.224829 + 0.861356 -0.490692 0.131481 + 0.861356 -0.490692 0.131481 + 0.861356 -0.490692 0.131481 + 0.861356 -0.490692 0.131481 + 0.861356 -0.490692 0.131481 + 0.861356 -0.490692 0.131481 + 0.999942 -0.0104157 0.00279081 + 0.999942 -0.0104157 0.00279081 + 0.999942 -0.0104157 0.00279081 + 0.999942 -0.0104157 0.00279081 + 0.999942 -0.0104157 0.00279081 + 0.999942 -0.0104157 0.00279081 + 0.870694 0.475066 -0.127293 + 0.870694 0.475066 -0.127293 + 0.870694 0.475066 -0.127293 + 0.870694 0.475066 -0.127293 + 0.870694 0.475066 -0.127293 + 0.504724 0.833865 -0.223434 + 0.504724 0.833865 -0.223434 + 0.504724 0.833865 -0.223434 + 0.504724 0.833865 -0.223434 + 0.504724 0.833865 -0.223434 + 0.504724 0.833865 -0.223434 + 0.504724 0.833865 -0.223434 + 3.82432e-07 0.965926 -0.25882 + 3.82432e-07 0.965926 -0.25882 + 3.82432e-07 0.965926 -0.25882 + 3.82432e-07 0.965926 -0.25882 + 3.82432e-07 0.965926 -0.25882 + -0.504724 0.833865 -0.223434 + -0.504724 0.833865 -0.223434 + -0.504724 0.833865 -0.223434 + -0.504724 0.833865 -0.223434 + -0.504724 0.833865 -0.223434 + -0.504724 0.833865 -0.223434 + -0.504724 0.833865 -0.223434 + -0.870694 0.475066 -0.127294 + -0.870694 0.475066 -0.127294 + -0.870694 0.475066 -0.127294 + -0.870694 0.475066 -0.127294 + -0.870694 0.475066 -0.127294 + -0.870694 0.475066 -0.127294 + -0.999942 -0.0104164 0.00279111 + -0.999942 -0.0104164 0.00279111 + -0.999942 -0.0104164 0.00279111 + -0.999942 -0.0104164 0.00279111 + -0.999942 -0.0104164 0.00279111 + -0.999942 -0.0104164 0.00279111 + -0.861356 -0.490692 0.131481 + -0.861356 -0.490692 0.131481 + -0.861356 -0.490692 0.131481 + -0.861356 -0.490692 0.131481 + -0.861356 -0.490692 0.131481 + -0.861356 -0.490692 0.131481 + -0.49539 -0.839071 0.224829 + -0.49539 -0.839071 0.224829 + -0.49539 -0.839071 0.224829 + -0.49539 -0.839071 0.224829 + -0.49539 -0.839071 0.224829 + -0.49539 -0.839071 0.224829 + 2.39682e-07 -0.991445 0.130527 + 2.39682e-07 -0.991445 0.130527 + 2.39682e-07 -0.991445 0.130527 + 2.39682e-07 -0.991445 0.130527 + 2.39682e-07 -0.991445 0.130527 + 0.49539 -0.861239 0.113385 + 0.49539 -0.861239 0.113385 + 0.49539 -0.861239 0.113385 + 0.49539 -0.861239 0.113385 + 0.49539 -0.861239 0.113385 + 0.49539 -0.861239 0.113385 + 0.49539 -0.861239 0.113385 + 0.49539 -0.861239 0.113385 + 0.861357 -0.503655 0.0663077 + 0.861357 -0.503655 0.0663077 + 0.861357 -0.503655 0.0663077 + 0.861357 -0.503655 0.0663077 + 0.861357 -0.503655 0.0663077 + 0.999942 -0.0106897 0.00140738 + 0.999942 -0.0106897 0.00140738 + 0.999942 -0.0106897 0.00140738 + 0.999942 -0.0106897 0.00140738 + 0.999942 -0.0106897 0.00140738 + 0.999942 -0.0106897 0.00140738 + 0.999942 -0.0106897 0.00140738 + 0.870692 0.487622 -0.0641969 + 0.870692 0.487622 -0.0641969 + 0.870692 0.487622 -0.0641969 + 0.870692 0.487622 -0.0641969 + 0.870692 0.487622 -0.0641969 + 0.504724 0.855895 -0.112681 + 0.504724 0.855895 -0.112681 + 0.504724 0.855895 -0.112681 + 0.504724 0.855895 -0.112681 + 0.504724 0.855895 -0.112681 + 0.504724 0.855895 -0.112681 + 0.504724 0.855895 -0.112681 + 3.01809e-07 0.991445 -0.130526 + 3.01809e-07 0.991445 -0.130526 + 3.01809e-07 0.991445 -0.130526 + 3.01809e-07 0.991445 -0.130526 + 3.01809e-07 0.991445 -0.130526 + -0.504724 0.855895 -0.112681 + -0.504724 0.855895 -0.112681 + -0.504724 0.855895 -0.112681 + -0.504724 0.855895 -0.112681 + -0.504724 0.855895 -0.112681 + -0.504724 0.855895 -0.112681 + -0.504724 0.855895 -0.112681 + -0.870692 0.487622 -0.0641967 + -0.870692 0.487622 -0.0641967 + -0.870692 0.487622 -0.0641967 + -0.870692 0.487622 -0.0641967 + -0.999942 -0.0106901 0.0014075 + -0.999942 -0.0106901 0.0014075 + -0.999942 -0.0106901 0.0014075 + -0.999942 -0.0106901 0.0014075 + -0.999942 -0.0106901 0.0014075 + -0.999942 -0.0106901 0.0014075 + -0.999942 -0.0106901 0.0014075 + -0.861356 -0.503655 0.0663078 + -0.861356 -0.503655 0.0663078 + -0.861356 -0.503655 0.0663078 + -0.861356 -0.503655 0.0663078 + -0.861356 -0.503655 0.0663078 + -0.861356 -0.503655 0.0663078 + -0.49539 -0.861239 0.113385 + -0.49539 -0.861239 0.113385 + -0.49539 -0.861239 0.113385 + -0.49539 -0.861239 0.113385 + -0.49539 -0.861239 0.113385 + -0.49539 -0.861239 0.113385 + 1.23727e-07 -1 0 + 1.23727e-07 -1 0 + 1.23727e-07 -1 0 + 1.23727e-07 -1 0 + 1.23727e-07 -1 0 + 1.23727e-07 -1 0 + 1.23727e-07 -1 0 + 0.495387 -0.868672 3.30132e-07 + 0.495387 -0.868672 3.30132e-07 + 0.495387 -0.868672 3.30132e-07 + 0.495387 -0.868672 3.30132e-07 + 0.861357 -0.508001 1.23848e-07 + 0.861357 -0.508001 1.23848e-07 + 0.861357 -0.508001 1.23848e-07 + 0.861357 -0.508001 1.23848e-07 + 0.861357 -0.508001 1.23848e-07 + 0.861357 -0.508001 1.23848e-07 + 0.861357 -0.508001 1.23848e-07 + 0.999942 -0.0107837 0 + 0.999942 -0.0107837 0 + 0.999942 -0.0107837 0 + 0.999942 -0.0107837 0 + 0.999942 -0.0107837 0 + 0.870693 0.491828 -1.49583e-07 + 0.870693 0.491828 -1.49583e-07 + 0.870693 0.491828 -1.49583e-07 + 0.870693 0.491828 -1.49583e-07 + 0.870693 0.491828 -1.49583e-07 + 0.870693 0.491828 -1.49583e-07 + 0.870693 0.491828 -1.49583e-07 + 0.504725 0.86328 -5.96493e-07 + 0.504725 0.86328 -5.96493e-07 + 0.504725 0.86328 -5.96493e-07 + 0.504725 0.86328 -5.96493e-07 + 0.504725 0.86328 -5.96493e-07 + -2.14795e-07 1 -8.03353e-07 + -2.14795e-07 1 -8.03353e-07 + -2.14795e-07 1 -8.03353e-07 + -2.14795e-07 1 -8.03353e-07 + -2.14795e-07 1 -8.03353e-07 + -2.14795e-07 1 -8.03353e-07 + -2.14795e-07 1 -8.03353e-07 + -0.504725 0.86328 -5.15869e-07 + -0.504725 0.86328 -5.15869e-07 + -0.504725 0.86328 -5.15869e-07 + -0.504725 0.86328 -5.15869e-07 + -0.504725 0.86328 -5.15869e-07 + -0.870693 0.491828 -1.80622e-07 + -0.870693 0.491828 -1.80622e-07 + -0.870693 0.491828 -1.80622e-07 + -0.870693 0.491828 -1.80622e-07 + -0.870693 0.491828 -1.80622e-07 + -0.870693 0.491828 -1.80622e-07 + -0.870693 0.491828 -1.80622e-07 + -0.870693 0.491828 -1.80622e-07 + -0.999942 -0.0107838 0 + -0.999942 -0.0107838 0 + -0.999942 -0.0107838 0 + -0.999942 -0.0107838 0 + -0.999942 -0.0107838 0 + -0.999942 -0.0107838 0 + -0.861357 -0.508001 0 + -0.861357 -0.508001 0 + -0.861357 -0.508001 0 + -0.861357 -0.508001 0 + -0.861357 -0.508001 0 + -0.495387 -0.868672 0 + -0.495387 -0.868672 0 + -0.495387 -0.868672 0 + -0.495387 -0.868672 0 + -0.495387 -0.868672 0 + -0.495387 -0.868672 0 + -1.26525e-07 -0.991445 -0.130526 + -1.26525e-07 -0.991445 -0.130526 + -1.26525e-07 -0.991445 -0.130526 + -1.26525e-07 -0.991445 -0.130526 + -1.26525e-07 -0.991445 -0.130526 + -1.26525e-07 -0.991445 -0.130526 + 0.495389 -0.86124 -0.113384 + 0.495389 -0.86124 -0.113384 + 0.495389 -0.86124 -0.113384 + 0.495389 -0.86124 -0.113384 + 0.495389 -0.86124 -0.113384 + 0.495389 -0.86124 -0.113384 + 0.861358 -0.503653 -0.0663074 + 0.861358 -0.503653 -0.0663074 + 0.861358 -0.503653 -0.0663074 + 0.861358 -0.503653 -0.0663074 + 0.861358 -0.503653 -0.0663074 + 0.861358 -0.503653 -0.0663074 + 0.999942 -0.0106906 -0.00140738 + 0.999942 -0.0106906 -0.00140738 + 0.999942 -0.0106906 -0.00140738 + 0.999942 -0.0106906 -0.00140738 + 0.999942 -0.0106906 -0.00140738 + 0.999942 -0.0106906 -0.00140738 + 0.870692 0.48762 0.0641962 + 0.870692 0.48762 0.0641962 + 0.870692 0.48762 0.0641962 + 0.870692 0.48762 0.0641962 + 0.870692 0.48762 0.0641962 + 0.870692 0.48762 0.0641962 + 0.870692 0.48762 0.0641962 + 0.504722 0.855897 0.112681 + 0.504722 0.855897 0.112681 + 0.504722 0.855897 0.112681 + 0.504722 0.855897 0.112681 + 0.504722 0.855897 0.112681 + 0 0.991445 0.130527 + 0 0.991445 0.130527 + 0 0.991445 0.130527 + 0 0.991445 0.130527 + 0 0.991445 0.130527 + 0 0.991445 0.130527 + -0.504722 0.855896 0.112682 + -0.504722 0.855896 0.112682 + -0.504722 0.855896 0.112682 + -0.504722 0.855896 0.112682 + -0.504722 0.855896 0.112682 + -0.504722 0.855896 0.112682 + -0.870692 0.487621 0.0641965 + -0.870692 0.487621 0.0641965 + -0.870692 0.487621 0.0641965 + -0.870692 0.487621 0.0641965 + -0.870692 0.487621 0.0641965 + -0.870692 0.487621 0.0641965 + -0.999942 -0.0106907 -0.0014075 + -0.999942 -0.0106907 -0.0014075 + -0.999942 -0.0106907 -0.0014075 + -0.999942 -0.0106907 -0.0014075 + -0.999942 -0.0106907 -0.0014075 + -0.861358 -0.503653 -0.0663074 + -0.861358 -0.503653 -0.0663074 + -0.861358 -0.503653 -0.0663074 + -0.861358 -0.503653 -0.0663074 + -0.861358 -0.503653 -0.0663074 + -0.861358 -0.503653 -0.0663074 + -0.861358 -0.503653 -0.0663074 + -0.495389 -0.86124 -0.113384 + -0.495389 -0.86124 -0.113384 + -0.495389 -0.86124 -0.113384 + -0.495389 -0.86124 -0.113384 + -0.495389 -0.86124 -0.113384 + -0.495389 -0.86124 -0.113384 + -1.96781e-07 -0.965926 -0.258819 + -1.96781e-07 -0.965926 -0.258819 + -1.96781e-07 -0.965926 -0.258819 + -1.96781e-07 -0.965926 -0.258819 + -1.96781e-07 -0.965926 -0.258819 + -1.96781e-07 -0.965926 -0.258819 + 0.495389 -0.839072 -0.224829 + 0.495389 -0.839072 -0.224829 + 0.495389 -0.839072 -0.224829 + 0.495389 -0.839072 -0.224829 + 0.495389 -0.839072 -0.224829 + 0.495389 -0.839072 -0.224829 + 0.495389 -0.839072 -0.224829 + 0.861357 -0.49069 -0.13148 + 0.861357 -0.49069 -0.13148 + 0.861357 -0.49069 -0.13148 + 0.861357 -0.49069 -0.13148 + 0.999942 -0.0104157 -0.00279105 + 0.999942 -0.0104157 -0.00279105 + 0.999942 -0.0104157 -0.00279105 + 0.999942 -0.0104157 -0.00279105 + 0.999942 -0.0104157 -0.00279105 + 0.999942 -0.0104157 -0.00279105 + 0.999942 -0.0104157 -0.00279105 + 0.999942 -0.0104157 -0.00279105 + 0.870692 0.475069 0.127294 + 0.870692 0.475069 0.127294 + 0.870692 0.475069 0.127294 + 0.870692 0.475069 0.127294 + 0.504724 0.833865 0.223433 + 0.504724 0.833865 0.223433 + 0.504724 0.833865 0.223433 + 0.504724 0.833865 0.223433 + 0.504724 0.833865 0.223433 + 0.504724 0.833865 0.223433 + 0.504724 0.833865 0.223433 + 0.504724 0.833865 0.223433 + 0 0.965926 0.258819 + 0 0.965926 0.258819 + 0 0.965926 0.258819 + 0 0.965926 0.258819 + 0 0.965926 0.258819 + -0.504724 0.833865 0.223433 + -0.504724 0.833865 0.223433 + -0.504724 0.833865 0.223433 + -0.504724 0.833865 0.223433 + -0.504724 0.833865 0.223433 + -0.504724 0.833865 0.223433 + -0.504724 0.833865 0.223433 + -0.870693 0.475069 0.127294 + -0.870693 0.475069 0.127294 + -0.870693 0.475069 0.127294 + -0.870693 0.475069 0.127294 + -0.999942 -0.0104156 -0.00279087 + -0.999942 -0.0104156 -0.00279087 + -0.999942 -0.0104156 -0.00279087 + -0.999942 -0.0104156 -0.00279087 + -0.999942 -0.0104156 -0.00279087 + -0.999942 -0.0104156 -0.00279087 + -0.999942 -0.0104156 -0.00279087 + -0.861357 -0.490691 -0.13148 + -0.861357 -0.490691 -0.13148 + -0.861357 -0.490691 -0.13148 + -0.861357 -0.490691 -0.13148 + -0.861357 -0.490691 -0.13148 + -0.495388 -0.839073 -0.224829 + -0.495388 -0.839073 -0.224829 + -0.495388 -0.839073 -0.224829 + -0.495388 -0.839073 -0.224829 + -0.495388 -0.839073 -0.224829 + -0.495388 -0.839073 -0.224829 + -0.495388 -0.839073 -0.224829 + -3.75843e-07 -0.92388 -0.382683 + -3.75843e-07 -0.92388 -0.382683 + -3.75843e-07 -0.92388 -0.382683 + -3.75843e-07 -0.92388 -0.382683 + -3.75843e-07 -0.92388 -0.382683 + -3.75843e-07 -0.92388 -0.382683 + 0.495387 -0.802549 -0.332426 + 0.495387 -0.802549 -0.332426 + 0.495387 -0.802549 -0.332426 + 0.495387 -0.802549 -0.332426 + 0.495387 -0.802549 -0.332426 + 0.495387 -0.802549 -0.332426 + 0.861357 -0.469331 -0.194403 + 0.861357 -0.469331 -0.194403 + 0.861357 -0.469331 -0.194403 + 0.861357 -0.469331 -0.194403 + 0.861357 -0.469331 -0.194403 + 0.861357 -0.469331 -0.194403 + 0.999942 -0.00996101 -0.00412601 + 0.999942 -0.00996101 -0.00412601 + 0.999942 -0.00996101 -0.00412601 + 0.999942 -0.00996101 -0.00412601 + 0.999942 -0.00996101 -0.00412601 + 0.999942 -0.00996101 -0.00412601 + 0.870693 0.454388 0.188214 + 0.870693 0.454388 0.188214 + 0.870693 0.454388 0.188214 + 0.870693 0.454388 0.188214 + 0.870693 0.454388 0.188214 + 0.870693 0.454388 0.188214 + 0.504726 0.797566 0.330363 + 0.504726 0.797566 0.330363 + 0.504726 0.797566 0.330363 + 0.504726 0.797566 0.330363 + 0.504726 0.797566 0.330363 + 0.504726 0.797566 0.330363 + 6.27957e-07 0.92388 0.382683 + 6.27957e-07 0.92388 0.382683 + 6.27957e-07 0.92388 0.382683 + 6.27957e-07 0.92388 0.382683 + 6.27957e-07 0.92388 0.382683 + 6.27957e-07 0.92388 0.382683 + -0.504726 0.797566 0.330363 + -0.504726 0.797566 0.330363 + -0.504726 0.797566 0.330363 + -0.504726 0.797566 0.330363 + -0.504726 0.797566 0.330363 + -0.504726 0.797566 0.330363 + -0.870694 0.454388 0.188214 + -0.870694 0.454388 0.188214 + -0.870694 0.454388 0.188214 + -0.870694 0.454388 0.188214 + -0.870694 0.454388 0.188214 + -0.870694 0.454388 0.188214 + -0.999942 -0.00996125 -0.00412589 + -0.999942 -0.00996125 -0.00412589 + -0.999942 -0.00996125 -0.00412589 + -0.999942 -0.00996125 -0.00412589 + -0.999942 -0.00996125 -0.00412589 + -0.999942 -0.00996125 -0.00412589 + -0.999942 -0.00996125 -0.00412589 + -0.861357 -0.469331 -0.194403 + -0.861357 -0.469331 -0.194403 + -0.861357 -0.469331 -0.194403 + -0.861357 -0.469331 -0.194403 + -0.861357 -0.469331 -0.194403 + -0.495387 -0.802549 -0.332426 + -0.495387 -0.802549 -0.332426 + -0.495387 -0.802549 -0.332426 + -0.495387 -0.802549 -0.332426 + -0.495387 -0.802549 -0.332426 + -0.495387 -0.802549 -0.332426 + -2.61442e-07 -0.866025 -0.5 + -2.61442e-07 -0.866025 -0.5 + -2.61442e-07 -0.866025 -0.5 + -2.61442e-07 -0.866025 -0.5 + -2.61442e-07 -0.866025 -0.5 + -2.61442e-07 -0.866025 -0.5 + 0.495387 -0.752292 -0.434336 + 0.495387 -0.752292 -0.434336 + 0.495387 -0.752292 -0.434336 + 0.495387 -0.752292 -0.434336 + 0.495387 -0.752292 -0.434336 + 0.861358 -0.43994 -0.254 + 0.861358 -0.43994 -0.254 + 0.861358 -0.43994 -0.254 + 0.861358 -0.43994 -0.254 + 0.861358 -0.43994 -0.254 + 0.861358 -0.43994 -0.254 + 0.861358 -0.43994 -0.254 + 0.999942 -0.00933766 -0.00539112 + 0.999942 -0.00933766 -0.00539112 + 0.999942 -0.00933766 -0.00539112 + 0.999942 -0.00933766 -0.00539112 + 0.999942 -0.00933766 -0.00539112 + 0.999942 -0.00933766 -0.00539112 + 0.870693 0.425935 0.245914 + 0.870693 0.425935 0.245914 + 0.870693 0.425935 0.245914 + 0.870693 0.425935 0.245914 + 0.870693 0.425935 0.245914 + 0.870693 0.425935 0.245914 + 0.504722 0.747624 0.431641 + 0.504722 0.747624 0.431641 + 0.504722 0.747624 0.431641 + 0.504722 0.747624 0.431641 + 0.504722 0.747624 0.431641 + 0.504722 0.747624 0.431641 + -1.70375e-07 0.866025 0.5 + -1.70375e-07 0.866025 0.5 + -1.70375e-07 0.866025 0.5 + -1.70375e-07 0.866025 0.5 + -1.70375e-07 0.866025 0.5 + -1.70375e-07 0.866025 0.5 + -0.504721 0.747624 0.431641 + -0.504721 0.747624 0.431641 + -0.504721 0.747624 0.431641 + -0.504721 0.747624 0.431641 + -0.504721 0.747624 0.431641 + -0.504721 0.747624 0.431641 + -0.870693 0.425935 0.245914 + -0.870693 0.425935 0.245914 + -0.870693 0.425935 0.245914 + -0.870693 0.425935 0.245914 + -0.870693 0.425935 0.245914 + -0.870693 0.425935 0.245914 + -0.999942 -0.00933778 -0.00539112 + -0.999942 -0.00933778 -0.00539112 + -0.999942 -0.00933778 -0.00539112 + -0.999942 -0.00933778 -0.00539112 + -0.999942 -0.00933778 -0.00539112 + -0.999942 -0.00933778 -0.00539112 + -0.861358 -0.43994 -0.253999 + -0.861358 -0.43994 -0.253999 + -0.861358 -0.43994 -0.253999 + -0.861358 -0.43994 -0.253999 + -0.861358 -0.43994 -0.253999 + -0.861358 -0.43994 -0.253999 + -0.861358 -0.43994 -0.253999 + -0.495387 -0.752292 -0.434336 + -0.495387 -0.752292 -0.434336 + -0.495387 -0.752292 -0.434336 + -0.495387 -0.752292 -0.434336 + -0.495387 -0.752292 -0.434336 + 6.96353e-07 -0.793353 -0.608762 + 6.96353e-07 -0.793353 -0.608762 + 6.96353e-07 -0.793353 -0.608762 + 6.96353e-07 -0.793353 -0.608762 + 0.495391 -0.689162 -0.528813 + 0.495391 -0.689162 -0.528813 + 0.495391 -0.689162 -0.528813 + 0.495391 -0.689162 -0.528813 + 0.495391 -0.689162 -0.528813 + 0.495391 -0.689162 -0.528813 + 0.495391 -0.689162 -0.528813 + 0.495391 -0.689162 -0.528813 + 0.861356 -0.403025 -0.309252 + 0.861356 -0.403025 -0.309252 + 0.861356 -0.403025 -0.309252 + 0.861356 -0.403025 -0.309252 + 0.861356 -0.403025 -0.309252 + 0.999942 -0.00855434 -0.00656396 + 0.999942 -0.00855434 -0.00656396 + 0.999942 -0.00855434 -0.00656396 + 0.999942 -0.00855434 -0.00656396 + 0.999942 -0.00855434 -0.00656396 + 0.999942 -0.00855434 -0.00656396 + 0.870694 0.390191 0.299404 + 0.870694 0.390191 0.299404 + 0.870694 0.390191 0.299404 + 0.870694 0.390191 0.299404 + 0.870694 0.390191 0.299404 + 0.870694 0.390191 0.299404 + 0.504726 0.684886 0.525531 + 0.504726 0.684886 0.525531 + 0.504726 0.684886 0.525531 + 0.504726 0.684886 0.525531 + 0.504726 0.684886 0.525531 + 0.504726 0.684886 0.525531 + 2.5313e-07 0.793354 0.608761 + 2.5313e-07 0.793354 0.608761 + 2.5313e-07 0.793354 0.608761 + 2.5313e-07 0.793354 0.608761 + 2.5313e-07 0.793354 0.608761 + 2.5313e-07 0.793354 0.608761 + -0.504726 0.684886 0.525531 + -0.504726 0.684886 0.525531 + -0.504726 0.684886 0.525531 + -0.504726 0.684886 0.525531 + -0.504726 0.684886 0.525531 + -0.504726 0.684886 0.525531 + -0.870694 0.390191 0.299404 + -0.870694 0.390191 0.299404 + -0.870694 0.390191 0.299404 + -0.870694 0.390191 0.299404 + -0.870694 0.390191 0.299404 + -0.870694 0.390191 0.299404 + -0.999942 -0.00855458 -0.00656396 + -0.999942 -0.00855458 -0.00656396 + -0.999942 -0.00855458 -0.00656396 + -0.999942 -0.00855458 -0.00656396 + -0.999942 -0.00855458 -0.00656396 + -0.999942 -0.00855458 -0.00656396 + -0.861356 -0.403025 -0.309252 + -0.861356 -0.403025 -0.309252 + -0.861356 -0.403025 -0.309252 + -0.861356 -0.403025 -0.309252 + -0.861356 -0.403025 -0.309252 + -0.49539 -0.689163 -0.528813 + -0.49539 -0.689163 -0.528813 + -0.49539 -0.689163 -0.528813 + -0.49539 -0.689163 -0.528813 + -0.49539 -0.689163 -0.528813 + -0.49539 -0.689163 -0.528813 + -0.49539 -0.689163 -0.528813 + -0.49539 -0.689163 -0.528813 + 8.65465e-07 -0.707107 -0.707106 + 8.65465e-07 -0.707107 -0.707106 + 8.65465e-07 -0.707107 -0.707106 + 8.65465e-07 -0.707107 -0.707106 + 8.65465e-07 -0.707107 -0.707106 + 8.65465e-07 -0.707107 -0.707106 + 0.495386 -0.614245 -0.614244 + 0.495386 -0.614245 -0.614244 + 0.495386 -0.614245 -0.614244 + 0.495386 -0.614245 -0.614244 + 0.495386 -0.614245 -0.614244 + 0.495386 -0.614245 -0.614244 + 0.861355 -0.359213 -0.359213 + 0.861355 -0.359213 -0.359213 + 0.861355 -0.359213 -0.359213 + 0.861355 -0.359213 -0.359213 + 0.861355 -0.359213 -0.359213 + 0.861355 -0.359213 -0.359213 + 0.999942 -0.00762457 -0.00762445 + 0.999942 -0.00762457 -0.00762445 + 0.999942 -0.00762457 -0.00762445 + 0.999942 -0.00762457 -0.00762445 + 0.999942 -0.00762457 -0.00762445 + 0.870691 0.347776 0.347776 + 0.870691 0.347776 0.347776 + 0.870691 0.347776 0.347776 + 0.870691 0.347776 0.347776 + 0.870691 0.347776 0.347776 + 0.870691 0.347776 0.347776 + 0.870691 0.347776 0.347776 + 0.870691 0.347776 0.347776 + 0.504722 0.610433 0.610433 + 0.504722 0.610433 0.610433 + 0.504722 0.610433 0.610433 + 0.504722 0.610433 0.610433 + 7.00062e-07 0.707107 0.707106 + 7.00062e-07 0.707107 0.707106 + 7.00062e-07 0.707107 0.707106 + 7.00062e-07 0.707107 0.707106 + 7.00062e-07 0.707107 0.707106 + 7.00062e-07 0.707107 0.707106 + 7.00062e-07 0.707107 0.707106 + 7.00062e-07 0.707107 0.707106 + -0.504722 0.610433 0.610433 + -0.504722 0.610433 0.610433 + -0.504722 0.610433 0.610433 + -0.504722 0.610433 0.610433 + -0.870692 0.347776 0.347776 + -0.870692 0.347776 0.347776 + -0.870692 0.347776 0.347776 + -0.870692 0.347776 0.347776 + -0.870692 0.347776 0.347776 + -0.870692 0.347776 0.347776 + -0.870692 0.347776 0.347776 + -0.870692 0.347776 0.347776 + -0.999942 -0.00762445 -0.00762463 + -0.999942 -0.00762445 -0.00762463 + -0.999942 -0.00762445 -0.00762463 + -0.999942 -0.00762445 -0.00762463 + -0.999942 -0.00762445 -0.00762463 + -0.861355 -0.359213 -0.359213 + -0.861355 -0.359213 -0.359213 + -0.861355 -0.359213 -0.359213 + -0.861355 -0.359213 -0.359213 + -0.861355 -0.359213 -0.359213 + -0.861355 -0.359213 -0.359213 + -0.495385 -0.614245 -0.614245 + -0.495385 -0.614245 -0.614245 + -0.495385 -0.614245 -0.614245 + -0.495385 -0.614245 -0.614245 + -0.495385 -0.614245 -0.614245 + -0.495385 -0.614245 -0.614245 + -9.79866e-07 -0.608762 -0.793353 + -9.79866e-07 -0.608762 -0.793353 + -9.79866e-07 -0.608762 -0.793353 + -9.79866e-07 -0.608762 -0.793353 + -9.79866e-07 -0.608762 -0.793353 + -9.79866e-07 -0.608762 -0.793353 + 0.495391 -0.528813 -0.689162 + 0.495391 -0.528813 -0.689162 + 0.495391 -0.528813 -0.689162 + 0.495391 -0.528813 -0.689162 + 0.495391 -0.528813 -0.689162 + 0.495391 -0.528813 -0.689162 + 0.861359 -0.309249 -0.403021 + 0.861359 -0.309249 -0.403021 + 0.861359 -0.309249 -0.403021 + 0.861359 -0.309249 -0.403021 + 0.861359 -0.309249 -0.403021 + 0.861359 -0.309249 -0.403021 + 0.999942 -0.00656456 -0.00855529 + 0.999942 -0.00656456 -0.00855529 + 0.999942 -0.00656456 -0.00855529 + 0.999942 -0.00656456 -0.00855529 + 0.999942 -0.00656456 -0.00855529 + 0.999942 -0.00656456 -0.00855529 + 0.870695 0.299404 0.390191 + 0.870695 0.299404 0.390191 + 0.870695 0.299404 0.390191 + 0.870695 0.299404 0.390191 + 0.870695 0.299404 0.390191 + 0.870695 0.299404 0.390191 + 0.504727 0.525531 0.684885 + 0.504727 0.525531 0.684885 + 0.504727 0.525531 0.684885 + 0.504727 0.525531 0.684885 + 0.504727 0.525531 0.684885 + 0.504727 0.525531 0.684885 + 5.0991e-07 0.608761 0.793354 + 5.0991e-07 0.608761 0.793354 + 5.0991e-07 0.608761 0.793354 + 5.0991e-07 0.608761 0.793354 + 5.0991e-07 0.608761 0.793354 + 5.0991e-07 0.608761 0.793354 + -0.504727 0.525531 0.684885 + -0.504727 0.525531 0.684885 + -0.504727 0.525531 0.684885 + -0.504727 0.525531 0.684885 + -0.504727 0.525531 0.684885 + -0.504727 0.525531 0.684885 + -0.870695 0.299404 0.39019 + -0.870695 0.299404 0.39019 + -0.870695 0.299404 0.39019 + -0.870695 0.299404 0.39019 + -0.870695 0.299404 0.39019 + -0.870695 0.299404 0.39019 + -0.999942 -0.00656432 -0.00855482 + -0.999942 -0.00656432 -0.00855482 + -0.999942 -0.00656432 -0.00855482 + -0.999942 -0.00656432 -0.00855482 + -0.999942 -0.00656432 -0.00855482 + -0.999942 -0.00656432 -0.00855482 + -0.861359 -0.309249 -0.403021 + -0.861359 -0.309249 -0.403021 + -0.861359 -0.309249 -0.403021 + -0.861359 -0.309249 -0.403021 + -0.861359 -0.309249 -0.403021 + -0.861359 -0.309249 -0.403021 + -0.495391 -0.528813 -0.689162 + -0.495391 -0.528813 -0.689162 + -0.495391 -0.528813 -0.689162 + -0.495391 -0.528813 -0.689162 + -0.495391 -0.528813 -0.689162 + -0.495391 -0.528813 -0.689162 + -1.45239e-06 -0.5 -0.866025 + -1.45239e-06 -0.5 -0.866025 + -1.45239e-06 -0.5 -0.866025 + -1.45239e-06 -0.5 -0.866025 + -1.45239e-06 -0.5 -0.866025 + -1.45239e-06 -0.5 -0.866025 + 0.495384 -0.434337 -0.752294 + 0.495384 -0.434337 -0.752294 + 0.495384 -0.434337 -0.752294 + 0.495384 -0.434337 -0.752294 + 0.495384 -0.434337 -0.752294 + 0.495384 -0.434337 -0.752294 + 0.861357 -0.254 -0.439941 + 0.861357 -0.254 -0.439941 + 0.861357 -0.254 -0.439941 + 0.861357 -0.254 -0.439941 + 0.861357 -0.254 -0.439941 + 0.861357 -0.254 -0.439941 + 0.999942 -0.00539124 -0.0093379 + 0.999942 -0.00539124 -0.0093379 + 0.999942 -0.00539124 -0.0093379 + 0.999942 -0.00539124 -0.0093379 + 0.999942 -0.00539124 -0.0093379 + 0.999942 -0.00539124 -0.0093379 + 0.999942 -0.00539124 -0.0093379 + 0.870693 0.245913 0.425934 + 0.870693 0.245913 0.425934 + 0.870693 0.245913 0.425934 + 0.870693 0.245913 0.425934 + 0.870693 0.245913 0.425934 + 0.504721 0.431641 0.747625 + 0.504721 0.431641 0.747625 + 0.504721 0.431641 0.747625 + 0.504721 0.431641 0.747625 + 0.504721 0.431641 0.747625 + 0.504721 0.431641 0.747625 + -2.56841e-06 0.5 0.866025 + -2.56841e-06 0.5 0.866025 + -2.56841e-06 0.5 0.866025 + -2.56841e-06 0.5 0.866025 + -2.56841e-06 0.5 0.866025 + -2.56841e-06 0.5 0.866025 + -0.504723 0.431641 0.747624 + -0.504723 0.431641 0.747624 + -0.504723 0.431641 0.747624 + -0.504723 0.431641 0.747624 + -0.504723 0.431641 0.747624 + -0.504723 0.431641 0.747624 + -0.870693 0.245914 0.425935 + -0.870693 0.245914 0.425935 + -0.870693 0.245914 0.425935 + -0.870693 0.245914 0.425935 + -0.870693 0.245914 0.425935 + -0.999942 -0.00539136 -0.00933796 + -0.999942 -0.00539136 -0.00933796 + -0.999942 -0.00539136 -0.00933796 + -0.999942 -0.00539136 -0.00933796 + -0.999942 -0.00539136 -0.00933796 + -0.999942 -0.00539136 -0.00933796 + -0.999942 -0.00539136 -0.00933796 + -0.861357 -0.254 -0.43994 + -0.861357 -0.254 -0.43994 + -0.861357 -0.254 -0.43994 + -0.861357 -0.254 -0.43994 + -0.861357 -0.254 -0.43994 + -0.861357 -0.254 -0.43994 + -0.495385 -0.434337 -0.752293 + -0.495385 -0.434337 -0.752293 + -0.495385 -0.434337 -0.752293 + -0.495385 -0.434337 -0.752293 + -0.495385 -0.434337 -0.752293 + -0.495385 -0.434337 -0.752293 + -1.81548e-06 -0.382684 -0.923879 + -1.81548e-06 -0.382684 -0.923879 + -1.81548e-06 -0.382684 -0.923879 + -1.81548e-06 -0.382684 -0.923879 + -1.81548e-06 -0.382684 -0.923879 + -1.81548e-06 -0.382684 -0.923879 + 0.495388 -0.332427 -0.802548 + 0.495388 -0.332427 -0.802548 + 0.495388 -0.332427 -0.802548 + 0.495388 -0.332427 -0.802548 + 0.495388 -0.332427 -0.802548 + 0.495388 -0.332427 -0.802548 + 0.861358 -0.194403 -0.469329 + 0.861358 -0.194403 -0.469329 + 0.861358 -0.194403 -0.469329 + 0.861358 -0.194403 -0.469329 + 0.861358 -0.194403 -0.469329 + 0.861358 -0.194403 -0.469329 + 0.999942 -0.00412619 -0.00996154 + 0.999942 -0.00412619 -0.00996154 + 0.999942 -0.00412619 -0.00996154 + 0.999942 -0.00412619 -0.00996154 + 0.999942 -0.00412619 -0.00996154 + 0.999942 -0.00412619 -0.00996154 + 0.870694 0.188214 0.454388 + 0.870694 0.188214 0.454388 + 0.870694 0.188214 0.454388 + 0.870694 0.188214 0.454388 + 0.870694 0.188214 0.454388 + 0.504723 0.330363 0.797568 + 0.504723 0.330363 0.797568 + 0.504723 0.330363 0.797568 + 0.504723 0.330363 0.797568 + 0.504723 0.330363 0.797568 + 0.504723 0.330363 0.797568 + 0.504723 0.330363 0.797568 + 0.504723 0.330363 0.797568 + -6.81502e-07 0.382683 0.92388 + -6.81502e-07 0.382683 0.92388 + -6.81502e-07 0.382683 0.92388 + -6.81502e-07 0.382683 0.92388 + -0.504724 0.330363 0.797567 + -0.504724 0.330363 0.797567 + -0.504724 0.330363 0.797567 + -0.504724 0.330363 0.797567 + -0.504724 0.330363 0.797567 + -0.504724 0.330363 0.797567 + -0.504724 0.330363 0.797567 + -0.504724 0.330363 0.797567 + -0.870694 0.188213 0.454388 + -0.870694 0.188213 0.454388 + -0.870694 0.188213 0.454388 + -0.870694 0.188213 0.454388 + -0.870694 0.188213 0.454388 + -0.999942 -0.00412637 -0.0099619 + -0.999942 -0.00412637 -0.0099619 + -0.999942 -0.00412637 -0.0099619 + -0.999942 -0.00412637 -0.0099619 + -0.999942 -0.00412637 -0.0099619 + -0.999942 -0.00412637 -0.0099619 + -0.861358 -0.194403 -0.46933 + -0.861358 -0.194403 -0.46933 + -0.861358 -0.194403 -0.46933 + -0.861358 -0.194403 -0.46933 + -0.861358 -0.194403 -0.46933 + -0.861358 -0.194403 -0.46933 + -0.495389 -0.332426 -0.802548 + -0.495389 -0.332426 -0.802548 + -0.495389 -0.332426 -0.802548 + -0.495389 -0.332426 -0.802548 + -0.495389 -0.332426 -0.802548 + -0.495389 -0.332426 -0.802548 + 0 -0.258819 -0.965926 + 0 -0.258819 -0.965926 + 0 -0.258819 -0.965926 + 0 -0.258819 -0.965926 + 0 -0.258819 -0.965926 + 0 -0.258819 -0.965926 + 0.495396 -0.224828 -0.839068 + 0.495396 -0.224828 -0.839068 + 0.495396 -0.224828 -0.839068 + 0.495396 -0.224828 -0.839068 + 0.495396 -0.224828 -0.839068 + 0.495396 -0.224828 -0.839068 + 0.861359 -0.13148 -0.490688 + 0.861359 -0.13148 -0.490688 + 0.861359 -0.13148 -0.490688 + 0.861359 -0.13148 -0.490688 + 0.861359 -0.13148 -0.490688 + 0.861359 -0.13148 -0.490688 + 0.999942 -0.00279087 -0.0104159 + 0.999942 -0.00279087 -0.0104159 + 0.999942 -0.00279087 -0.0104159 + 0.999942 -0.00279087 -0.0104159 + 0.999942 -0.00279087 -0.0104159 + 0.999942 -0.00279087 -0.0104159 + 0.870693 0.127294 0.475068 + 0.870693 0.127294 0.475068 + 0.870693 0.127294 0.475068 + 0.870693 0.127294 0.475068 + 0.870693 0.127294 0.475068 + 0.870693 0.127294 0.475068 + 0.504729 0.223433 0.833863 + 0.504729 0.223433 0.833863 + 0.504729 0.223433 0.833863 + 0.504729 0.223433 0.833863 + 0.504729 0.223433 0.833863 + -7.20143e-07 0.258819 0.965926 + -7.20143e-07 0.258819 0.965926 + -7.20143e-07 0.258819 0.965926 + -7.20143e-07 0.258819 0.965926 + -7.20143e-07 0.258819 0.965926 + -7.20143e-07 0.258819 0.965926 + -7.20143e-07 0.258819 0.965926 + -7.20143e-07 0.258819 0.965926 + -0.50473 0.223433 0.833862 + -0.50473 0.223433 0.833862 + -0.50473 0.223433 0.833862 + -0.50473 0.223433 0.833862 + -0.870694 0.127294 0.475067 + -0.870694 0.127294 0.475067 + -0.870694 0.127294 0.475067 + -0.870694 0.127294 0.475067 + -0.870694 0.127294 0.475067 + -0.870694 0.127294 0.475067 + -0.870694 0.127294 0.475067 + -0.999942 -0.00279093 -0.0104161 + -0.999942 -0.00279093 -0.0104161 + -0.999942 -0.00279093 -0.0104161 + -0.999942 -0.00279093 -0.0104161 + -0.999942 -0.00279093 -0.0104161 + -0.999942 -0.00279093 -0.0104161 + -0.861359 -0.131479 -0.490687 + -0.861359 -0.131479 -0.490687 + -0.861359 -0.131479 -0.490687 + -0.861359 -0.131479 -0.490687 + -0.861359 -0.131479 -0.490687 + -0.861359 -0.131479 -0.490687 + -0.495397 -0.224827 -0.839068 + -0.495397 -0.224827 -0.839068 + -0.495397 -0.224827 -0.839068 + -0.495397 -0.224827 -0.839068 + -0.495397 -0.224827 -0.839068 + -0.495397 -0.224827 -0.839068 + -4.42681e-07 -0.130526 -0.991445 + -4.42681e-07 -0.130526 -0.991445 + -4.42681e-07 -0.130526 -0.991445 + -4.42681e-07 -0.130526 -0.991445 + -4.42681e-07 -0.130526 -0.991445 + -4.42681e-07 -0.130526 -0.991445 + 0.49539 -0.113385 -0.861239 + 0.49539 -0.113385 -0.861239 + 0.49539 -0.113385 -0.861239 + 0.49539 -0.113385 -0.861239 + 0.49539 -0.113385 -0.861239 + 0.49539 -0.113385 -0.861239 + 0.861358 -0.0663076 -0.503653 + 0.861358 -0.0663076 -0.503653 + 0.861358 -0.0663076 -0.503653 + 0.861358 -0.0663076 -0.503653 + 0.861358 -0.0663076 -0.503653 + 0.861358 -0.0663076 -0.503653 + 0.999942 -0.00140721 -0.010689 + 0.999942 -0.00140721 -0.010689 + 0.999942 -0.00140721 -0.010689 + 0.999942 -0.00140721 -0.010689 + 0.999942 -0.00140721 -0.010689 + 0.870692 0.0641963 0.48762 + 0.870692 0.0641963 0.48762 + 0.870692 0.0641963 0.48762 + 0.870692 0.0641963 0.48762 + 0.870692 0.0641963 0.48762 + 0.870692 0.0641963 0.48762 + 0.870692 0.0641963 0.48762 + 0.504721 0.112681 0.855897 + 0.504721 0.112681 0.855897 + 0.504721 0.112681 0.855897 + 0.504721 0.112681 0.855897 + 0.504721 0.112681 0.855897 + 0.504721 0.112681 0.855897 + -4.29589e-07 0.130526 0.991445 + -4.29589e-07 0.130526 0.991445 + -4.29589e-07 0.130526 0.991445 + -4.29589e-07 0.130526 0.991445 + -4.29589e-07 0.130526 0.991445 + -4.29589e-07 0.130526 0.991445 + -0.50472 0.112681 0.855898 + -0.50472 0.112681 0.855898 + -0.50472 0.112681 0.855898 + -0.50472 0.112681 0.855898 + -0.50472 0.112681 0.855898 + -0.50472 0.112681 0.855898 + -0.50472 0.112681 0.855898 + -0.870692 0.0641964 0.487621 + -0.870692 0.0641964 0.487621 + -0.870692 0.0641964 0.487621 + -0.870692 0.0641964 0.487621 + -0.870692 0.0641964 0.487621 + -0.999942 -0.00140738 -0.0106903 + -0.999942 -0.00140738 -0.0106903 + -0.999942 -0.00140738 -0.0106903 + -0.999942 -0.00140738 -0.0106903 + -0.999942 -0.00140738 -0.0106903 + -0.861357 -0.0663077 -0.503654 + -0.861357 -0.0663077 -0.503654 + -0.861357 -0.0663077 -0.503654 + -0.861357 -0.0663077 -0.503654 + -0.861357 -0.0663077 -0.503654 + -0.861357 -0.0663077 -0.503654 + -0.861357 -0.0663077 -0.503654 + -0.49539 -0.113385 -0.861239 + -0.49539 -0.113385 -0.861239 + -0.49539 -0.113385 -0.861239 + -0.49539 -0.113385 -0.861239 + -0.49539 -0.113385 -0.861239 + -0.49539 -0.113385 -0.861239 + } + } + } + } + } + } + } + } + osg::MatrixTransform { + UniqueID 191 + Name "Y_Axis_Rot" + UserDataContainer TRUE { + osg::DefaultUserDataContainer { + UniqueID 192 + UDC_UserObjects 1 { + osg::StringValueObject { + UniqueID 193 + Name "dae_node_id" + Value "Y_Axis_Rot" + } + } + } + } + Children 1 { + osg::Geode { + UniqueID 194 + Drawables 1 { + osg::Geometry { + UniqueID 195 + Name "green-material" + DataVariance STATIC + StateSet TRUE { + osg::StateSet { + UniqueID 42 + } + } + PrimitiveSetList 1 { + osg::DrawElementsUInt { + UniqueID 196 + BufferObject TRUE { + osg::ElementBufferObject { + UniqueID 197 + Target 34963 + } + } + Mode TRIANGLES + vector 3456 { + 0 78 7 8 + 83 12 13 90 + 19 91 23 20 + 96 30 24 31 + 108 37 109 41 + 38 114 47 42 + 48 126 55 127 + 59 56 132 66 + 60 139 1 67 + 72 150 79 151 + 84 80 85 161 + 92 162 97 93 + 169 102 98 103 + 180 110 181 115 + 111 116 192 121 + 122 197 128 198 + 133 129 134 209 + 140 210 73 141 + 144 222 152 153 + 227 157 228 163 + 158 164 240 170 + 241 174 171 175 + 252 182 253 186 + 183 187 264 193 + 265 199 194 200 + 275 205 276 211 + 206 282 145 212 + 216 292 223 293 + 229 224 299 234 + 230 235 310 242 + 311 246 243 247 + 323 254 324 258 + 255 259 334 266 + 335 270 267 342 + 277 271 347 283 + 278 354 217 284 + 360 294 288 366 + 300 295 301 378 + 306 379 312 307 + 313 390 318 319 + 396 325 397 329 + 326 402 336 330 + 337 414 343 415 + 348 344 349 426 + 355 356 361 289 + 432 367 362 438 + 372 368 373 450 + 380 451 384 381 + 385 462 391 392 + 467 398 468 403 + 399 475 408 404 + 409 486 416 487 + 420 417 421 497 + 427 428 433 363 + 504 439 434 440 + 516 445 446 522 + 452 523 456 453 + 457 534 463 535 + 469 464 470 546 + 476 547 480 477 + 481 557 488 558 + 492 489 564 498 + 493 499 505 435 + 576 510 506 511 + 588 517 518 593 + 524 525 600 529 + 530 605 536 606 + 540 537 541 617 + 548 618 552 549 + 625 559 553 630 + 565 560 637 570 + 566 571 577 507 + 648 582 578 583 + 660 589 661 594 + 590 595 671 601 + 672 607 602 678 + 612 608 684 619 + 613 620 695 626 + 696 631 627 632 + 708 638 709 642 + 639 643 649 579 + 720 654 650 655 + 732 662 733 666 + 663 738 673 667 + 744 679 674 751 + 685 680 686 762 + 691 763 697 692 + 698 774 703 704 + 780 710 781 714 + 711 715 721 651 + 792 726 722 727 + 804 734 805 739 + 735 810 745 740 + 746 822 752 823 + 756 753 757 834 + 764 835 768 765 + 769 845 775 776 + 852 782 853 786 + 783 787 793 723 + 864 798 794 799 + 876 806 877 811 + 807 812 889 817 + 818 894 824 895 + 828 825 829 906 + 836 907 840 837 + 914 846 841 847 + 924 854 925 858 + 855 859 865 795 + 866 942 872 943 + 878 873 879 954 + 884 885 960 890 + 961 896 891 897 + 971 902 972 908 + 903 909 984 915 + 985 919 916 990 + 926 920 927 1002 + 932 1003 867 933 + 936 1014 944 1015 + 948 945 949 1025 + 955 956 1032 962 + 1033 966 963 1039 + 973 967 974 1050 + 979 980 1055 986 + 1056 991 987 1062 + 996 992 997 1074 + 1004 1075 937 1005 + 1008 1086 1016 1087 + 1020 1017 1092 1026 + 1021 1027 1104 1034 + 1035 1109 1040 1110 + 1044 1041 1045 1121 + 1051 1122 1057 1052 + 1129 1063 1058 1064 + 1140 1069 1070 1146 + 1076 1147 1009 1077 + 1080 1158 1088 1159 + 1093 1089 1164 1098 + 1094 1099 1176 1105 + 1177 1111 1106 1182 + 1116 1112 1189 1123 + 1117 1124 1200 1130 + 1201 1134 1131 1135 + 1211 1141 1142 1218 + 1148 1219 1081 1149 + 1152 1230 1160 1231 + 1165 1161 1166 1242 + 1171 1172 1247 1178 + 1248 1183 1179 1184 + 1260 1190 1261 1194 + 1191 1195 1272 1202 + 1273 1206 1203 1279 + 1212 1207 1213 1290 + 1220 1291 1153 1221 + 1224 1300 1232 1301 + 1236 1233 1237 1312 + 1243 1313 1249 1244 + 1320 1254 1250 1255 + 1330 1262 1331 1266 + 1263 1267 1342 1274 + 1275 1348 1280 1349 + 1284 1281 1285 1360 + 1292 1361 1225 1293 + 1368 1302 1296 1303 + 1380 1308 1381 1314 + 1309 1315 1391 1321 + 1322 1398 1326 1399 + 1332 1327 1333 1410 + 1338 1411 1343 1339 + 1416 1350 1344 1351 + 1428 1356 1429 1362 + 1357 1363 1369 1297 + 1440 1374 1370 1375 + 1452 1382 1453 1386 + 1383 1458 1392 1387 + 1393 1470 1400 1471 + 1404 1401 1405 1482 + 1412 1483 1417 1413 + 1418 1493 1423 1424 + 1500 1430 1501 1434 + 1431 1435 1441 1371 + 1512 1446 1442 1447 + 1525 1454 1526 1459 + 1455 1460 1536 1465 + 1466 1542 1472 1543 + 1476 1473 1477 1554 + 1484 1555 1488 1485 + 1562 1494 1489 1495 + 1573 1502 1574 1506 + 1503 1507 1513 1443 + 1514 1589 1520 1521 + 1596 1527 1597 1531 + 1528 1602 1537 1532 + 1608 1544 1538 1545 + 1619 1550 1620 1556 + 1551 1557 1631 1563 + 1632 1567 1564 1568 + 1644 1575 1645 1579 + 1576 1650 1515 1580 + 1656 1590 1584 1591 + 1667 1598 1668 1603 + 1599 1673 1609 1604 + 1610 1685 1615 1686 + 1621 1616 1691 1626 + 1622 1697 1633 1627 + 1634 1709 1639 1640 + 1715 1646 1716 1651 + 1647 1721 1585 1652 + 1728 1661 1657 1662 + 1740 1669 1741 1674 + 1670 1748 1679 1675 + 1680 1758 1687 1759 + 1692 1688 1766 1698 + 1693 1772 1703 1699 + 1704 1782 1710 1711 + 1788 1717 1789 1722 + 1718 1723 1729 1658 + 1730 1806 1736 1807 + 1742 1737 1743 1818 + 1749 1750 1824 1754 + 1825 1760 1755 1761 + 1835 1767 1768 1842 + 1773 1774 1847 1778 + 1848 1783 1779 1854 + 1790 1784 1791 1866 + 1796 1867 1731 1797 + 1800 1878 1808 1879 + 1812 1809 1813 1889 + 1819 1820 1896 1826 + 1897 1830 1827 1903 + 1836 1831 1837 1914 + 1843 1915 1849 1844 + 1920 1855 1850 1926 + 1860 1856 1861 1937 + 1868 1938 1801 1869 + 1872 1950 1880 1951 + 1884 1881 1956 1890 + 1885 1891 1968 1898 + 1899 1974 1904 1975 + 1908 1905 1909 1986 + 1916 1987 1921 1917 + 1992 1927 1922 1928 + 2003 1933 2004 1939 + 1934 2011 1873 1940 + 1944 2022 1952 2023 + 1957 1953 1958 2034 + 1963 1964 2040 1969 + 1970 2045 1976 2046 + 1980 1977 1981 2057 + 1988 2058 1993 1989 + 2065 1998 1994 2070 + 2005 1999 2006 2082 + 2012 2083 1945 2013 + 2016 2094 2024 2095 + 2028 2025 2029 2106 + 2035 2036 2111 2041 + 2112 2047 2042 2048 + 2124 2053 2125 2059 + 2054 2060 2136 2066 + 2137 2071 2067 2143 + 2076 2072 2077 2154 + 2084 2155 2017 2085 + 2088 2164 2096 2165 + 2100 2097 2101 2176 + 2107 2177 2113 2108 + 2183 2118 2114 2119 + 2194 2126 2195 2130 + 2127 2131 2206 2138 + 2139 2213 2144 2214 + 2148 2145 2149 2224 + 2156 2225 2089 2157 + 2232 2166 2160 2167 + 2244 2172 2245 2178 + 2173 2250 2184 2179 + 2185 2262 2190 2263 + 2196 2191 2197 2274 + 2202 2275 2207 2203 + 2208 2286 2215 2216 + 2291 2220 2292 2226 + 2221 2227 2233 2161 + 2304 2238 2234 2239 + 2316 2246 2317 2251 + 2247 2322 2256 2252 + 2257 2334 2264 2265 + 2339 2269 2270 2346 + 2276 2347 2280 2277 + 2281 2358 2287 2359 + 2293 2288 2365 2298 + 2294 2299 2305 2235 + 2376 2310 2306 2311 + 2388 2318 2389 2323 + 2319 2395 2328 2324 + 2329 2407 2335 2408 + 2340 2336 2341 2419 + 2348 2420 2352 2349 + 2353 2431 2360 2361 + 2437 2366 2438 2370 + 2367 2371 2377 2307 + 2378 2454 2384 2455 + 2390 2385 2460 2396 + 2391 2466 2401 2397 + 2402 2478 2409 2479 + 2413 2410 2414 2490 + 2421 2491 2425 2422 + 2426 2502 2432 2433 + 2508 2439 2440 2514 + 2444 2515 2379 2445 + 2448 2526 2456 2527 + 2461 2457 2532 2467 + 2462 2538 2472 2468 + 2473 2549 2480 2550 + 2484 2481 2485 2562 + 2492 2563 2496 2493 + 2497 2573 2503 2504 + 2579 2509 2510 2586 + 2516 2587 2449 2517 + 2520 2598 2528 2599 + 2533 2529 2604 2539 + 2534 2610 2544 2540 + 2616 2551 2545 2622 + 2556 2552 2557 2633 + 2564 2634 2568 2565 + 2641 2574 2569 2646 + 2580 2575 2581 2658 + 2588 2659 2521 2589 + 2592 2670 2600 2671 + 2605 2601 2676 2611 + 2606 2683 2617 2612 + 2688 2623 2618 2624 + 2699 2629 2700 2635 + 2630 2636 2712 2642 + 2713 2647 2643 2719 + 2652 2648 2653 2730 + 2660 2731 2593 2661 + 2664 2742 2672 2743 + 2677 2673 2678 2753 + 2684 2754 2689 2685 + 2761 2694 2690 2767 + 2701 2695 2702 2777 + 2707 2708 2783 2714 + 2715 2789 2720 2790 + 2724 2721 2725 2801 + 2732 2802 2665 2733 + 2736 2812 2744 2813 + 2748 2745 2820 2755 + 2749 2756 2830 2762 + 2763 2837 2768 2838 + 2772 2769 2844 2778 + 2773 2849 2784 2779 + 2855 2791 2785 2792 + 2867 2797 2868 2803 + 2798 2873 2737 2804 + 2880 2814 2808 2815 + 2891 2821 2892 2825 + 2822 2899 2831 2826 + 2832 2910 2839 2840 + 2916 2845 2917 2850 + 2846 2923 2856 2851 + 2857 2934 2862 2863 + 2939 2869 2940 2874 + 2870 2875 2881 2809 + 2952 2886 2882 2958 + 2893 2887 2894 2970 + 2900 2971 2904 2901 + 2905 2982 2911 2912 + 2988 2918 2919 2993 + 2924 2994 2928 2925 + 2929 3006 2935 3007 + 2941 2936 2942 3017 + 2947 2948 2953 2883 + 3024 2959 2954 2960 + 3036 2965 2966 3041 + 2972 3042 2976 2973 + 2977 3053 2983 2984 + 3060 2989 3061 2995 + 2990 3066 3000 2996 + 3001 3078 3008 3079 + 3012 3009 3085 3018 + 3013 3019 3025 2955 + 3096 3030 3026 3031 + 3108 3037 3109 3043 + 3038 3114 3048 3044 + 3121 3054 3049 3055 + 3131 3062 3132 3067 + 3063 3068 3144 3073 + 3074 3149 3080 3081 + 3156 3086 3157 3090 + 3087 3091 3097 3027 + 3168 3102 3098 3103 + 3180 3110 3181 3115 + 3111 3116 3192 3122 + 3193 3126 3123 3199 + 3133 3127 3134 3209 + 3139 3140 3215 3145 + 3216 3150 3146 3151 + 3228 3158 3229 3162 + 3159 3163 3169 3099 + 3240 3174 3170 3175 + 3251 3182 3252 3186 + 3183 3187 3264 3194 + 3195 3270 3200 3271 + 3204 3201 3277 3210 + 3205 3282 3217 3211 + 3288 3222 3218 3223 + 3300 3230 3301 3234 + 3231 3235 3241 3171 + 3312 3246 3242 3318 + 3253 3247 3325 3258 + 3254 3259 3336 3265 + 3266 3342 3272 3273 + 3348 3278 3349 3283 + 3279 3354 3289 3284 + 3360 3294 3290 3295 + 3372 3302 3373 3306 + 3303 3307 3313 3243 + 3384 3319 3314 3320 + 3397 3326 3398 3330 + 3327 3331 3409 3337 + 3338 3414 3343 3344 + 3420 3350 3421 3355 + 3351 3428 3361 3356 + 3434 3366 3362 3367 + 3445 3374 3446 3378 + 3375 3379 3385 3315 + 2 3391 3386 3392 + 14 3399 15 3403 + 3400 3404 25 3410 + 26 3415 3411 32 + 3422 3416 3423 43 + 3429 3430 49 3435 + 50 3439 3436 3440 + 61 3447 62 3451 + 3448 68 3387 3452 + 3 74 81 9 + 82 86 16 87 + 94 95 99 27 + 100 104 33 34 + 105 112 113 117 + 44 118 123 51 + 52 124 130 131 + 135 63 136 142 + 69 143 75 4 + 76 146 154 155 + 159 88 89 160 + 165 166 172 101 + 173 176 106 107 + 177 184 185 188 + 119 120 189 195 + 125 196 201 202 + 207 137 138 208 + 213 214 147 77 + 148 218 225 156 + 226 231 232 236 + 167 168 237 244 + 245 248 178 179 + 249 256 257 260 + 190 191 261 268 + 269 272 203 204 + 273 279 280 285 + 215 286 219 149 + 220 290 296 297 + 302 233 303 308 + 238 239 309 314 + 315 320 250 251 + 321 327 328 331 + 262 263 332 338 + 339 345 274 346 + 350 281 351 357 + 287 358 291 221 + 364 369 298 370 + 374 304 305 375 + 382 383 386 316 + 317 387 393 322 + 394 400 401 405 + 333 406 410 340 + 341 411 418 419 + 422 352 353 423 + 429 359 430 365 + 436 441 371 442 + 447 376 377 448 + 454 455 458 388 + 389 459 465 395 + 466 471 472 478 + 407 479 482 412 + 413 483 490 491 + 494 424 425 495 + 500 431 501 437 + 508 512 443 444 + 513 519 449 520 + 526 527 531 460 + 461 532 538 539 + 542 473 474 543 + 550 551 554 484 + 485 555 561 562 + 567 496 568 572 + 502 503 573 509 + 580 584 514 515 + 585 591 521 592 + 596 528 597 603 + 533 604 609 610 + 614 544 545 615 + 621 622 628 556 + 629 633 563 634 + 640 569 641 644 + 574 575 645 581 + 652 656 586 587 + 657 664 665 668 + 598 599 669 675 + 676 681 611 682 + 687 616 688 693 + 623 624 694 699 + 700 705 635 636 + 706 712 713 716 + 646 647 717 653 + 724 728 658 659 + 729 736 737 741 + 670 742 747 677 + 748 754 683 755 + 758 689 690 759 + 766 767 770 701 + 702 771 777 707 + 778 784 785 788 + 718 719 789 725 + 796 800 730 731 + 801 808 809 813 + 743 814 819 749 + 750 820 826 827 + 830 760 761 831 + 838 839 842 772 + 773 843 848 779 + 849 856 857 860 + 790 791 861 797 + 868 874 802 803 + 875 880 881 886 + 815 816 887 892 + 821 893 898 899 + 904 832 833 905 + 910 911 917 844 + 918 921 850 851 + 922 928 929 934 + 862 863 935 869 + 870 938 946 947 + 950 882 883 951 + 957 888 958 964 + 965 968 900 901 + 969 975 976 981 + 912 913 982 988 + 989 993 923 994 + 998 930 931 999 + 1006 1007 939 871 + 940 1010 1018 1019 + 1022 952 953 1023 + 1028 959 1029 1036 + 1037 1042 970 1043 + 1046 977 978 1047 + 1053 983 1054 1059 + 1060 1065 995 1066 + 1071 1000 1001 1072 + 1078 1079 1011 941 + 1012 1082 1090 1091 + 1095 1024 1096 1100 + 1030 1031 1101 1107 + 1038 1108 1113 1114 + 1118 1048 1049 1119 + 1125 1126 1132 1061 + 1133 1136 1067 1068 + 1137 1143 1073 1144 + 1150 1151 1083 1013 + 1084 1154 1162 1163 + 1167 1097 1168 1173 + 1102 1103 1174 1180 + 1181 1185 1115 1186 + 1192 1120 1193 1196 + 1127 1128 1197 1204 + 1205 1208 1138 1139 + 1209 1214 1145 1215 + 1222 1223 1155 1085 + 1156 1226 1234 1235 + 1238 1169 1170 1239 + 1245 1175 1246 1251 + 1252 1256 1187 1188 + 1257 1264 1265 1268 + 1198 1199 1269 1276 + 1277 1282 1210 1283 + 1286 1216 1217 1287 + 1294 1295 1227 1157 + 1228 1298 1304 1305 + 1310 1240 1241 1311 + 1316 1317 1323 1253 + 1324 1328 1258 1259 + 1329 1334 1335 1340 + 1270 1271 1341 1345 + 1278 1346 1352 1353 + 1358 1288 1289 1359 + 1364 1365 1299 1229 + 1372 1376 1306 1307 + 1377 1384 1385 1388 + 1318 1319 1389 1394 + 1325 1395 1402 1403 + 1406 1336 1337 1407 + 1414 1415 1419 1347 + 1420 1425 1354 1355 + 1426 1432 1433 1436 + 1366 1367 1437 1373 + 1444 1448 1378 1379 + 1449 1456 1457 1461 + 1390 1462 1467 1396 + 1397 1468 1474 1475 + 1478 1408 1409 1479 + 1486 1487 1490 1421 + 1422 1491 1496 1427 + 1497 1504 1505 1508 + 1438 1439 1509 1445 + 1516 1522 1450 1451 + 1523 1529 1530 1533 + 1463 1464 1534 1539 + 1469 1540 1546 1547 + 1552 1480 1481 1553 + 1558 1559 1565 1492 + 1566 1569 1498 1499 + 1570 1577 1578 1581 + 1510 1511 1582 1517 + 1518 1586 1592 1524 + 1593 1600 1601 1605 + 1535 1606 1611 1541 + 1612 1617 1548 1549 + 1618 1623 1624 1628 + 1560 1561 1629 1635 + 1636 1641 1571 1572 + 1642 1648 1649 1653 + 1583 1654 1587 1519 + 1659 1663 1594 1595 + 1664 1671 1672 1676 + 1607 1677 1681 1613 + 1614 1682 1689 1690 + 1694 1625 1695 1700 + 1630 1701 1705 1637 + 1638 1706 1712 1643 + 1713 1719 1720 1724 + 1655 1725 1660 1588 + 1732 1738 1665 1666 + 1739 1744 1745 1751 + 1678 1752 1756 1683 + 1684 1757 1762 1763 + 1769 1696 1770 1775 + 1702 1776 1780 1707 + 1708 1781 1785 1714 + 1786 1792 1793 1798 + 1726 1727 1799 1733 + 1734 1802 1810 1811 + 1814 1746 1747 1815 + 1821 1753 1822 1828 + 1829 1832 1764 1765 + 1833 1838 1771 1839 + 1845 1777 1846 1851 + 1852 1857 1787 1858 + 1862 1794 1795 1863 + 1870 1871 1803 1735 + 1804 1874 1882 1883 + 1886 1816 1817 1887 + 1892 1823 1893 1900 + 1901 1906 1834 1907 + 1910 1840 1841 1911 + 1918 1919 1923 1853 + 1924 1929 1859 1930 + 1935 1864 1865 1936 + 1941 1942 1875 1805 + 1876 1946 1954 1955 + 1959 1888 1960 1965 + 1894 1895 1966 1971 + 1902 1972 1978 1979 + 1982 1912 1913 1983 + 1990 1991 1995 1925 + 1996 2000 1931 1932 + 2001 2007 2008 2014 + 1943 2015 1947 1877 + 1948 2018 2026 2027 + 2030 1961 1962 2031 + 2037 1967 2038 2043 + 1973 2044 2049 2050 + 2055 1984 1985 2056 + 2061 2062 2068 1997 + 2069 2073 2002 2074 + 2078 2009 2010 2079 + 2086 2087 2019 1949 + 2020 2090 2098 2099 + 2102 2032 2033 2103 + 2109 2039 2110 2115 + 2116 2120 2051 2052 + 2121 2128 2129 2132 + 2063 2064 2133 2140 + 2141 2146 2075 2147 + 2150 2080 2081 2151 + 2158 2159 2091 2021 + 2092 2162 2168 2169 + 2174 2104 2105 2175 + 2180 2181 2186 2117 + 2187 2192 2122 2123 + 2193 2198 2199 2204 + 2134 2135 2205 2209 + 2142 2210 2217 2218 + 2222 2152 2153 2223 + 2228 2229 2163 2093 + 2236 2240 2170 2171 + 2241 2248 2249 2253 + 2182 2254 2258 2188 + 2189 2259 2266 2267 + 2271 2200 2201 2272 + 2278 2279 2282 2211 + 2212 2283 2289 2219 + 2290 2295 2296 2300 + 2230 2231 2301 2237 + 2308 2312 2242 2243 + 2313 2320 2321 2325 + 2255 2326 2330 2260 + 2261 2331 2337 2268 + 2338 2342 2273 2343 + 2350 2351 2354 2284 + 2285 2355 2362 2363 + 2368 2297 2369 2372 + 2302 2303 2373 2309 + 2380 2386 2314 2315 + 2387 2392 2393 2398 + 2327 2399 2403 2332 + 2333 2404 2411 2412 + 2415 2344 2345 2416 + 2423 2424 2427 2356 + 2357 2428 2434 2364 + 2435 2441 2442 2446 + 2374 2375 2447 2381 + 2382 2450 2458 2459 + 2463 2394 2464 2469 + 2400 2470 2474 2405 + 2406 2475 2482 2483 + 2486 2417 2418 2487 + 2494 2495 2498 2429 + 2430 2499 2505 2436 + 2506 2511 2443 2512 + 2518 2519 2451 2383 + 2452 2522 2530 2531 + 2535 2465 2536 2541 + 2471 2542 2546 2476 + 2477 2547 2553 2554 + 2558 2488 2489 2559 + 2566 2567 2570 2500 + 2501 2571 2576 2507 + 2577 2582 2513 2583 + 2590 2591 2523 2453 + 2524 2594 2602 2603 + 2607 2537 2608 2613 + 2543 2614 2619 2548 + 2620 2625 2555 2626 + 2631 2560 2561 2632 + 2637 2638 2644 2572 + 2645 2649 2578 2650 + 2654 2584 2585 2655 + 2662 2663 2595 2525 + 2596 2666 2674 2675 + 2679 2609 2680 2686 + 2615 2687 2691 2621 + 2692 2696 2627 2628 + 2697 2703 2704 2709 + 2639 2640 2710 2716 + 2717 2722 2651 2723 + 2726 2656 2657 2727 + 2734 2735 2667 2597 + 2668 2738 2746 2747 + 2750 2681 2682 2751 + 2757 2758 2764 2693 + 2765 2770 2698 2771 + 2774 2705 2706 2775 + 2780 2711 2781 2786 + 2718 2787 2793 2794 + 2799 2728 2729 2800 + 2805 2806 2739 2669 + 2740 2810 2816 2817 + 2823 2752 2824 2827 + 2759 2760 2828 2833 + 2766 2834 2841 2842 + 2847 2776 2848 2852 + 2782 2853 2858 2788 + 2859 2864 2795 2796 + 2865 2871 2872 2876 + 2807 2877 2811 2741 + 2884 2888 2818 2819 + 2889 2895 2896 2902 + 2829 2903 2906 2835 + 2836 2907 2913 2843 + 2914 2920 2921 2926 + 2854 2927 2930 2860 + 2861 2931 2937 2866 + 2938 2943 2944 2949 + 2878 2879 2950 2885 + 2956 2961 2890 2962 + 2967 2897 2898 2968 + 2974 2975 2978 2908 + 2909 2979 2985 2915 + 2986 2991 2922 2992 + 2997 2998 3002 2932 + 2933 3003 3010 3011 + 3014 2945 2946 3015 + 3020 2951 3021 2957 + 3028 3032 2963 2964 + 3033 3039 2969 3040 + 3045 3046 3050 2980 + 2981 3051 3056 2987 + 3057 3064 3065 3069 + 2999 3070 3075 3004 + 3005 3076 3082 3083 + 3088 3016 3089 3092 + 3022 3023 3093 3029 + 3100 3104 3034 3035 + 3105 3112 3113 3117 + 3047 3118 3124 3052 + 3125 3128 3058 3059 + 3129 3135 3136 3141 + 3071 3072 3142 3147 + 3077 3148 3152 3084 + 3153 3160 3161 3164 + 3094 3095 3165 3101 + 3172 3176 3106 3107 + 3177 3184 3185 3188 + 3119 3120 3189 3196 + 3197 3202 3130 3203 + 3206 3137 3138 3207 + 3212 3143 3213 3219 + 3220 3224 3154 3155 + 3225 3232 3233 3236 + 3166 3167 3237 3173 + 3244 3248 3178 3179 + 3249 3255 3256 3260 + 3190 3191 3261 3267 + 3198 3268 3274 3275 + 3280 3208 3281 3285 + 3214 3286 3291 3221 + 3292 3296 3226 3227 + 3297 3304 3305 3308 + 3238 3239 3309 3245 + 3316 3321 3250 3322 + 3328 3257 3329 3332 + 3262 3263 3333 3339 + 3269 3340 3345 3276 + 3346 3352 3353 3357 + 3287 3358 3363 3293 + 3364 3368 3298 3299 + 3369 3376 3377 3380 + 3310 3311 3381 3317 + 3388 3393 3323 3324 + 3394 3401 3402 3405 + 3334 3335 3406 3412 + 3341 3413 3417 3347 + 3418 3424 3425 3431 + 3359 3432 3437 3365 + 3438 3441 3370 3371 + 3442 3449 3450 3453 + 3382 3383 3454 3389 + 5 10 3395 3396 + 11 17 18 21 + 3407 3408 22 28 + 29 35 3419 36 + 39 3426 3427 40 + 45 3433 46 53 + 54 57 3443 3444 + 58 64 65 70 + 3455 71 6 3390 + + } + } + } + VertexArray TRUE { + osg::Vec3Array { + UniqueID 198 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 199 + } + } + Binding BIND_PER_VERTEX + vector 3456 { + 1.50845e-07 0 1.998 + 1.50845e-07 0 1.998 + 1.50845e-07 0 1.998 + 1.50845e-07 0 1.998 + 1.50845e-07 0 1.998 + 1.50845e-07 0 1.998 + 1.50845e-07 0 1.998 + 1.50349e-07 -0.0245 1.99144 + 1.50349e-07 -0.0245 1.99144 + 1.50349e-07 -0.0245 1.99144 + 1.50349e-07 -0.0245 1.99144 + 1.50349e-07 -0.0245 1.99144 + 1.48995e-07 -0.0424354 1.9735 + 1.48995e-07 -0.0424354 1.9735 + 1.48995e-07 -0.0424354 1.9735 + 1.48995e-07 -0.0424354 1.9735 + 1.48995e-07 -0.0424354 1.9735 + 1.48995e-07 -0.0424354 1.9735 + 1.48995e-07 -0.0424354 1.9735 + 1.47145e-07 -0.049 1.949 + 1.47145e-07 -0.049 1.949 + 1.47145e-07 -0.049 1.949 + 1.47145e-07 -0.049 1.949 + 1.45296e-07 -0.0424354 1.9245 + 1.45296e-07 -0.0424354 1.9245 + 1.45296e-07 -0.0424354 1.9245 + 1.45296e-07 -0.0424354 1.9245 + 1.45296e-07 -0.0424354 1.9245 + 1.45296e-07 -0.0424354 1.9245 + 1.45296e-07 -0.0424354 1.9245 + 1.43942e-07 -0.0245001 1.90656 + 1.43942e-07 -0.0245001 1.90656 + 1.43942e-07 -0.0245001 1.90656 + 1.43942e-07 -0.0245001 1.90656 + 1.43942e-07 -0.0245001 1.90656 + 1.43942e-07 -0.0245001 1.90656 + 1.43942e-07 -0.0245001 1.90656 + 1.43446e-07 0 1.9 + 1.43446e-07 0 1.9 + 1.43446e-07 0 1.9 + 1.43446e-07 0 1.9 + 1.43942e-07 0.0244999 1.90656 + 1.43942e-07 0.0244999 1.90656 + 1.43942e-07 0.0244999 1.90656 + 1.43942e-07 0.0244999 1.90656 + 1.43942e-07 0.0244999 1.90656 + 1.43942e-07 0.0244999 1.90656 + 1.45296e-07 0.0424352 1.9245 + 1.45296e-07 0.0424352 1.9245 + 1.45296e-07 0.0424352 1.9245 + 1.45296e-07 0.0424352 1.9245 + 1.45296e-07 0.0424352 1.9245 + 1.45296e-07 0.0424352 1.9245 + 1.45296e-07 0.0424352 1.9245 + 1.45296e-07 0.0424352 1.9245 + 1.47145e-07 0.0489999 1.949 + 1.47145e-07 0.0489999 1.949 + 1.47145e-07 0.0489999 1.949 + 1.47145e-07 0.0489999 1.949 + 1.48995e-07 0.0424352 1.9735 + 1.48995e-07 0.0424352 1.9735 + 1.48995e-07 0.0424352 1.9735 + 1.48995e-07 0.0424352 1.9735 + 1.48995e-07 0.0424352 1.9735 + 1.48995e-07 0.0424352 1.9735 + 1.48995e-07 0.0424352 1.9735 + 1.50349e-07 0.0244998 1.99144 + 1.50349e-07 0.0244998 1.99144 + 1.50349e-07 0.0244998 1.99144 + 1.50349e-07 0.0244998 1.99144 + 1.50349e-07 0.0244998 1.99144 + 1.50349e-07 0.0244998 1.99144 + -0.260791 0 1.98091 + -0.260791 0 1.98091 + -0.260791 0 1.98091 + -0.260791 0 1.98091 + -0.260791 0 1.98091 + -0.260791 0 1.98091 + -0.259934 -0.0245 1.9744 + -0.259934 -0.0245 1.9744 + -0.259934 -0.0245 1.9744 + -0.259934 -0.0245 1.9744 + -0.259934 -0.0245 1.9744 + -0.257593 -0.0424354 1.95662 + -0.257593 -0.0424354 1.95662 + -0.257593 -0.0424354 1.95662 + -0.257593 -0.0424354 1.95662 + -0.257593 -0.0424354 1.95662 + -0.257593 -0.0424354 1.95662 + -0.257593 -0.0424354 1.95662 + -0.254395 -0.049 1.93233 + -0.254395 -0.049 1.93233 + -0.254395 -0.049 1.93233 + -0.254395 -0.049 1.93233 + -0.254395 -0.049 1.93233 + -0.254395 -0.049 1.93233 + -0.251197 -0.0424353 1.90804 + -0.251197 -0.0424353 1.90804 + -0.251197 -0.0424353 1.90804 + -0.251197 -0.0424353 1.90804 + -0.251197 -0.0424353 1.90804 + -0.251197 -0.0424353 1.90804 + -0.248856 -0.0245001 1.89025 + -0.248856 -0.0245001 1.89025 + -0.248856 -0.0245001 1.89025 + -0.248856 -0.0245001 1.89025 + -0.248856 -0.0245001 1.89025 + -0.248856 -0.0245001 1.89025 + -0.248 0 1.88374 + -0.248 0 1.88374 + -0.248 0 1.88374 + -0.248 0 1.88374 + -0.248 0 1.88374 + -0.248 0 1.88374 + -0.248856 0.0244999 1.89025 + -0.248856 0.0244999 1.89025 + -0.248856 0.0244999 1.89025 + -0.248856 0.0244999 1.89025 + -0.248856 0.0244999 1.89025 + -0.248856 0.0244999 1.89025 + -0.248856 0.0244999 1.89025 + -0.251197 0.0424352 1.90804 + -0.251197 0.0424352 1.90804 + -0.251197 0.0424352 1.90804 + -0.251197 0.0424352 1.90804 + -0.251197 0.0424352 1.90804 + -0.254395 0.0489999 1.93233 + -0.254395 0.0489999 1.93233 + -0.254395 0.0489999 1.93233 + -0.254395 0.0489999 1.93233 + -0.254395 0.0489999 1.93233 + -0.254395 0.0489999 1.93233 + -0.257593 0.0424352 1.95662 + -0.257593 0.0424352 1.95662 + -0.257593 0.0424352 1.95662 + -0.257593 0.0424352 1.95662 + -0.257593 0.0424352 1.95662 + -0.257593 0.0424352 1.95662 + -0.257593 0.0424352 1.95662 + -0.259934 0.0245 1.9744 + -0.259934 0.0245 1.9744 + -0.259934 0.0245 1.9744 + -0.259934 0.0245 1.9744 + -0.259934 0.0245 1.9744 + -0.51712 0 1.92992 + -0.51712 0 1.92992 + -0.51712 0 1.92992 + -0.51712 0 1.92992 + -0.51712 0 1.92992 + -0.51712 0 1.92992 + -0.515421 -0.0245 1.92358 + -0.515421 -0.0245 1.92358 + -0.515421 -0.0245 1.92358 + -0.515421 -0.0245 1.92358 + -0.515421 -0.0245 1.92358 + -0.515421 -0.0245 1.92358 + -0.515421 -0.0245 1.92358 + -0.510779 -0.0424354 1.90625 + -0.510779 -0.0424354 1.90625 + -0.510779 -0.0424354 1.90625 + -0.510779 -0.0424354 1.90625 + -0.504438 -0.0490001 1.88259 + -0.504438 -0.0490001 1.88259 + -0.504438 -0.0490001 1.88259 + -0.504438 -0.0490001 1.88259 + -0.504438 -0.0490001 1.88259 + -0.504438 -0.0490001 1.88259 + -0.504438 -0.0490001 1.88259 + -0.504438 -0.0490001 1.88259 + -0.498097 -0.0424353 1.85892 + -0.498097 -0.0424353 1.85892 + -0.498097 -0.0424353 1.85892 + -0.498097 -0.0424353 1.85892 + -0.498097 -0.0424353 1.85892 + -0.493455 -0.0245 1.8416 + -0.493455 -0.0245 1.8416 + -0.493455 -0.0245 1.8416 + -0.493455 -0.0245 1.8416 + -0.493455 -0.0245 1.8416 + -0.493455 -0.0245 1.8416 + -0.491756 0 1.83526 + -0.491756 0 1.83526 + -0.491756 0 1.83526 + -0.491756 0 1.83526 + -0.491756 0 1.83526 + -0.491756 0 1.83526 + -0.493455 0.0244999 1.8416 + -0.493455 0.0244999 1.8416 + -0.493455 0.0244999 1.8416 + -0.493455 0.0244999 1.8416 + -0.493455 0.0244999 1.8416 + -0.493455 0.0244999 1.8416 + -0.498097 0.0424352 1.85892 + -0.498097 0.0424352 1.85892 + -0.498097 0.0424352 1.85892 + -0.498097 0.0424352 1.85892 + -0.498097 0.0424352 1.85892 + -0.504438 0.0489999 1.88259 + -0.504438 0.0489999 1.88259 + -0.504438 0.0489999 1.88259 + -0.504438 0.0489999 1.88259 + -0.504438 0.0489999 1.88259 + -0.504438 0.0489999 1.88259 + -0.504438 0.0489999 1.88259 + -0.504438 0.0489999 1.88259 + -0.510779 0.0424352 1.90625 + -0.510779 0.0424352 1.90625 + -0.510779 0.0424352 1.90625 + -0.510779 0.0424352 1.90625 + -0.515421 0.0244999 1.92358 + -0.515421 0.0244999 1.92358 + -0.515421 0.0244999 1.92358 + -0.515421 0.0244999 1.92358 + -0.515421 0.0244999 1.92358 + -0.515421 0.0244999 1.92358 + -0.515421 0.0244999 1.92358 + -0.764601 0 1.84591 + -0.764601 0 1.84591 + -0.764601 0 1.84591 + -0.764601 0 1.84591 + -0.764601 0 1.84591 + -0.764601 0 1.84591 + -0.762089 -0.0245 1.83985 + -0.762089 -0.0245 1.83985 + -0.762089 -0.0245 1.83985 + -0.762089 -0.0245 1.83985 + -0.762089 -0.0245 1.83985 + -0.755225 -0.0424353 1.82328 + -0.755225 -0.0424353 1.82328 + -0.755225 -0.0424353 1.82328 + -0.755225 -0.0424353 1.82328 + -0.755225 -0.0424353 1.82328 + -0.755225 -0.0424353 1.82328 + -0.755225 -0.0424353 1.82328 + -0.74585 -0.049 1.80064 + -0.74585 -0.049 1.80064 + -0.74585 -0.049 1.80064 + -0.74585 -0.049 1.80064 + -0.74585 -0.049 1.80064 + -0.74585 -0.049 1.80064 + -0.736474 -0.0424353 1.77801 + -0.736474 -0.0424353 1.77801 + -0.736474 -0.0424353 1.77801 + -0.736474 -0.0424353 1.77801 + -0.736474 -0.0424353 1.77801 + -0.736474 -0.0424353 1.77801 + -0.72961 -0.0245 1.76144 + -0.72961 -0.0245 1.76144 + -0.72961 -0.0245 1.76144 + -0.72961 -0.0245 1.76144 + -0.72961 -0.0245 1.76144 + -0.72961 -0.0245 1.76144 + -0.727098 0 1.75537 + -0.727098 0 1.75537 + -0.727098 0 1.75537 + -0.727098 0 1.75537 + -0.727098 0 1.75537 + -0.727098 0 1.75537 + -0.72961 0.0244999 1.76144 + -0.72961 0.0244999 1.76144 + -0.72961 0.0244999 1.76144 + -0.72961 0.0244999 1.76144 + -0.72961 0.0244999 1.76144 + -0.72961 0.0244999 1.76144 + -0.736474 0.0424352 1.77801 + -0.736474 0.0424352 1.77801 + -0.736474 0.0424352 1.77801 + -0.736474 0.0424352 1.77801 + -0.736474 0.0424352 1.77801 + -0.736474 0.0424352 1.77801 + -0.74585 0.0489999 1.80064 + -0.74585 0.0489999 1.80064 + -0.74585 0.0489999 1.80064 + -0.74585 0.0489999 1.80064 + -0.74585 0.0489999 1.80064 + -0.755225 0.0424352 1.82328 + -0.755225 0.0424352 1.82328 + -0.755225 0.0424352 1.82328 + -0.755225 0.0424352 1.82328 + -0.755225 0.0424352 1.82328 + -0.755225 0.0424352 1.82328 + -0.755225 0.0424352 1.82328 + -0.762089 0.0244999 1.83985 + -0.762089 0.0244999 1.83985 + -0.762089 0.0244999 1.83985 + -0.762089 0.0244999 1.83985 + -0.762089 0.0244999 1.83985 + -0.762089 0.0244999 1.83985 + -0.999 0 1.73032 + -0.999 0 1.73032 + -0.999 0 1.73032 + -0.999 0 1.73032 + -0.995718 -0.0245 1.72463 + -0.995718 -0.0245 1.72463 + -0.995718 -0.0245 1.72463 + -0.995718 -0.0245 1.72463 + -0.995718 -0.0245 1.72463 + -0.995718 -0.0245 1.72463 + -0.995718 -0.0245 1.72463 + -0.98675 -0.0424353 1.7091 + -0.98675 -0.0424353 1.7091 + -0.98675 -0.0424353 1.7091 + -0.98675 -0.0424353 1.7091 + -0.98675 -0.0424353 1.7091 + -0.98675 -0.0424353 1.7091 + -0.98675 -0.0424353 1.7091 + -0.9745 -0.049 1.68788 + -0.9745 -0.049 1.68788 + -0.9745 -0.049 1.68788 + -0.9745 -0.049 1.68788 + -0.96225 -0.0424353 1.66667 + -0.96225 -0.0424353 1.66667 + -0.96225 -0.0424353 1.66667 + -0.96225 -0.0424353 1.66667 + -0.96225 -0.0424353 1.66667 + -0.96225 -0.0424353 1.66667 + -0.96225 -0.0424353 1.66667 + -0.96225 -0.0424353 1.66667 + -0.953282 -0.0245 1.65113 + -0.953282 -0.0245 1.65113 + -0.953282 -0.0245 1.65113 + -0.953282 -0.0245 1.65113 + -0.953282 -0.0245 1.65113 + -0.95 0 1.64545 + -0.95 0 1.64545 + -0.95 0 1.64545 + -0.95 0 1.64545 + -0.95 0 1.64545 + -0.95 0 1.64545 + -0.953282 0.0244999 1.65113 + -0.953282 0.0244999 1.65113 + -0.953282 0.0244999 1.65113 + -0.953282 0.0244999 1.65113 + -0.953282 0.0244999 1.65113 + -0.96225 0.0424352 1.66667 + -0.96225 0.0424352 1.66667 + -0.96225 0.0424352 1.66667 + -0.96225 0.0424352 1.66667 + -0.96225 0.0424352 1.66667 + -0.96225 0.0424352 1.66667 + -0.96225 0.0424352 1.66667 + -0.96225 0.0424352 1.66667 + -0.9745 0.0489999 1.68788 + -0.9745 0.0489999 1.68788 + -0.9745 0.0489999 1.68788 + -0.9745 0.0489999 1.68788 + -0.9745 0.0489999 1.68788 + -0.98675 0.0424352 1.7091 + -0.98675 0.0424352 1.7091 + -0.98675 0.0424352 1.7091 + -0.98675 0.0424352 1.7091 + -0.98675 0.0424352 1.7091 + -0.98675 0.0424352 1.7091 + -0.98675 0.0424352 1.7091 + -0.995718 0.0244999 1.72463 + -0.995718 0.0244999 1.72463 + -0.995718 0.0244999 1.72463 + -0.995718 0.0244999 1.72463 + -0.995718 0.0244999 1.72463 + -0.995718 0.0244999 1.72463 + -1.21631 0 1.58512 + -1.21631 0 1.58512 + -1.21631 0 1.58512 + -1.21631 0 1.58512 + -1.21631 0 1.58512 + -1.21631 0 1.58512 + -1.21231 -0.0245 1.57991 + -1.21231 -0.0245 1.57991 + -1.21231 -0.0245 1.57991 + -1.21231 -0.0245 1.57991 + -1.21231 -0.0245 1.57991 + -1.21231 -0.0245 1.57991 + -1.20139 -0.0424353 1.56568 + -1.20139 -0.0424353 1.56568 + -1.20139 -0.0424353 1.56568 + -1.20139 -0.0424353 1.56568 + -1.20139 -0.0424353 1.56568 + -1.20139 -0.0424353 1.56568 + -1.18648 -0.049 1.54625 + -1.18648 -0.049 1.54625 + -1.18648 -0.049 1.54625 + -1.18648 -0.049 1.54625 + -1.18648 -0.049 1.54625 + -1.18648 -0.049 1.54625 + -1.17156 -0.0424353 1.52681 + -1.17156 -0.0424353 1.52681 + -1.17156 -0.0424353 1.52681 + -1.17156 -0.0424353 1.52681 + -1.17156 -0.0424353 1.52681 + -1.17156 -0.0424353 1.52681 + -1.16064 -0.0245 1.51258 + -1.16064 -0.0245 1.51258 + -1.16064 -0.0245 1.51258 + -1.16064 -0.0245 1.51258 + -1.16064 -0.0245 1.51258 + -1.16064 -0.0245 1.51258 + -1.15665 0 1.50737 + -1.15665 0 1.50737 + -1.15665 0 1.50737 + -1.15665 0 1.50737 + -1.15665 0 1.50737 + -1.15665 0 1.50737 + -1.16064 0.0244999 1.51258 + -1.16064 0.0244999 1.51258 + -1.16064 0.0244999 1.51258 + -1.16064 0.0244999 1.51258 + -1.16064 0.0244999 1.51258 + -1.16064 0.0244999 1.51258 + -1.17156 0.0424352 1.52681 + -1.17156 0.0424352 1.52681 + -1.17156 0.0424352 1.52681 + -1.17156 0.0424352 1.52681 + -1.17156 0.0424352 1.52681 + -1.17156 0.0424352 1.52681 + -1.18648 0.0489999 1.54625 + -1.18648 0.0489999 1.54625 + -1.18648 0.0489999 1.54625 + -1.18648 0.0489999 1.54625 + -1.18648 0.0489999 1.54625 + -1.18648 0.0489999 1.54625 + -1.20139 0.0424352 1.56568 + -1.20139 0.0424352 1.56568 + -1.20139 0.0424352 1.56568 + -1.20139 0.0424352 1.56568 + -1.20139 0.0424352 1.56568 + -1.20139 0.0424352 1.56568 + -1.21231 0.0244999 1.57991 + -1.21231 0.0244999 1.57991 + -1.21231 0.0244999 1.57991 + -1.21231 0.0244999 1.57991 + -1.21231 0.0244999 1.57991 + -1.21231 0.0244999 1.57991 + -1.4128 0 1.4128 + -1.4128 0 1.4128 + -1.4128 0 1.4128 + -1.4128 0 1.4128 + -1.4128 0 1.4128 + -1.4128 0 1.4128 + -1.40816 -0.0245 1.40816 + -1.40816 -0.0245 1.40816 + -1.40816 -0.0245 1.40816 + -1.40816 -0.0245 1.40816 + -1.40816 -0.0245 1.40816 + -1.40816 -0.0245 1.40816 + -1.40816 -0.0245 1.40816 + -1.39548 -0.0424353 1.39548 + -1.39548 -0.0424353 1.39548 + -1.39548 -0.0424353 1.39548 + -1.39548 -0.0424353 1.39548 + -1.39548 -0.0424353 1.39548 + -1.37815 -0.049 1.37815 + -1.37815 -0.049 1.37815 + -1.37815 -0.049 1.37815 + -1.37815 -0.049 1.37815 + -1.37815 -0.049 1.37815 + -1.37815 -0.049 1.37815 + -1.36083 -0.0424353 1.36083 + -1.36083 -0.0424353 1.36083 + -1.36083 -0.0424353 1.36083 + -1.36083 -0.0424353 1.36083 + -1.36083 -0.0424353 1.36083 + -1.36083 -0.0424353 1.36083 + -1.34815 -0.0245 1.34815 + -1.34815 -0.0245 1.34815 + -1.34815 -0.0245 1.34815 + -1.34815 -0.0245 1.34815 + -1.34815 -0.0245 1.34815 + -1.3435 0 1.3435 + -1.3435 0 1.3435 + -1.3435 0 1.3435 + -1.3435 0 1.3435 + -1.3435 0 1.3435 + -1.3435 0 1.3435 + -1.3435 0 1.3435 + -1.3435 0 1.3435 + -1.34815 0.0244999 1.34815 + -1.34815 0.0244999 1.34815 + -1.34815 0.0244999 1.34815 + -1.34815 0.0244999 1.34815 + -1.34815 0.0244999 1.34815 + -1.36083 0.0424352 1.36083 + -1.36083 0.0424352 1.36083 + -1.36083 0.0424352 1.36083 + -1.36083 0.0424352 1.36083 + -1.36083 0.0424352 1.36083 + -1.36083 0.0424352 1.36083 + -1.37815 0.0489999 1.37815 + -1.37815 0.0489999 1.37815 + -1.37815 0.0489999 1.37815 + -1.37815 0.0489999 1.37815 + -1.37815 0.0489999 1.37815 + -1.37815 0.0489999 1.37815 + -1.39548 0.0424352 1.39548 + -1.39548 0.0424352 1.39548 + -1.39548 0.0424352 1.39548 + -1.39548 0.0424352 1.39548 + -1.39548 0.0424352 1.39548 + -1.40816 0.0244999 1.40816 + -1.40816 0.0244999 1.40816 + -1.40816 0.0244999 1.40816 + -1.40816 0.0244999 1.40816 + -1.40816 0.0244999 1.40816 + -1.40816 0.0244999 1.40816 + -1.40816 0.0244999 1.40816 + -1.58512 0 1.21631 + -1.58512 0 1.21631 + -1.58512 0 1.21631 + -1.58512 0 1.21631 + -1.58512 0 1.21631 + -1.58512 0 1.21631 + -1.57991 -0.0245 1.21231 + -1.57991 -0.0245 1.21231 + -1.57991 -0.0245 1.21231 + -1.57991 -0.0245 1.21231 + -1.57991 -0.0245 1.21231 + -1.57991 -0.0245 1.21231 + -1.56568 -0.0424353 1.20139 + -1.56568 -0.0424353 1.20139 + -1.56568 -0.0424353 1.20139 + -1.56568 -0.0424353 1.20139 + -1.56568 -0.0424353 1.20139 + -1.56568 -0.0424353 1.20139 + -1.54624 -0.049 1.18648 + -1.54624 -0.049 1.18648 + -1.54624 -0.049 1.18648 + -1.54624 -0.049 1.18648 + -1.54624 -0.049 1.18648 + -1.54624 -0.049 1.18648 + -1.54624 -0.049 1.18648 + -1.52681 -0.0424353 1.17156 + -1.52681 -0.0424353 1.17156 + -1.52681 -0.0424353 1.17156 + -1.52681 -0.0424353 1.17156 + -1.52681 -0.0424353 1.17156 + -1.51258 -0.0245 1.16064 + -1.51258 -0.0245 1.16064 + -1.51258 -0.0245 1.16064 + -1.51258 -0.0245 1.16064 + -1.51258 -0.0245 1.16064 + -1.51258 -0.0245 1.16064 + -1.50737 0 1.15665 + -1.50737 0 1.15665 + -1.50737 0 1.15665 + -1.50737 0 1.15665 + -1.50737 0 1.15665 + -1.50737 0 1.15665 + -1.51258 0.0244999 1.16064 + -1.51258 0.0244999 1.16064 + -1.51258 0.0244999 1.16064 + -1.51258 0.0244999 1.16064 + -1.51258 0.0244999 1.16064 + -1.51258 0.0244999 1.16064 + -1.52681 0.0424352 1.17156 + -1.52681 0.0424352 1.17156 + -1.52681 0.0424352 1.17156 + -1.52681 0.0424352 1.17156 + -1.52681 0.0424352 1.17156 + -1.54624 0.0489999 1.18648 + -1.54624 0.0489999 1.18648 + -1.54624 0.0489999 1.18648 + -1.54624 0.0489999 1.18648 + -1.54624 0.0489999 1.18648 + -1.54624 0.0489999 1.18648 + -1.54624 0.0489999 1.18648 + -1.56568 0.0424352 1.20139 + -1.56568 0.0424352 1.20139 + -1.56568 0.0424352 1.20139 + -1.56568 0.0424352 1.20139 + -1.56568 0.0424352 1.20139 + -1.56568 0.0424352 1.20139 + -1.57991 0.0244999 1.21231 + -1.57991 0.0244999 1.21231 + -1.57991 0.0244999 1.21231 + -1.57991 0.0244999 1.21231 + -1.57991 0.0244999 1.21231 + -1.57991 0.0244999 1.21231 + -1.73032 0 0.999 + -1.73032 0 0.999 + -1.73032 0 0.999 + -1.73032 0 0.999 + -1.73032 0 0.999 + -1.73032 0 0.999 + -1.72463 -0.0245 0.995718 + -1.72463 -0.0245 0.995718 + -1.72463 -0.0245 0.995718 + -1.72463 -0.0245 0.995718 + -1.72463 -0.0245 0.995718 + -1.72463 -0.0245 0.995718 + -1.7091 -0.0424353 0.98675 + -1.7091 -0.0424353 0.98675 + -1.7091 -0.0424353 0.98675 + -1.7091 -0.0424353 0.98675 + -1.7091 -0.0424353 0.98675 + -1.68788 -0.049 0.9745 + -1.68788 -0.049 0.9745 + -1.68788 -0.049 0.9745 + -1.68788 -0.049 0.9745 + -1.68788 -0.049 0.9745 + -1.68788 -0.049 0.9745 + -1.68788 -0.049 0.9745 + -1.66666 -0.0424353 0.96225 + -1.66666 -0.0424353 0.96225 + -1.66666 -0.0424353 0.96225 + -1.66666 -0.0424353 0.96225 + -1.66666 -0.0424353 0.96225 + -1.65113 -0.0245 0.953282 + -1.65113 -0.0245 0.953282 + -1.65113 -0.0245 0.953282 + -1.65113 -0.0245 0.953282 + -1.65113 -0.0245 0.953282 + -1.65113 -0.0245 0.953282 + -1.65113 -0.0245 0.953282 + -1.64545 0 0.95 + -1.64545 0 0.95 + -1.64545 0 0.95 + -1.64545 0 0.95 + -1.64545 0 0.95 + -1.65113 0.0245 0.953282 + -1.65113 0.0245 0.953282 + -1.65113 0.0245 0.953282 + -1.65113 0.0245 0.953282 + -1.65113 0.0245 0.953282 + -1.65113 0.0245 0.953282 + -1.65113 0.0245 0.953282 + -1.65113 0.0245 0.953282 + -1.66666 0.0424352 0.96225 + -1.66666 0.0424352 0.96225 + -1.66666 0.0424352 0.96225 + -1.66666 0.0424352 0.96225 + -1.66666 0.0424352 0.96225 + -1.68788 0.0489999 0.9745 + -1.68788 0.0489999 0.9745 + -1.68788 0.0489999 0.9745 + -1.68788 0.0489999 0.9745 + -1.68788 0.0489999 0.9745 + -1.68788 0.0489999 0.9745 + -1.68788 0.0489999 0.9745 + -1.7091 0.0424352 0.98675 + -1.7091 0.0424352 0.98675 + -1.7091 0.0424352 0.98675 + -1.7091 0.0424352 0.98675 + -1.7091 0.0424352 0.98675 + -1.72463 0.0244999 0.995718 + -1.72463 0.0244999 0.995718 + -1.72463 0.0244999 0.995718 + -1.72463 0.0244999 0.995718 + -1.72463 0.0244999 0.995718 + -1.72463 0.0244999 0.995718 + -1.84591 0 0.764602 + -1.84591 0 0.764602 + -1.84591 0 0.764602 + -1.84591 0 0.764602 + -1.84591 0 0.764602 + -1.84591 0 0.764602 + -1.83985 -0.0245 0.76209 + -1.83985 -0.0245 0.76209 + -1.83985 -0.0245 0.76209 + -1.83985 -0.0245 0.76209 + -1.83985 -0.0245 0.76209 + -1.83985 -0.0245 0.76209 + -1.82328 -0.0424353 0.755226 + -1.82328 -0.0424353 0.755226 + -1.82328 -0.0424353 0.755226 + -1.82328 -0.0424353 0.755226 + -1.82328 -0.0424353 0.755226 + -1.82328 -0.0424353 0.755226 + -1.80064 -0.049 0.745851 + -1.80064 -0.049 0.745851 + -1.80064 -0.049 0.745851 + -1.80064 -0.049 0.745851 + -1.80064 -0.049 0.745851 + -1.77801 -0.0424353 0.736475 + -1.77801 -0.0424353 0.736475 + -1.77801 -0.0424353 0.736475 + -1.77801 -0.0424353 0.736475 + -1.77801 -0.0424353 0.736475 + -1.77801 -0.0424353 0.736475 + -1.77801 -0.0424353 0.736475 + -1.76144 -0.0245 0.729611 + -1.76144 -0.0245 0.729611 + -1.76144 -0.0245 0.729611 + -1.76144 -0.0245 0.729611 + -1.76144 -0.0245 0.729611 + -1.76144 -0.0245 0.729611 + -1.75537 0 0.727099 + -1.75537 0 0.727099 + -1.75537 0 0.727099 + -1.75537 0 0.727099 + -1.75537 0 0.727099 + -1.75537 0 0.727099 + -1.75537 0 0.727099 + -1.76144 0.0245 0.729611 + -1.76144 0.0245 0.729611 + -1.76144 0.0245 0.729611 + -1.76144 0.0245 0.729611 + -1.77801 0.0424352 0.736475 + -1.77801 0.0424352 0.736475 + -1.77801 0.0424352 0.736475 + -1.77801 0.0424352 0.736475 + -1.77801 0.0424352 0.736475 + -1.77801 0.0424352 0.736475 + -1.77801 0.0424352 0.736475 + -1.77801 0.0424352 0.736475 + -1.80064 0.0489999 0.745851 + -1.80064 0.0489999 0.745851 + -1.80064 0.0489999 0.745851 + -1.80064 0.0489999 0.745851 + -1.80064 0.0489999 0.745851 + -1.82328 0.0424352 0.755226 + -1.82328 0.0424352 0.755226 + -1.82328 0.0424352 0.755226 + -1.82328 0.0424352 0.755226 + -1.82328 0.0424352 0.755226 + -1.82328 0.0424352 0.755226 + -1.83985 0.0245 0.76209 + -1.83985 0.0245 0.76209 + -1.83985 0.0245 0.76209 + -1.83985 0.0245 0.76209 + -1.83985 0.0245 0.76209 + -1.83985 0.0245 0.76209 + -1.92992 0 0.51712 + -1.92992 0 0.51712 + -1.92992 0 0.51712 + -1.92992 0 0.51712 + -1.92992 0 0.51712 + -1.92992 0 0.51712 + -1.92358 -0.0245 0.515422 + -1.92358 -0.0245 0.515422 + -1.92358 -0.0245 0.515422 + -1.92358 -0.0245 0.515422 + -1.92358 -0.0245 0.515422 + -1.92358 -0.0245 0.515422 + -1.90625 -0.0424352 0.51078 + -1.90625 -0.0424352 0.51078 + -1.90625 -0.0424352 0.51078 + -1.90625 -0.0424352 0.51078 + -1.90625 -0.0424352 0.51078 + -1.90625 -0.0424352 0.51078 + -1.88259 -0.049 0.504438 + -1.88259 -0.049 0.504438 + -1.88259 -0.049 0.504438 + -1.88259 -0.049 0.504438 + -1.88259 -0.049 0.504438 + -1.88259 -0.049 0.504438 + -1.85892 -0.0424352 0.498097 + -1.85892 -0.0424352 0.498097 + -1.85892 -0.0424352 0.498097 + -1.85892 -0.0424352 0.498097 + -1.85892 -0.0424352 0.498097 + -1.85892 -0.0424352 0.498097 + -1.85892 -0.0424352 0.498097 + -1.8416 -0.0245 0.493455 + -1.8416 -0.0245 0.493455 + -1.8416 -0.0245 0.493455 + -1.8416 -0.0245 0.493455 + -1.8416 -0.0245 0.493455 + -1.83526 0 0.491756 + -1.83526 0 0.491756 + -1.83526 0 0.491756 + -1.83526 0 0.491756 + -1.83526 0 0.491756 + -1.83526 0 0.491756 + -1.8416 0.0245 0.493455 + -1.8416 0.0245 0.493455 + -1.8416 0.0245 0.493455 + -1.8416 0.0245 0.493455 + -1.8416 0.0245 0.493455 + -1.8416 0.0245 0.493455 + -1.85892 0.0424352 0.498097 + -1.85892 0.0424352 0.498097 + -1.85892 0.0424352 0.498097 + -1.85892 0.0424352 0.498097 + -1.85892 0.0424352 0.498097 + -1.85892 0.0424352 0.498097 + -1.88259 0.049 0.504438 + -1.88259 0.049 0.504438 + -1.88259 0.049 0.504438 + -1.88259 0.049 0.504438 + -1.88259 0.049 0.504438 + -1.88259 0.049 0.504438 + -1.90625 0.0424352 0.51078 + -1.90625 0.0424352 0.51078 + -1.90625 0.0424352 0.51078 + -1.90625 0.0424352 0.51078 + -1.90625 0.0424352 0.51078 + -1.90625 0.0424352 0.51078 + -1.92358 0.0245 0.515422 + -1.92358 0.0245 0.515422 + -1.92358 0.0245 0.515422 + -1.92358 0.0245 0.515422 + -1.92358 0.0245 0.515422 + -1.92358 0.0245 0.515422 + -1.98091 0 0.260791 + -1.98091 0 0.260791 + -1.98091 0 0.260791 + -1.98091 0 0.260791 + -1.98091 0 0.260791 + -1.98091 0 0.260791 + -1.9744 -0.0245 0.259934 + -1.9744 -0.0245 0.259934 + -1.9744 -0.0245 0.259934 + -1.9744 -0.0245 0.259934 + -1.9744 -0.0245 0.259934 + -1.9744 -0.0245 0.259934 + -1.95662 -0.0424352 0.257593 + -1.95662 -0.0424352 0.257593 + -1.95662 -0.0424352 0.257593 + -1.95662 -0.0424352 0.257593 + -1.95662 -0.0424352 0.257593 + -1.95662 -0.0424352 0.257593 + -1.93233 -0.049 0.254395 + -1.93233 -0.049 0.254395 + -1.93233 -0.049 0.254395 + -1.93233 -0.049 0.254395 + -1.93233 -0.049 0.254395 + -1.93233 -0.049 0.254395 + -1.93233 -0.049 0.254395 + -1.90804 -0.0424352 0.251197 + -1.90804 -0.0424352 0.251197 + -1.90804 -0.0424352 0.251197 + -1.90804 -0.0424352 0.251197 + -1.90804 -0.0424352 0.251197 + -1.89025 -0.0245 0.248856 + -1.89025 -0.0245 0.248856 + -1.89025 -0.0245 0.248856 + -1.89025 -0.0245 0.248856 + -1.89025 -0.0245 0.248856 + -1.89025 -0.0245 0.248856 + -1.88374 0 0.247999 + -1.88374 0 0.247999 + -1.88374 0 0.247999 + -1.88374 0 0.247999 + -1.88374 0 0.247999 + -1.88374 0 0.247999 + -1.89025 0.0245 0.248856 + -1.89025 0.0245 0.248856 + -1.89025 0.0245 0.248856 + -1.89025 0.0245 0.248856 + -1.89025 0.0245 0.248856 + -1.89025 0.0245 0.248856 + -1.90804 0.0424352 0.251197 + -1.90804 0.0424352 0.251197 + -1.90804 0.0424352 0.251197 + -1.90804 0.0424352 0.251197 + -1.90804 0.0424352 0.251197 + -1.93233 0.049 0.254395 + -1.93233 0.049 0.254395 + -1.93233 0.049 0.254395 + -1.93233 0.049 0.254395 + -1.93233 0.049 0.254395 + -1.93233 0.049 0.254395 + -1.93233 0.049 0.254395 + -1.95662 0.0424352 0.257593 + -1.95662 0.0424352 0.257593 + -1.95662 0.0424352 0.257593 + -1.95662 0.0424352 0.257593 + -1.95662 0.0424352 0.257593 + -1.95662 0.0424352 0.257593 + -1.9744 0.0245 0.259934 + -1.9744 0.0245 0.259934 + -1.9744 0.0245 0.259934 + -1.9744 0.0245 0.259934 + -1.9744 0.0245 0.259934 + -1.9744 0.0245 0.259934 + -1.998 0 3.0169e-07 + -1.998 0 3.0169e-07 + -1.998 0 3.0169e-07 + -1.998 0 3.0169e-07 + -1.998 0 3.0169e-07 + -1.998 0 3.0169e-07 + -1.998 0 3.0169e-07 + -1.998 0 3.0169e-07 + -1.99144 -0.0245 2.99326e-07 + -1.99144 -0.0245 2.99326e-07 + -1.99144 -0.0245 2.99326e-07 + -1.99144 -0.0245 2.99326e-07 + -1.9735 -0.0424352 2.95763e-07 + -1.9735 -0.0424352 2.95763e-07 + -1.9735 -0.0424352 2.95763e-07 + -1.9735 -0.0424352 2.95763e-07 + -1.9735 -0.0424352 2.95763e-07 + -1.9735 -0.0424352 2.95763e-07 + -1.9735 -0.0424352 2.95763e-07 + -1.9735 -0.0424352 2.95763e-07 + -1.949 -0.049 2.92199e-07 + -1.949 -0.049 2.92199e-07 + -1.949 -0.049 2.92199e-07 + -1.949 -0.049 2.92199e-07 + -1.949 -0.049 2.92199e-07 + -1.9245 -0.0424352 2.88636e-07 + -1.9245 -0.0424352 2.88636e-07 + -1.9245 -0.0424352 2.88636e-07 + -1.9245 -0.0424352 2.88636e-07 + -1.9245 -0.0424352 2.88636e-07 + -1.90656 -0.0245 2.86854e-07 + -1.90656 -0.0245 2.86854e-07 + -1.90656 -0.0245 2.86854e-07 + -1.90656 -0.0245 2.86854e-07 + -1.90656 -0.0245 2.86854e-07 + -1.90656 -0.0245 2.86854e-07 + -1.90656 -0.0245 2.86854e-07 + -1.90656 -0.0245 2.86854e-07 + -1.9 0 2.86892e-07 + -1.9 0 2.86892e-07 + -1.9 0 2.86892e-07 + -1.9 0 2.86892e-07 + -1.90656 0.0245 2.88636e-07 + -1.90656 0.0245 2.88636e-07 + -1.90656 0.0245 2.88636e-07 + -1.90656 0.0245 2.88636e-07 + -1.90656 0.0245 2.88636e-07 + -1.90656 0.0245 2.88636e-07 + -1.90656 0.0245 2.88636e-07 + -1.90656 0.0245 2.88636e-07 + -1.9245 0.0424352 2.92199e-07 + -1.9245 0.0424352 2.92199e-07 + -1.9245 0.0424352 2.92199e-07 + -1.9245 0.0424352 2.92199e-07 + -1.9245 0.0424352 2.92199e-07 + -1.949 0.049 2.95763e-07 + -1.949 0.049 2.95763e-07 + -1.949 0.049 2.95763e-07 + -1.949 0.049 2.95763e-07 + -1.949 0.049 2.95763e-07 + -1.9735 0.0424352 2.99326e-07 + -1.9735 0.0424352 2.99326e-07 + -1.9735 0.0424352 2.99326e-07 + -1.9735 0.0424352 2.99326e-07 + -1.9735 0.0424352 2.99326e-07 + -1.9735 0.0424352 2.99326e-07 + -1.9735 0.0424352 2.99326e-07 + -1.9735 0.0424352 2.99326e-07 + -1.99144 0.0245 3.01108e-07 + -1.99144 0.0245 3.01108e-07 + -1.99144 0.0245 3.01108e-07 + -1.99144 0.0245 3.01108e-07 + -1.98091 0 -0.260791 + -1.98091 0 -0.260791 + -1.98091 0 -0.260791 + -1.98091 0 -0.260791 + -1.98091 0 -0.260791 + -1.98091 0 -0.260791 + -1.9744 -0.0245 -0.259935 + -1.9744 -0.0245 -0.259935 + -1.9744 -0.0245 -0.259935 + -1.9744 -0.0245 -0.259935 + -1.9744 -0.0245 -0.259935 + -1.9744 -0.0245 -0.259935 + -1.95662 -0.0424352 -0.257594 + -1.95662 -0.0424352 -0.257594 + -1.95662 -0.0424352 -0.257594 + -1.95662 -0.0424352 -0.257594 + -1.95662 -0.0424352 -0.257594 + -1.95662 -0.0424352 -0.257594 + -1.93233 -0.049 -0.254396 + -1.93233 -0.049 -0.254396 + -1.93233 -0.049 -0.254396 + -1.93233 -0.049 -0.254396 + -1.93233 -0.049 -0.254396 + -1.93233 -0.049 -0.254396 + -1.90804 -0.0424352 -0.251198 + -1.90804 -0.0424352 -0.251198 + -1.90804 -0.0424352 -0.251198 + -1.90804 -0.0424352 -0.251198 + -1.90804 -0.0424352 -0.251198 + -1.90804 -0.0424352 -0.251198 + -1.89025 -0.0245 -0.248857 + -1.89025 -0.0245 -0.248857 + -1.89025 -0.0245 -0.248857 + -1.89025 -0.0245 -0.248857 + -1.89025 -0.0245 -0.248857 + -1.88374 0 -0.248 + -1.88374 0 -0.248 + -1.88374 0 -0.248 + -1.88374 0 -0.248 + -1.88374 0 -0.248 + -1.88374 0 -0.248 + -1.88374 0 -0.248 + -1.88374 0 -0.248 + -1.89025 0.0245 -0.248857 + -1.89025 0.0245 -0.248857 + -1.89025 0.0245 -0.248857 + -1.89025 0.0245 -0.248857 + -1.89025 0.0245 -0.248857 + -1.90804 0.0424352 -0.251198 + -1.90804 0.0424352 -0.251198 + -1.90804 0.0424352 -0.251198 + -1.90804 0.0424352 -0.251198 + -1.90804 0.0424352 -0.251198 + -1.90804 0.0424352 -0.251198 + -1.93233 0.049 -0.254396 + -1.93233 0.049 -0.254396 + -1.93233 0.049 -0.254396 + -1.93233 0.049 -0.254396 + -1.93233 0.049 -0.254396 + -1.93233 0.049 -0.254396 + -1.95662 0.0424352 -0.257594 + -1.95662 0.0424352 -0.257594 + -1.95662 0.0424352 -0.257594 + -1.95662 0.0424352 -0.257594 + -1.95662 0.0424352 -0.257594 + -1.95662 0.0424352 -0.257594 + -1.9744 0.0245 -0.259935 + -1.9744 0.0245 -0.259935 + -1.9744 0.0245 -0.259935 + -1.9744 0.0245 -0.259935 + -1.9744 0.0245 -0.259935 + -1.9744 0.0245 -0.259935 + -1.92992 0 -0.51712 + -1.92992 0 -0.51712 + -1.92992 0 -0.51712 + -1.92992 0 -0.51712 + -1.92992 0 -0.51712 + -1.92992 0 -0.51712 + -1.92358 -0.0245 -0.515421 + -1.92358 -0.0245 -0.515421 + -1.92358 -0.0245 -0.515421 + -1.92358 -0.0245 -0.515421 + -1.92358 -0.0245 -0.515421 + -1.92358 -0.0245 -0.515421 + -1.90625 -0.0424352 -0.510779 + -1.90625 -0.0424352 -0.510779 + -1.90625 -0.0424352 -0.510779 + -1.90625 -0.0424352 -0.510779 + -1.90625 -0.0424352 -0.510779 + -1.88259 -0.049 -0.504438 + -1.88259 -0.049 -0.504438 + -1.88259 -0.049 -0.504438 + -1.88259 -0.049 -0.504438 + -1.88259 -0.049 -0.504438 + -1.88259 -0.049 -0.504438 + -1.88259 -0.049 -0.504438 + -1.85892 -0.0424352 -0.498097 + -1.85892 -0.0424352 -0.498097 + -1.85892 -0.0424352 -0.498097 + -1.85892 -0.0424352 -0.498097 + -1.85892 -0.0424352 -0.498097 + -1.85892 -0.0424352 -0.498097 + -1.85892 -0.0424352 -0.498097 + -1.8416 -0.0245 -0.493455 + -1.8416 -0.0245 -0.493455 + -1.8416 -0.0245 -0.493455 + -1.8416 -0.0245 -0.493455 + -1.8416 -0.0245 -0.493455 + -1.83526 0 -0.491756 + -1.83526 0 -0.491756 + -1.83526 0 -0.491756 + -1.83526 0 -0.491756 + -1.83526 0 -0.491756 + -1.83526 0 -0.491756 + -1.8416 0.0245 -0.493455 + -1.8416 0.0245 -0.493455 + -1.8416 0.0245 -0.493455 + -1.8416 0.0245 -0.493455 + -1.8416 0.0245 -0.493455 + -1.85892 0.0424352 -0.498097 + -1.85892 0.0424352 -0.498097 + -1.85892 0.0424352 -0.498097 + -1.85892 0.0424352 -0.498097 + -1.85892 0.0424352 -0.498097 + -1.85892 0.0424352 -0.498097 + -1.85892 0.0424352 -0.498097 + -1.88259 0.049 -0.504438 + -1.88259 0.049 -0.504438 + -1.88259 0.049 -0.504438 + -1.88259 0.049 -0.504438 + -1.88259 0.049 -0.504438 + -1.88259 0.049 -0.504438 + -1.88259 0.049 -0.504438 + -1.90625 0.0424352 -0.510779 + -1.90625 0.0424352 -0.510779 + -1.90625 0.0424352 -0.510779 + -1.90625 0.0424352 -0.510779 + -1.90625 0.0424352 -0.510779 + -1.92358 0.0245 -0.515421 + -1.92358 0.0245 -0.515421 + -1.92358 0.0245 -0.515421 + -1.92358 0.0245 -0.515421 + -1.92358 0.0245 -0.515421 + -1.92358 0.0245 -0.515421 + -1.84591 0 -0.764602 + -1.84591 0 -0.764602 + -1.84591 0 -0.764602 + -1.84591 0 -0.764602 + -1.84591 0 -0.764602 + -1.84591 0 -0.764602 + -1.83985 -0.0245 -0.762089 + -1.83985 -0.0245 -0.762089 + -1.83985 -0.0245 -0.762089 + -1.83985 -0.0245 -0.762089 + -1.83985 -0.0245 -0.762089 + -1.83985 -0.0245 -0.762089 + -1.82328 -0.0424352 -0.755226 + -1.82328 -0.0424352 -0.755226 + -1.82328 -0.0424352 -0.755226 + -1.82328 -0.0424352 -0.755226 + -1.82328 -0.0424352 -0.755226 + -1.82328 -0.0424352 -0.755226 + -1.80064 -0.0489999 -0.74585 + -1.80064 -0.0489999 -0.74585 + -1.80064 -0.0489999 -0.74585 + -1.80064 -0.0489999 -0.74585 + -1.80064 -0.0489999 -0.74585 + -1.80064 -0.0489999 -0.74585 + -1.77801 -0.0424352 -0.736474 + -1.77801 -0.0424352 -0.736474 + -1.77801 -0.0424352 -0.736474 + -1.77801 -0.0424352 -0.736474 + -1.77801 -0.0424352 -0.736474 + -1.76144 -0.0245 -0.729611 + -1.76144 -0.0245 -0.729611 + -1.76144 -0.0245 -0.729611 + -1.76144 -0.0245 -0.729611 + -1.76144 -0.0245 -0.729611 + -1.76144 -0.0245 -0.729611 + -1.76144 -0.0245 -0.729611 + -1.75537 0 -0.727098 + -1.75537 0 -0.727098 + -1.75537 0 -0.727098 + -1.75537 0 -0.727098 + -1.75537 0 -0.727098 + -1.76144 0.0245 -0.729611 + -1.76144 0.0245 -0.729611 + -1.76144 0.0245 -0.729611 + -1.76144 0.0245 -0.729611 + -1.76144 0.0245 -0.729611 + -1.76144 0.0245 -0.729611 + -1.76144 0.0245 -0.729611 + -1.76144 0.0245 -0.729611 + -1.77801 0.0424353 -0.736474 + -1.77801 0.0424353 -0.736474 + -1.77801 0.0424353 -0.736474 + -1.77801 0.0424353 -0.736474 + -1.77801 0.0424353 -0.736474 + -1.80064 0.049 -0.74585 + -1.80064 0.049 -0.74585 + -1.80064 0.049 -0.74585 + -1.80064 0.049 -0.74585 + -1.80064 0.049 -0.74585 + -1.80064 0.049 -0.74585 + -1.82328 0.0424353 -0.755226 + -1.82328 0.0424353 -0.755226 + -1.82328 0.0424353 -0.755226 + -1.82328 0.0424353 -0.755226 + -1.82328 0.0424353 -0.755226 + -1.82328 0.0424353 -0.755226 + -1.83985 0.0245 -0.762089 + -1.83985 0.0245 -0.762089 + -1.83985 0.0245 -0.762089 + -1.83985 0.0245 -0.762089 + -1.83985 0.0245 -0.762089 + -1.83985 0.0245 -0.762089 + -1.73032 0 -0.998999 + -1.73032 0 -0.998999 + -1.73032 0 -0.998999 + -1.73032 0 -0.998999 + -1.73032 0 -0.998999 + -1.73032 0 -0.998999 + -1.72463 -0.0244999 -0.995717 + -1.72463 -0.0244999 -0.995717 + -1.72463 -0.0244999 -0.995717 + -1.72463 -0.0244999 -0.995717 + -1.72463 -0.0244999 -0.995717 + -1.72463 -0.0244999 -0.995717 + -1.7091 -0.0424352 -0.986749 + -1.7091 -0.0424352 -0.986749 + -1.7091 -0.0424352 -0.986749 + -1.7091 -0.0424352 -0.986749 + -1.7091 -0.0424352 -0.986749 + -1.7091 -0.0424352 -0.986749 + -1.7091 -0.0424352 -0.986749 + -1.68788 -0.0489999 -0.974499 + -1.68788 -0.0489999 -0.974499 + -1.68788 -0.0489999 -0.974499 + -1.68788 -0.0489999 -0.974499 + -1.68788 -0.0489999 -0.974499 + -1.66667 -0.0424352 -0.962249 + -1.66667 -0.0424352 -0.962249 + -1.66667 -0.0424352 -0.962249 + -1.66667 -0.0424352 -0.962249 + -1.66667 -0.0424352 -0.962249 + -1.66667 -0.0424352 -0.962249 + -1.65113 -0.0245 -0.953282 + -1.65113 -0.0245 -0.953282 + -1.65113 -0.0245 -0.953282 + -1.65113 -0.0245 -0.953282 + -1.65113 -0.0245 -0.953282 + -1.65113 -0.0245 -0.953282 + -1.65113 -0.0245 -0.953282 + -1.64545 0 -0.949999 + -1.64545 0 -0.949999 + -1.64545 0 -0.949999 + -1.64545 0 -0.949999 + -1.64545 0 -0.949999 + -1.65113 0.0245 -0.953282 + -1.65113 0.0245 -0.953282 + -1.65113 0.0245 -0.953282 + -1.65113 0.0245 -0.953282 + -1.65113 0.0245 -0.953282 + -1.65113 0.0245 -0.953282 + -1.66667 0.0424353 -0.962249 + -1.66667 0.0424353 -0.962249 + -1.66667 0.0424353 -0.962249 + -1.66667 0.0424353 -0.962249 + -1.66667 0.0424353 -0.962249 + -1.66667 0.0424353 -0.962249 + -1.68788 0.049 -0.974499 + -1.68788 0.049 -0.974499 + -1.68788 0.049 -0.974499 + -1.68788 0.049 -0.974499 + -1.68788 0.049 -0.974499 + -1.7091 0.0424353 -0.986749 + -1.7091 0.0424353 -0.986749 + -1.7091 0.0424353 -0.986749 + -1.7091 0.0424353 -0.986749 + -1.7091 0.0424353 -0.986749 + -1.7091 0.0424353 -0.986749 + -1.7091 0.0424353 -0.986749 + -1.72463 0.0245 -0.995717 + -1.72463 0.0245 -0.995717 + -1.72463 0.0245 -0.995717 + -1.72463 0.0245 -0.995717 + -1.72463 0.0245 -0.995717 + -1.72463 0.0245 -0.995717 + -1.58512 0 -1.21631 + -1.58512 0 -1.21631 + -1.58512 0 -1.21631 + -1.58512 0 -1.21631 + -1.58512 0 -1.21631 + -1.58512 0 -1.21631 + -1.57991 -0.0244999 -1.21231 + -1.57991 -0.0244999 -1.21231 + -1.57991 -0.0244999 -1.21231 + -1.57991 -0.0244999 -1.21231 + -1.57991 -0.0244999 -1.21231 + -1.57991 -0.0244999 -1.21231 + -1.56568 -0.0424352 -1.20139 + -1.56568 -0.0424352 -1.20139 + -1.56568 -0.0424352 -1.20139 + -1.56568 -0.0424352 -1.20139 + -1.56568 -0.0424352 -1.20139 + -1.56568 -0.0424352 -1.20139 + -1.54624 -0.0489999 -1.18648 + -1.54624 -0.0489999 -1.18648 + -1.54624 -0.0489999 -1.18648 + -1.54624 -0.0489999 -1.18648 + -1.54624 -0.0489999 -1.18648 + -1.52681 -0.0424352 -1.17156 + -1.52681 -0.0424352 -1.17156 + -1.52681 -0.0424352 -1.17156 + -1.52681 -0.0424352 -1.17156 + -1.52681 -0.0424352 -1.17156 + -1.52681 -0.0424352 -1.17156 + -1.52681 -0.0424352 -1.17156 + -1.51258 -0.0244999 -1.16064 + -1.51258 -0.0244999 -1.16064 + -1.51258 -0.0244999 -1.16064 + -1.51258 -0.0244999 -1.16064 + -1.51258 -0.0244999 -1.16064 + -1.51258 -0.0244999 -1.16064 + -1.50737 0 -1.15665 + -1.50737 0 -1.15665 + -1.50737 0 -1.15665 + -1.50737 0 -1.15665 + -1.50737 0 -1.15665 + -1.50737 0 -1.15665 + -1.51258 0.0245 -1.16064 + -1.51258 0.0245 -1.16064 + -1.51258 0.0245 -1.16064 + -1.51258 0.0245 -1.16064 + -1.51258 0.0245 -1.16064 + -1.51258 0.0245 -1.16064 + -1.52681 0.0424353 -1.17156 + -1.52681 0.0424353 -1.17156 + -1.52681 0.0424353 -1.17156 + -1.52681 0.0424353 -1.17156 + -1.52681 0.0424353 -1.17156 + -1.52681 0.0424353 -1.17156 + -1.52681 0.0424353 -1.17156 + -1.54624 0.049 -1.18648 + -1.54624 0.049 -1.18648 + -1.54624 0.049 -1.18648 + -1.54624 0.049 -1.18648 + -1.54624 0.049 -1.18648 + -1.56568 0.0424353 -1.20139 + -1.56568 0.0424353 -1.20139 + -1.56568 0.0424353 -1.20139 + -1.56568 0.0424353 -1.20139 + -1.56568 0.0424353 -1.20139 + -1.56568 0.0424353 -1.20139 + -1.57991 0.0245 -1.21231 + -1.57991 0.0245 -1.21231 + -1.57991 0.0245 -1.21231 + -1.57991 0.0245 -1.21231 + -1.57991 0.0245 -1.21231 + -1.57991 0.0245 -1.21231 + -1.4128 0 -1.4128 + -1.4128 0 -1.4128 + -1.4128 0 -1.4128 + -1.4128 0 -1.4128 + -1.40816 -0.0244999 -1.40816 + -1.40816 -0.0244999 -1.40816 + -1.40816 -0.0244999 -1.40816 + -1.40816 -0.0244999 -1.40816 + -1.40816 -0.0244999 -1.40816 + -1.40816 -0.0244999 -1.40816 + -1.40816 -0.0244999 -1.40816 + -1.40816 -0.0244999 -1.40816 + -1.39548 -0.0424352 -1.39548 + -1.39548 -0.0424352 -1.39548 + -1.39548 -0.0424352 -1.39548 + -1.39548 -0.0424352 -1.39548 + -1.37815 -0.0489999 -1.37815 + -1.37815 -0.0489999 -1.37815 + -1.37815 -0.0489999 -1.37815 + -1.37815 -0.0489999 -1.37815 + -1.37815 -0.0489999 -1.37815 + -1.37815 -0.0489999 -1.37815 + -1.37815 -0.0489999 -1.37815 + -1.37815 -0.0489999 -1.37815 + -1.36083 -0.0424352 -1.36083 + -1.36083 -0.0424352 -1.36083 + -1.36083 -0.0424352 -1.36083 + -1.36083 -0.0424352 -1.36083 + -1.36083 -0.0424352 -1.36083 + -1.36083 -0.0424352 -1.36083 + -1.34814 -0.0244999 -1.34815 + -1.34814 -0.0244999 -1.34815 + -1.34814 -0.0244999 -1.34815 + -1.34814 -0.0244999 -1.34815 + -1.3435 0 -1.3435 + -1.3435 0 -1.3435 + -1.3435 0 -1.3435 + -1.3435 0 -1.3435 + -1.3435 0 -1.3435 + -1.3435 0 -1.3435 + -1.3435 0 -1.3435 + -1.3435 0 -1.3435 + -1.34814 0.0245 -1.34815 + -1.34814 0.0245 -1.34815 + -1.34814 0.0245 -1.34815 + -1.34814 0.0245 -1.34815 + -1.36083 0.0424353 -1.36083 + -1.36083 0.0424353 -1.36083 + -1.36083 0.0424353 -1.36083 + -1.36083 0.0424353 -1.36083 + -1.36083 0.0424353 -1.36083 + -1.36083 0.0424353 -1.36083 + -1.37815 0.049 -1.37815 + -1.37815 0.049 -1.37815 + -1.37815 0.049 -1.37815 + -1.37815 0.049 -1.37815 + -1.37815 0.049 -1.37815 + -1.37815 0.049 -1.37815 + -1.37815 0.049 -1.37815 + -1.37815 0.049 -1.37815 + -1.39548 0.0424353 -1.39548 + -1.39548 0.0424353 -1.39548 + -1.39548 0.0424353 -1.39548 + -1.39548 0.0424353 -1.39548 + -1.40816 0.0245 -1.40816 + -1.40816 0.0245 -1.40816 + -1.40816 0.0245 -1.40816 + -1.40816 0.0245 -1.40816 + -1.40816 0.0245 -1.40816 + -1.40816 0.0245 -1.40816 + -1.40816 0.0245 -1.40816 + -1.40816 0.0245 -1.40816 + -1.21631 0 -1.58512 + -1.21631 0 -1.58512 + -1.21631 0 -1.58512 + -1.21631 0 -1.58512 + -1.21631 0 -1.58512 + -1.21631 0 -1.58512 + -1.21231 -0.0244999 -1.57991 + -1.21231 -0.0244999 -1.57991 + -1.21231 -0.0244999 -1.57991 + -1.21231 -0.0244999 -1.57991 + -1.21231 -0.0244999 -1.57991 + -1.21231 -0.0244999 -1.57991 + -1.20139 -0.0424352 -1.56568 + -1.20139 -0.0424352 -1.56568 + -1.20139 -0.0424352 -1.56568 + -1.20139 -0.0424352 -1.56568 + -1.20139 -0.0424352 -1.56568 + -1.20139 -0.0424352 -1.56568 + -1.18648 -0.0489999 -1.54624 + -1.18648 -0.0489999 -1.54624 + -1.18648 -0.0489999 -1.54624 + -1.18648 -0.0489999 -1.54624 + -1.18648 -0.0489999 -1.54624 + -1.17156 -0.0424352 -1.52681 + -1.17156 -0.0424352 -1.52681 + -1.17156 -0.0424352 -1.52681 + -1.17156 -0.0424352 -1.52681 + -1.17156 -0.0424352 -1.52681 + -1.17156 -0.0424352 -1.52681 + -1.17156 -0.0424352 -1.52681 + -1.16064 -0.0244999 -1.51258 + -1.16064 -0.0244999 -1.51258 + -1.16064 -0.0244999 -1.51258 + -1.16064 -0.0244999 -1.51258 + -1.16064 -0.0244999 -1.51258 + -1.16064 -0.0244999 -1.51258 + -1.15665 0 -1.50737 + -1.15665 0 -1.50737 + -1.15665 0 -1.50737 + -1.15665 0 -1.50737 + -1.15665 0 -1.50737 + -1.15665 0 -1.50737 + -1.16064 0.0245 -1.51258 + -1.16064 0.0245 -1.51258 + -1.16064 0.0245 -1.51258 + -1.16064 0.0245 -1.51258 + -1.16064 0.0245 -1.51258 + -1.16064 0.0245 -1.51258 + -1.17156 0.0424353 -1.52681 + -1.17156 0.0424353 -1.52681 + -1.17156 0.0424353 -1.52681 + -1.17156 0.0424353 -1.52681 + -1.17156 0.0424353 -1.52681 + -1.17156 0.0424353 -1.52681 + -1.17156 0.0424353 -1.52681 + -1.18648 0.049 -1.54624 + -1.18648 0.049 -1.54624 + -1.18648 0.049 -1.54624 + -1.18648 0.049 -1.54624 + -1.18648 0.049 -1.54624 + -1.20139 0.0424353 -1.56568 + -1.20139 0.0424353 -1.56568 + -1.20139 0.0424353 -1.56568 + -1.20139 0.0424353 -1.56568 + -1.20139 0.0424353 -1.56568 + -1.20139 0.0424353 -1.56568 + -1.21231 0.0245 -1.57991 + -1.21231 0.0245 -1.57991 + -1.21231 0.0245 -1.57991 + -1.21231 0.0245 -1.57991 + -1.21231 0.0245 -1.57991 + -1.21231 0.0245 -1.57991 + -0.999 0 -1.73032 + -0.999 0 -1.73032 + -0.999 0 -1.73032 + -0.999 0 -1.73032 + -0.999 0 -1.73032 + -0.999 0 -1.73032 + -0.995718 -0.0244999 -1.72463 + -0.995718 -0.0244999 -1.72463 + -0.995718 -0.0244999 -1.72463 + -0.995718 -0.0244999 -1.72463 + -0.995718 -0.0244999 -1.72463 + -0.995718 -0.0244999 -1.72463 + -0.98675 -0.0424352 -1.7091 + -0.98675 -0.0424352 -1.7091 + -0.98675 -0.0424352 -1.7091 + -0.98675 -0.0424352 -1.7091 + -0.98675 -0.0424352 -1.7091 + -0.98675 -0.0424352 -1.7091 + -0.9745 -0.0489999 -1.68788 + -0.9745 -0.0489999 -1.68788 + -0.9745 -0.0489999 -1.68788 + -0.9745 -0.0489999 -1.68788 + -0.9745 -0.0489999 -1.68788 + -0.9745 -0.0489999 -1.68788 + -0.9745 -0.0489999 -1.68788 + -0.96225 -0.0424352 -1.66666 + -0.96225 -0.0424352 -1.66666 + -0.96225 -0.0424352 -1.66666 + -0.96225 -0.0424352 -1.66666 + -0.96225 -0.0424352 -1.66666 + -0.953283 -0.0244999 -1.65113 + -0.953283 -0.0244999 -1.65113 + -0.953283 -0.0244999 -1.65113 + -0.953283 -0.0244999 -1.65113 + -0.953283 -0.0244999 -1.65113 + -0.953283 -0.0244999 -1.65113 + -0.95 0 -1.64545 + -0.95 0 -1.64545 + -0.95 0 -1.64545 + -0.95 0 -1.64545 + -0.95 0 -1.64545 + -0.95 0 -1.64545 + -0.953283 0.0245 -1.65113 + -0.953283 0.0245 -1.65113 + -0.953283 0.0245 -1.65113 + -0.953283 0.0245 -1.65113 + -0.953283 0.0245 -1.65113 + -0.953283 0.0245 -1.65113 + -0.96225 0.0424353 -1.66666 + -0.96225 0.0424353 -1.66666 + -0.96225 0.0424353 -1.66666 + -0.96225 0.0424353 -1.66666 + -0.96225 0.0424353 -1.66666 + -0.9745 0.049 -1.68788 + -0.9745 0.049 -1.68788 + -0.9745 0.049 -1.68788 + -0.9745 0.049 -1.68788 + -0.9745 0.049 -1.68788 + -0.9745 0.049 -1.68788 + -0.9745 0.049 -1.68788 + -0.98675 0.0424353 -1.7091 + -0.98675 0.0424353 -1.7091 + -0.98675 0.0424353 -1.7091 + -0.98675 0.0424353 -1.7091 + -0.98675 0.0424353 -1.7091 + -0.98675 0.0424353 -1.7091 + -0.995718 0.0245 -1.72463 + -0.995718 0.0245 -1.72463 + -0.995718 0.0245 -1.72463 + -0.995718 0.0245 -1.72463 + -0.995718 0.0245 -1.72463 + -0.995718 0.0245 -1.72463 + -0.764602 0 -1.84591 + -0.764602 0 -1.84591 + -0.764602 0 -1.84591 + -0.764602 0 -1.84591 + -0.764602 0 -1.84591 + -0.764602 0 -1.84591 + -0.764602 0 -1.84591 + -0.764602 0 -1.84591 + -0.762089 -0.0244999 -1.83985 + -0.762089 -0.0244999 -1.83985 + -0.762089 -0.0244999 -1.83985 + -0.762089 -0.0244999 -1.83985 + -0.762089 -0.0244999 -1.83985 + -0.755226 -0.0424352 -1.82328 + -0.755226 -0.0424352 -1.82328 + -0.755226 -0.0424352 -1.82328 + -0.755226 -0.0424352 -1.82328 + -0.755226 -0.0424352 -1.82328 + -0.755226 -0.0424352 -1.82328 + -0.74585 -0.0489999 -1.80064 + -0.74585 -0.0489999 -1.80064 + -0.74585 -0.0489999 -1.80064 + -0.74585 -0.0489999 -1.80064 + -0.74585 -0.0489999 -1.80064 + -0.736474 -0.0424352 -1.77801 + -0.736474 -0.0424352 -1.77801 + -0.736474 -0.0424352 -1.77801 + -0.736474 -0.0424352 -1.77801 + -0.736474 -0.0424352 -1.77801 + -0.736474 -0.0424352 -1.77801 + -0.729611 -0.0244999 -1.76144 + -0.729611 -0.0244999 -1.76144 + -0.729611 -0.0244999 -1.76144 + -0.729611 -0.0244999 -1.76144 + -0.729611 -0.0244999 -1.76144 + -0.729611 -0.0244999 -1.76144 + -0.729611 -0.0244999 -1.76144 + -0.729611 -0.0244999 -1.76144 + -0.727099 0 -1.75537 + -0.727099 0 -1.75537 + -0.727099 0 -1.75537 + -0.727099 0 -1.75537 + -0.729611 0.0245 -1.76144 + -0.729611 0.0245 -1.76144 + -0.729611 0.0245 -1.76144 + -0.729611 0.0245 -1.76144 + -0.729611 0.0245 -1.76144 + -0.729611 0.0245 -1.76144 + -0.729611 0.0245 -1.76144 + -0.729611 0.0245 -1.76144 + -0.736474 0.0424353 -1.77801 + -0.736474 0.0424353 -1.77801 + -0.736474 0.0424353 -1.77801 + -0.736474 0.0424353 -1.77801 + -0.736474 0.0424353 -1.77801 + -0.74585 0.049 -1.80064 + -0.74585 0.049 -1.80064 + -0.74585 0.049 -1.80064 + -0.74585 0.049 -1.80064 + -0.74585 0.049 -1.80064 + -0.74585 0.049 -1.80064 + -0.755226 0.0424353 -1.82328 + -0.755226 0.0424353 -1.82328 + -0.755226 0.0424353 -1.82328 + -0.755226 0.0424353 -1.82328 + -0.755226 0.0424353 -1.82328 + -0.755226 0.0424353 -1.82328 + -0.762089 0.0245 -1.83985 + -0.762089 0.0245 -1.83985 + -0.762089 0.0245 -1.83985 + -0.762089 0.0245 -1.83985 + -0.762089 0.0245 -1.83985 + -0.51712 0 -1.92992 + -0.51712 0 -1.92992 + -0.51712 0 -1.92992 + -0.51712 0 -1.92992 + -0.51712 0 -1.92992 + -0.515421 -0.0244999 -1.92358 + -0.515421 -0.0244999 -1.92358 + -0.515421 -0.0244999 -1.92358 + -0.515421 -0.0244999 -1.92358 + -0.515421 -0.0244999 -1.92358 + -0.515421 -0.0244999 -1.92358 + -0.515421 -0.0244999 -1.92358 + -0.510779 -0.0424352 -1.90625 + -0.510779 -0.0424352 -1.90625 + -0.510779 -0.0424352 -1.90625 + -0.510779 -0.0424352 -1.90625 + -0.510779 -0.0424352 -1.90625 + -0.510779 -0.0424352 -1.90625 + -0.504438 -0.0489999 -1.88259 + -0.504438 -0.0489999 -1.88259 + -0.504438 -0.0489999 -1.88259 + -0.504438 -0.0489999 -1.88259 + -0.504438 -0.0489999 -1.88259 + -0.504438 -0.0489999 -1.88259 + -0.498097 -0.0424352 -1.85892 + -0.498097 -0.0424352 -1.85892 + -0.498097 -0.0424352 -1.85892 + -0.498097 -0.0424352 -1.85892 + -0.498097 -0.0424352 -1.85892 + -0.498097 -0.0424352 -1.85892 + -0.498097 -0.0424352 -1.85892 + -0.493455 -0.0244999 -1.8416 + -0.493455 -0.0244999 -1.8416 + -0.493455 -0.0244999 -1.8416 + -0.493455 -0.0244999 -1.8416 + -0.491756 0 -1.83526 + -0.491756 0 -1.83526 + -0.491756 0 -1.83526 + -0.491756 0 -1.83526 + -0.491756 0 -1.83526 + -0.491756 0 -1.83526 + -0.491756 0 -1.83526 + -0.493455 0.0245 -1.8416 + -0.493455 0.0245 -1.8416 + -0.493455 0.0245 -1.8416 + -0.493455 0.0245 -1.8416 + -0.493455 0.0245 -1.8416 + -0.498097 0.0424353 -1.85892 + -0.498097 0.0424353 -1.85892 + -0.498097 0.0424353 -1.85892 + -0.498097 0.0424353 -1.85892 + -0.498097 0.0424353 -1.85892 + -0.498097 0.0424353 -1.85892 + -0.498097 0.0424353 -1.85892 + -0.498097 0.0424353 -1.85892 + -0.504438 0.049 -1.88259 + -0.504438 0.049 -1.88259 + -0.504438 0.049 -1.88259 + -0.504438 0.049 -1.88259 + -0.504438 0.049 -1.88259 + -0.510779 0.0424353 -1.90625 + -0.510779 0.0424353 -1.90625 + -0.510779 0.0424353 -1.90625 + -0.510779 0.0424353 -1.90625 + -0.510779 0.0424353 -1.90625 + -0.510779 0.0424353 -1.90625 + -0.515421 0.0245 -1.92358 + -0.515421 0.0245 -1.92358 + -0.515421 0.0245 -1.92358 + -0.515421 0.0245 -1.92358 + -0.515421 0.0245 -1.92358 + -0.515421 0.0245 -1.92358 + -0.260792 0 -1.98091 + -0.260792 0 -1.98091 + -0.260792 0 -1.98091 + -0.260792 0 -1.98091 + -0.260792 0 -1.98091 + -0.259935 -0.0245 -1.9744 + -0.259935 -0.0245 -1.9744 + -0.259935 -0.0245 -1.9744 + -0.259935 -0.0245 -1.9744 + -0.259935 -0.0245 -1.9744 + -0.259935 -0.0245 -1.9744 + -0.257594 -0.0424352 -1.95662 + -0.257594 -0.0424352 -1.95662 + -0.257594 -0.0424352 -1.95662 + -0.257594 -0.0424352 -1.95662 + -0.257594 -0.0424352 -1.95662 + -0.257594 -0.0424352 -1.95662 + -0.254396 -0.0489999 -1.93233 + -0.254396 -0.0489999 -1.93233 + -0.254396 -0.0489999 -1.93233 + -0.254396 -0.0489999 -1.93233 + -0.254396 -0.0489999 -1.93233 + -0.254396 -0.0489999 -1.93233 + -0.251198 -0.0424352 -1.90804 + -0.251198 -0.0424352 -1.90804 + -0.251198 -0.0424352 -1.90804 + -0.251198 -0.0424352 -1.90804 + -0.251198 -0.0424352 -1.90804 + -0.251198 -0.0424352 -1.90804 + -0.248857 -0.0244999 -1.89025 + -0.248857 -0.0244999 -1.89025 + -0.248857 -0.0244999 -1.89025 + -0.248857 -0.0244999 -1.89025 + -0.248857 -0.0244999 -1.89025 + -0.248857 -0.0244999 -1.89025 + -0.248 0 -1.88374 + -0.248 0 -1.88374 + -0.248 0 -1.88374 + -0.248 0 -1.88374 + -0.248 0 -1.88374 + -0.248 0 -1.88374 + -0.248857 0.0245 -1.89025 + -0.248857 0.0245 -1.89025 + -0.248857 0.0245 -1.89025 + -0.248857 0.0245 -1.89025 + -0.248857 0.0245 -1.89025 + -0.248857 0.0245 -1.89025 + -0.251198 0.0424354 -1.90804 + -0.251198 0.0424354 -1.90804 + -0.251198 0.0424354 -1.90804 + -0.251198 0.0424354 -1.90804 + -0.251198 0.0424354 -1.90804 + -0.251198 0.0424354 -1.90804 + -0.254396 0.049 -1.93233 + -0.254396 0.049 -1.93233 + -0.254396 0.049 -1.93233 + -0.254396 0.049 -1.93233 + -0.254396 0.049 -1.93233 + -0.254396 0.049 -1.93233 + -0.257594 0.0424354 -1.95662 + -0.257594 0.0424354 -1.95662 + -0.257594 0.0424354 -1.95662 + -0.257594 0.0424354 -1.95662 + -0.257594 0.0424354 -1.95662 + -0.257594 0.0424354 -1.95662 + -0.259935 0.0245 -1.9744 + -0.259935 0.0245 -1.9744 + -0.259935 0.0245 -1.9744 + -0.259935 0.0245 -1.9744 + -0.259935 0.0245 -1.9744 + -0.259935 0.0245 -1.9744 + -0.259935 0.0245 -1.9744 + -3.25515e-07 0 -1.998 + -3.25515e-07 0 -1.998 + -3.25515e-07 0 -1.998 + -3.25515e-07 0 -1.998 + -3.25515e-07 0 -1.998 + -3.25515e-07 0 -1.998 + -3.25515e-07 0 -1.998 + -3.25515e-07 0 -1.998 + -3.24446e-07 -0.0244998 -1.99144 + -3.24446e-07 -0.0244998 -1.99144 + -3.24446e-07 -0.0244998 -1.99144 + -3.24446e-07 -0.0244998 -1.99144 + -3.21524e-07 -0.0424352 -1.9735 + -3.21524e-07 -0.0424352 -1.9735 + -3.21524e-07 -0.0424352 -1.9735 + -3.21524e-07 -0.0424352 -1.9735 + -3.21524e-07 -0.0424352 -1.9735 + -3.21524e-07 -0.0424352 -1.9735 + -3.21524e-07 -0.0424352 -1.9735 + -3.21524e-07 -0.0424352 -1.9735 + -3.17532e-07 -0.0489999 -1.949 + -3.17532e-07 -0.0489999 -1.949 + -3.17532e-07 -0.0489999 -1.949 + -3.17532e-07 -0.0489999 -1.949 + -3.17532e-07 -0.0489999 -1.949 + -3.17532e-07 -0.0489999 -1.949 + -3.13541e-07 -0.0424352 -1.9245 + -3.13541e-07 -0.0424352 -1.9245 + -3.13541e-07 -0.0424352 -1.9245 + -3.13541e-07 -0.0424352 -1.9245 + -3.10619e-07 -0.0244999 -1.90656 + -3.10619e-07 -0.0244999 -1.90656 + -3.10619e-07 -0.0244999 -1.90656 + -3.10619e-07 -0.0244999 -1.90656 + -3.10619e-07 -0.0244999 -1.90656 + -3.10619e-07 -0.0244999 -1.90656 + -3.10619e-07 -0.0244999 -1.90656 + -3.10619e-07 -0.0244999 -1.90656 + -3.09549e-07 0 -1.9 + -3.09549e-07 0 -1.9 + -3.09549e-07 0 -1.9 + -3.09549e-07 0 -1.9 + -3.09549e-07 0 -1.9 + -3.09549e-07 0 -1.9 + -3.10619e-07 0.0245001 -1.90656 + -3.10619e-07 0.0245001 -1.90656 + -3.10619e-07 0.0245001 -1.90656 + -3.10619e-07 0.0245001 -1.90656 + -3.10619e-07 0.0245001 -1.90656 + -3.10619e-07 0.0245001 -1.90656 + -3.13541e-07 0.0424354 -1.9245 + -3.13541e-07 0.0424354 -1.9245 + -3.13541e-07 0.0424354 -1.9245 + -3.13541e-07 0.0424354 -1.9245 + -3.17532e-07 0.049 -1.949 + -3.17532e-07 0.049 -1.949 + -3.17532e-07 0.049 -1.949 + -3.17532e-07 0.049 -1.949 + -3.17532e-07 0.049 -1.949 + -3.17532e-07 0.049 -1.949 + -3.21524e-07 0.0424354 -1.9735 + -3.21524e-07 0.0424354 -1.9735 + -3.21524e-07 0.0424354 -1.9735 + -3.21524e-07 0.0424354 -1.9735 + -3.21524e-07 0.0424354 -1.9735 + -3.21524e-07 0.0424354 -1.9735 + -3.21524e-07 0.0424354 -1.9735 + -3.21524e-07 0.0424354 -1.9735 + -3.24446e-07 0.0245 -1.99144 + -3.24446e-07 0.0245 -1.99144 + -3.24446e-07 0.0245 -1.99144 + -3.24446e-07 0.0245 -1.99144 + 0.260791 0 -1.98091 + 0.260791 0 -1.98091 + 0.260791 0 -1.98091 + 0.260791 0 -1.98091 + 0.260791 0 -1.98091 + 0.260791 0 -1.98091 + 0.259935 -0.0245 -1.9744 + 0.259935 -0.0245 -1.9744 + 0.259935 -0.0245 -1.9744 + 0.259935 -0.0245 -1.9744 + 0.259935 -0.0245 -1.9744 + 0.259935 -0.0245 -1.9744 + 0.257594 -0.0424352 -1.95662 + 0.257594 -0.0424352 -1.95662 + 0.257594 -0.0424352 -1.95662 + 0.257594 -0.0424352 -1.95662 + 0.257594 -0.0424352 -1.95662 + 0.257594 -0.0424352 -1.95662 + 0.254396 -0.0489999 -1.93233 + 0.254396 -0.0489999 -1.93233 + 0.254396 -0.0489999 -1.93233 + 0.254396 -0.0489999 -1.93233 + 0.254396 -0.0489999 -1.93233 + 0.254396 -0.0489999 -1.93233 + 0.251198 -0.0424352 -1.90804 + 0.251198 -0.0424352 -1.90804 + 0.251198 -0.0424352 -1.90804 + 0.251198 -0.0424352 -1.90804 + 0.251198 -0.0424352 -1.90804 + 0.251198 -0.0424352 -1.90804 + 0.248857 -0.0244999 -1.89025 + 0.248857 -0.0244999 -1.89025 + 0.248857 -0.0244999 -1.89025 + 0.248857 -0.0244999 -1.89025 + 0.248857 -0.0244999 -1.89025 + 0.248 0 -1.88374 + 0.248 0 -1.88374 + 0.248 0 -1.88374 + 0.248 0 -1.88374 + 0.248 0 -1.88374 + 0.248 0 -1.88374 + 0.248 0 -1.88374 + 0.248857 0.0245 -1.89025 + 0.248857 0.0245 -1.89025 + 0.248857 0.0245 -1.89025 + 0.248857 0.0245 -1.89025 + 0.248857 0.0245 -1.89025 + 0.251198 0.0424354 -1.90804 + 0.251198 0.0424354 -1.90804 + 0.251198 0.0424354 -1.90804 + 0.251198 0.0424354 -1.90804 + 0.251198 0.0424354 -1.90804 + 0.251198 0.0424354 -1.90804 + 0.251198 0.0424354 -1.90804 + 0.254396 0.049 -1.93233 + 0.254396 0.049 -1.93233 + 0.254396 0.049 -1.93233 + 0.254396 0.049 -1.93233 + 0.254396 0.049 -1.93233 + 0.254396 0.049 -1.93233 + 0.257594 0.0424354 -1.95662 + 0.257594 0.0424354 -1.95662 + 0.257594 0.0424354 -1.95662 + 0.257594 0.0424354 -1.95662 + 0.257594 0.0424354 -1.95662 + 0.257594 0.0424354 -1.95662 + 0.259935 0.0245 -1.9744 + 0.259935 0.0245 -1.9744 + 0.259935 0.0245 -1.9744 + 0.259935 0.0245 -1.9744 + 0.259935 0.0245 -1.9744 + 0.259935 0.0245 -1.9744 + 0.51712 0 -1.92992 + 0.51712 0 -1.92992 + 0.51712 0 -1.92992 + 0.51712 0 -1.92992 + 0.51712 0 -1.92992 + 0.51712 0 -1.92992 + 0.515421 -0.0244999 -1.92358 + 0.515421 -0.0244999 -1.92358 + 0.515421 -0.0244999 -1.92358 + 0.515421 -0.0244999 -1.92358 + 0.515421 -0.0244999 -1.92358 + 0.515421 -0.0244999 -1.92358 + 0.510779 -0.0424352 -1.90625 + 0.510779 -0.0424352 -1.90625 + 0.510779 -0.0424352 -1.90625 + 0.510779 -0.0424352 -1.90625 + 0.510779 -0.0424352 -1.90625 + 0.504438 -0.0489999 -1.88259 + 0.504438 -0.0489999 -1.88259 + 0.504438 -0.0489999 -1.88259 + 0.504438 -0.0489999 -1.88259 + 0.504438 -0.0489999 -1.88259 + 0.504438 -0.0489999 -1.88259 + 0.504438 -0.0489999 -1.88259 + 0.498097 -0.0424352 -1.85892 + 0.498097 -0.0424352 -1.85892 + 0.498097 -0.0424352 -1.85892 + 0.498097 -0.0424352 -1.85892 + 0.498097 -0.0424352 -1.85892 + 0.498097 -0.0424352 -1.85892 + 0.498097 -0.0424352 -1.85892 + 0.493455 -0.0244999 -1.8416 + 0.493455 -0.0244999 -1.8416 + 0.493455 -0.0244999 -1.8416 + 0.493455 -0.0244999 -1.8416 + 0.493455 -0.0244999 -1.8416 + 0.491756 0 -1.83526 + 0.491756 0 -1.83526 + 0.491756 0 -1.83526 + 0.491756 0 -1.83526 + 0.491756 0 -1.83526 + 0.491756 0 -1.83526 + 0.493455 0.0245 -1.8416 + 0.493455 0.0245 -1.8416 + 0.493455 0.0245 -1.8416 + 0.493455 0.0245 -1.8416 + 0.493455 0.0245 -1.8416 + 0.493455 0.0245 -1.8416 + 0.498097 0.0424353 -1.85892 + 0.498097 0.0424353 -1.85892 + 0.498097 0.0424353 -1.85892 + 0.498097 0.0424353 -1.85892 + 0.498097 0.0424353 -1.85892 + 0.498097 0.0424353 -1.85892 + 0.504438 0.049 -1.88259 + 0.504438 0.049 -1.88259 + 0.504438 0.049 -1.88259 + 0.504438 0.049 -1.88259 + 0.504438 0.049 -1.88259 + 0.504438 0.049 -1.88259 + 0.504438 0.049 -1.88259 + 0.510779 0.0424353 -1.90625 + 0.510779 0.0424353 -1.90625 + 0.510779 0.0424353 -1.90625 + 0.510779 0.0424353 -1.90625 + 0.515421 0.0245 -1.92358 + 0.515421 0.0245 -1.92358 + 0.515421 0.0245 -1.92358 + 0.515421 0.0245 -1.92358 + 0.515421 0.0245 -1.92358 + 0.515421 0.0245 -1.92358 + 0.515421 0.0245 -1.92358 + 0.764601 0 -1.84591 + 0.764601 0 -1.84591 + 0.764601 0 -1.84591 + 0.764601 0 -1.84591 + 0.764601 0 -1.84591 + 0.764601 0 -1.84591 + 0.762088 -0.0244999 -1.83985 + 0.762088 -0.0244999 -1.83985 + 0.762088 -0.0244999 -1.83985 + 0.762088 -0.0244999 -1.83985 + 0.762088 -0.0244999 -1.83985 + 0.762088 -0.0244999 -1.83985 + 0.755225 -0.0424352 -1.82328 + 0.755225 -0.0424352 -1.82328 + 0.755225 -0.0424352 -1.82328 + 0.755225 -0.0424352 -1.82328 + 0.755225 -0.0424352 -1.82328 + 0.755225 -0.0424352 -1.82328 + 0.755225 -0.0424352 -1.82328 + 0.745849 -0.0489999 -1.80064 + 0.745849 -0.0489999 -1.80064 + 0.745849 -0.0489999 -1.80064 + 0.745849 -0.0489999 -1.80064 + 0.745849 -0.0489999 -1.80064 + 0.736473 -0.0424352 -1.77801 + 0.736473 -0.0424352 -1.77801 + 0.736473 -0.0424352 -1.77801 + 0.736473 -0.0424352 -1.77801 + 0.736473 -0.0424352 -1.77801 + 0.736473 -0.0424352 -1.77801 + 0.72961 -0.0244999 -1.76144 + 0.72961 -0.0244999 -1.76144 + 0.72961 -0.0244999 -1.76144 + 0.72961 -0.0244999 -1.76144 + 0.72961 -0.0244999 -1.76144 + 0.72961 -0.0244999 -1.76144 + 0.727098 0 -1.75537 + 0.727098 0 -1.75537 + 0.727098 0 -1.75537 + 0.727098 0 -1.75537 + 0.727098 0 -1.75537 + 0.727098 0 -1.75537 + 0.72961 0.0245 -1.76144 + 0.72961 0.0245 -1.76144 + 0.72961 0.0245 -1.76144 + 0.72961 0.0245 -1.76144 + 0.72961 0.0245 -1.76144 + 0.72961 0.0245 -1.76144 + 0.736473 0.0424353 -1.77801 + 0.736473 0.0424353 -1.77801 + 0.736473 0.0424353 -1.77801 + 0.736473 0.0424353 -1.77801 + 0.736473 0.0424353 -1.77801 + 0.736473 0.0424353 -1.77801 + 0.745849 0.049 -1.80064 + 0.745849 0.049 -1.80064 + 0.745849 0.049 -1.80064 + 0.745849 0.049 -1.80064 + 0.745849 0.049 -1.80064 + 0.755225 0.0424353 -1.82328 + 0.755225 0.0424353 -1.82328 + 0.755225 0.0424353 -1.82328 + 0.755225 0.0424353 -1.82328 + 0.755225 0.0424353 -1.82328 + 0.755225 0.0424353 -1.82328 + 0.755225 0.0424353 -1.82328 + 0.755225 0.0424353 -1.82328 + 0.762088 0.0245 -1.83985 + 0.762088 0.0245 -1.83985 + 0.762088 0.0245 -1.83985 + 0.762088 0.0245 -1.83985 + 0.762088 0.0245 -1.83985 + 0.998999 0 -1.73032 + 0.998999 0 -1.73032 + 0.998999 0 -1.73032 + 0.998999 0 -1.73032 + 0.998999 0 -1.73032 + 0.998999 0 -1.73032 + 0.995717 -0.0244999 -1.72463 + 0.995717 -0.0244999 -1.72463 + 0.995717 -0.0244999 -1.72463 + 0.995717 -0.0244999 -1.72463 + 0.995717 -0.0244999 -1.72463 + 0.995717 -0.0244999 -1.72463 + 0.986749 -0.0424352 -1.7091 + 0.986749 -0.0424352 -1.7091 + 0.986749 -0.0424352 -1.7091 + 0.986749 -0.0424352 -1.7091 + 0.986749 -0.0424352 -1.7091 + 0.986749 -0.0424352 -1.7091 + 0.974499 -0.0489999 -1.68788 + 0.974499 -0.0489999 -1.68788 + 0.974499 -0.0489999 -1.68788 + 0.974499 -0.0489999 -1.68788 + 0.974499 -0.0489999 -1.68788 + 0.974499 -0.0489999 -1.68788 + 0.962249 -0.0424352 -1.66667 + 0.962249 -0.0424352 -1.66667 + 0.962249 -0.0424352 -1.66667 + 0.962249 -0.0424352 -1.66667 + 0.962249 -0.0424352 -1.66667 + 0.953282 -0.0244999 -1.65113 + 0.953282 -0.0244999 -1.65113 + 0.953282 -0.0244999 -1.65113 + 0.953282 -0.0244999 -1.65113 + 0.953282 -0.0244999 -1.65113 + 0.953282 -0.0244999 -1.65113 + 0.953282 -0.0244999 -1.65113 + 0.953282 -0.0244999 -1.65113 + 0.949999 0 -1.64545 + 0.949999 0 -1.64545 + 0.949999 0 -1.64545 + 0.949999 0 -1.64545 + 0.953282 0.0245 -1.65113 + 0.953282 0.0245 -1.65113 + 0.953282 0.0245 -1.65113 + 0.953282 0.0245 -1.65113 + 0.953282 0.0245 -1.65113 + 0.953282 0.0245 -1.65113 + 0.953282 0.0245 -1.65113 + 0.953282 0.0245 -1.65113 + 0.962249 0.0424353 -1.66667 + 0.962249 0.0424353 -1.66667 + 0.962249 0.0424353 -1.66667 + 0.962249 0.0424353 -1.66667 + 0.962249 0.0424353 -1.66667 + 0.974499 0.049 -1.68788 + 0.974499 0.049 -1.68788 + 0.974499 0.049 -1.68788 + 0.974499 0.049 -1.68788 + 0.974499 0.049 -1.68788 + 0.974499 0.049 -1.68788 + 0.986749 0.0424353 -1.7091 + 0.986749 0.0424353 -1.7091 + 0.986749 0.0424353 -1.7091 + 0.986749 0.0424353 -1.7091 + 0.986749 0.0424353 -1.7091 + 0.986749 0.0424353 -1.7091 + 0.995717 0.0245 -1.72463 + 0.995717 0.0245 -1.72463 + 0.995717 0.0245 -1.72463 + 0.995717 0.0245 -1.72463 + 0.995717 0.0245 -1.72463 + 0.995717 0.0245 -1.72463 + 1.21631 0 -1.58512 + 1.21631 0 -1.58512 + 1.21631 0 -1.58512 + 1.21631 0 -1.58512 + 1.21631 0 -1.58512 + 1.21631 0 -1.58512 + 1.21231 -0.0244999 -1.57991 + 1.21231 -0.0244999 -1.57991 + 1.21231 -0.0244999 -1.57991 + 1.21231 -0.0244999 -1.57991 + 1.21231 -0.0244999 -1.57991 + 1.21231 -0.0244999 -1.57991 + 1.20139 -0.0424352 -1.56568 + 1.20139 -0.0424352 -1.56568 + 1.20139 -0.0424352 -1.56568 + 1.20139 -0.0424352 -1.56568 + 1.20139 -0.0424352 -1.56568 + 1.20139 -0.0424352 -1.56568 + 1.18648 -0.0489999 -1.54625 + 1.18648 -0.0489999 -1.54625 + 1.18648 -0.0489999 -1.54625 + 1.18648 -0.0489999 -1.54625 + 1.18648 -0.0489999 -1.54625 + 1.17156 -0.0424352 -1.52681 + 1.17156 -0.0424352 -1.52681 + 1.17156 -0.0424352 -1.52681 + 1.17156 -0.0424352 -1.52681 + 1.17156 -0.0424352 -1.52681 + 1.17156 -0.0424352 -1.52681 + 1.17156 -0.0424352 -1.52681 + 1.16064 -0.0244999 -1.51258 + 1.16064 -0.0244999 -1.51258 + 1.16064 -0.0244999 -1.51258 + 1.16064 -0.0244999 -1.51258 + 1.16064 -0.0244999 -1.51258 + 1.16064 -0.0244999 -1.51258 + 1.15665 0 -1.50737 + 1.15665 0 -1.50737 + 1.15665 0 -1.50737 + 1.15665 0 -1.50737 + 1.15665 0 -1.50737 + 1.15665 0 -1.50737 + 1.16064 0.0245 -1.51258 + 1.16064 0.0245 -1.51258 + 1.16064 0.0245 -1.51258 + 1.16064 0.0245 -1.51258 + 1.16064 0.0245 -1.51258 + 1.16064 0.0245 -1.51258 + 1.17156 0.0424353 -1.52681 + 1.17156 0.0424353 -1.52681 + 1.17156 0.0424353 -1.52681 + 1.17156 0.0424353 -1.52681 + 1.17156 0.0424353 -1.52681 + 1.17156 0.0424353 -1.52681 + 1.17156 0.0424353 -1.52681 + 1.18648 0.049 -1.54625 + 1.18648 0.049 -1.54625 + 1.18648 0.049 -1.54625 + 1.18648 0.049 -1.54625 + 1.18648 0.049 -1.54625 + 1.20139 0.0424353 -1.56568 + 1.20139 0.0424353 -1.56568 + 1.20139 0.0424353 -1.56568 + 1.20139 0.0424353 -1.56568 + 1.20139 0.0424353 -1.56568 + 1.20139 0.0424353 -1.56568 + 1.21231 0.0245 -1.57991 + 1.21231 0.0245 -1.57991 + 1.21231 0.0245 -1.57991 + 1.21231 0.0245 -1.57991 + 1.21231 0.0245 -1.57991 + 1.21231 0.0245 -1.57991 + 1.4128 0 -1.4128 + 1.4128 0 -1.4128 + 1.4128 0 -1.4128 + 1.4128 0 -1.4128 + 1.40816 -0.0244999 -1.40816 + 1.40816 -0.0244999 -1.40816 + 1.40816 -0.0244999 -1.40816 + 1.40816 -0.0244999 -1.40816 + 1.40816 -0.0244999 -1.40816 + 1.40816 -0.0244999 -1.40816 + 1.40816 -0.0244999 -1.40816 + 1.40816 -0.0244999 -1.40816 + 1.39547 -0.0424352 -1.39548 + 1.39547 -0.0424352 -1.39548 + 1.39547 -0.0424352 -1.39548 + 1.39547 -0.0424352 -1.39548 + 1.37815 -0.0489999 -1.37815 + 1.37815 -0.0489999 -1.37815 + 1.37815 -0.0489999 -1.37815 + 1.37815 -0.0489999 -1.37815 + 1.37815 -0.0489999 -1.37815 + 1.37815 -0.0489999 -1.37815 + 1.37815 -0.0489999 -1.37815 + 1.36083 -0.0424352 -1.36083 + 1.36083 -0.0424352 -1.36083 + 1.36083 -0.0424352 -1.36083 + 1.36083 -0.0424352 -1.36083 + 1.36083 -0.0424352 -1.36083 + 1.36083 -0.0424352 -1.36083 + 1.36083 -0.0424352 -1.36083 + 1.34814 -0.0244999 -1.34815 + 1.34814 -0.0244999 -1.34815 + 1.34814 -0.0244999 -1.34815 + 1.34814 -0.0244999 -1.34815 + 1.3435 0 -1.3435 + 1.3435 0 -1.3435 + 1.3435 0 -1.3435 + 1.3435 0 -1.3435 + 1.3435 0 -1.3435 + 1.3435 0 -1.3435 + 1.3435 0 -1.3435 + 1.3435 0 -1.3435 + 1.34814 0.0245 -1.34815 + 1.34814 0.0245 -1.34815 + 1.34814 0.0245 -1.34815 + 1.34814 0.0245 -1.34815 + 1.36083 0.0424353 -1.36083 + 1.36083 0.0424353 -1.36083 + 1.36083 0.0424353 -1.36083 + 1.36083 0.0424353 -1.36083 + 1.36083 0.0424353 -1.36083 + 1.36083 0.0424353 -1.36083 + 1.36083 0.0424353 -1.36083 + 1.37815 0.049 -1.37815 + 1.37815 0.049 -1.37815 + 1.37815 0.049 -1.37815 + 1.37815 0.049 -1.37815 + 1.37815 0.049 -1.37815 + 1.37815 0.049 -1.37815 + 1.37815 0.049 -1.37815 + 1.39547 0.0424353 -1.39548 + 1.39547 0.0424353 -1.39548 + 1.39547 0.0424353 -1.39548 + 1.39547 0.0424353 -1.39548 + 1.40816 0.0245 -1.40816 + 1.40816 0.0245 -1.40816 + 1.40816 0.0245 -1.40816 + 1.40816 0.0245 -1.40816 + 1.40816 0.0245 -1.40816 + 1.40816 0.0245 -1.40816 + 1.40816 0.0245 -1.40816 + 1.40816 0.0245 -1.40816 + 1.58512 0 -1.21631 + 1.58512 0 -1.21631 + 1.58512 0 -1.21631 + 1.58512 0 -1.21631 + 1.58512 0 -1.21631 + 1.58512 0 -1.21631 + 1.57991 -0.0244999 -1.21231 + 1.57991 -0.0244999 -1.21231 + 1.57991 -0.0244999 -1.21231 + 1.57991 -0.0244999 -1.21231 + 1.57991 -0.0244999 -1.21231 + 1.57991 -0.0244999 -1.21231 + 1.56568 -0.0424352 -1.20139 + 1.56568 -0.0424352 -1.20139 + 1.56568 -0.0424352 -1.20139 + 1.56568 -0.0424352 -1.20139 + 1.56568 -0.0424352 -1.20139 + 1.56568 -0.0424352 -1.20139 + 1.54624 -0.0489999 -1.18648 + 1.54624 -0.0489999 -1.18648 + 1.54624 -0.0489999 -1.18648 + 1.54624 -0.0489999 -1.18648 + 1.54624 -0.0489999 -1.18648 + 1.54624 -0.0489999 -1.18648 + 1.52681 -0.0424352 -1.17156 + 1.52681 -0.0424352 -1.17156 + 1.52681 -0.0424352 -1.17156 + 1.52681 -0.0424352 -1.17156 + 1.52681 -0.0424352 -1.17156 + 1.52681 -0.0424352 -1.17156 + 1.51258 -0.0244999 -1.16064 + 1.51258 -0.0244999 -1.16064 + 1.51258 -0.0244999 -1.16064 + 1.51258 -0.0244999 -1.16064 + 1.51258 -0.0244999 -1.16064 + 1.51258 -0.0244999 -1.16064 + 1.51258 -0.0244999 -1.16064 + 1.50737 0 -1.15665 + 1.50737 0 -1.15665 + 1.50737 0 -1.15665 + 1.50737 0 -1.15665 + 1.50737 0 -1.15665 + 1.51258 0.0245 -1.16064 + 1.51258 0.0245 -1.16064 + 1.51258 0.0245 -1.16064 + 1.51258 0.0245 -1.16064 + 1.51258 0.0245 -1.16064 + 1.51258 0.0245 -1.16064 + 1.52681 0.0424353 -1.17156 + 1.52681 0.0424353 -1.17156 + 1.52681 0.0424353 -1.17156 + 1.52681 0.0424353 -1.17156 + 1.52681 0.0424353 -1.17156 + 1.52681 0.0424353 -1.17156 + 1.54624 0.049 -1.18648 + 1.54624 0.049 -1.18648 + 1.54624 0.049 -1.18648 + 1.54624 0.049 -1.18648 + 1.54624 0.049 -1.18648 + 1.56568 0.0424353 -1.20139 + 1.56568 0.0424353 -1.20139 + 1.56568 0.0424353 -1.20139 + 1.56568 0.0424353 -1.20139 + 1.56568 0.0424353 -1.20139 + 1.56568 0.0424353 -1.20139 + 1.56568 0.0424353 -1.20139 + 1.57991 0.0245 -1.21231 + 1.57991 0.0245 -1.21231 + 1.57991 0.0245 -1.21231 + 1.57991 0.0245 -1.21231 + 1.57991 0.0245 -1.21231 + 1.57991 0.0245 -1.21231 + 1.73032 0 -0.998999 + 1.73032 0 -0.998999 + 1.73032 0 -0.998999 + 1.73032 0 -0.998999 + 1.73032 0 -0.998999 + 1.73032 0 -0.998999 + 1.72463 -0.0244999 -0.995717 + 1.72463 -0.0244999 -0.995717 + 1.72463 -0.0244999 -0.995717 + 1.72463 -0.0244999 -0.995717 + 1.72463 -0.0244999 -0.995717 + 1.72463 -0.0244999 -0.995717 + 1.7091 -0.0424352 -0.986749 + 1.7091 -0.0424352 -0.986749 + 1.7091 -0.0424352 -0.986749 + 1.7091 -0.0424352 -0.986749 + 1.7091 -0.0424352 -0.986749 + 1.7091 -0.0424352 -0.986749 + 1.68788 -0.0489999 -0.9745 + 1.68788 -0.0489999 -0.9745 + 1.68788 -0.0489999 -0.9745 + 1.68788 -0.0489999 -0.9745 + 1.68788 -0.0489999 -0.9745 + 1.68788 -0.0489999 -0.9745 + 1.66667 -0.0424352 -0.96225 + 1.66667 -0.0424352 -0.96225 + 1.66667 -0.0424352 -0.96225 + 1.66667 -0.0424352 -0.96225 + 1.66667 -0.0424352 -0.96225 + 1.66667 -0.0424352 -0.96225 + 1.65113 -0.0245 -0.953282 + 1.65113 -0.0245 -0.953282 + 1.65113 -0.0245 -0.953282 + 1.65113 -0.0245 -0.953282 + 1.65113 -0.0245 -0.953282 + 1.64545 0 -0.95 + 1.64545 0 -0.95 + 1.64545 0 -0.95 + 1.64545 0 -0.95 + 1.64545 0 -0.95 + 1.64545 0 -0.95 + 1.64545 0 -0.95 + 1.65113 0.0245 -0.953282 + 1.65113 0.0245 -0.953282 + 1.65113 0.0245 -0.953282 + 1.65113 0.0245 -0.953282 + 1.65113 0.0245 -0.953282 + 1.65113 0.0245 -0.953282 + 1.66667 0.0424353 -0.96225 + 1.66667 0.0424353 -0.96225 + 1.66667 0.0424353 -0.96225 + 1.66667 0.0424353 -0.96225 + 1.66667 0.0424353 -0.96225 + 1.66667 0.0424353 -0.96225 + 1.68788 0.049 -0.9745 + 1.68788 0.049 -0.9745 + 1.68788 0.049 -0.9745 + 1.68788 0.049 -0.9745 + 1.68788 0.049 -0.9745 + 1.68788 0.049 -0.9745 + 1.68788 0.049 -0.9745 + 1.7091 0.0424353 -0.986749 + 1.7091 0.0424353 -0.986749 + 1.7091 0.0424353 -0.986749 + 1.7091 0.0424353 -0.986749 + 1.7091 0.0424353 -0.986749 + 1.72463 0.0245 -0.995717 + 1.72463 0.0245 -0.995717 + 1.72463 0.0245 -0.995717 + 1.72463 0.0245 -0.995717 + 1.72463 0.0245 -0.995717 + 1.72463 0.0245 -0.995717 + 1.84591 0 -0.764602 + 1.84591 0 -0.764602 + 1.84591 0 -0.764602 + 1.84591 0 -0.764602 + 1.84591 0 -0.764602 + 1.84591 0 -0.764602 + 1.84591 0 -0.764602 + 1.84591 0 -0.764602 + 1.83985 -0.0245 -0.762089 + 1.83985 -0.0245 -0.762089 + 1.83985 -0.0245 -0.762089 + 1.83985 -0.0245 -0.762089 + 1.82328 -0.0424352 -0.755226 + 1.82328 -0.0424352 -0.755226 + 1.82328 -0.0424352 -0.755226 + 1.82328 -0.0424352 -0.755226 + 1.82328 -0.0424352 -0.755226 + 1.82328 -0.0424352 -0.755226 + 1.82328 -0.0424352 -0.755226 + 1.80064 -0.0489999 -0.74585 + 1.80064 -0.0489999 -0.74585 + 1.80064 -0.0489999 -0.74585 + 1.80064 -0.0489999 -0.74585 + 1.80064 -0.0489999 -0.74585 + 1.80064 -0.0489999 -0.74585 + 1.77801 -0.0424352 -0.736474 + 1.77801 -0.0424352 -0.736474 + 1.77801 -0.0424352 -0.736474 + 1.77801 -0.0424352 -0.736474 + 1.77801 -0.0424352 -0.736474 + 1.77801 -0.0424352 -0.736474 + 1.76144 -0.0245 -0.729611 + 1.76144 -0.0245 -0.729611 + 1.76144 -0.0245 -0.729611 + 1.76144 -0.0245 -0.729611 + 1.76144 -0.0245 -0.729611 + 1.76144 -0.0245 -0.729611 + 1.75537 0 -0.727099 + 1.75537 0 -0.727099 + 1.75537 0 -0.727099 + 1.75537 0 -0.727099 + 1.75537 0 -0.727099 + 1.75537 0 -0.727099 + 1.76144 0.0245 -0.729611 + 1.76144 0.0245 -0.729611 + 1.76144 0.0245 -0.729611 + 1.76144 0.0245 -0.729611 + 1.76144 0.0245 -0.729611 + 1.76144 0.0245 -0.729611 + 1.77801 0.0424353 -0.736474 + 1.77801 0.0424353 -0.736474 + 1.77801 0.0424353 -0.736474 + 1.77801 0.0424353 -0.736474 + 1.77801 0.0424353 -0.736474 + 1.77801 0.0424353 -0.736474 + 1.80064 0.049 -0.74585 + 1.80064 0.049 -0.74585 + 1.80064 0.049 -0.74585 + 1.80064 0.049 -0.74585 + 1.80064 0.049 -0.74585 + 1.80064 0.049 -0.74585 + 1.82328 0.0424353 -0.755226 + 1.82328 0.0424353 -0.755226 + 1.82328 0.0424353 -0.755226 + 1.82328 0.0424353 -0.755226 + 1.82328 0.0424353 -0.755226 + 1.82328 0.0424353 -0.755226 + 1.82328 0.0424353 -0.755226 + 1.83985 0.0245 -0.762089 + 1.83985 0.0245 -0.762089 + 1.83985 0.0245 -0.762089 + 1.83985 0.0245 -0.762089 + 1.92992 0 -0.517121 + 1.92992 0 -0.517121 + 1.92992 0 -0.517121 + 1.92992 0 -0.517121 + 1.92992 0 -0.517121 + 1.92992 0 -0.517121 + 1.92358 -0.0245 -0.515422 + 1.92358 -0.0245 -0.515422 + 1.92358 -0.0245 -0.515422 + 1.92358 -0.0245 -0.515422 + 1.92358 -0.0245 -0.515422 + 1.92358 -0.0245 -0.515422 + 1.90625 -0.0424352 -0.51078 + 1.90625 -0.0424352 -0.51078 + 1.90625 -0.0424352 -0.51078 + 1.90625 -0.0424352 -0.51078 + 1.90625 -0.0424352 -0.51078 + 1.90625 -0.0424352 -0.51078 + 1.88259 -0.049 -0.504439 + 1.88259 -0.049 -0.504439 + 1.88259 -0.049 -0.504439 + 1.88259 -0.049 -0.504439 + 1.88259 -0.049 -0.504439 + 1.88259 -0.049 -0.504439 + 1.85892 -0.0424352 -0.498098 + 1.85892 -0.0424352 -0.498098 + 1.85892 -0.0424352 -0.498098 + 1.85892 -0.0424352 -0.498098 + 1.85892 -0.0424352 -0.498098 + 1.85892 -0.0424352 -0.498098 + 1.8416 -0.0245 -0.493456 + 1.8416 -0.0245 -0.493456 + 1.8416 -0.0245 -0.493456 + 1.8416 -0.0245 -0.493456 + 1.8416 -0.0245 -0.493456 + 1.8416 -0.0245 -0.493456 + 1.83526 0 -0.491757 + 1.83526 0 -0.491757 + 1.83526 0 -0.491757 + 1.83526 0 -0.491757 + 1.83526 0 -0.491757 + 1.83526 0 -0.491757 + 1.8416 0.0245 -0.493456 + 1.8416 0.0245 -0.493456 + 1.8416 0.0245 -0.493456 + 1.8416 0.0245 -0.493456 + 1.8416 0.0245 -0.493456 + 1.8416 0.0245 -0.493456 + 1.85892 0.0424352 -0.498098 + 1.85892 0.0424352 -0.498098 + 1.85892 0.0424352 -0.498098 + 1.85892 0.0424352 -0.498098 + 1.85892 0.0424352 -0.498098 + 1.85892 0.0424352 -0.498098 + 1.88259 0.049 -0.504439 + 1.88259 0.049 -0.504439 + 1.88259 0.049 -0.504439 + 1.88259 0.049 -0.504439 + 1.88259 0.049 -0.504439 + 1.88259 0.049 -0.504439 + 1.90625 0.0424352 -0.51078 + 1.90625 0.0424352 -0.51078 + 1.90625 0.0424352 -0.51078 + 1.90625 0.0424352 -0.51078 + 1.90625 0.0424352 -0.51078 + 1.90625 0.0424352 -0.51078 + 1.92358 0.0245 -0.515422 + 1.92358 0.0245 -0.515422 + 1.92358 0.0245 -0.515422 + 1.92358 0.0245 -0.515422 + 1.92358 0.0245 -0.515422 + 1.92358 0.0245 -0.515422 + 1.98091 0 -0.260793 + 1.98091 0 -0.260793 + 1.98091 0 -0.260793 + 1.98091 0 -0.260793 + 1.98091 0 -0.260793 + 1.98091 0 -0.260793 + 1.9744 -0.0245 -0.259936 + 1.9744 -0.0245 -0.259936 + 1.9744 -0.0245 -0.259936 + 1.9744 -0.0245 -0.259936 + 1.9744 -0.0245 -0.259936 + 1.9744 -0.0245 -0.259936 + 1.95662 -0.0424352 -0.257595 + 1.95662 -0.0424352 -0.257595 + 1.95662 -0.0424352 -0.257595 + 1.95662 -0.0424352 -0.257595 + 1.95662 -0.0424352 -0.257595 + 1.95662 -0.0424352 -0.257595 + 1.93233 -0.049 -0.254397 + 1.93233 -0.049 -0.254397 + 1.93233 -0.049 -0.254397 + 1.93233 -0.049 -0.254397 + 1.93233 -0.049 -0.254397 + 1.93233 -0.049 -0.254397 + 1.90804 -0.0424352 -0.251199 + 1.90804 -0.0424352 -0.251199 + 1.90804 -0.0424352 -0.251199 + 1.90804 -0.0424352 -0.251199 + 1.90804 -0.0424352 -0.251199 + 1.89025 -0.0245 -0.248858 + 1.89025 -0.0245 -0.248858 + 1.89025 -0.0245 -0.248858 + 1.89025 -0.0245 -0.248858 + 1.89025 -0.0245 -0.248858 + 1.89025 -0.0245 -0.248858 + 1.89025 -0.0245 -0.248858 + 1.88374 0 -0.248001 + 1.88374 0 -0.248001 + 1.88374 0 -0.248001 + 1.88374 0 -0.248001 + 1.88374 0 -0.248001 + 1.88374 0 -0.248001 + 1.89025 0.0245 -0.248858 + 1.89025 0.0245 -0.248858 + 1.89025 0.0245 -0.248858 + 1.89025 0.0245 -0.248858 + 1.89025 0.0245 -0.248858 + 1.89025 0.0245 -0.248858 + 1.90804 0.0424352 -0.251199 + 1.90804 0.0424352 -0.251199 + 1.90804 0.0424352 -0.251199 + 1.90804 0.0424352 -0.251199 + 1.90804 0.0424352 -0.251199 + 1.93233 0.049 -0.254397 + 1.93233 0.049 -0.254397 + 1.93233 0.049 -0.254397 + 1.93233 0.049 -0.254397 + 1.93233 0.049 -0.254397 + 1.93233 0.049 -0.254397 + 1.95662 0.0424352 -0.257595 + 1.95662 0.0424352 -0.257595 + 1.95662 0.0424352 -0.257595 + 1.95662 0.0424352 -0.257595 + 1.95662 0.0424352 -0.257595 + 1.95662 0.0424352 -0.257595 + 1.95662 0.0424352 -0.257595 + 1.9744 0.0245 -0.259936 + 1.9744 0.0245 -0.259936 + 1.9744 0.0245 -0.259936 + 1.9744 0.0245 -0.259936 + 1.9744 0.0245 -0.259936 + 1.9744 0.0245 -0.259936 + 1.998 0 0 + 1.998 0 0 + 1.998 0 0 + 1.998 0 0 + 1.998 0 0 + 1.998 0 0 + 1.99144 -0.0245 0 + 1.99144 -0.0245 0 + 1.99144 -0.0245 0 + 1.99144 -0.0245 0 + 1.99144 -0.0245 0 + 1.99144 -0.0245 0 + 1.9735 -0.0424352 0 + 1.9735 -0.0424352 0 + 1.9735 -0.0424352 0 + 1.9735 -0.0424352 0 + 1.9735 -0.0424352 0 + 1.9735 -0.0424352 0 + 1.949 -0.049 0 + 1.949 -0.049 0 + 1.949 -0.049 0 + 1.949 -0.049 0 + 1.949 -0.049 0 + 1.949 -0.049 0 + 1.9245 -0.0424352 0 + 1.9245 -0.0424352 0 + 1.9245 -0.0424352 0 + 1.9245 -0.0424352 0 + 1.9245 -0.0424352 0 + 1.9245 -0.0424352 0 + 1.90656 -0.0245 0 + 1.90656 -0.0245 0 + 1.90656 -0.0245 0 + 1.90656 -0.0245 0 + 1.90656 -0.0245 0 + 1.90656 -0.0245 0 + 1.90656 -0.0245 0 + 1.9 0 0 + 1.9 0 0 + 1.9 0 0 + 1.9 0 0 + 1.90656 0.0245 0 + 1.90656 0.0245 0 + 1.90656 0.0245 0 + 1.90656 0.0245 0 + 1.90656 0.0245 0 + 1.90656 0.0245 0 + 1.90656 0.0245 0 + 1.90656 0.0245 0 + 1.9245 0.0424352 0 + 1.9245 0.0424352 0 + 1.9245 0.0424352 0 + 1.9245 0.0424352 0 + 1.9245 0.0424352 0 + 1.949 0.049 0 + 1.949 0.049 0 + 1.949 0.049 0 + 1.949 0.049 0 + 1.949 0.049 0 + 1.949 0.049 0 + 1.9735 0.0424352 0 + 1.9735 0.0424352 0 + 1.9735 0.0424352 0 + 1.9735 0.0424352 0 + 1.9735 0.0424352 0 + 1.9735 0.0424352 0 + 1.99144 0.0245 0 + 1.99144 0.0245 0 + 1.99144 0.0245 0 + 1.99144 0.0245 0 + 1.99144 0.0245 0 + 1.99144 0.0245 0 + 1.98091 0 0.260791 + 1.98091 0 0.260791 + 1.98091 0 0.260791 + 1.98091 0 0.260791 + 1.98091 0 0.260791 + 1.98091 0 0.260791 + 1.9744 -0.0245 0.259934 + 1.9744 -0.0245 0.259934 + 1.9744 -0.0245 0.259934 + 1.9744 -0.0245 0.259934 + 1.9744 -0.0245 0.259934 + 1.9744 -0.0245 0.259934 + 1.95662 -0.0424352 0.257593 + 1.95662 -0.0424352 0.257593 + 1.95662 -0.0424352 0.257593 + 1.95662 -0.0424352 0.257593 + 1.95662 -0.0424352 0.257593 + 1.95662 -0.0424352 0.257593 + 1.95662 -0.0424352 0.257593 + 1.93233 -0.049 0.254395 + 1.93233 -0.049 0.254395 + 1.93233 -0.049 0.254395 + 1.93233 -0.049 0.254395 + 1.93233 -0.049 0.254395 + 1.90804 -0.0424352 0.251197 + 1.90804 -0.0424352 0.251197 + 1.90804 -0.0424352 0.251197 + 1.90804 -0.0424352 0.251197 + 1.90804 -0.0424352 0.251197 + 1.90804 -0.0424352 0.251197 + 1.89025 -0.0245 0.248856 + 1.89025 -0.0245 0.248856 + 1.89025 -0.0245 0.248856 + 1.89025 -0.0245 0.248856 + 1.89025 -0.0245 0.248856 + 1.88374 0 0.247999 + 1.88374 0 0.247999 + 1.88374 0 0.247999 + 1.88374 0 0.247999 + 1.88374 0 0.247999 + 1.88374 0 0.247999 + 1.88374 0 0.247999 + 1.88374 0 0.247999 + 1.89025 0.0245 0.248856 + 1.89025 0.0245 0.248856 + 1.89025 0.0245 0.248856 + 1.89025 0.0245 0.248856 + 1.89025 0.0245 0.248856 + 1.90804 0.0424352 0.251197 + 1.90804 0.0424352 0.251197 + 1.90804 0.0424352 0.251197 + 1.90804 0.0424352 0.251197 + 1.90804 0.0424352 0.251197 + 1.90804 0.0424352 0.251197 + 1.90804 0.0424352 0.251197 + 1.93233 0.049 0.254395 + 1.93233 0.049 0.254395 + 1.93233 0.049 0.254395 + 1.93233 0.049 0.254395 + 1.93233 0.049 0.254395 + 1.95662 0.0424352 0.257593 + 1.95662 0.0424352 0.257593 + 1.95662 0.0424352 0.257593 + 1.95662 0.0424352 0.257593 + 1.95662 0.0424352 0.257593 + 1.95662 0.0424352 0.257593 + 1.9744 0.0245 0.259934 + 1.9744 0.0245 0.259934 + 1.9744 0.0245 0.259934 + 1.9744 0.0245 0.259934 + 1.9744 0.0245 0.259934 + 1.9744 0.0245 0.259934 + 1.92992 0 0.517119 + 1.92992 0 0.517119 + 1.92992 0 0.517119 + 1.92992 0 0.517119 + 1.92992 0 0.517119 + 1.92992 0 0.517119 + 1.92358 -0.0245 0.51542 + 1.92358 -0.0245 0.51542 + 1.92358 -0.0245 0.51542 + 1.92358 -0.0245 0.51542 + 1.92358 -0.0245 0.51542 + 1.92358 -0.0245 0.51542 + 1.90625 -0.0424352 0.510778 + 1.90625 -0.0424352 0.510778 + 1.90625 -0.0424352 0.510778 + 1.90625 -0.0424352 0.510778 + 1.90625 -0.0424352 0.510778 + 1.88259 -0.049 0.504437 + 1.88259 -0.049 0.504437 + 1.88259 -0.049 0.504437 + 1.88259 -0.049 0.504437 + 1.88259 -0.049 0.504437 + 1.88259 -0.049 0.504437 + 1.88259 -0.049 0.504437 + 1.88259 -0.049 0.504437 + 1.85892 -0.0424352 0.498096 + 1.85892 -0.0424352 0.498096 + 1.85892 -0.0424352 0.498096 + 1.85892 -0.0424352 0.498096 + 1.85892 -0.0424352 0.498096 + 1.85892 -0.0424352 0.498096 + 1.8416 -0.0245 0.493454 + 1.8416 -0.0245 0.493454 + 1.8416 -0.0245 0.493454 + 1.8416 -0.0245 0.493454 + 1.8416 -0.0245 0.493454 + 1.83526 0 0.491755 + 1.83526 0 0.491755 + 1.83526 0 0.491755 + 1.83526 0 0.491755 + 1.83526 0 0.491755 + 1.8416 0.0245 0.493454 + 1.8416 0.0245 0.493454 + 1.8416 0.0245 0.493454 + 1.8416 0.0245 0.493454 + 1.8416 0.0245 0.493454 + 1.8416 0.0245 0.493454 + 1.85892 0.0424352 0.498096 + 1.85892 0.0424352 0.498096 + 1.85892 0.0424352 0.498096 + 1.85892 0.0424352 0.498096 + 1.85892 0.0424352 0.498096 + 1.85892 0.0424352 0.498096 + 1.88259 0.049 0.504437 + 1.88259 0.049 0.504437 + 1.88259 0.049 0.504437 + 1.88259 0.049 0.504437 + 1.88259 0.049 0.504437 + 1.88259 0.049 0.504437 + 1.88259 0.049 0.504437 + 1.88259 0.049 0.504437 + 1.90625 0.0424352 0.510778 + 1.90625 0.0424352 0.510778 + 1.90625 0.0424352 0.510778 + 1.90625 0.0424352 0.510778 + 1.92358 0.0245 0.51542 + 1.92358 0.0245 0.51542 + 1.92358 0.0245 0.51542 + 1.92358 0.0245 0.51542 + 1.92358 0.0245 0.51542 + 1.92358 0.0245 0.51542 + 1.92358 0.0245 0.51542 + 1.84591 0 0.764602 + 1.84591 0 0.764602 + 1.84591 0 0.764602 + 1.84591 0 0.764602 + 1.83985 -0.0245 0.762089 + 1.83985 -0.0245 0.762089 + 1.83985 -0.0245 0.762089 + 1.83985 -0.0245 0.762089 + 1.83985 -0.0245 0.762089 + 1.83985 -0.0245 0.762089 + 1.83985 -0.0245 0.762089 + 1.83985 -0.0245 0.762089 + 1.82328 -0.0424353 0.755226 + 1.82328 -0.0424353 0.755226 + 1.82328 -0.0424353 0.755226 + 1.82328 -0.0424353 0.755226 + 1.82328 -0.0424353 0.755226 + 1.80064 -0.049 0.74585 + 1.80064 -0.049 0.74585 + 1.80064 -0.049 0.74585 + 1.80064 -0.049 0.74585 + 1.80064 -0.049 0.74585 + 1.77801 -0.0424353 0.736475 + 1.77801 -0.0424353 0.736475 + 1.77801 -0.0424353 0.736475 + 1.77801 -0.0424353 0.736475 + 1.77801 -0.0424353 0.736475 + 1.77801 -0.0424353 0.736475 + 1.77801 -0.0424353 0.736475 + 1.76144 -0.0245 0.729611 + 1.76144 -0.0245 0.729611 + 1.76144 -0.0245 0.729611 + 1.76144 -0.0245 0.729611 + 1.76144 -0.0245 0.729611 + 1.76144 -0.0245 0.729611 + 1.76144 -0.0245 0.729611 + 1.75537 0 0.727099 + 1.75537 0 0.727099 + 1.75537 0 0.727099 + 1.75537 0 0.727099 + 1.75537 0 0.727099 + 1.76144 0.0245 0.729611 + 1.76144 0.0245 0.729611 + 1.76144 0.0245 0.729611 + 1.76144 0.0245 0.729611 + 1.76144 0.0245 0.729611 + 1.76144 0.0245 0.729611 + 1.77801 0.0424352 0.736475 + 1.77801 0.0424352 0.736475 + 1.77801 0.0424352 0.736475 + 1.77801 0.0424352 0.736475 + 1.77801 0.0424352 0.736475 + 1.77801 0.0424352 0.736475 + 1.77801 0.0424352 0.736475 + 1.80064 0.0489999 0.74585 + 1.80064 0.0489999 0.74585 + 1.80064 0.0489999 0.74585 + 1.80064 0.0489999 0.74585 + 1.80064 0.0489999 0.74585 + 1.82328 0.0424352 0.755226 + 1.82328 0.0424352 0.755226 + 1.82328 0.0424352 0.755226 + 1.82328 0.0424352 0.755226 + 1.82328 0.0424352 0.755226 + 1.82328 0.0424352 0.755226 + 1.83985 0.0245 0.762089 + 1.83985 0.0245 0.762089 + 1.83985 0.0245 0.762089 + 1.83985 0.0245 0.762089 + 1.83985 0.0245 0.762089 + 1.83985 0.0245 0.762089 + 1.83985 0.0245 0.762089 + 1.73032 0 0.998999 + 1.73032 0 0.998999 + 1.73032 0 0.998999 + 1.73032 0 0.998999 + 1.73032 0 0.998999 + 1.73032 0 0.998999 + 1.72463 -0.0245 0.995717 + 1.72463 -0.0245 0.995717 + 1.72463 -0.0245 0.995717 + 1.72463 -0.0245 0.995717 + 1.72463 -0.0245 0.995717 + 1.7091 -0.0424353 0.986749 + 1.7091 -0.0424353 0.986749 + 1.7091 -0.0424353 0.986749 + 1.7091 -0.0424353 0.986749 + 1.7091 -0.0424353 0.986749 + 1.7091 -0.0424353 0.986749 + 1.7091 -0.0424353 0.986749 + 1.7091 -0.0424353 0.986749 + 1.68788 -0.049 0.9745 + 1.68788 -0.049 0.9745 + 1.68788 -0.049 0.9745 + 1.68788 -0.049 0.9745 + 1.68788 -0.049 0.9745 + 1.66667 -0.0424353 0.96225 + 1.66667 -0.0424353 0.96225 + 1.66667 -0.0424353 0.96225 + 1.66667 -0.0424353 0.96225 + 1.66667 -0.0424353 0.96225 + 1.66667 -0.0424353 0.96225 + 1.65113 -0.0245 0.953282 + 1.65113 -0.0245 0.953282 + 1.65113 -0.0245 0.953282 + 1.65113 -0.0245 0.953282 + 1.65113 -0.0245 0.953282 + 1.65113 -0.0245 0.953282 + 1.64545 0 0.95 + 1.64545 0 0.95 + 1.64545 0 0.95 + 1.64545 0 0.95 + 1.64545 0 0.95 + 1.64545 0 0.95 + 1.64545 0 0.95 + 1.65113 0.0245 0.953282 + 1.65113 0.0245 0.953282 + 1.65113 0.0245 0.953282 + 1.65113 0.0245 0.953282 + 1.65113 0.0245 0.953282 + 1.66667 0.0424352 0.96225 + 1.66667 0.0424352 0.96225 + 1.66667 0.0424352 0.96225 + 1.66667 0.0424352 0.96225 + 1.66667 0.0424352 0.96225 + 1.66667 0.0424352 0.96225 + 1.68788 0.0489999 0.9745 + 1.68788 0.0489999 0.9745 + 1.68788 0.0489999 0.9745 + 1.68788 0.0489999 0.9745 + 1.68788 0.0489999 0.9745 + 1.7091 0.0424352 0.986749 + 1.7091 0.0424352 0.986749 + 1.7091 0.0424352 0.986749 + 1.7091 0.0424352 0.986749 + 1.7091 0.0424352 0.986749 + 1.7091 0.0424352 0.986749 + 1.7091 0.0424352 0.986749 + 1.7091 0.0424352 0.986749 + 1.72463 0.0244999 0.995717 + 1.72463 0.0244999 0.995717 + 1.72463 0.0244999 0.995717 + 1.72463 0.0244999 0.995717 + 1.72463 0.0244999 0.995717 + 1.58512 0 1.2163 + 1.58512 0 1.2163 + 1.58512 0 1.2163 + 1.58512 0 1.2163 + 1.58512 0 1.2163 + 1.58512 0 1.2163 + 1.57991 -0.0245 1.21231 + 1.57991 -0.0245 1.21231 + 1.57991 -0.0245 1.21231 + 1.57991 -0.0245 1.21231 + 1.57991 -0.0245 1.21231 + 1.57991 -0.0245 1.21231 + 1.57991 -0.0245 1.21231 + 1.56568 -0.0424353 1.20139 + 1.56568 -0.0424353 1.20139 + 1.56568 -0.0424353 1.20139 + 1.56568 -0.0424353 1.20139 + 1.56568 -0.0424353 1.20139 + 1.54625 -0.049 1.18648 + 1.54625 -0.049 1.18648 + 1.54625 -0.049 1.18648 + 1.54625 -0.049 1.18648 + 1.54625 -0.049 1.18648 + 1.54625 -0.049 1.18648 + 1.52681 -0.0424353 1.17156 + 1.52681 -0.0424353 1.17156 + 1.52681 -0.0424353 1.17156 + 1.52681 -0.0424353 1.17156 + 1.52681 -0.0424353 1.17156 + 1.52681 -0.0424353 1.17156 + 1.51258 -0.0245 1.16064 + 1.51258 -0.0245 1.16064 + 1.51258 -0.0245 1.16064 + 1.51258 -0.0245 1.16064 + 1.51258 -0.0245 1.16064 + 1.51258 -0.0245 1.16064 + 1.50737 0 1.15665 + 1.50737 0 1.15665 + 1.50737 0 1.15665 + 1.50737 0 1.15665 + 1.50737 0 1.15665 + 1.51258 0.0244999 1.16064 + 1.51258 0.0244999 1.16064 + 1.51258 0.0244999 1.16064 + 1.51258 0.0244999 1.16064 + 1.51258 0.0244999 1.16064 + 1.51258 0.0244999 1.16064 + 1.51258 0.0244999 1.16064 + 1.52681 0.0424352 1.17156 + 1.52681 0.0424352 1.17156 + 1.52681 0.0424352 1.17156 + 1.52681 0.0424352 1.17156 + 1.52681 0.0424352 1.17156 + 1.52681 0.0424352 1.17156 + 1.54625 0.0489999 1.18648 + 1.54625 0.0489999 1.18648 + 1.54625 0.0489999 1.18648 + 1.54625 0.0489999 1.18648 + 1.54625 0.0489999 1.18648 + 1.54625 0.0489999 1.18648 + 1.56568 0.0424352 1.20139 + 1.56568 0.0424352 1.20139 + 1.56568 0.0424352 1.20139 + 1.56568 0.0424352 1.20139 + 1.56568 0.0424352 1.20139 + 1.57991 0.0244999 1.21231 + 1.57991 0.0244999 1.21231 + 1.57991 0.0244999 1.21231 + 1.57991 0.0244999 1.21231 + 1.57991 0.0244999 1.21231 + 1.57991 0.0244999 1.21231 + 1.57991 0.0244999 1.21231 + 1.4128 0 1.4128 + 1.4128 0 1.4128 + 1.4128 0 1.4128 + 1.4128 0 1.4128 + 1.4128 0 1.4128 + 1.4128 0 1.4128 + 1.40816 -0.0245 1.40816 + 1.40816 -0.0245 1.40816 + 1.40816 -0.0245 1.40816 + 1.40816 -0.0245 1.40816 + 1.40816 -0.0245 1.40816 + 1.40816 -0.0245 1.40816 + 1.39548 -0.0424353 1.39547 + 1.39548 -0.0424353 1.39547 + 1.39548 -0.0424353 1.39547 + 1.39548 -0.0424353 1.39547 + 1.39548 -0.0424353 1.39547 + 1.37815 -0.049 1.37815 + 1.37815 -0.049 1.37815 + 1.37815 -0.049 1.37815 + 1.37815 -0.049 1.37815 + 1.37815 -0.049 1.37815 + 1.37815 -0.049 1.37815 + 1.37815 -0.049 1.37815 + 1.36083 -0.0424353 1.36083 + 1.36083 -0.0424353 1.36083 + 1.36083 -0.0424353 1.36083 + 1.36083 -0.0424353 1.36083 + 1.36083 -0.0424353 1.36083 + 1.34815 -0.0245 1.34814 + 1.34815 -0.0245 1.34814 + 1.34815 -0.0245 1.34814 + 1.34815 -0.0245 1.34814 + 1.34815 -0.0245 1.34814 + 1.34815 -0.0245 1.34814 + 1.34815 -0.0245 1.34814 + 1.3435 0 1.3435 + 1.3435 0 1.3435 + 1.3435 0 1.3435 + 1.3435 0 1.3435 + 1.3435 0 1.3435 + 1.3435 0 1.3435 + 1.34815 0.0244999 1.34814 + 1.34815 0.0244999 1.34814 + 1.34815 0.0244999 1.34814 + 1.34815 0.0244999 1.34814 + 1.34815 0.0244999 1.34814 + 1.34815 0.0244999 1.34814 + 1.34815 0.0244999 1.34814 + 1.36083 0.0424352 1.36083 + 1.36083 0.0424352 1.36083 + 1.36083 0.0424352 1.36083 + 1.36083 0.0424352 1.36083 + 1.36083 0.0424352 1.36083 + 1.37815 0.0489999 1.37815 + 1.37815 0.0489999 1.37815 + 1.37815 0.0489999 1.37815 + 1.37815 0.0489999 1.37815 + 1.37815 0.0489999 1.37815 + 1.37815 0.0489999 1.37815 + 1.37815 0.0489999 1.37815 + 1.39548 0.0424352 1.39547 + 1.39548 0.0424352 1.39547 + 1.39548 0.0424352 1.39547 + 1.39548 0.0424352 1.39547 + 1.39548 0.0424352 1.39547 + 1.40816 0.0244999 1.40816 + 1.40816 0.0244999 1.40816 + 1.40816 0.0244999 1.40816 + 1.40816 0.0244999 1.40816 + 1.40816 0.0244999 1.40816 + 1.40816 0.0244999 1.40816 + 1.21631 0 1.58512 + 1.21631 0 1.58512 + 1.21631 0 1.58512 + 1.21631 0 1.58512 + 1.21631 0 1.58512 + 1.21631 0 1.58512 + 1.21231 -0.0245 1.57991 + 1.21231 -0.0245 1.57991 + 1.21231 -0.0245 1.57991 + 1.21231 -0.0245 1.57991 + 1.21231 -0.0245 1.57991 + 1.21231 -0.0245 1.57991 + 1.20139 -0.0424353 1.56568 + 1.20139 -0.0424353 1.56568 + 1.20139 -0.0424353 1.56568 + 1.20139 -0.0424353 1.56568 + 1.20139 -0.0424353 1.56568 + 1.20139 -0.0424353 1.56568 + 1.18648 -0.049 1.54625 + 1.18648 -0.049 1.54625 + 1.18648 -0.049 1.54625 + 1.18648 -0.049 1.54625 + 1.18648 -0.049 1.54625 + 1.18648 -0.049 1.54625 + 1.18648 -0.049 1.54625 + 1.17156 -0.0424353 1.52681 + 1.17156 -0.0424353 1.52681 + 1.17156 -0.0424353 1.52681 + 1.17156 -0.0424353 1.52681 + 1.17156 -0.0424353 1.52681 + 1.16064 -0.0245 1.51258 + 1.16064 -0.0245 1.51258 + 1.16064 -0.0245 1.51258 + 1.16064 -0.0245 1.51258 + 1.16064 -0.0245 1.51258 + 1.15665 0 1.50737 + 1.15665 0 1.50737 + 1.15665 0 1.50737 + 1.15665 0 1.50737 + 1.15665 0 1.50737 + 1.15665 0 1.50737 + 1.15665 0 1.50737 + 1.15665 0 1.50737 + 1.16064 0.0244999 1.51258 + 1.16064 0.0244999 1.51258 + 1.16064 0.0244999 1.51258 + 1.16064 0.0244999 1.51258 + 1.16064 0.0244999 1.51258 + 1.17156 0.0424352 1.52681 + 1.17156 0.0424352 1.52681 + 1.17156 0.0424352 1.52681 + 1.17156 0.0424352 1.52681 + 1.17156 0.0424352 1.52681 + 1.18648 0.0489999 1.54625 + 1.18648 0.0489999 1.54625 + 1.18648 0.0489999 1.54625 + 1.18648 0.0489999 1.54625 + 1.18648 0.0489999 1.54625 + 1.18648 0.0489999 1.54625 + 1.18648 0.0489999 1.54625 + 1.20139 0.0424352 1.56568 + 1.20139 0.0424352 1.56568 + 1.20139 0.0424352 1.56568 + 1.20139 0.0424352 1.56568 + 1.20139 0.0424352 1.56568 + 1.20139 0.0424352 1.56568 + 1.21231 0.0244999 1.57991 + 1.21231 0.0244999 1.57991 + 1.21231 0.0244999 1.57991 + 1.21231 0.0244999 1.57991 + 1.21231 0.0244999 1.57991 + 1.21231 0.0244999 1.57991 + 0.999 0 1.73032 + 0.999 0 1.73032 + 0.999 0 1.73032 + 0.999 0 1.73032 + 0.999 0 1.73032 + 0.999 0 1.73032 + 0.995718 -0.0245 1.72463 + 0.995718 -0.0245 1.72463 + 0.995718 -0.0245 1.72463 + 0.995718 -0.0245 1.72463 + 0.995718 -0.0245 1.72463 + 0.995718 -0.0245 1.72463 + 0.98675 -0.0424353 1.7091 + 0.98675 -0.0424353 1.7091 + 0.98675 -0.0424353 1.7091 + 0.98675 -0.0424353 1.7091 + 0.98675 -0.0424353 1.7091 + 0.98675 -0.0424353 1.7091 + 0.9745 -0.049 1.68788 + 0.9745 -0.049 1.68788 + 0.9745 -0.049 1.68788 + 0.9745 -0.049 1.68788 + 0.9745 -0.049 1.68788 + 0.9745 -0.049 1.68788 + 0.96225 -0.0424353 1.66666 + 0.96225 -0.0424353 1.66666 + 0.96225 -0.0424353 1.66666 + 0.96225 -0.0424353 1.66666 + 0.96225 -0.0424353 1.66666 + 0.96225 -0.0424353 1.66666 + 0.96225 -0.0424353 1.66666 + 0.953282 -0.0245 1.65113 + 0.953282 -0.0245 1.65113 + 0.953282 -0.0245 1.65113 + 0.953282 -0.0245 1.65113 + 0.953282 -0.0245 1.65113 + 0.95 0 1.64545 + 0.95 0 1.64545 + 0.95 0 1.64545 + 0.95 0 1.64545 + 0.95 0 1.64545 + 0.953282 0.0244999 1.65113 + 0.953282 0.0244999 1.65113 + 0.953282 0.0244999 1.65113 + 0.953282 0.0244999 1.65113 + 0.953282 0.0244999 1.65113 + 0.953282 0.0244999 1.65113 + 0.96225 0.0424352 1.66666 + 0.96225 0.0424352 1.66666 + 0.96225 0.0424352 1.66666 + 0.96225 0.0424352 1.66666 + 0.96225 0.0424352 1.66666 + 0.96225 0.0424352 1.66666 + 0.96225 0.0424352 1.66666 + 0.9745 0.0489999 1.68788 + 0.9745 0.0489999 1.68788 + 0.9745 0.0489999 1.68788 + 0.9745 0.0489999 1.68788 + 0.9745 0.0489999 1.68788 + 0.9745 0.0489999 1.68788 + 0.98675 0.0424352 1.7091 + 0.98675 0.0424352 1.7091 + 0.98675 0.0424352 1.7091 + 0.98675 0.0424352 1.7091 + 0.98675 0.0424352 1.7091 + 0.98675 0.0424352 1.7091 + 0.995718 0.0244999 1.72463 + 0.995718 0.0244999 1.72463 + 0.995718 0.0244999 1.72463 + 0.995718 0.0244999 1.72463 + 0.995718 0.0244999 1.72463 + 0.995718 0.0244999 1.72463 + 0.764602 0 1.84591 + 0.764602 0 1.84591 + 0.764602 0 1.84591 + 0.764602 0 1.84591 + 0.764602 0 1.84591 + 0.764602 0 1.84591 + 0.76209 -0.0245 1.83985 + 0.76209 -0.0245 1.83985 + 0.76209 -0.0245 1.83985 + 0.76209 -0.0245 1.83985 + 0.76209 -0.0245 1.83985 + 0.755226 -0.0424353 1.82328 + 0.755226 -0.0424353 1.82328 + 0.755226 -0.0424353 1.82328 + 0.755226 -0.0424353 1.82328 + 0.755226 -0.0424353 1.82328 + 0.755226 -0.0424353 1.82328 + 0.755226 -0.0424353 1.82328 + 0.745851 -0.049 1.80064 + 0.745851 -0.049 1.80064 + 0.745851 -0.049 1.80064 + 0.745851 -0.049 1.80064 + 0.745851 -0.049 1.80064 + 0.745851 -0.049 1.80064 + 0.736475 -0.0424353 1.77801 + 0.736475 -0.0424353 1.77801 + 0.736475 -0.0424353 1.77801 + 0.736475 -0.0424353 1.77801 + 0.736475 -0.0424353 1.77801 + 0.736475 -0.0424353 1.77801 + 0.729611 -0.0245 1.76144 + 0.729611 -0.0245 1.76144 + 0.729611 -0.0245 1.76144 + 0.729611 -0.0245 1.76144 + 0.729611 -0.0245 1.76144 + 0.729611 -0.0245 1.76144 + 0.729611 -0.0245 1.76144 + 0.727099 0 1.75537 + 0.727099 0 1.75537 + 0.727099 0 1.75537 + 0.727099 0 1.75537 + 0.727099 0 1.75537 + 0.729611 0.0244999 1.76144 + 0.729611 0.0244999 1.76144 + 0.729611 0.0244999 1.76144 + 0.729611 0.0244999 1.76144 + 0.729611 0.0244999 1.76144 + 0.729611 0.0244999 1.76144 + 0.736475 0.0424352 1.77801 + 0.736475 0.0424352 1.77801 + 0.736475 0.0424352 1.77801 + 0.736475 0.0424352 1.77801 + 0.736475 0.0424352 1.77801 + 0.736475 0.0424352 1.77801 + 0.745851 0.0489999 1.80064 + 0.745851 0.0489999 1.80064 + 0.745851 0.0489999 1.80064 + 0.745851 0.0489999 1.80064 + 0.745851 0.0489999 1.80064 + 0.745851 0.0489999 1.80064 + 0.755226 0.0424352 1.82328 + 0.755226 0.0424352 1.82328 + 0.755226 0.0424352 1.82328 + 0.755226 0.0424352 1.82328 + 0.755226 0.0424352 1.82328 + 0.755226 0.0424352 1.82328 + 0.76209 0.0244999 1.83985 + 0.76209 0.0244999 1.83985 + 0.76209 0.0244999 1.83985 + 0.76209 0.0244999 1.83985 + 0.76209 0.0244999 1.83985 + 0.76209 0.0244999 1.83985 + 0.51712 0 1.92992 + 0.51712 0 1.92992 + 0.51712 0 1.92992 + 0.51712 0 1.92992 + 0.51712 0 1.92992 + 0.51712 0 1.92992 + 0.515421 -0.0245 1.92358 + 0.515421 -0.0245 1.92358 + 0.515421 -0.0245 1.92358 + 0.515421 -0.0245 1.92358 + 0.515421 -0.0245 1.92358 + 0.515421 -0.0245 1.92358 + 0.515421 -0.0245 1.92358 + 0.510779 -0.0424353 1.90625 + 0.510779 -0.0424353 1.90625 + 0.510779 -0.0424353 1.90625 + 0.510779 -0.0424353 1.90625 + 0.510779 -0.0424353 1.90625 + 0.504438 -0.049 1.88259 + 0.504438 -0.049 1.88259 + 0.504438 -0.049 1.88259 + 0.504438 -0.049 1.88259 + 0.504438 -0.049 1.88259 + 0.504438 -0.049 1.88259 + 0.498097 -0.0424353 1.85892 + 0.498097 -0.0424353 1.85892 + 0.498097 -0.0424353 1.85892 + 0.498097 -0.0424353 1.85892 + 0.498097 -0.0424353 1.85892 + 0.498097 -0.0424353 1.85892 + 0.493455 -0.0245 1.8416 + 0.493455 -0.0245 1.8416 + 0.493455 -0.0245 1.8416 + 0.493455 -0.0245 1.8416 + 0.493455 -0.0245 1.8416 + 0.493455 -0.0245 1.8416 + 0.491756 0 1.83526 + 0.491756 0 1.83526 + 0.491756 0 1.83526 + 0.491756 0 1.83526 + 0.491756 0 1.83526 + 0.491756 0 1.83526 + 0.493455 0.0244999 1.8416 + 0.493455 0.0244999 1.8416 + 0.493455 0.0244999 1.8416 + 0.493455 0.0244999 1.8416 + 0.493455 0.0244999 1.8416 + 0.493455 0.0244999 1.8416 + 0.498097 0.0424352 1.85892 + 0.498097 0.0424352 1.85892 + 0.498097 0.0424352 1.85892 + 0.498097 0.0424352 1.85892 + 0.498097 0.0424352 1.85892 + 0.498097 0.0424352 1.85892 + 0.504438 0.0489999 1.88259 + 0.504438 0.0489999 1.88259 + 0.504438 0.0489999 1.88259 + 0.504438 0.0489999 1.88259 + 0.504438 0.0489999 1.88259 + 0.504438 0.0489999 1.88259 + 0.510779 0.0424352 1.90625 + 0.510779 0.0424352 1.90625 + 0.510779 0.0424352 1.90625 + 0.510779 0.0424352 1.90625 + 0.510779 0.0424352 1.90625 + 0.510779 0.0424352 1.90625 + 0.515421 0.0244999 1.92358 + 0.515421 0.0244999 1.92358 + 0.515421 0.0244999 1.92358 + 0.515421 0.0244999 1.92358 + 0.515421 0.0244999 1.92358 + 0.515421 0.0244999 1.92358 + 0.260791 0 1.98091 + 0.260791 0 1.98091 + 0.260791 0 1.98091 + 0.260791 0 1.98091 + 0.260791 0 1.98091 + 0.260791 0 1.98091 + 0.260791 0 1.98091 + 0.259935 -0.0245 1.9744 + 0.259935 -0.0245 1.9744 + 0.259935 -0.0245 1.9744 + 0.259935 -0.0245 1.9744 + 0.259935 -0.0245 1.9744 + 0.259935 -0.0245 1.9744 + 0.257594 -0.0424354 1.95662 + 0.257594 -0.0424354 1.95662 + 0.257594 -0.0424354 1.95662 + 0.257594 -0.0424354 1.95662 + 0.257594 -0.0424354 1.95662 + 0.257594 -0.0424354 1.95662 + 0.254396 -0.049 1.93233 + 0.254396 -0.049 1.93233 + 0.254396 -0.049 1.93233 + 0.254396 -0.049 1.93233 + 0.254396 -0.049 1.93233 + 0.254396 -0.049 1.93233 + 0.251198 -0.0424353 1.90804 + 0.251198 -0.0424353 1.90804 + 0.251198 -0.0424353 1.90804 + 0.251198 -0.0424353 1.90804 + 0.251198 -0.0424353 1.90804 + 0.248857 -0.0245001 1.89025 + 0.248857 -0.0245001 1.89025 + 0.248857 -0.0245001 1.89025 + 0.248857 -0.0245001 1.89025 + 0.248857 -0.0245001 1.89025 + 0.248857 -0.0245001 1.89025 + 0.248 0 1.88374 + 0.248 0 1.88374 + 0.248 0 1.88374 + 0.248 0 1.88374 + 0.248 0 1.88374 + 0.248 0 1.88374 + 0.248 0 1.88374 + 0.248 0 1.88374 + 0.248857 0.0244999 1.89025 + 0.248857 0.0244999 1.89025 + 0.248857 0.0244999 1.89025 + 0.248857 0.0244999 1.89025 + 0.248857 0.0244999 1.89025 + 0.248857 0.0244999 1.89025 + 0.251198 0.0424352 1.90804 + 0.251198 0.0424352 1.90804 + 0.251198 0.0424352 1.90804 + 0.251198 0.0424352 1.90804 + 0.251198 0.0424352 1.90804 + 0.254396 0.0489999 1.93233 + 0.254396 0.0489999 1.93233 + 0.254396 0.0489999 1.93233 + 0.254396 0.0489999 1.93233 + 0.254396 0.0489999 1.93233 + 0.254396 0.0489999 1.93233 + 0.257594 0.0424352 1.95662 + 0.257594 0.0424352 1.95662 + 0.257594 0.0424352 1.95662 + 0.257594 0.0424352 1.95662 + 0.257594 0.0424352 1.95662 + 0.257594 0.0424352 1.95662 + 0.259935 0.0245 1.9744 + 0.259935 0.0245 1.9744 + 0.259935 0.0245 1.9744 + 0.259935 0.0245 1.9744 + 0.259935 0.0245 1.9744 + } + } + } + NormalArray TRUE { + osg::Vec3Array { + UniqueID 200 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 199 + } + } + Binding BIND_PER_VERTEX + vector 3456 { + 0 1.28825e-06 1 + 0 1.28825e-06 1 + 0 1.28825e-06 1 + 0 1.28825e-06 1 + 0 1.28825e-06 1 + 0 1.28825e-06 1 + 0 1.28825e-06 1 + 0 -0.495388 0.868672 + 0 -0.495388 0.868672 + 0 -0.495388 0.868672 + 0 -0.495388 0.868672 + 0 -0.495388 0.868672 + 0 -0.861356 0.508002 + 0 -0.861356 0.508002 + 0 -0.861356 0.508002 + 0 -0.861356 0.508002 + 0 -0.861356 0.508002 + 0 -0.861356 0.508002 + 0 -0.861356 0.508002 + 0 -0.999942 0.0107828 + 0 -0.999942 0.0107828 + 0 -0.999942 0.0107828 + 0 -0.999942 0.0107828 + 1.94252e-07 -0.870693 -0.491827 + 1.94252e-07 -0.870693 -0.491827 + 1.94252e-07 -0.870693 -0.491827 + 1.94252e-07 -0.870693 -0.491827 + 1.94252e-07 -0.870693 -0.491827 + 1.94252e-07 -0.870693 -0.491827 + 1.94252e-07 -0.870693 -0.491827 + 1.63455e-07 -0.504723 -0.863282 + 1.63455e-07 -0.504723 -0.863282 + 1.63455e-07 -0.504723 -0.863282 + 1.63455e-07 -0.504723 -0.863282 + 1.63455e-07 -0.504723 -0.863282 + 1.63455e-07 -0.504723 -0.863282 + 1.63455e-07 -0.504723 -0.863282 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0 -1 + 0 0.504723 -0.863282 + 0 0.504723 -0.863282 + 0 0.504723 -0.863282 + 0 0.504723 -0.863282 + 0 0.504723 -0.863282 + 0 0.504723 -0.863282 + 0 0.870692 -0.491829 + 0 0.870692 -0.491829 + 0 0.870692 -0.491829 + 0 0.870692 -0.491829 + 0 0.870692 -0.491829 + 0 0.870692 -0.491829 + 0 0.870692 -0.491829 + 0 0.870692 -0.491829 + 0 0.999942 0.0107829 + 0 0.999942 0.0107829 + 0 0.999942 0.0107829 + 0 0.999942 0.0107829 + -3.83084e-07 0.861355 0.508004 + -3.83084e-07 0.861355 0.508004 + -3.83084e-07 0.861355 0.508004 + -3.83084e-07 0.861355 0.508004 + -3.83084e-07 0.861355 0.508004 + -3.83084e-07 0.861355 0.508004 + -3.83084e-07 0.861355 0.508004 + -2.68077e-07 0.495389 0.868671 + -2.68077e-07 0.495389 0.868671 + -2.68077e-07 0.495389 0.868671 + -2.68077e-07 0.495389 0.868671 + -2.68077e-07 0.495389 0.868671 + -2.68077e-07 0.495389 0.868671 + -0.130526 0 0.991445 + -0.130526 0 0.991445 + -0.130526 0 0.991445 + -0.130526 0 0.991445 + -0.130526 0 0.991445 + -0.130526 0 0.991445 + -0.113384 -0.495387 0.861241 + -0.113384 -0.495387 0.861241 + -0.113384 -0.495387 0.861241 + -0.113384 -0.495387 0.861241 + -0.113384 -0.495387 0.861241 + -0.066307 -0.861358 0.503653 + -0.066307 -0.861358 0.503653 + -0.066307 -0.861358 0.503653 + -0.066307 -0.861358 0.503653 + -0.066307 -0.861358 0.503653 + -0.066307 -0.861358 0.503653 + -0.066307 -0.861358 0.503653 + -0.00140697 -0.999942 0.0106886 + -0.00140697 -0.999942 0.0106886 + -0.00140697 -0.999942 0.0106886 + -0.00140697 -0.999942 0.0106886 + -0.00140697 -0.999942 0.0106886 + -0.00140697 -0.999942 0.0106886 + 0.0641961 -0.870694 -0.487619 + 0.0641961 -0.870694 -0.487619 + 0.0641961 -0.870694 -0.487619 + 0.0641961 -0.870694 -0.487619 + 0.0641961 -0.870694 -0.487619 + 0.0641961 -0.870694 -0.487619 + 0.112681 -0.504724 -0.855895 + 0.112681 -0.504724 -0.855895 + 0.112681 -0.504724 -0.855895 + 0.112681 -0.504724 -0.855895 + 0.112681 -0.504724 -0.855895 + 0.112681 -0.504724 -0.855895 + 0.130527 0 -0.991445 + 0.130527 0 -0.991445 + 0.130527 0 -0.991445 + 0.130527 0 -0.991445 + 0.130527 0 -0.991445 + 0.130527 0 -0.991445 + 0.112681 0.504721 -0.855897 + 0.112681 0.504721 -0.855897 + 0.112681 0.504721 -0.855897 + 0.112681 0.504721 -0.855897 + 0.112681 0.504721 -0.855897 + 0.112681 0.504721 -0.855897 + 0.112681 0.504721 -0.855897 + 0.0641965 0.870692 -0.487621 + 0.0641965 0.870692 -0.487621 + 0.0641965 0.870692 -0.487621 + 0.0641965 0.870692 -0.487621 + 0.0641965 0.870692 -0.487621 + -0.0014075 0.999942 0.0106913 + -0.0014075 0.999942 0.0106913 + -0.0014075 0.999942 0.0106913 + -0.0014075 0.999942 0.0106913 + -0.0014075 0.999942 0.0106913 + -0.0014075 0.999942 0.0106913 + -0.0663068 0.861358 0.503652 + -0.0663068 0.861358 0.503652 + -0.0663068 0.861358 0.503652 + -0.0663068 0.861358 0.503652 + -0.0663068 0.861358 0.503652 + -0.0663068 0.861358 0.503652 + -0.0663068 0.861358 0.503652 + -0.113384 0.49539 0.861239 + -0.113384 0.49539 0.861239 + -0.113384 0.49539 0.861239 + -0.113384 0.49539 0.861239 + -0.113384 0.49539 0.861239 + -0.258819 6.64642e-07 0.965926 + -0.258819 6.64642e-07 0.965926 + -0.258819 6.64642e-07 0.965926 + -0.258819 6.64642e-07 0.965926 + -0.258819 6.64642e-07 0.965926 + -0.258819 6.64642e-07 0.965926 + -0.224829 -0.495385 0.839074 + -0.224829 -0.495385 0.839074 + -0.224829 -0.495385 0.839074 + -0.224829 -0.495385 0.839074 + -0.224829 -0.495385 0.839074 + -0.224829 -0.495385 0.839074 + -0.224829 -0.495385 0.839074 + -0.131481 -0.861355 0.490694 + -0.131481 -0.861355 0.490694 + -0.131481 -0.861355 0.490694 + -0.131481 -0.861355 0.490694 + -0.00279039 -0.999942 0.0104136 + -0.00279039 -0.999942 0.0104136 + -0.00279039 -0.999942 0.0104136 + -0.00279039 -0.999942 0.0104136 + -0.00279039 -0.999942 0.0104136 + -0.00279039 -0.999942 0.0104136 + -0.00279039 -0.999942 0.0104136 + -0.00279039 -0.999942 0.0104136 + 0.127294 -0.870692 -0.47507 + 0.127294 -0.870692 -0.47507 + 0.127294 -0.870692 -0.47507 + 0.127294 -0.870692 -0.47507 + 0.127294 -0.870692 -0.47507 + 0.223433 -0.504725 -0.833865 + 0.223433 -0.504725 -0.833865 + 0.223433 -0.504725 -0.833865 + 0.223433 -0.504725 -0.833865 + 0.223433 -0.504725 -0.833865 + 0.223433 -0.504725 -0.833865 + 0.258819 -7.00974e-07 -0.965926 + 0.258819 -7.00974e-07 -0.965926 + 0.258819 -7.00974e-07 -0.965926 + 0.258819 -7.00974e-07 -0.965926 + 0.258819 -7.00974e-07 -0.965926 + 0.258819 -7.00974e-07 -0.965926 + 0.223434 0.504724 -0.833865 + 0.223434 0.504724 -0.833865 + 0.223434 0.504724 -0.833865 + 0.223434 0.504724 -0.833865 + 0.223434 0.504724 -0.833865 + 0.223434 0.504724 -0.833865 + 0.127294 0.870693 -0.475068 + 0.127294 0.870693 -0.475068 + 0.127294 0.870693 -0.475068 + 0.127294 0.870693 -0.475068 + 0.127294 0.870693 -0.475068 + -0.00279081 0.999942 0.0104157 + -0.00279081 0.999942 0.0104157 + -0.00279081 0.999942 0.0104157 + -0.00279081 0.999942 0.0104157 + -0.00279081 0.999942 0.0104157 + -0.00279081 0.999942 0.0104157 + -0.00279081 0.999942 0.0104157 + -0.00279081 0.999942 0.0104157 + -0.13148 0.861356 0.490692 + -0.13148 0.861356 0.490692 + -0.13148 0.861356 0.490692 + -0.13148 0.861356 0.490692 + -0.224829 0.495387 0.839073 + -0.224829 0.495387 0.839073 + -0.224829 0.495387 0.839073 + -0.224829 0.495387 0.839073 + -0.224829 0.495387 0.839073 + -0.224829 0.495387 0.839073 + -0.224829 0.495387 0.839073 + -0.382683 -6.2796e-07 0.92388 + -0.382683 -6.2796e-07 0.92388 + -0.382683 -6.2796e-07 0.92388 + -0.382683 -6.2796e-07 0.92388 + -0.382683 -6.2796e-07 0.92388 + -0.382683 -6.2796e-07 0.92388 + -0.332425 -0.495389 0.802548 + -0.332425 -0.495389 0.802548 + -0.332425 -0.495389 0.802548 + -0.332425 -0.495389 0.802548 + -0.332425 -0.495389 0.802548 + -0.194403 -0.861357 0.469331 + -0.194403 -0.861357 0.469331 + -0.194403 -0.861357 0.469331 + -0.194403 -0.861357 0.469331 + -0.194403 -0.861357 0.469331 + -0.194403 -0.861357 0.469331 + -0.194403 -0.861357 0.469331 + -0.00412679 -0.999942 0.00996232 + -0.00412679 -0.999942 0.00996232 + -0.00412679 -0.999942 0.00996232 + -0.00412679 -0.999942 0.00996232 + -0.00412679 -0.999942 0.00996232 + -0.00412679 -0.999942 0.00996232 + 0.188214 -0.870692 -0.45439 + 0.188214 -0.870692 -0.45439 + 0.188214 -0.870692 -0.45439 + 0.188214 -0.870692 -0.45439 + 0.188214 -0.870692 -0.45439 + 0.188214 -0.870692 -0.45439 + 0.330363 -0.504724 -0.797567 + 0.330363 -0.504724 -0.797567 + 0.330363 -0.504724 -0.797567 + 0.330363 -0.504724 -0.797567 + 0.330363 -0.504724 -0.797567 + 0.330363 -0.504724 -0.797567 + 0.382683 -4.72184e-07 -0.92388 + 0.382683 -4.72184e-07 -0.92388 + 0.382683 -4.72184e-07 -0.92388 + 0.382683 -4.72184e-07 -0.92388 + 0.382683 -4.72184e-07 -0.92388 + 0.382683 -4.72184e-07 -0.92388 + 0.330363 0.504724 -0.797568 + 0.330363 0.504724 -0.797568 + 0.330363 0.504724 -0.797568 + 0.330363 0.504724 -0.797568 + 0.330363 0.504724 -0.797568 + 0.330363 0.504724 -0.797568 + 0.188214 0.870692 -0.45439 + 0.188214 0.870692 -0.45439 + 0.188214 0.870692 -0.45439 + 0.188214 0.870692 -0.45439 + 0.188214 0.870692 -0.45439 + 0.188214 0.870692 -0.45439 + -0.00412661 0.999942 0.00996232 + -0.00412661 0.999942 0.00996232 + -0.00412661 0.999942 0.00996232 + -0.00412661 0.999942 0.00996232 + -0.00412661 0.999942 0.00996232 + -0.194403 0.861357 0.469331 + -0.194403 0.861357 0.469331 + -0.194403 0.861357 0.469331 + -0.194403 0.861357 0.469331 + -0.194403 0.861357 0.469331 + -0.194403 0.861357 0.469331 + -0.194403 0.861357 0.469331 + -0.332426 0.495389 0.802548 + -0.332426 0.495389 0.802548 + -0.332426 0.495389 0.802548 + -0.332426 0.495389 0.802548 + -0.332426 0.495389 0.802548 + -0.332426 0.495389 0.802548 + -0.5 0 0.866026 + -0.5 0 0.866026 + -0.5 0 0.866026 + -0.5 0 0.866026 + -0.434335 -0.49539 0.752291 + -0.434335 -0.49539 0.752291 + -0.434335 -0.49539 0.752291 + -0.434335 -0.49539 0.752291 + -0.434335 -0.49539 0.752291 + -0.434335 -0.49539 0.752291 + -0.434335 -0.49539 0.752291 + -0.253999 -0.861359 0.439939 + -0.253999 -0.861359 0.439939 + -0.253999 -0.861359 0.439939 + -0.253999 -0.861359 0.439939 + -0.253999 -0.861359 0.439939 + -0.253999 -0.861359 0.439939 + -0.253999 -0.861359 0.439939 + -0.005391 -0.999942 0.00933772 + -0.005391 -0.999942 0.00933772 + -0.005391 -0.999942 0.00933772 + -0.005391 -0.999942 0.00933772 + 0.245913 -0.870693 -0.425934 + 0.245913 -0.870693 -0.425934 + 0.245913 -0.870693 -0.425934 + 0.245913 -0.870693 -0.425934 + 0.245913 -0.870693 -0.425934 + 0.245913 -0.870693 -0.425934 + 0.245913 -0.870693 -0.425934 + 0.245913 -0.870693 -0.425934 + 0.43164 -0.504725 -0.747622 + 0.43164 -0.504725 -0.747622 + 0.43164 -0.504725 -0.747622 + 0.43164 -0.504725 -0.747622 + 0.43164 -0.504725 -0.747622 + 0.5 -4.62448e-07 -0.866026 + 0.5 -4.62448e-07 -0.866026 + 0.5 -4.62448e-07 -0.866026 + 0.5 -4.62448e-07 -0.866026 + 0.5 -4.62448e-07 -0.866026 + 0.5 -4.62448e-07 -0.866026 + 0.43164 0.504725 -0.747623 + 0.43164 0.504725 -0.747623 + 0.43164 0.504725 -0.747623 + 0.43164 0.504725 -0.747623 + 0.43164 0.504725 -0.747623 + 0.245913 0.870694 -0.425934 + 0.245913 0.870694 -0.425934 + 0.245913 0.870694 -0.425934 + 0.245913 0.870694 -0.425934 + 0.245913 0.870694 -0.425934 + 0.245913 0.870694 -0.425934 + 0.245913 0.870694 -0.425934 + 0.245913 0.870694 -0.425934 + -0.00539118 0.999942 0.00933796 + -0.00539118 0.999942 0.00933796 + -0.00539118 0.999942 0.00933796 + -0.00539118 0.999942 0.00933796 + -0.00539118 0.999942 0.00933796 + -0.253999 0.861359 0.439938 + -0.253999 0.861359 0.439938 + -0.253999 0.861359 0.439938 + -0.253999 0.861359 0.439938 + -0.253999 0.861359 0.439938 + -0.253999 0.861359 0.439938 + -0.253999 0.861359 0.439938 + -0.434335 0.49539 0.752291 + -0.434335 0.49539 0.752291 + -0.434335 0.49539 0.752291 + -0.434335 0.49539 0.752291 + -0.434335 0.49539 0.752291 + -0.434335 0.49539 0.752291 + -0.608762 3.2828e-07 0.793353 + -0.608762 3.2828e-07 0.793353 + -0.608762 3.2828e-07 0.793353 + -0.608762 3.2828e-07 0.793353 + -0.608762 3.2828e-07 0.793353 + -0.608762 3.2828e-07 0.793353 + -0.528814 -0.495388 0.689164 + -0.528814 -0.495388 0.689164 + -0.528814 -0.495388 0.689164 + -0.528814 -0.495388 0.689164 + -0.528814 -0.495388 0.689164 + -0.528814 -0.495388 0.689164 + -0.309253 -0.861355 0.403026 + -0.309253 -0.861355 0.403026 + -0.309253 -0.861355 0.403026 + -0.309253 -0.861355 0.403026 + -0.309253 -0.861355 0.403026 + -0.309253 -0.861355 0.403026 + -0.00656533 -0.999942 0.00855631 + -0.00656533 -0.999942 0.00855631 + -0.00656533 -0.999942 0.00855631 + -0.00656533 -0.999942 0.00855631 + -0.00656533 -0.999942 0.00855631 + -0.00656533 -0.999942 0.00855631 + 0.299406 -0.870693 -0.390193 + 0.299406 -0.870693 -0.390193 + 0.299406 -0.870693 -0.390193 + 0.299406 -0.870693 -0.390193 + 0.299406 -0.870693 -0.390193 + 0.299406 -0.870693 -0.390193 + 0.525532 -0.504724 -0.684887 + 0.525532 -0.504724 -0.684887 + 0.525532 -0.504724 -0.684887 + 0.525532 -0.504724 -0.684887 + 0.525532 -0.504724 -0.684887 + 0.525532 -0.504724 -0.684887 + 0.608762 -6.96106e-07 -0.793353 + 0.608762 -6.96106e-07 -0.793353 + 0.608762 -6.96106e-07 -0.793353 + 0.608762 -6.96106e-07 -0.793353 + 0.608762 -6.96106e-07 -0.793353 + 0.608762 -6.96106e-07 -0.793353 + 0.525533 0.504722 -0.684887 + 0.525533 0.504722 -0.684887 + 0.525533 0.504722 -0.684887 + 0.525533 0.504722 -0.684887 + 0.525533 0.504722 -0.684887 + 0.525533 0.504722 -0.684887 + 0.299406 0.870692 -0.390193 + 0.299406 0.870692 -0.390193 + 0.299406 0.870692 -0.390193 + 0.299406 0.870692 -0.390193 + 0.299406 0.870692 -0.390193 + 0.299406 0.870692 -0.390193 + -0.00656545 0.999942 0.00855654 + -0.00656545 0.999942 0.00855654 + -0.00656545 0.999942 0.00855654 + -0.00656545 0.999942 0.00855654 + -0.00656545 0.999942 0.00855654 + -0.00656545 0.999942 0.00855654 + -0.309253 0.861355 0.403026 + -0.309253 0.861355 0.403026 + -0.309253 0.861355 0.403026 + -0.309253 0.861355 0.403026 + -0.309253 0.861355 0.403026 + -0.309253 0.861355 0.403026 + -0.528814 0.495389 0.689163 + -0.528814 0.495389 0.689163 + -0.528814 0.495389 0.689163 + -0.528814 0.495389 0.689163 + -0.528814 0.495389 0.689163 + -0.528814 0.495389 0.689163 + -0.707107 -2.18854e-07 0.707107 + -0.707107 -2.18854e-07 0.707107 + -0.707107 -2.18854e-07 0.707107 + -0.707107 -2.18854e-07 0.707107 + -0.707107 -2.18854e-07 0.707107 + -0.707107 -2.18854e-07 0.707107 + -0.614242 -0.495392 0.614242 + -0.614242 -0.495392 0.614242 + -0.614242 -0.495392 0.614242 + -0.614242 -0.495392 0.614242 + -0.614242 -0.495392 0.614242 + -0.614242 -0.495392 0.614242 + -0.614242 -0.495392 0.614242 + -0.359209 -0.861358 0.359209 + -0.359209 -0.861358 0.359209 + -0.359209 -0.861358 0.359209 + -0.359209 -0.861358 0.359209 + -0.359209 -0.861358 0.359209 + -0.00762474 -0.999942 0.00762486 + -0.00762474 -0.999942 0.00762486 + -0.00762474 -0.999942 0.00762486 + -0.00762474 -0.999942 0.00762486 + -0.00762474 -0.999942 0.00762486 + -0.00762474 -0.999942 0.00762486 + 0.347775 -0.870692 -0.347775 + 0.347775 -0.870692 -0.347775 + 0.347775 -0.870692 -0.347775 + 0.347775 -0.870692 -0.347775 + 0.347775 -0.870692 -0.347775 + 0.347775 -0.870692 -0.347775 + 0.610432 -0.504724 -0.610432 + 0.610432 -0.504724 -0.610432 + 0.610432 -0.504724 -0.610432 + 0.610432 -0.504724 -0.610432 + 0.610432 -0.504724 -0.610432 + 0.707107 4.55451e-07 -0.707107 + 0.707107 4.55451e-07 -0.707107 + 0.707107 4.55451e-07 -0.707107 + 0.707107 4.55451e-07 -0.707107 + 0.707107 4.55451e-07 -0.707107 + 0.707107 4.55451e-07 -0.707107 + 0.707107 4.55451e-07 -0.707107 + 0.707107 4.55451e-07 -0.707107 + 0.610432 0.504725 -0.610431 + 0.610432 0.504725 -0.610431 + 0.610432 0.504725 -0.610431 + 0.610432 0.504725 -0.610431 + 0.610432 0.504725 -0.610431 + 0.347775 0.870692 -0.347775 + 0.347775 0.870692 -0.347775 + 0.347775 0.870692 -0.347775 + 0.347775 0.870692 -0.347775 + 0.347775 0.870692 -0.347775 + 0.347775 0.870692 -0.347775 + -0.0076251 0.999942 0.00762516 + -0.0076251 0.999942 0.00762516 + -0.0076251 0.999942 0.00762516 + -0.0076251 0.999942 0.00762516 + -0.0076251 0.999942 0.00762516 + -0.0076251 0.999942 0.00762516 + -0.35921 0.861358 0.35921 + -0.35921 0.861358 0.35921 + -0.35921 0.861358 0.35921 + -0.35921 0.861358 0.35921 + -0.35921 0.861358 0.35921 + -0.614243 0.495391 0.614242 + -0.614243 0.495391 0.614242 + -0.614243 0.495391 0.614242 + -0.614243 0.495391 0.614242 + -0.614243 0.495391 0.614242 + -0.614243 0.495391 0.614242 + -0.614243 0.495391 0.614242 + -0.793353 3.58124e-07 0.608761 + -0.793353 3.58124e-07 0.608761 + -0.793353 3.58124e-07 0.608761 + -0.793353 3.58124e-07 0.608761 + -0.793353 3.58124e-07 0.608761 + -0.793353 3.58124e-07 0.608761 + -0.689164 -0.495388 0.528814 + -0.689164 -0.495388 0.528814 + -0.689164 -0.495388 0.528814 + -0.689164 -0.495388 0.528814 + -0.689164 -0.495388 0.528814 + -0.689164 -0.495388 0.528814 + -0.403026 -0.861355 0.309253 + -0.403026 -0.861355 0.309253 + -0.403026 -0.861355 0.309253 + -0.403026 -0.861355 0.309253 + -0.403026 -0.861355 0.309253 + -0.403026 -0.861355 0.309253 + -0.00855649 -0.999942 0.00656551 + -0.00855649 -0.999942 0.00656551 + -0.00855649 -0.999942 0.00656551 + -0.00855649 -0.999942 0.00656551 + -0.00855649 -0.999942 0.00656551 + -0.00855649 -0.999942 0.00656551 + -0.00855649 -0.999942 0.00656551 + 0.390193 -0.870693 -0.299405 + 0.390193 -0.870693 -0.299405 + 0.390193 -0.870693 -0.299405 + 0.390193 -0.870693 -0.299405 + 0.390193 -0.870693 -0.299405 + 0.684887 -0.504723 -0.525533 + 0.684887 -0.504723 -0.525533 + 0.684887 -0.504723 -0.525533 + 0.684887 -0.504723 -0.525533 + 0.684887 -0.504723 -0.525533 + 0.684887 -0.504723 -0.525533 + 0.793353 -1.3122e-06 -0.608762 + 0.793353 -1.3122e-06 -0.608762 + 0.793353 -1.3122e-06 -0.608762 + 0.793353 -1.3122e-06 -0.608762 + 0.793353 -1.3122e-06 -0.608762 + 0.793353 -1.3122e-06 -0.608762 + 0.684887 0.504723 -0.525533 + 0.684887 0.504723 -0.525533 + 0.684887 0.504723 -0.525533 + 0.684887 0.504723 -0.525533 + 0.684887 0.504723 -0.525533 + 0.684887 0.504723 -0.525533 + 0.390192 0.870693 -0.299405 + 0.390192 0.870693 -0.299405 + 0.390192 0.870693 -0.299405 + 0.390192 0.870693 -0.299405 + 0.390192 0.870693 -0.299405 + -0.00855631 0.999942 0.00656527 + -0.00855631 0.999942 0.00656527 + -0.00855631 0.999942 0.00656527 + -0.00855631 0.999942 0.00656527 + -0.00855631 0.999942 0.00656527 + -0.00855631 0.999942 0.00656527 + -0.00855631 0.999942 0.00656527 + -0.403026 0.861355 0.309253 + -0.403026 0.861355 0.309253 + -0.403026 0.861355 0.309253 + -0.403026 0.861355 0.309253 + -0.403026 0.861355 0.309253 + -0.403026 0.861355 0.309253 + -0.689164 0.495387 0.528814 + -0.689164 0.495387 0.528814 + -0.689164 0.495387 0.528814 + -0.689164 0.495387 0.528814 + -0.689164 0.495387 0.528814 + -0.689164 0.495387 0.528814 + -0.866025 1.77072e-06 0.500001 + -0.866025 1.77072e-06 0.500001 + -0.866025 1.77072e-06 0.500001 + -0.866025 1.77072e-06 0.500001 + -0.866025 1.77072e-06 0.500001 + -0.866025 1.77072e-06 0.500001 + -0.752293 -0.495386 0.434337 + -0.752293 -0.495386 0.434337 + -0.752293 -0.495386 0.434337 + -0.752293 -0.495386 0.434337 + -0.752293 -0.495386 0.434337 + -0.752293 -0.495386 0.434337 + -0.439938 -0.861359 0.253999 + -0.439938 -0.861359 0.253999 + -0.439938 -0.861359 0.253999 + -0.439938 -0.861359 0.253999 + -0.439938 -0.861359 0.253999 + -0.00933766 -0.999942 0.00539118 + -0.00933766 -0.999942 0.00539118 + -0.00933766 -0.999942 0.00539118 + -0.00933766 -0.999942 0.00539118 + -0.00933766 -0.999942 0.00539118 + -0.00933766 -0.999942 0.00539118 + -0.00933766 -0.999942 0.00539118 + 0.425935 -0.870693 -0.245914 + 0.425935 -0.870693 -0.245914 + 0.425935 -0.870693 -0.245914 + 0.425935 -0.870693 -0.245914 + 0.425935 -0.870693 -0.245914 + 0.747623 -0.504725 -0.431641 + 0.747623 -0.504725 -0.431641 + 0.747623 -0.504725 -0.431641 + 0.747623 -0.504725 -0.431641 + 0.747623 -0.504725 -0.431641 + 0.747623 -0.504725 -0.431641 + 0.747623 -0.504725 -0.431641 + 0.866025 -6.35258e-07 -0.5 + 0.866025 -6.35258e-07 -0.5 + 0.866025 -6.35258e-07 -0.5 + 0.866025 -6.35258e-07 -0.5 + 0.866025 -6.35258e-07 -0.5 + 0.747622 0.504726 -0.43164 + 0.747622 0.504726 -0.43164 + 0.747622 0.504726 -0.43164 + 0.747622 0.504726 -0.43164 + 0.747622 0.504726 -0.43164 + 0.747622 0.504726 -0.43164 + 0.747622 0.504726 -0.43164 + 0.747622 0.504726 -0.43164 + 0.425933 0.870694 -0.245913 + 0.425933 0.870694 -0.245913 + 0.425933 0.870694 -0.245913 + 0.425933 0.870694 -0.245913 + 0.425933 0.870694 -0.245913 + -0.00933766 0.999942 0.0053913 + -0.00933766 0.999942 0.0053913 + -0.00933766 0.999942 0.0053913 + -0.00933766 0.999942 0.0053913 + -0.00933766 0.999942 0.0053913 + -0.00933766 0.999942 0.0053913 + -0.00933766 0.999942 0.0053913 + -0.439938 0.861359 0.253998 + -0.439938 0.861359 0.253998 + -0.439938 0.861359 0.253998 + -0.439938 0.861359 0.253998 + -0.439938 0.861359 0.253998 + -0.752291 0.495389 0.434336 + -0.752291 0.495389 0.434336 + -0.752291 0.495389 0.434336 + -0.752291 0.495389 0.434336 + -0.752291 0.495389 0.434336 + -0.752291 0.495389 0.434336 + -0.92388 7.4609e-07 0.382683 + -0.92388 7.4609e-07 0.382683 + -0.92388 7.4609e-07 0.382683 + -0.92388 7.4609e-07 0.382683 + -0.92388 7.4609e-07 0.382683 + -0.92388 7.4609e-07 0.382683 + -0.80255 -0.495385 0.332427 + -0.80255 -0.495385 0.332427 + -0.80255 -0.495385 0.332427 + -0.80255 -0.495385 0.332427 + -0.80255 -0.495385 0.332427 + -0.80255 -0.495385 0.332427 + -0.469332 -0.861356 0.194403 + -0.469332 -0.861356 0.194403 + -0.469332 -0.861356 0.194403 + -0.469332 -0.861356 0.194403 + -0.469332 -0.861356 0.194403 + -0.469332 -0.861356 0.194403 + -0.00996214 -0.999942 0.00412631 + -0.00996214 -0.999942 0.00412631 + -0.00996214 -0.999942 0.00412631 + -0.00996214 -0.999942 0.00412631 + -0.00996214 -0.999942 0.00412631 + 0.454389 -0.870693 -0.188215 + 0.454389 -0.870693 -0.188215 + 0.454389 -0.870693 -0.188215 + 0.454389 -0.870693 -0.188215 + 0.454389 -0.870693 -0.188215 + 0.454389 -0.870693 -0.188215 + 0.454389 -0.870693 -0.188215 + 0.797569 -0.504721 -0.330364 + 0.797569 -0.504721 -0.330364 + 0.797569 -0.504721 -0.330364 + 0.797569 -0.504721 -0.330364 + 0.797569 -0.504721 -0.330364 + 0.797569 -0.504721 -0.330364 + 0.92388 1.84158e-06 -0.382684 + 0.92388 1.84158e-06 -0.382684 + 0.92388 1.84158e-06 -0.382684 + 0.92388 1.84158e-06 -0.382684 + 0.92388 1.84158e-06 -0.382684 + 0.92388 1.84158e-06 -0.382684 + 0.92388 1.84158e-06 -0.382684 + 0.797569 0.504721 -0.330364 + 0.797569 0.504721 -0.330364 + 0.797569 0.504721 -0.330364 + 0.797569 0.504721 -0.330364 + 0.454389 0.870693 -0.188215 + 0.454389 0.870693 -0.188215 + 0.454389 0.870693 -0.188215 + 0.454389 0.870693 -0.188215 + 0.454389 0.870693 -0.188215 + 0.454389 0.870693 -0.188215 + 0.454389 0.870693 -0.188215 + 0.454389 0.870693 -0.188215 + -0.00996268 0.999942 0.00412661 + -0.00996268 0.999942 0.00412661 + -0.00996268 0.999942 0.00412661 + -0.00996268 0.999942 0.00412661 + -0.00996268 0.999942 0.00412661 + -0.469331 0.861357 0.194403 + -0.469331 0.861357 0.194403 + -0.469331 0.861357 0.194403 + -0.469331 0.861357 0.194403 + -0.469331 0.861357 0.194403 + -0.469331 0.861357 0.194403 + -0.802549 0.495387 0.332427 + -0.802549 0.495387 0.332427 + -0.802549 0.495387 0.332427 + -0.802549 0.495387 0.332427 + -0.802549 0.495387 0.332427 + -0.802549 0.495387 0.332427 + -0.965926 -4.57602e-07 0.258819 + -0.965926 -4.57602e-07 0.258819 + -0.965926 -4.57602e-07 0.258819 + -0.965926 -4.57602e-07 0.258819 + -0.965926 -4.57602e-07 0.258819 + -0.965926 -4.57602e-07 0.258819 + -0.839072 -0.495388 0.224829 + -0.839072 -0.495388 0.224829 + -0.839072 -0.495388 0.224829 + -0.839072 -0.495388 0.224829 + -0.839072 -0.495388 0.224829 + -0.839072 -0.495388 0.224829 + -0.49069 -0.861357 0.13148 + -0.49069 -0.861357 0.13148 + -0.49069 -0.861357 0.13148 + -0.49069 -0.861357 0.13148 + -0.49069 -0.861357 0.13148 + -0.49069 -0.861357 0.13148 + -0.0104154 -0.999942 0.00279051 + -0.0104154 -0.999942 0.00279051 + -0.0104154 -0.999942 0.00279051 + -0.0104154 -0.999942 0.00279051 + -0.0104154 -0.999942 0.00279051 + -0.0104154 -0.999942 0.00279051 + 0.475068 -0.870693 -0.127294 + 0.475068 -0.870693 -0.127294 + 0.475068 -0.870693 -0.127294 + 0.475068 -0.870693 -0.127294 + 0.475068 -0.870693 -0.127294 + 0.475068 -0.870693 -0.127294 + 0.475068 -0.870693 -0.127294 + 0.833864 -0.504726 -0.223433 + 0.833864 -0.504726 -0.223433 + 0.833864 -0.504726 -0.223433 + 0.833864 -0.504726 -0.223433 + 0.833864 -0.504726 -0.223433 + 0.965926 -1.85345e-06 -0.258819 + 0.965926 -1.85345e-06 -0.258819 + 0.965926 -1.85345e-06 -0.258819 + 0.965926 -1.85345e-06 -0.258819 + 0.965926 -1.85345e-06 -0.258819 + 0.965926 -1.85345e-06 -0.258819 + 0.833866 0.504723 -0.223433 + 0.833866 0.504723 -0.223433 + 0.833866 0.504723 -0.223433 + 0.833866 0.504723 -0.223433 + 0.833866 0.504723 -0.223433 + 0.833866 0.504723 -0.223433 + 0.475069 0.870693 -0.127294 + 0.475069 0.870693 -0.127294 + 0.475069 0.870693 -0.127294 + 0.475069 0.870693 -0.127294 + 0.475069 0.870693 -0.127294 + 0.475069 0.870693 -0.127294 + -0.010416 0.999942 0.00279081 + -0.010416 0.999942 0.00279081 + -0.010416 0.999942 0.00279081 + -0.010416 0.999942 0.00279081 + -0.010416 0.999942 0.00279081 + -0.010416 0.999942 0.00279081 + -0.490689 0.861358 0.13148 + -0.490689 0.861358 0.13148 + -0.490689 0.861358 0.13148 + -0.490689 0.861358 0.13148 + -0.490689 0.861358 0.13148 + -0.490689 0.861358 0.13148 + -0.839072 0.495389 0.224829 + -0.839072 0.495389 0.224829 + -0.839072 0.495389 0.224829 + -0.839072 0.495389 0.224829 + -0.839072 0.495389 0.224829 + -0.839072 0.495389 0.224829 + -0.991445 -3.08384e-07 0.130526 + -0.991445 -3.08384e-07 0.130526 + -0.991445 -3.08384e-07 0.130526 + -0.991445 -3.08384e-07 0.130526 + -0.991445 -3.08384e-07 0.130526 + -0.991445 -3.08384e-07 0.130526 + -0.86124 -0.495388 0.113384 + -0.86124 -0.495388 0.113384 + -0.86124 -0.495388 0.113384 + -0.86124 -0.495388 0.113384 + -0.86124 -0.495388 0.113384 + -0.86124 -0.495388 0.113384 + -0.503652 -0.861358 0.0663071 + -0.503652 -0.861358 0.0663071 + -0.503652 -0.861358 0.0663071 + -0.503652 -0.861358 0.0663071 + -0.503652 -0.861358 0.0663071 + -0.503652 -0.861358 0.0663071 + -0.0106919 -0.999942 0.00140762 + -0.0106919 -0.999942 0.00140762 + -0.0106919 -0.999942 0.00140762 + -0.0106919 -0.999942 0.00140762 + -0.0106919 -0.999942 0.00140762 + -0.0106919 -0.999942 0.00140762 + -0.0106919 -0.999942 0.00140762 + 0.487618 -0.870694 -0.064196 + 0.487618 -0.870694 -0.064196 + 0.487618 -0.870694 -0.064196 + 0.487618 -0.870694 -0.064196 + 0.487618 -0.870694 -0.064196 + 0.855895 -0.504725 -0.112681 + 0.855895 -0.504725 -0.112681 + 0.855895 -0.504725 -0.112681 + 0.855895 -0.504725 -0.112681 + 0.855895 -0.504725 -0.112681 + 0.855895 -0.504725 -0.112681 + 0.991445 0 -0.130526 + 0.991445 0 -0.130526 + 0.991445 0 -0.130526 + 0.991445 0 -0.130526 + 0.991445 0 -0.130526 + 0.991445 0 -0.130526 + 0.855894 0.504726 -0.112681 + 0.855894 0.504726 -0.112681 + 0.855894 0.504726 -0.112681 + 0.855894 0.504726 -0.112681 + 0.855894 0.504726 -0.112681 + 0.855894 0.504726 -0.112681 + 0.487617 0.870694 -0.0641958 + 0.487617 0.870694 -0.0641958 + 0.487617 0.870694 -0.0641958 + 0.487617 0.870694 -0.0641958 + 0.487617 0.870694 -0.0641958 + -0.0106915 0.999942 0.00140762 + -0.0106915 0.999942 0.00140762 + -0.0106915 0.999942 0.00140762 + -0.0106915 0.999942 0.00140762 + -0.0106915 0.999942 0.00140762 + -0.0106915 0.999942 0.00140762 + -0.0106915 0.999942 0.00140762 + -0.503653 0.861358 0.0663071 + -0.503653 0.861358 0.0663071 + -0.503653 0.861358 0.0663071 + -0.503653 0.861358 0.0663071 + -0.503653 0.861358 0.0663071 + -0.503653 0.861358 0.0663071 + -0.86124 0.495388 0.113384 + -0.86124 0.495388 0.113384 + -0.86124 0.495388 0.113384 + -0.86124 0.495388 0.113384 + -0.86124 0.495388 0.113384 + -0.86124 0.495388 0.113384 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -0.868671 -0.495389 0 + -0.868671 -0.495389 0 + -0.868671 -0.495389 0 + -0.868671 -0.495389 0 + -0.508 -0.861357 0 + -0.508 -0.861357 0 + -0.508 -0.861357 0 + -0.508 -0.861357 0 + -0.508 -0.861357 0 + -0.508 -0.861357 0 + -0.508 -0.861357 0 + -0.508 -0.861357 0 + -0.0107847 -0.999942 0 + -0.0107847 -0.999942 0 + -0.0107847 -0.999942 0 + -0.0107847 -0.999942 0 + -0.0107847 -0.999942 0 + 0.491828 -0.870693 0 + 0.491828 -0.870693 0 + 0.491828 -0.870693 0 + 0.491828 -0.870693 0 + 0.491828 -0.870693 0 + 0.863281 -0.504723 0 + 0.863281 -0.504723 0 + 0.863281 -0.504723 0 + 0.863281 -0.504723 0 + 0.863281 -0.504723 0 + 0.863281 -0.504723 0 + 0.863281 -0.504723 0 + 0.863281 -0.504723 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 0.863281 0.504723 0 + 0.863281 0.504723 0 + 0.863281 0.504723 0 + 0.863281 0.504723 0 + 0.863281 0.504723 0 + 0.863281 0.504723 0 + 0.863281 0.504723 0 + 0.863281 0.504723 0 + 0.491828 0.870692 0 + 0.491828 0.870692 0 + 0.491828 0.870692 0 + 0.491828 0.870692 0 + 0.491828 0.870692 0 + -0.0107844 0.999942 0 + -0.0107844 0.999942 0 + -0.0107844 0.999942 0 + -0.0107844 0.999942 0 + -0.0107844 0.999942 0 + -0.508 0.861357 0 + -0.508 0.861357 0 + -0.508 0.861357 0 + -0.508 0.861357 0 + -0.508 0.861357 0 + -0.508 0.861357 0 + -0.508 0.861357 0 + -0.508 0.861357 0 + -0.868671 0.495389 0 + -0.868671 0.495389 0 + -0.868671 0.495389 0 + -0.868671 0.495389 0 + -0.991445 -3.29834e-07 -0.130526 + -0.991445 -3.29834e-07 -0.130526 + -0.991445 -3.29834e-07 -0.130526 + -0.991445 -3.29834e-07 -0.130526 + -0.991445 -3.29834e-07 -0.130526 + -0.991445 -3.29834e-07 -0.130526 + -0.861241 -0.495387 -0.113385 + -0.861241 -0.495387 -0.113385 + -0.861241 -0.495387 -0.113385 + -0.861241 -0.495387 -0.113385 + -0.861241 -0.495387 -0.113385 + -0.861241 -0.495387 -0.113385 + -0.503653 -0.861358 -0.0663074 + -0.503653 -0.861358 -0.0663074 + -0.503653 -0.861358 -0.0663074 + -0.503653 -0.861358 -0.0663074 + -0.503653 -0.861358 -0.0663074 + -0.503653 -0.861358 -0.0663074 + -0.0106917 -0.999942 -0.00140768 + -0.0106917 -0.999942 -0.00140768 + -0.0106917 -0.999942 -0.00140768 + -0.0106917 -0.999942 -0.00140768 + -0.0106917 -0.999942 -0.00140768 + -0.0106917 -0.999942 -0.00140768 + 0.487613 -0.870697 0.0641955 + 0.487613 -0.870697 0.0641955 + 0.487613 -0.870697 0.0641955 + 0.487613 -0.870697 0.0641955 + 0.487613 -0.870697 0.0641955 + 0.487613 -0.870697 0.0641955 + 0.855894 -0.504727 0.112681 + 0.855894 -0.504727 0.112681 + 0.855894 -0.504727 0.112681 + 0.855894 -0.504727 0.112681 + 0.855894 -0.504727 0.112681 + 0.991445 0 0.130526 + 0.991445 0 0.130526 + 0.991445 0 0.130526 + 0.991445 0 0.130526 + 0.991445 0 0.130526 + 0.991445 0 0.130526 + 0.991445 0 0.130526 + 0.991445 0 0.130526 + 0.855893 0.504727 0.112681 + 0.855893 0.504727 0.112681 + 0.855893 0.504727 0.112681 + 0.855893 0.504727 0.112681 + 0.855893 0.504727 0.112681 + 0.487612 0.870697 0.0641954 + 0.487612 0.870697 0.0641954 + 0.487612 0.870697 0.0641954 + 0.487612 0.870697 0.0641954 + 0.487612 0.870697 0.0641954 + 0.487612 0.870697 0.0641954 + -0.0106917 0.999942 -0.0014075 + -0.0106917 0.999942 -0.0014075 + -0.0106917 0.999942 -0.0014075 + -0.0106917 0.999942 -0.0014075 + -0.0106917 0.999942 -0.0014075 + -0.0106917 0.999942 -0.0014075 + -0.503653 0.861358 -0.0663072 + -0.503653 0.861358 -0.0663072 + -0.503653 0.861358 -0.0663072 + -0.503653 0.861358 -0.0663072 + -0.503653 0.861358 -0.0663072 + -0.503653 0.861358 -0.0663072 + -0.861241 0.495386 -0.113385 + -0.861241 0.495386 -0.113385 + -0.861241 0.495386 -0.113385 + -0.861241 0.495386 -0.113385 + -0.861241 0.495386 -0.113385 + -0.861241 0.495386 -0.113385 + -0.965926 1.16266e-06 -0.258819 + -0.965926 1.16266e-06 -0.258819 + -0.965926 1.16266e-06 -0.258819 + -0.965926 1.16266e-06 -0.258819 + -0.965926 1.16266e-06 -0.258819 + -0.965926 1.16266e-06 -0.258819 + -0.839073 -0.495387 -0.224829 + -0.839073 -0.495387 -0.224829 + -0.839073 -0.495387 -0.224829 + -0.839073 -0.495387 -0.224829 + -0.839073 -0.495387 -0.224829 + -0.839073 -0.495387 -0.224829 + -0.490691 -0.861357 -0.13148 + -0.490691 -0.861357 -0.13148 + -0.490691 -0.861357 -0.13148 + -0.490691 -0.861357 -0.13148 + -0.490691 -0.861357 -0.13148 + -0.010415 -0.999942 -0.00279057 + -0.010415 -0.999942 -0.00279057 + -0.010415 -0.999942 -0.00279057 + -0.010415 -0.999942 -0.00279057 + -0.010415 -0.999942 -0.00279057 + -0.010415 -0.999942 -0.00279057 + -0.010415 -0.999942 -0.00279057 + 0.475069 -0.870693 0.127294 + 0.475069 -0.870693 0.127294 + 0.475069 -0.870693 0.127294 + 0.475069 -0.870693 0.127294 + 0.475069 -0.870693 0.127294 + 0.475069 -0.870693 0.127294 + 0.475069 -0.870693 0.127294 + 0.833866 -0.504724 0.223433 + 0.833866 -0.504724 0.223433 + 0.833866 -0.504724 0.223433 + 0.833866 -0.504724 0.223433 + 0.833866 -0.504724 0.223433 + 0.965926 2.85988e-07 0.258819 + 0.965926 2.85988e-07 0.258819 + 0.965926 2.85988e-07 0.258819 + 0.965926 2.85988e-07 0.258819 + 0.965926 2.85988e-07 0.258819 + 0.965926 2.85988e-07 0.258819 + 0.833865 0.504724 0.223433 + 0.833865 0.504724 0.223433 + 0.833865 0.504724 0.223433 + 0.833865 0.504724 0.223433 + 0.833865 0.504724 0.223433 + 0.475069 0.870693 0.127294 + 0.475069 0.870693 0.127294 + 0.475069 0.870693 0.127294 + 0.475069 0.870693 0.127294 + 0.475069 0.870693 0.127294 + 0.475069 0.870693 0.127294 + 0.475069 0.870693 0.127294 + -0.0104146 0.999942 -0.00279033 + -0.0104146 0.999942 -0.00279033 + -0.0104146 0.999942 -0.00279033 + -0.0104146 0.999942 -0.00279033 + -0.0104146 0.999942 -0.00279033 + -0.0104146 0.999942 -0.00279033 + -0.0104146 0.999942 -0.00279033 + -0.490689 0.861358 -0.13148 + -0.490689 0.861358 -0.13148 + -0.490689 0.861358 -0.13148 + -0.490689 0.861358 -0.13148 + -0.490689 0.861358 -0.13148 + -0.839072 0.49539 -0.224828 + -0.839072 0.49539 -0.224828 + -0.839072 0.49539 -0.224828 + -0.839072 0.49539 -0.224828 + -0.839072 0.49539 -0.224828 + -0.839072 0.49539 -0.224828 + -0.92388 0 -0.382683 + -0.92388 0 -0.382683 + -0.92388 0 -0.382683 + -0.92388 0 -0.382683 + -0.92388 0 -0.382683 + -0.92388 0 -0.382683 + -0.802549 -0.495388 -0.332426 + -0.802549 -0.495388 -0.332426 + -0.802549 -0.495388 -0.332426 + -0.802549 -0.495388 -0.332426 + -0.802549 -0.495388 -0.332426 + -0.802549 -0.495388 -0.332426 + -0.469331 -0.861357 -0.194403 + -0.469331 -0.861357 -0.194403 + -0.469331 -0.861357 -0.194403 + -0.469331 -0.861357 -0.194403 + -0.469331 -0.861357 -0.194403 + -0.469331 -0.861357 -0.194403 + -0.00996226 -0.999942 -0.00412661 + -0.00996226 -0.999942 -0.00412661 + -0.00996226 -0.999942 -0.00412661 + -0.00996226 -0.999942 -0.00412661 + -0.00996226 -0.999942 -0.00412661 + -0.00996226 -0.999942 -0.00412661 + 0.454388 -0.870693 0.188214 + 0.454388 -0.870693 0.188214 + 0.454388 -0.870693 0.188214 + 0.454388 -0.870693 0.188214 + 0.454388 -0.870693 0.188214 + 0.797568 -0.504723 0.330363 + 0.797568 -0.504723 0.330363 + 0.797568 -0.504723 0.330363 + 0.797568 -0.504723 0.330363 + 0.797568 -0.504723 0.330363 + 0.797568 -0.504723 0.330363 + 0.797568 -0.504723 0.330363 + 0.92388 2.09927e-07 0.382683 + 0.92388 2.09927e-07 0.382683 + 0.92388 2.09927e-07 0.382683 + 0.92388 2.09927e-07 0.382683 + 0.92388 2.09927e-07 0.382683 + 0.797568 0.504723 0.330364 + 0.797568 0.504723 0.330364 + 0.797568 0.504723 0.330364 + 0.797568 0.504723 0.330364 + 0.797568 0.504723 0.330364 + 0.797568 0.504723 0.330364 + 0.797568 0.504723 0.330364 + 0.797568 0.504723 0.330364 + 0.454389 0.870693 0.188214 + 0.454389 0.870693 0.188214 + 0.454389 0.870693 0.188214 + 0.454389 0.870693 0.188214 + 0.454389 0.870693 0.188214 + -0.00996387 0.999942 -0.00412709 + -0.00996387 0.999942 -0.00412709 + -0.00996387 0.999942 -0.00412709 + -0.00996387 0.999942 -0.00412709 + -0.00996387 0.999942 -0.00412709 + -0.00996387 0.999942 -0.00412709 + -0.469333 0.861356 -0.194404 + -0.469333 0.861356 -0.194404 + -0.469333 0.861356 -0.194404 + -0.469333 0.861356 -0.194404 + -0.469333 0.861356 -0.194404 + -0.469333 0.861356 -0.194404 + -0.802549 0.495387 -0.332426 + -0.802549 0.495387 -0.332426 + -0.802549 0.495387 -0.332426 + -0.802549 0.495387 -0.332426 + -0.802549 0.495387 -0.332426 + -0.802549 0.495387 -0.332426 + -0.866026 -1.59291e-06 -0.5 + -0.866026 -1.59291e-06 -0.5 + -0.866026 -1.59291e-06 -0.5 + -0.866026 -1.59291e-06 -0.5 + -0.866026 -1.59291e-06 -0.5 + -0.866026 -1.59291e-06 -0.5 + -0.75229 -0.495392 -0.434335 + -0.75229 -0.495392 -0.434335 + -0.75229 -0.495392 -0.434335 + -0.75229 -0.495392 -0.434335 + -0.75229 -0.495392 -0.434335 + -0.75229 -0.495392 -0.434335 + -0.439941 -0.861357 -0.254001 + -0.439941 -0.861357 -0.254001 + -0.439941 -0.861357 -0.254001 + -0.439941 -0.861357 -0.254001 + -0.439941 -0.861357 -0.254001 + -0.439941 -0.861357 -0.254001 + -0.439941 -0.861357 -0.254001 + -0.00933832 -0.999942 -0.00539154 + -0.00933832 -0.999942 -0.00539154 + -0.00933832 -0.999942 -0.00539154 + -0.00933832 -0.999942 -0.00539154 + -0.00933832 -0.999942 -0.00539154 + 0.425934 -0.870693 0.245913 + 0.425934 -0.870693 0.245913 + 0.425934 -0.870693 0.245913 + 0.425934 -0.870693 0.245913 + 0.425934 -0.870693 0.245913 + 0.425934 -0.870693 0.245913 + 0.747622 -0.504726 0.43164 + 0.747622 -0.504726 0.43164 + 0.747622 -0.504726 0.43164 + 0.747622 -0.504726 0.43164 + 0.747622 -0.504726 0.43164 + 0.747622 -0.504726 0.43164 + 0.747622 -0.504726 0.43164 + 0.866026 3.74827e-07 0.5 + 0.866026 3.74827e-07 0.5 + 0.866026 3.74827e-07 0.5 + 0.866026 3.74827e-07 0.5 + 0.866026 3.74827e-07 0.5 + 0.747622 0.504725 0.43164 + 0.747622 0.504725 0.43164 + 0.747622 0.504725 0.43164 + 0.747622 0.504725 0.43164 + 0.747622 0.504725 0.43164 + 0.747622 0.504725 0.43164 + 0.425935 0.870693 0.245914 + 0.425935 0.870693 0.245914 + 0.425935 0.870693 0.245914 + 0.425935 0.870693 0.245914 + 0.425935 0.870693 0.245914 + 0.425935 0.870693 0.245914 + -0.00933862 0.999942 -0.00539172 + -0.00933862 0.999942 -0.00539172 + -0.00933862 0.999942 -0.00539172 + -0.00933862 0.999942 -0.00539172 + -0.00933862 0.999942 -0.00539172 + -0.439942 0.861356 -0.254001 + -0.439942 0.861356 -0.254001 + -0.439942 0.861356 -0.254001 + -0.439942 0.861356 -0.254001 + -0.439942 0.861356 -0.254001 + -0.439942 0.861356 -0.254001 + -0.439942 0.861356 -0.254001 + -0.752291 0.49539 -0.434335 + -0.752291 0.49539 -0.434335 + -0.752291 0.49539 -0.434335 + -0.752291 0.49539 -0.434335 + -0.752291 0.49539 -0.434335 + -0.752291 0.49539 -0.434335 + -0.793353 -4.604e-07 -0.608762 + -0.793353 -4.604e-07 -0.608762 + -0.793353 -4.604e-07 -0.608762 + -0.793353 -4.604e-07 -0.608762 + -0.793353 -4.604e-07 -0.608762 + -0.793353 -4.604e-07 -0.608762 + -0.689164 -0.495388 -0.528814 + -0.689164 -0.495388 -0.528814 + -0.689164 -0.495388 -0.528814 + -0.689164 -0.495388 -0.528814 + -0.689164 -0.495388 -0.528814 + -0.689164 -0.495388 -0.528814 + -0.403024 -0.861357 -0.309251 + -0.403024 -0.861357 -0.309251 + -0.403024 -0.861357 -0.309251 + -0.403024 -0.861357 -0.309251 + -0.403024 -0.861357 -0.309251 + -0.403024 -0.861357 -0.309251 + -0.00855607 -0.999942 -0.00656545 + -0.00855607 -0.999942 -0.00656545 + -0.00855607 -0.999942 -0.00656545 + -0.00855607 -0.999942 -0.00656545 + -0.00855607 -0.999942 -0.00656545 + 0.390193 -0.870693 0.299405 + 0.390193 -0.870693 0.299405 + 0.390193 -0.870693 0.299405 + 0.390193 -0.870693 0.299405 + 0.390193 -0.870693 0.299405 + 0.390193 -0.870693 0.299405 + 0.390193 -0.870693 0.299405 + 0.684888 -0.504722 0.525533 + 0.684888 -0.504722 0.525533 + 0.684888 -0.504722 0.525533 + 0.684888 -0.504722 0.525533 + 0.684888 -0.504722 0.525533 + 0.684888 -0.504722 0.525533 + 0.793354 -2.2733e-06 0.608761 + 0.793354 -2.2733e-06 0.608761 + 0.793354 -2.2733e-06 0.608761 + 0.793354 -2.2733e-06 0.608761 + 0.793354 -2.2733e-06 0.608761 + 0.793354 -2.2733e-06 0.608761 + 0.684888 0.504721 0.525533 + 0.684888 0.504721 0.525533 + 0.684888 0.504721 0.525533 + 0.684888 0.504721 0.525533 + 0.684888 0.504721 0.525533 + 0.684888 0.504721 0.525533 + 0.390193 0.870693 0.299405 + 0.390193 0.870693 0.299405 + 0.390193 0.870693 0.299405 + 0.390193 0.870693 0.299405 + 0.390193 0.870693 0.299405 + 0.390193 0.870693 0.299405 + 0.390193 0.870693 0.299405 + -0.00855577 0.999942 -0.00656527 + -0.00855577 0.999942 -0.00656527 + -0.00855577 0.999942 -0.00656527 + -0.00855577 0.999942 -0.00656527 + -0.00855577 0.999942 -0.00656527 + -0.403022 0.861358 -0.30925 + -0.403022 0.861358 -0.30925 + -0.403022 0.861358 -0.30925 + -0.403022 0.861358 -0.30925 + -0.403022 0.861358 -0.30925 + -0.403022 0.861358 -0.30925 + -0.689164 0.495388 -0.528814 + -0.689164 0.495388 -0.528814 + -0.689164 0.495388 -0.528814 + -0.689164 0.495388 -0.528814 + -0.689164 0.495388 -0.528814 + -0.689164 0.495388 -0.528814 + -0.707107 5.72003e-07 -0.707107 + -0.707107 5.72003e-07 -0.707107 + -0.707107 5.72003e-07 -0.707107 + -0.707107 5.72003e-07 -0.707107 + -0.614244 -0.495387 -0.614244 + -0.614244 -0.495387 -0.614244 + -0.614244 -0.495387 -0.614244 + -0.614244 -0.495387 -0.614244 + -0.614244 -0.495387 -0.614244 + -0.614244 -0.495387 -0.614244 + -0.614244 -0.495387 -0.614244 + -0.614244 -0.495387 -0.614244 + -0.359211 -0.861356 -0.359211 + -0.359211 -0.861356 -0.359211 + -0.359211 -0.861356 -0.359211 + -0.359211 -0.861356 -0.359211 + -0.00762492 -0.999942 -0.00762498 + -0.00762492 -0.999942 -0.00762498 + -0.00762492 -0.999942 -0.00762498 + -0.00762492 -0.999942 -0.00762498 + -0.00762492 -0.999942 -0.00762498 + -0.00762492 -0.999942 -0.00762498 + -0.00762492 -0.999942 -0.00762498 + -0.00762492 -0.999942 -0.00762498 + 0.347776 -0.870692 0.347776 + 0.347776 -0.870692 0.347776 + 0.347776 -0.870692 0.347776 + 0.347776 -0.870692 0.347776 + 0.347776 -0.870692 0.347776 + 0.347776 -0.870692 0.347776 + 0.610433 -0.504721 0.610433 + 0.610433 -0.504721 0.610433 + 0.610433 -0.504721 0.610433 + 0.610433 -0.504721 0.610433 + 0.707107 1.62678e-06 0.707107 + 0.707107 1.62678e-06 0.707107 + 0.707107 1.62678e-06 0.707107 + 0.707107 1.62678e-06 0.707107 + 0.707107 1.62678e-06 0.707107 + 0.707107 1.62678e-06 0.707107 + 0.707107 1.62678e-06 0.707107 + 0.707107 1.62678e-06 0.707107 + 0.610432 0.504723 0.610432 + 0.610432 0.504723 0.610432 + 0.610432 0.504723 0.610432 + 0.610432 0.504723 0.610432 + 0.347775 0.870692 0.347775 + 0.347775 0.870692 0.347775 + 0.347775 0.870692 0.347775 + 0.347775 0.870692 0.347775 + 0.347775 0.870692 0.347775 + 0.347775 0.870692 0.347775 + -0.0076251 0.999942 -0.00762516 + -0.0076251 0.999942 -0.00762516 + -0.0076251 0.999942 -0.00762516 + -0.0076251 0.999942 -0.00762516 + -0.0076251 0.999942 -0.00762516 + -0.0076251 0.999942 -0.00762516 + -0.0076251 0.999942 -0.00762516 + -0.0076251 0.999942 -0.00762516 + -0.359211 0.861357 -0.359211 + -0.359211 0.861357 -0.359211 + -0.359211 0.861357 -0.359211 + -0.359211 0.861357 -0.359211 + -0.614244 0.495389 -0.614243 + -0.614244 0.495389 -0.614243 + -0.614244 0.495389 -0.614243 + -0.614244 0.495389 -0.614243 + -0.614244 0.495389 -0.614243 + -0.614244 0.495389 -0.614243 + -0.614244 0.495389 -0.614243 + -0.614244 0.495389 -0.614243 + -0.608762 3.0341e-07 -0.793353 + -0.608762 3.0341e-07 -0.793353 + -0.608762 3.0341e-07 -0.793353 + -0.608762 3.0341e-07 -0.793353 + -0.608762 3.0341e-07 -0.793353 + -0.608762 3.0341e-07 -0.793353 + -0.528814 -0.495388 -0.689164 + -0.528814 -0.495388 -0.689164 + -0.528814 -0.495388 -0.689164 + -0.528814 -0.495388 -0.689164 + -0.528814 -0.495388 -0.689164 + -0.528814 -0.495388 -0.689164 + -0.309251 -0.861357 -0.403024 + -0.309251 -0.861357 -0.403024 + -0.309251 -0.861357 -0.403024 + -0.309251 -0.861357 -0.403024 + -0.309251 -0.861357 -0.403024 + -0.309251 -0.861357 -0.403024 + -0.00656545 -0.999942 -0.00855619 + -0.00656545 -0.999942 -0.00855619 + -0.00656545 -0.999942 -0.00855619 + -0.00656545 -0.999942 -0.00855619 + -0.00656545 -0.999942 -0.00855619 + 0.299405 -0.870693 0.390193 + 0.299405 -0.870693 0.390193 + 0.299405 -0.870693 0.390193 + 0.299405 -0.870693 0.390193 + 0.299405 -0.870693 0.390193 + 0.299405 -0.870693 0.390193 + 0.299405 -0.870693 0.390193 + 0.525533 -0.504722 0.684888 + 0.525533 -0.504722 0.684888 + 0.525533 -0.504722 0.684888 + 0.525533 -0.504722 0.684888 + 0.525533 -0.504722 0.684888 + 0.525533 -0.504722 0.684888 + 0.608761 6.33128e-07 0.793354 + 0.608761 6.33128e-07 0.793354 + 0.608761 6.33128e-07 0.793354 + 0.608761 6.33128e-07 0.793354 + 0.608761 6.33128e-07 0.793354 + 0.608761 6.33128e-07 0.793354 + 0.525533 0.504723 0.684887 + 0.525533 0.504723 0.684887 + 0.525533 0.504723 0.684887 + 0.525533 0.504723 0.684887 + 0.525533 0.504723 0.684887 + 0.525533 0.504723 0.684887 + 0.299405 0.870693 0.390193 + 0.299405 0.870693 0.390193 + 0.299405 0.870693 0.390193 + 0.299405 0.870693 0.390193 + 0.299405 0.870693 0.390193 + 0.299405 0.870693 0.390193 + 0.299405 0.870693 0.390193 + -0.00656539 0.999942 -0.00855613 + -0.00656539 0.999942 -0.00855613 + -0.00656539 0.999942 -0.00855613 + -0.00656539 0.999942 -0.00855613 + -0.00656539 0.999942 -0.00855613 + -0.309251 0.861357 -0.403024 + -0.309251 0.861357 -0.403024 + -0.309251 0.861357 -0.403024 + -0.309251 0.861357 -0.403024 + -0.309251 0.861357 -0.403024 + -0.309251 0.861357 -0.403024 + -0.528814 0.495388 -0.689164 + -0.528814 0.495388 -0.689164 + -0.528814 0.495388 -0.689164 + -0.528814 0.495388 -0.689164 + -0.528814 0.495388 -0.689164 + -0.528814 0.495388 -0.689164 + -0.500001 9.79865e-07 -0.866025 + -0.500001 9.79865e-07 -0.866025 + -0.500001 9.79865e-07 -0.866025 + -0.500001 9.79865e-07 -0.866025 + -0.500001 9.79865e-07 -0.866025 + -0.500001 9.79865e-07 -0.866025 + -0.434336 -0.495388 -0.752292 + -0.434336 -0.495388 -0.752292 + -0.434336 -0.495388 -0.752292 + -0.434336 -0.495388 -0.752292 + -0.434336 -0.495388 -0.752292 + -0.434336 -0.495388 -0.752292 + -0.253999 -0.861358 -0.439939 + -0.253999 -0.861358 -0.439939 + -0.253999 -0.861358 -0.439939 + -0.253999 -0.861358 -0.439939 + -0.253999 -0.861358 -0.439939 + -0.253999 -0.861358 -0.439939 + -0.00539124 -0.999942 -0.00933814 + -0.00539124 -0.999942 -0.00933814 + -0.00539124 -0.999942 -0.00933814 + -0.00539124 -0.999942 -0.00933814 + -0.00539124 -0.999942 -0.00933814 + -0.00539124 -0.999942 -0.00933814 + -0.00539124 -0.999942 -0.00933814 + 0.245914 -0.870693 0.425934 + 0.245914 -0.870693 0.425934 + 0.245914 -0.870693 0.425934 + 0.245914 -0.870693 0.425934 + 0.245914 -0.870693 0.425934 + 0.431641 -0.504725 0.747623 + 0.431641 -0.504725 0.747623 + 0.431641 -0.504725 0.747623 + 0.431641 -0.504725 0.747623 + 0.431641 -0.504725 0.747623 + 0.431641 -0.504725 0.747623 + 0.5 7.07972e-07 0.866025 + 0.5 7.07972e-07 0.866025 + 0.5 7.07972e-07 0.866025 + 0.5 7.07972e-07 0.866025 + 0.5 7.07972e-07 0.866025 + 0.5 7.07972e-07 0.866025 + 0.431641 0.504726 0.747622 + 0.431641 0.504726 0.747622 + 0.431641 0.504726 0.747622 + 0.431641 0.504726 0.747622 + 0.431641 0.504726 0.747622 + 0.431641 0.504726 0.747622 + 0.245914 0.870693 0.425934 + 0.245914 0.870693 0.425934 + 0.245914 0.870693 0.425934 + 0.245914 0.870693 0.425934 + 0.245914 0.870693 0.425934 + -0.00539118 0.999942 -0.00933814 + -0.00539118 0.999942 -0.00933814 + -0.00539118 0.999942 -0.00933814 + -0.00539118 0.999942 -0.00933814 + -0.00539118 0.999942 -0.00933814 + -0.00539118 0.999942 -0.00933814 + -0.00539118 0.999942 -0.00933814 + -0.253999 0.861358 -0.439939 + -0.253999 0.861358 -0.439939 + -0.253999 0.861358 -0.439939 + -0.253999 0.861358 -0.439939 + -0.253999 0.861358 -0.439939 + -0.253999 0.861358 -0.439939 + -0.434336 0.495389 -0.752291 + -0.434336 0.495389 -0.752291 + -0.434336 0.495389 -0.752291 + -0.434336 0.495389 -0.752291 + -0.434336 0.495389 -0.752291 + -0.434336 0.495389 -0.752291 + -0.382683 8.69507e-07 -0.92388 + -0.382683 8.69507e-07 -0.92388 + -0.382683 8.69507e-07 -0.92388 + -0.382683 8.69507e-07 -0.92388 + -0.382683 8.69507e-07 -0.92388 + -0.382683 8.69507e-07 -0.92388 + -0.382683 8.69507e-07 -0.92388 + -0.382683 8.69507e-07 -0.92388 + -0.332426 -0.495388 -0.802548 + -0.332426 -0.495388 -0.802548 + -0.332426 -0.495388 -0.802548 + -0.332426 -0.495388 -0.802548 + -0.332426 -0.495388 -0.802548 + -0.194404 -0.861356 -0.469332 + -0.194404 -0.861356 -0.469332 + -0.194404 -0.861356 -0.469332 + -0.194404 -0.861356 -0.469332 + -0.194404 -0.861356 -0.469332 + -0.194404 -0.861356 -0.469332 + -0.00412649 -0.999942 -0.00996226 + -0.00412649 -0.999942 -0.00996226 + -0.00412649 -0.999942 -0.00996226 + -0.00412649 -0.999942 -0.00996226 + -0.00412649 -0.999942 -0.00996226 + 0.188215 -0.870693 0.45439 + 0.188215 -0.870693 0.45439 + 0.188215 -0.870693 0.45439 + 0.188215 -0.870693 0.45439 + 0.188215 -0.870693 0.45439 + 0.188215 -0.870693 0.45439 + 0.330364 -0.504722 0.797569 + 0.330364 -0.504722 0.797569 + 0.330364 -0.504722 0.797569 + 0.330364 -0.504722 0.797569 + 0.330364 -0.504722 0.797569 + 0.330364 -0.504722 0.797569 + 0.330364 -0.504722 0.797569 + 0.330364 -0.504722 0.797569 + 0.382683 3.06676e-07 0.92388 + 0.382683 3.06676e-07 0.92388 + 0.382683 3.06676e-07 0.92388 + 0.382683 3.06676e-07 0.92388 + 0.330364 0.504722 0.797569 + 0.330364 0.504722 0.797569 + 0.330364 0.504722 0.797569 + 0.330364 0.504722 0.797569 + 0.330364 0.504722 0.797569 + 0.330364 0.504722 0.797569 + 0.330364 0.504722 0.797569 + 0.330364 0.504722 0.797569 + 0.188215 0.870692 0.45439 + 0.188215 0.870692 0.45439 + 0.188215 0.870692 0.45439 + 0.188215 0.870692 0.45439 + 0.188215 0.870692 0.45439 + -0.00412655 0.999942 -0.00996238 + -0.00412655 0.999942 -0.00996238 + -0.00412655 0.999942 -0.00996238 + -0.00412655 0.999942 -0.00996238 + -0.00412655 0.999942 -0.00996238 + -0.00412655 0.999942 -0.00996238 + -0.194404 0.861356 -0.469332 + -0.194404 0.861356 -0.469332 + -0.194404 0.861356 -0.469332 + -0.194404 0.861356 -0.469332 + -0.194404 0.861356 -0.469332 + -0.194404 0.861356 -0.469332 + -0.332426 0.495388 -0.802548 + -0.332426 0.495388 -0.802548 + -0.332426 0.495388 -0.802548 + -0.332426 0.495388 -0.802548 + -0.332426 0.495388 -0.802548 + -0.258819 -5.14492e-07 -0.965926 + -0.258819 -5.14492e-07 -0.965926 + -0.258819 -5.14492e-07 -0.965926 + -0.258819 -5.14492e-07 -0.965926 + -0.258819 -5.14492e-07 -0.965926 + -0.224829 -0.495389 -0.839072 + -0.224829 -0.495389 -0.839072 + -0.224829 -0.495389 -0.839072 + -0.224829 -0.495389 -0.839072 + -0.224829 -0.495389 -0.839072 + -0.224829 -0.495389 -0.839072 + -0.224829 -0.495389 -0.839072 + -0.131481 -0.861356 -0.490692 + -0.131481 -0.861356 -0.490692 + -0.131481 -0.861356 -0.490692 + -0.131481 -0.861356 -0.490692 + -0.131481 -0.861356 -0.490692 + -0.131481 -0.861356 -0.490692 + -0.00279057 -0.999942 -0.0104151 + -0.00279057 -0.999942 -0.0104151 + -0.00279057 -0.999942 -0.0104151 + -0.00279057 -0.999942 -0.0104151 + -0.00279057 -0.999942 -0.0104151 + -0.00279057 -0.999942 -0.0104151 + 0.127294 -0.870693 0.475068 + 0.127294 -0.870693 0.475068 + 0.127294 -0.870693 0.475068 + 0.127294 -0.870693 0.475068 + 0.127294 -0.870693 0.475068 + 0.127294 -0.870693 0.475068 + 0.127294 -0.870693 0.475068 + 0.223433 -0.504726 0.833865 + 0.223433 -0.504726 0.833865 + 0.223433 -0.504726 0.833865 + 0.223433 -0.504726 0.833865 + 0.258819 8.71046e-07 0.965926 + 0.258819 8.71046e-07 0.965926 + 0.258819 8.71046e-07 0.965926 + 0.258819 8.71046e-07 0.965926 + 0.258819 8.71046e-07 0.965926 + 0.258819 8.71046e-07 0.965926 + 0.258819 8.71046e-07 0.965926 + 0.223433 0.504726 0.833864 + 0.223433 0.504726 0.833864 + 0.223433 0.504726 0.833864 + 0.223433 0.504726 0.833864 + 0.223433 0.504726 0.833864 + 0.127294 0.870693 0.475068 + 0.127294 0.870693 0.475068 + 0.127294 0.870693 0.475068 + 0.127294 0.870693 0.475068 + 0.127294 0.870693 0.475068 + 0.127294 0.870693 0.475068 + 0.127294 0.870693 0.475068 + 0.127294 0.870693 0.475068 + -0.00279093 0.999942 -0.0104155 + -0.00279093 0.999942 -0.0104155 + -0.00279093 0.999942 -0.0104155 + -0.00279093 0.999942 -0.0104155 + -0.00279093 0.999942 -0.0104155 + -0.131481 0.861355 -0.490694 + -0.131481 0.861355 -0.490694 + -0.131481 0.861355 -0.490694 + -0.131481 0.861355 -0.490694 + -0.131481 0.861355 -0.490694 + -0.131481 0.861355 -0.490694 + -0.224829 0.495387 -0.839073 + -0.224829 0.495387 -0.839073 + -0.224829 0.495387 -0.839073 + -0.224829 0.495387 -0.839073 + -0.224829 0.495387 -0.839073 + -0.224829 0.495387 -0.839073 + -0.130526 -3.38228e-07 -0.991445 + -0.130526 -3.38228e-07 -0.991445 + -0.130526 -3.38228e-07 -0.991445 + -0.130526 -3.38228e-07 -0.991445 + -0.130526 -3.38228e-07 -0.991445 + -0.113384 -0.49539 -0.861239 + -0.113384 -0.49539 -0.861239 + -0.113384 -0.49539 -0.861239 + -0.113384 -0.49539 -0.861239 + -0.113384 -0.49539 -0.861239 + -0.113384 -0.49539 -0.861239 + -0.0663072 -0.861358 -0.503653 + -0.0663072 -0.861358 -0.503653 + -0.0663072 -0.861358 -0.503653 + -0.0663072 -0.861358 -0.503653 + -0.0663072 -0.861358 -0.503653 + -0.0663072 -0.861358 -0.503653 + -0.0014075 -0.999942 -0.0106911 + -0.0014075 -0.999942 -0.0106911 + -0.0014075 -0.999942 -0.0106911 + -0.0014075 -0.999942 -0.0106911 + -0.0014075 -0.999942 -0.0106911 + -0.0014075 -0.999942 -0.0106911 + 0.0641959 -0.870694 0.487618 + 0.0641959 -0.870694 0.487618 + 0.0641959 -0.870694 0.487618 + 0.0641959 -0.870694 0.487618 + 0.0641959 -0.870694 0.487618 + 0.0641959 -0.870694 0.487618 + 0.112681 -0.504722 0.855896 + 0.112681 -0.504722 0.855896 + 0.112681 -0.504722 0.855896 + 0.112681 -0.504722 0.855896 + 0.112681 -0.504722 0.855896 + 0.112681 -0.504722 0.855896 + 0.130526 2.82975e-06 0.991445 + 0.130526 2.82975e-06 0.991445 + 0.130526 2.82975e-06 0.991445 + 0.130526 2.82975e-06 0.991445 + 0.130526 2.82975e-06 0.991445 + 0.130526 2.82975e-06 0.991445 + 0.112681 0.504722 0.855896 + 0.112681 0.504722 0.855896 + 0.112681 0.504722 0.855896 + 0.112681 0.504722 0.855896 + 0.112681 0.504722 0.855896 + 0.112681 0.504722 0.855896 + 0.0641958 0.870693 0.487619 + 0.0641958 0.870693 0.487619 + 0.0641958 0.870693 0.487619 + 0.0641958 0.870693 0.487619 + 0.0641958 0.870693 0.487619 + 0.0641958 0.870693 0.487619 + -0.0014075 0.999942 -0.0106909 + -0.0014075 0.999942 -0.0106909 + -0.0014075 0.999942 -0.0106909 + -0.0014075 0.999942 -0.0106909 + -0.0014075 0.999942 -0.0106909 + -0.0014075 0.999942 -0.0106909 + -0.0663072 0.861357 -0.503654 + -0.0663072 0.861357 -0.503654 + -0.0663072 0.861357 -0.503654 + -0.0663072 0.861357 -0.503654 + -0.0663072 0.861357 -0.503654 + -0.0663072 0.861357 -0.503654 + -0.113384 0.495387 -0.861241 + -0.113384 0.495387 -0.861241 + -0.113384 0.495387 -0.861241 + -0.113384 0.495387 -0.861241 + -0.113384 0.495387 -0.861241 + -0.113384 0.495387 -0.861241 + -0.113384 0.495387 -0.861241 + 0 -1.07469e-06 -1 + 0 -1.07469e-06 -1 + 0 -1.07469e-06 -1 + 0 -1.07469e-06 -1 + 0 -1.07469e-06 -1 + 0 -1.07469e-06 -1 + 0 -1.07469e-06 -1 + 0 -1.07469e-06 -1 + 0 -0.495389 -0.868671 + 0 -0.495389 -0.868671 + 0 -0.495389 -0.868671 + 0 -0.495389 -0.868671 + 0 -0.861355 -0.508004 + 0 -0.861355 -0.508004 + 0 -0.861355 -0.508004 + 0 -0.861355 -0.508004 + 0 -0.861355 -0.508004 + 0 -0.861355 -0.508004 + 0 -0.861355 -0.508004 + 0 -0.861355 -0.508004 + 0 -0.999942 -0.0107829 + 0 -0.999942 -0.0107829 + 0 -0.999942 -0.0107829 + 0 -0.999942 -0.0107829 + 0 -0.999942 -0.0107829 + 0 -0.999942 -0.0107829 + 0 -0.870692 0.491829 + 0 -0.870692 0.491829 + 0 -0.870692 0.491829 + 0 -0.870692 0.491829 + 0 -0.504723 0.863282 + 0 -0.504723 0.863282 + 0 -0.504723 0.863282 + 0 -0.504723 0.863282 + 0 -0.504723 0.863282 + 0 -0.504723 0.863282 + 0 -0.504723 0.863282 + 0 -0.504723 0.863282 + 0 -1.44211e-07 1 + 0 -1.44211e-07 1 + 0 -1.44211e-07 1 + 0 -1.44211e-07 1 + 0 -1.44211e-07 1 + 0 -1.44211e-07 1 + 0 0.504723 0.863282 + 0 0.504723 0.863282 + 0 0.504723 0.863282 + 0 0.504723 0.863282 + 0 0.504723 0.863282 + 0 0.504723 0.863282 + 0 0.870693 0.491827 + 0 0.870693 0.491827 + 0 0.870693 0.491827 + 0 0.870693 0.491827 + 0 0.999942 -0.0107829 + 0 0.999942 -0.0107829 + 0 0.999942 -0.0107829 + 0 0.999942 -0.0107829 + 0 0.999942 -0.0107829 + 0 0.999942 -0.0107829 + 0 0.861356 -0.508002 + 0 0.861356 -0.508002 + 0 0.861356 -0.508002 + 0 0.861356 -0.508002 + 0 0.861356 -0.508002 + 0 0.861356 -0.508002 + 0 0.861356 -0.508002 + 0 0.861356 -0.508002 + 0 0.495388 -0.868672 + 0 0.495388 -0.868672 + 0 0.495388 -0.868672 + 0 0.495388 -0.868672 + 0.130526 0 -0.991445 + 0.130526 0 -0.991445 + 0.130526 0 -0.991445 + 0.130526 0 -0.991445 + 0.130526 0 -0.991445 + 0.130526 0 -0.991445 + 0.113384 -0.49539 -0.861239 + 0.113384 -0.49539 -0.861239 + 0.113384 -0.49539 -0.861239 + 0.113384 -0.49539 -0.861239 + 0.113384 -0.49539 -0.861239 + 0.113384 -0.49539 -0.861239 + 0.0663072 -0.861358 -0.503652 + 0.0663072 -0.861358 -0.503652 + 0.0663072 -0.861358 -0.503652 + 0.0663072 -0.861358 -0.503652 + 0.0663072 -0.861358 -0.503652 + 0.0663072 -0.861358 -0.503652 + 0.00140756 -0.999942 -0.0106913 + 0.00140756 -0.999942 -0.0106913 + 0.00140756 -0.999942 -0.0106913 + 0.00140756 -0.999942 -0.0106913 + 0.00140756 -0.999942 -0.0106913 + 0.00140756 -0.999942 -0.0106913 + -0.0641958 -0.870694 0.487618 + -0.0641958 -0.870694 0.487618 + -0.0641958 -0.870694 0.487618 + -0.0641958 -0.870694 0.487618 + -0.0641958 -0.870694 0.487618 + -0.0641958 -0.870694 0.487618 + -0.112681 -0.504722 0.855896 + -0.112681 -0.504722 0.855896 + -0.112681 -0.504722 0.855896 + -0.112681 -0.504722 0.855896 + -0.112681 -0.504722 0.855896 + -0.130526 2.7397e-06 0.991445 + -0.130526 2.7397e-06 0.991445 + -0.130526 2.7397e-06 0.991445 + -0.130526 2.7397e-06 0.991445 + -0.130526 2.7397e-06 0.991445 + -0.130526 2.7397e-06 0.991445 + -0.130526 2.7397e-06 0.991445 + -0.112681 0.504722 0.855897 + -0.112681 0.504722 0.855897 + -0.112681 0.504722 0.855897 + -0.112681 0.504722 0.855897 + -0.112681 0.504722 0.855897 + -0.0641958 0.870693 0.487619 + -0.0641958 0.870693 0.487619 + -0.0641958 0.870693 0.487619 + -0.0641958 0.870693 0.487619 + -0.0641958 0.870693 0.487619 + -0.0641958 0.870693 0.487619 + -0.0641958 0.870693 0.487619 + 0.0014075 0.999942 -0.010691 + 0.0014075 0.999942 -0.010691 + 0.0014075 0.999942 -0.010691 + 0.0014075 0.999942 -0.010691 + 0.0014075 0.999942 -0.010691 + 0.0014075 0.999942 -0.010691 + 0.0663072 0.861357 -0.503653 + 0.0663072 0.861357 -0.503653 + 0.0663072 0.861357 -0.503653 + 0.0663072 0.861357 -0.503653 + 0.0663072 0.861357 -0.503653 + 0.0663072 0.861357 -0.503653 + 0.113384 0.495387 -0.861241 + 0.113384 0.495387 -0.861241 + 0.113384 0.495387 -0.861241 + 0.113384 0.495387 -0.861241 + 0.113384 0.495387 -0.861241 + 0.113384 0.495387 -0.861241 + 0.258819 -6.205e-07 -0.965926 + 0.258819 -6.205e-07 -0.965926 + 0.258819 -6.205e-07 -0.965926 + 0.258819 -6.205e-07 -0.965926 + 0.258819 -6.205e-07 -0.965926 + 0.258819 -6.205e-07 -0.965926 + 0.224828 -0.495389 -0.839072 + 0.224828 -0.495389 -0.839072 + 0.224828 -0.495389 -0.839072 + 0.224828 -0.495389 -0.839072 + 0.224828 -0.495389 -0.839072 + 0.224828 -0.495389 -0.839072 + 0.13148 -0.861356 -0.490692 + 0.13148 -0.861356 -0.490692 + 0.13148 -0.861356 -0.490692 + 0.13148 -0.861356 -0.490692 + 0.13148 -0.861356 -0.490692 + 0.00279057 -0.999942 -0.0104151 + 0.00279057 -0.999942 -0.0104151 + 0.00279057 -0.999942 -0.0104151 + 0.00279057 -0.999942 -0.0104151 + 0.00279057 -0.999942 -0.0104151 + 0.00279057 -0.999942 -0.0104151 + 0.00279057 -0.999942 -0.0104151 + -0.127294 -0.870693 0.475068 + -0.127294 -0.870693 0.475068 + -0.127294 -0.870693 0.475068 + -0.127294 -0.870693 0.475068 + -0.127294 -0.870693 0.475068 + -0.127294 -0.870693 0.475068 + -0.127294 -0.870693 0.475068 + -0.223433 -0.504726 0.833864 + -0.223433 -0.504726 0.833864 + -0.223433 -0.504726 0.833864 + -0.223433 -0.504726 0.833864 + -0.223433 -0.504726 0.833864 + -0.258819 4.81616e-07 0.965926 + -0.258819 4.81616e-07 0.965926 + -0.258819 4.81616e-07 0.965926 + -0.258819 4.81616e-07 0.965926 + -0.258819 4.81616e-07 0.965926 + -0.258819 4.81616e-07 0.965926 + -0.223433 0.504726 0.833864 + -0.223433 0.504726 0.833864 + -0.223433 0.504726 0.833864 + -0.223433 0.504726 0.833864 + -0.223433 0.504726 0.833864 + -0.223433 0.504726 0.833864 + -0.127294 0.870693 0.475068 + -0.127294 0.870693 0.475068 + -0.127294 0.870693 0.475068 + -0.127294 0.870693 0.475068 + -0.127294 0.870693 0.475068 + -0.127294 0.870693 0.475068 + 0.00279105 0.999942 -0.0104156 + 0.00279105 0.999942 -0.0104156 + 0.00279105 0.999942 -0.0104156 + 0.00279105 0.999942 -0.0104156 + 0.00279105 0.999942 -0.0104156 + 0.00279105 0.999942 -0.0104156 + 0.00279105 0.999942 -0.0104156 + 0.131481 0.861355 -0.490693 + 0.131481 0.861355 -0.490693 + 0.131481 0.861355 -0.490693 + 0.131481 0.861355 -0.490693 + 0.224829 0.495388 -0.839073 + 0.224829 0.495388 -0.839073 + 0.224829 0.495388 -0.839073 + 0.224829 0.495388 -0.839073 + 0.224829 0.495388 -0.839073 + 0.224829 0.495388 -0.839073 + 0.224829 0.495388 -0.839073 + 0.382683 9.03081e-07 -0.92388 + 0.382683 9.03081e-07 -0.92388 + 0.382683 9.03081e-07 -0.92388 + 0.382683 9.03081e-07 -0.92388 + 0.382683 9.03081e-07 -0.92388 + 0.382683 9.03081e-07 -0.92388 + 0.332426 -0.495389 -0.802548 + 0.332426 -0.495389 -0.802548 + 0.332426 -0.495389 -0.802548 + 0.332426 -0.495389 -0.802548 + 0.332426 -0.495389 -0.802548 + 0.332426 -0.495389 -0.802548 + 0.194403 -0.861357 -0.469331 + 0.194403 -0.861357 -0.469331 + 0.194403 -0.861357 -0.469331 + 0.194403 -0.861357 -0.469331 + 0.194403 -0.861357 -0.469331 + 0.194403 -0.861357 -0.469331 + 0.194403 -0.861357 -0.469331 + 0.00412655 -0.999942 -0.00996232 + 0.00412655 -0.999942 -0.00996232 + 0.00412655 -0.999942 -0.00996232 + 0.00412655 -0.999942 -0.00996232 + 0.00412655 -0.999942 -0.00996232 + -0.188214 -0.870693 0.45439 + -0.188214 -0.870693 0.45439 + -0.188214 -0.870693 0.45439 + -0.188214 -0.870693 0.45439 + -0.188214 -0.870693 0.45439 + -0.188214 -0.870693 0.45439 + -0.330363 -0.504725 0.797567 + -0.330363 -0.504725 0.797567 + -0.330363 -0.504725 0.797567 + -0.330363 -0.504725 0.797567 + -0.330363 -0.504725 0.797567 + -0.330363 -0.504725 0.797567 + -0.382684 3.99471e-07 0.92388 + -0.382684 3.99471e-07 0.92388 + -0.382684 3.99471e-07 0.92388 + -0.382684 3.99471e-07 0.92388 + -0.382684 3.99471e-07 0.92388 + -0.382684 3.99471e-07 0.92388 + -0.330363 0.504726 0.797566 + -0.330363 0.504726 0.797566 + -0.330363 0.504726 0.797566 + -0.330363 0.504726 0.797566 + -0.330363 0.504726 0.797566 + -0.330363 0.504726 0.797566 + -0.188214 0.870693 0.45439 + -0.188214 0.870693 0.45439 + -0.188214 0.870693 0.45439 + -0.188214 0.870693 0.45439 + -0.188214 0.870693 0.45439 + -0.188214 0.870693 0.45439 + 0.00412637 0.999942 -0.00996214 + 0.00412637 0.999942 -0.00996214 + 0.00412637 0.999942 -0.00996214 + 0.00412637 0.999942 -0.00996214 + 0.00412637 0.999942 -0.00996214 + 0.194403 0.861357 -0.469331 + 0.194403 0.861357 -0.469331 + 0.194403 0.861357 -0.469331 + 0.194403 0.861357 -0.469331 + 0.194403 0.861357 -0.469331 + 0.194403 0.861357 -0.469331 + 0.194403 0.861357 -0.469331 + 0.194403 0.861357 -0.469331 + 0.332426 0.495389 -0.802548 + 0.332426 0.495389 -0.802548 + 0.332426 0.495389 -0.802548 + 0.332426 0.495389 -0.802548 + 0.332426 0.495389 -0.802548 + 0.5 4.93042e-07 -0.866026 + 0.5 4.93042e-07 -0.866026 + 0.5 4.93042e-07 -0.866026 + 0.5 4.93042e-07 -0.866026 + 0.5 4.93042e-07 -0.866026 + 0.5 4.93042e-07 -0.866026 + 0.434335 -0.49539 -0.752291 + 0.434335 -0.49539 -0.752291 + 0.434335 -0.49539 -0.752291 + 0.434335 -0.49539 -0.752291 + 0.434335 -0.49539 -0.752291 + 0.434335 -0.49539 -0.752291 + 0.254 -0.861357 -0.439941 + 0.254 -0.861357 -0.439941 + 0.254 -0.861357 -0.439941 + 0.254 -0.861357 -0.439941 + 0.254 -0.861357 -0.439941 + 0.254 -0.861357 -0.439941 + 0.0053913 -0.999942 -0.00933814 + 0.0053913 -0.999942 -0.00933814 + 0.0053913 -0.999942 -0.00933814 + 0.0053913 -0.999942 -0.00933814 + 0.0053913 -0.999942 -0.00933814 + 0.0053913 -0.999942 -0.00933814 + -0.245913 -0.870693 0.425934 + -0.245913 -0.870693 0.425934 + -0.245913 -0.870693 0.425934 + -0.245913 -0.870693 0.425934 + -0.245913 -0.870693 0.425934 + -0.43164 -0.504725 0.747623 + -0.43164 -0.504725 0.747623 + -0.43164 -0.504725 0.747623 + -0.43164 -0.504725 0.747623 + -0.43164 -0.504725 0.747623 + -0.43164 -0.504725 0.747623 + -0.43164 -0.504725 0.747623 + -0.43164 -0.504725 0.747623 + -0.499999 1.18776e-06 0.866026 + -0.499999 1.18776e-06 0.866026 + -0.499999 1.18776e-06 0.866026 + -0.499999 1.18776e-06 0.866026 + -0.43164 0.504726 0.747623 + -0.43164 0.504726 0.747623 + -0.43164 0.504726 0.747623 + -0.43164 0.504726 0.747623 + -0.43164 0.504726 0.747623 + -0.43164 0.504726 0.747623 + -0.43164 0.504726 0.747623 + -0.43164 0.504726 0.747623 + -0.245913 0.870693 0.425934 + -0.245913 0.870693 0.425934 + -0.245913 0.870693 0.425934 + -0.245913 0.870693 0.425934 + -0.245913 0.870693 0.425934 + 0.00539142 0.999942 -0.00933838 + 0.00539142 0.999942 -0.00933838 + 0.00539142 0.999942 -0.00933838 + 0.00539142 0.999942 -0.00933838 + 0.00539142 0.999942 -0.00933838 + 0.00539142 0.999942 -0.00933838 + 0.254 0.861357 -0.439942 + 0.254 0.861357 -0.439942 + 0.254 0.861357 -0.439942 + 0.254 0.861357 -0.439942 + 0.254 0.861357 -0.439942 + 0.254 0.861357 -0.439942 + 0.434335 0.49539 -0.752291 + 0.434335 0.49539 -0.752291 + 0.434335 0.49539 -0.752291 + 0.434335 0.49539 -0.752291 + 0.434335 0.49539 -0.752291 + 0.434335 0.49539 -0.752291 + 0.608762 3.75532e-07 -0.793353 + 0.608762 3.75532e-07 -0.793353 + 0.608762 3.75532e-07 -0.793353 + 0.608762 3.75532e-07 -0.793353 + 0.608762 3.75532e-07 -0.793353 + 0.608762 3.75532e-07 -0.793353 + 0.528814 -0.495387 -0.689164 + 0.528814 -0.495387 -0.689164 + 0.528814 -0.495387 -0.689164 + 0.528814 -0.495387 -0.689164 + 0.528814 -0.495387 -0.689164 + 0.528814 -0.495387 -0.689164 + 0.309251 -0.861357 -0.403024 + 0.309251 -0.861357 -0.403024 + 0.309251 -0.861357 -0.403024 + 0.309251 -0.861357 -0.403024 + 0.309251 -0.861357 -0.403024 + 0.309251 -0.861357 -0.403024 + 0.00656503 -0.999942 -0.00855553 + 0.00656503 -0.999942 -0.00855553 + 0.00656503 -0.999942 -0.00855553 + 0.00656503 -0.999942 -0.00855553 + 0.00656503 -0.999942 -0.00855553 + -0.299405 -0.870693 0.390193 + -0.299405 -0.870693 0.390193 + -0.299405 -0.870693 0.390193 + -0.299405 -0.870693 0.390193 + -0.299405 -0.870693 0.390193 + -0.299405 -0.870693 0.390193 + -0.299405 -0.870693 0.390193 + -0.525533 -0.504721 0.684888 + -0.525533 -0.504721 0.684888 + -0.525533 -0.504721 0.684888 + -0.525533 -0.504721 0.684888 + -0.525533 -0.504721 0.684888 + -0.525533 -0.504721 0.684888 + -0.608761 8.56746e-07 0.793353 + -0.608761 8.56746e-07 0.793353 + -0.608761 8.56746e-07 0.793353 + -0.608761 8.56746e-07 0.793353 + -0.608761 8.56746e-07 0.793353 + -0.608761 8.56746e-07 0.793353 + -0.525533 0.504722 0.684888 + -0.525533 0.504722 0.684888 + -0.525533 0.504722 0.684888 + -0.525533 0.504722 0.684888 + -0.525533 0.504722 0.684888 + -0.525533 0.504722 0.684888 + -0.299405 0.870693 0.390193 + -0.299405 0.870693 0.390193 + -0.299405 0.870693 0.390193 + -0.299405 0.870693 0.390193 + -0.299405 0.870693 0.390193 + -0.299405 0.870693 0.390193 + -0.299405 0.870693 0.390193 + 0.00656486 0.999942 -0.00855541 + 0.00656486 0.999942 -0.00855541 + 0.00656486 0.999942 -0.00855541 + 0.00656486 0.999942 -0.00855541 + 0.00656486 0.999942 -0.00855541 + 0.309251 0.861357 -0.403023 + 0.309251 0.861357 -0.403023 + 0.309251 0.861357 -0.403023 + 0.309251 0.861357 -0.403023 + 0.309251 0.861357 -0.403023 + 0.309251 0.861357 -0.403023 + 0.528814 0.495388 -0.689164 + 0.528814 0.495388 -0.689164 + 0.528814 0.495388 -0.689164 + 0.528814 0.495388 -0.689164 + 0.528814 0.495388 -0.689164 + 0.528814 0.495388 -0.689164 + 0.707106 6.11795e-07 -0.707107 + 0.707106 6.11795e-07 -0.707107 + 0.707106 6.11795e-07 -0.707107 + 0.707106 6.11795e-07 -0.707107 + 0.614244 -0.495387 -0.614244 + 0.614244 -0.495387 -0.614244 + 0.614244 -0.495387 -0.614244 + 0.614244 -0.495387 -0.614244 + 0.614244 -0.495387 -0.614244 + 0.614244 -0.495387 -0.614244 + 0.614244 -0.495387 -0.614244 + 0.614244 -0.495387 -0.614244 + 0.359211 -0.861356 -0.359212 + 0.359211 -0.861356 -0.359212 + 0.359211 -0.861356 -0.359212 + 0.359211 -0.861356 -0.359212 + 0.00762468 -0.999942 -0.00762474 + 0.00762468 -0.999942 -0.00762474 + 0.00762468 -0.999942 -0.00762474 + 0.00762468 -0.999942 -0.00762474 + 0.00762468 -0.999942 -0.00762474 + 0.00762468 -0.999942 -0.00762474 + 0.00762468 -0.999942 -0.00762474 + -0.347775 -0.870692 0.347775 + -0.347775 -0.870692 0.347775 + -0.347775 -0.870692 0.347775 + -0.347775 -0.870692 0.347775 + -0.347775 -0.870692 0.347775 + -0.347775 -0.870692 0.347775 + -0.347775 -0.870692 0.347775 + -0.610432 -0.504724 0.610432 + -0.610432 -0.504724 0.610432 + -0.610432 -0.504724 0.610432 + -0.610432 -0.504724 0.610432 + -0.707107 1.51726e-06 0.707107 + -0.707107 1.51726e-06 0.707107 + -0.707107 1.51726e-06 0.707107 + -0.707107 1.51726e-06 0.707107 + -0.707107 1.51726e-06 0.707107 + -0.707107 1.51726e-06 0.707107 + -0.707107 1.51726e-06 0.707107 + -0.707107 1.51726e-06 0.707107 + -0.610431 0.504726 0.610431 + -0.610431 0.504726 0.610431 + -0.610431 0.504726 0.610431 + -0.610431 0.504726 0.610431 + -0.347775 0.870693 0.347775 + -0.347775 0.870693 0.347775 + -0.347775 0.870693 0.347775 + -0.347775 0.870693 0.347775 + -0.347775 0.870693 0.347775 + -0.347775 0.870693 0.347775 + -0.347775 0.870693 0.347775 + 0.00762492 0.999942 -0.00762492 + 0.00762492 0.999942 -0.00762492 + 0.00762492 0.999942 -0.00762492 + 0.00762492 0.999942 -0.00762492 + 0.00762492 0.999942 -0.00762492 + 0.00762492 0.999942 -0.00762492 + 0.00762492 0.999942 -0.00762492 + 0.359211 0.861356 -0.359211 + 0.359211 0.861356 -0.359211 + 0.359211 0.861356 -0.359211 + 0.359211 0.861356 -0.359211 + 0.614244 0.495388 -0.614244 + 0.614244 0.495388 -0.614244 + 0.614244 0.495388 -0.614244 + 0.614244 0.495388 -0.614244 + 0.614244 0.495388 -0.614244 + 0.614244 0.495388 -0.614244 + 0.614244 0.495388 -0.614244 + 0.614244 0.495388 -0.614244 + 0.793353 -9.79867e-07 -0.608762 + 0.793353 -9.79867e-07 -0.608762 + 0.793353 -9.79867e-07 -0.608762 + 0.793353 -9.79867e-07 -0.608762 + 0.793353 -9.79867e-07 -0.608762 + 0.793353 -9.79867e-07 -0.608762 + 0.689163 -0.49539 -0.528813 + 0.689163 -0.49539 -0.528813 + 0.689163 -0.49539 -0.528813 + 0.689163 -0.49539 -0.528813 + 0.689163 -0.49539 -0.528813 + 0.689163 -0.49539 -0.528813 + 0.403025 -0.861356 -0.309252 + 0.403025 -0.861356 -0.309252 + 0.403025 -0.861356 -0.309252 + 0.403025 -0.861356 -0.309252 + 0.403025 -0.861356 -0.309252 + 0.403025 -0.861356 -0.309252 + 0.00855619 -0.999942 -0.00656539 + 0.00855619 -0.999942 -0.00656539 + 0.00855619 -0.999942 -0.00656539 + 0.00855619 -0.999942 -0.00656539 + 0.00855619 -0.999942 -0.00656539 + 0.00855619 -0.999942 -0.00656539 + -0.390193 -0.870692 0.299406 + -0.390193 -0.870692 0.299406 + -0.390193 -0.870692 0.299406 + -0.390193 -0.870692 0.299406 + -0.390193 -0.870692 0.299406 + -0.390193 -0.870692 0.299406 + -0.684886 -0.504726 0.525531 + -0.684886 -0.504726 0.525531 + -0.684886 -0.504726 0.525531 + -0.684886 -0.504726 0.525531 + -0.684886 -0.504726 0.525531 + -0.684886 -0.504726 0.525531 + -0.684886 -0.504726 0.525531 + -0.793353 -4.76444e-06 0.608761 + -0.793353 -4.76444e-06 0.608761 + -0.793353 -4.76444e-06 0.608761 + -0.793353 -4.76444e-06 0.608761 + -0.793353 -4.76444e-06 0.608761 + -0.684887 0.504723 0.525532 + -0.684887 0.504723 0.525532 + -0.684887 0.504723 0.525532 + -0.684887 0.504723 0.525532 + -0.684887 0.504723 0.525532 + -0.684887 0.504723 0.525532 + -0.390193 0.870693 0.299405 + -0.390193 0.870693 0.299405 + -0.390193 0.870693 0.299405 + -0.390193 0.870693 0.299405 + -0.390193 0.870693 0.299405 + -0.390193 0.870693 0.299405 + 0.00855529 0.999942 -0.00656468 + 0.00855529 0.999942 -0.00656468 + 0.00855529 0.999942 -0.00656468 + 0.00855529 0.999942 -0.00656468 + 0.00855529 0.999942 -0.00656468 + 0.403025 0.861356 -0.309252 + 0.403025 0.861356 -0.309252 + 0.403025 0.861356 -0.309252 + 0.403025 0.861356 -0.309252 + 0.403025 0.861356 -0.309252 + 0.403025 0.861356 -0.309252 + 0.403025 0.861356 -0.309252 + 0.689164 0.495388 -0.528814 + 0.689164 0.495388 -0.528814 + 0.689164 0.495388 -0.528814 + 0.689164 0.495388 -0.528814 + 0.689164 0.495388 -0.528814 + 0.689164 0.495388 -0.528814 + 0.866025 5.27237e-07 -0.5 + 0.866025 5.27237e-07 -0.5 + 0.866025 5.27237e-07 -0.5 + 0.866025 5.27237e-07 -0.5 + 0.866025 5.27237e-07 -0.5 + 0.866025 5.27237e-07 -0.5 + 0.752292 -0.495388 -0.434336 + 0.752292 -0.495388 -0.434336 + 0.752292 -0.495388 -0.434336 + 0.752292 -0.495388 -0.434336 + 0.752292 -0.495388 -0.434336 + 0.752292 -0.495388 -0.434336 + 0.43994 -0.861358 -0.254 + 0.43994 -0.861358 -0.254 + 0.43994 -0.861358 -0.254 + 0.43994 -0.861358 -0.254 + 0.43994 -0.861358 -0.254 + 0.43994 -0.861358 -0.254 + 0.00933939 -0.999942 -0.00539195 + 0.00933939 -0.999942 -0.00539195 + 0.00933939 -0.999942 -0.00539195 + 0.00933939 -0.999942 -0.00539195 + 0.00933939 -0.999942 -0.00539195 + 0.00933939 -0.999942 -0.00539195 + -0.425934 -0.870694 0.245913 + -0.425934 -0.870694 0.245913 + -0.425934 -0.870694 0.245913 + -0.425934 -0.870694 0.245913 + -0.425934 -0.870694 0.245913 + -0.425934 -0.870694 0.245913 + -0.747624 -0.504723 0.431641 + -0.747624 -0.504723 0.431641 + -0.747624 -0.504723 0.431641 + -0.747624 -0.504723 0.431641 + -0.747624 -0.504723 0.431641 + -0.866025 1.92616e-06 0.5 + -0.866025 1.92616e-06 0.5 + -0.866025 1.92616e-06 0.5 + -0.866025 1.92616e-06 0.5 + -0.866025 1.92616e-06 0.5 + -0.866025 1.92616e-06 0.5 + -0.866025 1.92616e-06 0.5 + -0.747623 0.504724 0.431641 + -0.747623 0.504724 0.431641 + -0.747623 0.504724 0.431641 + -0.747623 0.504724 0.431641 + -0.747623 0.504724 0.431641 + -0.747623 0.504724 0.431641 + -0.425934 0.870694 0.245913 + -0.425934 0.870694 0.245913 + -0.425934 0.870694 0.245913 + -0.425934 0.870694 0.245913 + -0.425934 0.870694 0.245913 + -0.425934 0.870694 0.245913 + 0.00934052 0.999942 -0.00539267 + 0.00934052 0.999942 -0.00539267 + 0.00934052 0.999942 -0.00539267 + 0.00934052 0.999942 -0.00539267 + 0.00934052 0.999942 -0.00539267 + 0.00934052 0.999942 -0.00539267 + 0.00934052 0.999942 -0.00539267 + 0.43994 0.861358 -0.254 + 0.43994 0.861358 -0.254 + 0.43994 0.861358 -0.254 + 0.43994 0.861358 -0.254 + 0.43994 0.861358 -0.254 + 0.752291 0.49539 -0.434336 + 0.752291 0.49539 -0.434336 + 0.752291 0.49539 -0.434336 + 0.752291 0.49539 -0.434336 + 0.752291 0.49539 -0.434336 + 0.752291 0.49539 -0.434336 + 0.92388 3.6745e-07 -0.382683 + 0.92388 3.6745e-07 -0.382683 + 0.92388 3.6745e-07 -0.382683 + 0.92388 3.6745e-07 -0.382683 + 0.92388 3.6745e-07 -0.382683 + 0.92388 3.6745e-07 -0.382683 + 0.92388 3.6745e-07 -0.382683 + 0.92388 3.6745e-07 -0.382683 + 0.802548 -0.495388 -0.332426 + 0.802548 -0.495388 -0.332426 + 0.802548 -0.495388 -0.332426 + 0.802548 -0.495388 -0.332426 + 0.469331 -0.861357 -0.194404 + 0.469331 -0.861357 -0.194404 + 0.469331 -0.861357 -0.194404 + 0.469331 -0.861357 -0.194404 + 0.469331 -0.861357 -0.194404 + 0.469331 -0.861357 -0.194404 + 0.469331 -0.861357 -0.194404 + 0.00996083 -0.999942 -0.00412595 + 0.00996083 -0.999942 -0.00412595 + 0.00996083 -0.999942 -0.00412595 + 0.00996083 -0.999942 -0.00412595 + 0.00996083 -0.999942 -0.00412595 + 0.00996083 -0.999942 -0.00412595 + -0.454388 -0.870693 0.188214 + -0.454388 -0.870693 0.188214 + -0.454388 -0.870693 0.188214 + -0.454388 -0.870693 0.188214 + -0.454388 -0.870693 0.188214 + -0.454388 -0.870693 0.188214 + -0.797567 -0.504725 0.330363 + -0.797567 -0.504725 0.330363 + -0.797567 -0.504725 0.330363 + -0.797567 -0.504725 0.330363 + -0.797567 -0.504725 0.330363 + -0.797567 -0.504725 0.330363 + -0.923879 1.80507e-06 0.382684 + -0.923879 1.80507e-06 0.382684 + -0.923879 1.80507e-06 0.382684 + -0.923879 1.80507e-06 0.382684 + -0.923879 1.80507e-06 0.382684 + -0.923879 1.80507e-06 0.382684 + -0.797567 0.504726 0.330363 + -0.797567 0.504726 0.330363 + -0.797567 0.504726 0.330363 + -0.797567 0.504726 0.330363 + -0.797567 0.504726 0.330363 + -0.797567 0.504726 0.330363 + -0.45439 0.870693 0.188215 + -0.45439 0.870693 0.188215 + -0.45439 0.870693 0.188215 + -0.45439 0.870693 0.188215 + -0.45439 0.870693 0.188215 + -0.45439 0.870693 0.188215 + 0.00996143 0.999942 -0.00412607 + 0.00996143 0.999942 -0.00412607 + 0.00996143 0.999942 -0.00412607 + 0.00996143 0.999942 -0.00412607 + 0.00996143 0.999942 -0.00412607 + 0.00996143 0.999942 -0.00412607 + 0.469331 0.861357 -0.194404 + 0.469331 0.861357 -0.194404 + 0.469331 0.861357 -0.194404 + 0.469331 0.861357 -0.194404 + 0.469331 0.861357 -0.194404 + 0.469331 0.861357 -0.194404 + 0.469331 0.861357 -0.194404 + 0.802548 0.495388 -0.332426 + 0.802548 0.495388 -0.332426 + 0.802548 0.495388 -0.332426 + 0.802548 0.495388 -0.332426 + 0.965926 6.18324e-07 -0.25882 + 0.965926 6.18324e-07 -0.25882 + 0.965926 6.18324e-07 -0.25882 + 0.965926 6.18324e-07 -0.25882 + 0.965926 6.18324e-07 -0.25882 + 0.965926 6.18324e-07 -0.25882 + 0.839071 -0.495391 -0.224829 + 0.839071 -0.495391 -0.224829 + 0.839071 -0.495391 -0.224829 + 0.839071 -0.495391 -0.224829 + 0.839071 -0.495391 -0.224829 + 0.839071 -0.495391 -0.224829 + 0.490691 -0.861357 -0.131481 + 0.490691 -0.861357 -0.131481 + 0.490691 -0.861357 -0.131481 + 0.490691 -0.861357 -0.131481 + 0.490691 -0.861357 -0.131481 + 0.490691 -0.861357 -0.131481 + 0.0104155 -0.999942 -0.00279081 + 0.0104155 -0.999942 -0.00279081 + 0.0104155 -0.999942 -0.00279081 + 0.0104155 -0.999942 -0.00279081 + 0.0104155 -0.999942 -0.00279081 + 0.0104155 -0.999942 -0.00279081 + -0.475067 -0.870694 0.127294 + -0.475067 -0.870694 0.127294 + -0.475067 -0.870694 0.127294 + -0.475067 -0.870694 0.127294 + -0.475067 -0.870694 0.127294 + -0.475067 -0.870694 0.127294 + -0.833866 -0.504722 0.223434 + -0.833866 -0.504722 0.223434 + -0.833866 -0.504722 0.223434 + -0.833866 -0.504722 0.223434 + -0.833866 -0.504722 0.223434 + -0.833866 -0.504722 0.223434 + -0.965926 -2.43698e-06 0.258819 + -0.965926 -2.43698e-06 0.258819 + -0.965926 -2.43698e-06 0.258819 + -0.965926 -2.43698e-06 0.258819 + -0.965926 -2.43698e-06 0.258819 + -0.965926 -2.43698e-06 0.258819 + -0.833867 0.504721 0.223435 + -0.833867 0.504721 0.223435 + -0.833867 0.504721 0.223435 + -0.833867 0.504721 0.223435 + -0.833867 0.504721 0.223435 + -0.833867 0.504721 0.223435 + -0.475067 0.870694 0.127294 + -0.475067 0.870694 0.127294 + -0.475067 0.870694 0.127294 + -0.475067 0.870694 0.127294 + -0.475067 0.870694 0.127294 + -0.475067 0.870694 0.127294 + 0.0104154 0.999942 -0.00279057 + 0.0104154 0.999942 -0.00279057 + 0.0104154 0.999942 -0.00279057 + 0.0104154 0.999942 -0.00279057 + 0.0104154 0.999942 -0.00279057 + 0.0104154 0.999942 -0.00279057 + 0.49069 0.861357 -0.13148 + 0.49069 0.861357 -0.13148 + 0.49069 0.861357 -0.13148 + 0.49069 0.861357 -0.13148 + 0.49069 0.861357 -0.13148 + 0.49069 0.861357 -0.13148 + 0.83907 0.495393 -0.224829 + 0.83907 0.495393 -0.224829 + 0.83907 0.495393 -0.224829 + 0.83907 0.495393 -0.224829 + 0.83907 0.495393 -0.224829 + 0.83907 0.495393 -0.224829 + 0.991445 2.19413e-06 -0.130526 + 0.991445 2.19413e-06 -0.130526 + 0.991445 2.19413e-06 -0.130526 + 0.991445 2.19413e-06 -0.130526 + 0.991445 2.19413e-06 -0.130526 + 0.991445 2.19413e-06 -0.130526 + 0.861238 -0.495391 -0.113384 + 0.861238 -0.495391 -0.113384 + 0.861238 -0.495391 -0.113384 + 0.861238 -0.495391 -0.113384 + 0.861238 -0.495391 -0.113384 + 0.861238 -0.495391 -0.113384 + 0.503656 -0.861356 -0.0663077 + 0.503656 -0.861356 -0.0663077 + 0.503656 -0.861356 -0.0663077 + 0.503656 -0.861356 -0.0663077 + 0.503656 -0.861356 -0.0663077 + 0.503656 -0.861356 -0.0663077 + 0.0106897 -0.999942 -0.00140738 + 0.0106897 -0.999942 -0.00140738 + 0.0106897 -0.999942 -0.00140738 + 0.0106897 -0.999942 -0.00140738 + 0.0106897 -0.999942 -0.00140738 + 0.0106897 -0.999942 -0.00140738 + -0.48762 -0.870693 0.0641965 + -0.48762 -0.870693 0.0641965 + -0.48762 -0.870693 0.0641965 + -0.48762 -0.870693 0.0641965 + -0.48762 -0.870693 0.0641965 + -0.855897 -0.504721 0.112681 + -0.855897 -0.504721 0.112681 + -0.855897 -0.504721 0.112681 + -0.855897 -0.504721 0.112681 + -0.855897 -0.504721 0.112681 + -0.855897 -0.504721 0.112681 + -0.855897 -0.504721 0.112681 + -0.991445 -1.23826e-07 0.130526 + -0.991445 -1.23826e-07 0.130526 + -0.991445 -1.23826e-07 0.130526 + -0.991445 -1.23826e-07 0.130526 + -0.991445 -1.23826e-07 0.130526 + -0.991445 -1.23826e-07 0.130526 + -0.855896 0.504722 0.112681 + -0.855896 0.504722 0.112681 + -0.855896 0.504722 0.112681 + -0.855896 0.504722 0.112681 + -0.855896 0.504722 0.112681 + -0.855896 0.504722 0.112681 + -0.487619 0.870694 0.0641964 + -0.487619 0.870694 0.0641964 + -0.487619 0.870694 0.0641964 + -0.487619 0.870694 0.0641964 + -0.487619 0.870694 0.0641964 + 0.0106895 0.999942 -0.00140726 + 0.0106895 0.999942 -0.00140726 + 0.0106895 0.999942 -0.00140726 + 0.0106895 0.999942 -0.00140726 + 0.0106895 0.999942 -0.00140726 + 0.0106895 0.999942 -0.00140726 + 0.503654 0.861357 -0.0663074 + 0.503654 0.861357 -0.0663074 + 0.503654 0.861357 -0.0663074 + 0.503654 0.861357 -0.0663074 + 0.503654 0.861357 -0.0663074 + 0.503654 0.861357 -0.0663074 + 0.503654 0.861357 -0.0663074 + 0.861237 0.495394 -0.113384 + 0.861237 0.495394 -0.113384 + 0.861237 0.495394 -0.113384 + 0.861237 0.495394 -0.113384 + 0.861237 0.495394 -0.113384 + 0.861237 0.495394 -0.113384 + 1 0 -4.46877e-07 + 1 0 -4.46877e-07 + 1 0 -4.46877e-07 + 1 0 -4.46877e-07 + 1 0 -4.46877e-07 + 1 0 -4.46877e-07 + 0.868673 -0.495385 -5.65941e-07 + 0.868673 -0.495385 -5.65941e-07 + 0.868673 -0.495385 -5.65941e-07 + 0.868673 -0.495385 -5.65941e-07 + 0.868673 -0.495385 -5.65941e-07 + 0.868673 -0.495385 -5.65941e-07 + 0.508001 -0.861357 -4.06857e-07 + 0.508001 -0.861357 -4.06857e-07 + 0.508001 -0.861357 -4.06857e-07 + 0.508001 -0.861357 -4.06857e-07 + 0.508001 -0.861357 -4.06857e-07 + 0.508001 -0.861357 -4.06857e-07 + 0.0107825 -0.999942 0 + 0.0107825 -0.999942 0 + 0.0107825 -0.999942 0 + 0.0107825 -0.999942 0 + 0.0107825 -0.999942 0 + 0.0107825 -0.999942 0 + -0.491825 -0.870694 0 + -0.491825 -0.870694 0 + -0.491825 -0.870694 0 + -0.491825 -0.870694 0 + -0.491825 -0.870694 0 + -0.491825 -0.870694 0 + -0.86328 -0.504726 0 + -0.86328 -0.504726 0 + -0.86328 -0.504726 0 + -0.86328 -0.504726 0 + -0.86328 -0.504726 0 + -0.86328 -0.504726 0 + -0.86328 -0.504726 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -0.86328 0.504725 0 + -0.86328 0.504725 0 + -0.86328 0.504725 0 + -0.86328 0.504725 0 + -0.86328 0.504725 0 + -0.86328 0.504725 0 + -0.86328 0.504725 0 + -0.86328 0.504725 0 + -0.491826 0.870694 0 + -0.491826 0.870694 0 + -0.491826 0.870694 0 + -0.491826 0.870694 0 + -0.491826 0.870694 0 + 0.0107824 0.999942 0 + 0.0107824 0.999942 0 + 0.0107824 0.999942 0 + 0.0107824 0.999942 0 + 0.0107824 0.999942 0 + 0.0107824 0.999942 0 + 0.508001 0.861356 -3.38314e-07 + 0.508001 0.861356 -3.38314e-07 + 0.508001 0.861356 -3.38314e-07 + 0.508001 0.861356 -3.38314e-07 + 0.508001 0.861356 -3.38314e-07 + 0.508001 0.861356 -3.38314e-07 + 0.868673 0.495385 -5.20021e-07 + 0.868673 0.495385 -5.20021e-07 + 0.868673 0.495385 -5.20021e-07 + 0.868673 0.495385 -5.20021e-07 + 0.868673 0.495385 -5.20021e-07 + 0.868673 0.495385 -5.20021e-07 + 0.991445 -1.47353e-07 0.130526 + 0.991445 -1.47353e-07 0.130526 + 0.991445 -1.47353e-07 0.130526 + 0.991445 -1.47353e-07 0.130526 + 0.991445 -1.47353e-07 0.130526 + 0.991445 -1.47353e-07 0.130526 + 0.86124 -0.495389 0.113384 + 0.86124 -0.495389 0.113384 + 0.86124 -0.495389 0.113384 + 0.86124 -0.495389 0.113384 + 0.86124 -0.495389 0.113384 + 0.86124 -0.495389 0.113384 + 0.503655 -0.861356 0.0663076 + 0.503655 -0.861356 0.0663076 + 0.503655 -0.861356 0.0663076 + 0.503655 -0.861356 0.0663076 + 0.503655 -0.861356 0.0663076 + 0.503655 -0.861356 0.0663076 + 0.503655 -0.861356 0.0663076 + 0.010691 -0.999942 0.00140738 + 0.010691 -0.999942 0.00140738 + 0.010691 -0.999942 0.00140738 + 0.010691 -0.999942 0.00140738 + 0.010691 -0.999942 0.00140738 + -0.48762 -0.870692 -0.0641963 + -0.48762 -0.870692 -0.0641963 + -0.48762 -0.870692 -0.0641963 + -0.48762 -0.870692 -0.0641963 + -0.48762 -0.870692 -0.0641963 + -0.48762 -0.870692 -0.0641963 + -0.855896 -0.504722 -0.112681 + -0.855896 -0.504722 -0.112681 + -0.855896 -0.504722 -0.112681 + -0.855896 -0.504722 -0.112681 + -0.855896 -0.504722 -0.112681 + -0.991445 0 -0.130526 + -0.991445 0 -0.130526 + -0.991445 0 -0.130526 + -0.991445 0 -0.130526 + -0.991445 0 -0.130526 + -0.991445 0 -0.130526 + -0.991445 0 -0.130526 + -0.991445 0 -0.130526 + -0.855896 0.504723 -0.112681 + -0.855896 0.504723 -0.112681 + -0.855896 0.504723 -0.112681 + -0.855896 0.504723 -0.112681 + -0.855896 0.504723 -0.112681 + -0.487619 0.870693 -0.0641961 + -0.487619 0.870693 -0.0641961 + -0.487619 0.870693 -0.0641961 + -0.487619 0.870693 -0.0641961 + -0.487619 0.870693 -0.0641961 + -0.487619 0.870693 -0.0641961 + -0.487619 0.870693 -0.0641961 + 0.0106907 0.999942 0.00140738 + 0.0106907 0.999942 0.00140738 + 0.0106907 0.999942 0.00140738 + 0.0106907 0.999942 0.00140738 + 0.0106907 0.999942 0.00140738 + 0.503655 0.861356 0.0663075 + 0.503655 0.861356 0.0663075 + 0.503655 0.861356 0.0663075 + 0.503655 0.861356 0.0663075 + 0.503655 0.861356 0.0663075 + 0.503655 0.861356 0.0663075 + 0.86124 0.495388 0.113384 + 0.86124 0.495388 0.113384 + 0.86124 0.495388 0.113384 + 0.86124 0.495388 0.113384 + 0.86124 0.495388 0.113384 + 0.86124 0.495388 0.113384 + 0.965926 1.68927e-06 0.258819 + 0.965926 1.68927e-06 0.258819 + 0.965926 1.68927e-06 0.258819 + 0.965926 1.68927e-06 0.258819 + 0.965926 1.68927e-06 0.258819 + 0.965926 1.68927e-06 0.258819 + 0.839073 -0.495387 0.224828 + 0.839073 -0.495387 0.224828 + 0.839073 -0.495387 0.224828 + 0.839073 -0.495387 0.224828 + 0.839073 -0.495387 0.224828 + 0.839073 -0.495387 0.224828 + 0.490687 -0.861359 0.131479 + 0.490687 -0.861359 0.131479 + 0.490687 -0.861359 0.131479 + 0.490687 -0.861359 0.131479 + 0.490687 -0.861359 0.131479 + 0.0104155 -0.999942 0.00279051 + 0.0104155 -0.999942 0.00279051 + 0.0104155 -0.999942 0.00279051 + 0.0104155 -0.999942 0.00279051 + 0.0104155 -0.999942 0.00279051 + 0.0104155 -0.999942 0.00279051 + 0.0104155 -0.999942 0.00279051 + 0.0104155 -0.999942 0.00279051 + -0.475066 -0.870694 -0.127294 + -0.475066 -0.870694 -0.127294 + -0.475066 -0.870694 -0.127294 + -0.475066 -0.870694 -0.127294 + -0.475066 -0.870694 -0.127294 + -0.475066 -0.870694 -0.127294 + -0.833864 -0.504726 -0.223433 + -0.833864 -0.504726 -0.223433 + -0.833864 -0.504726 -0.223433 + -0.833864 -0.504726 -0.223433 + -0.833864 -0.504726 -0.223433 + -0.965926 -5.64978e-07 -0.258819 + -0.965926 -5.64978e-07 -0.258819 + -0.965926 -5.64978e-07 -0.258819 + -0.965926 -5.64978e-07 -0.258819 + -0.965926 -5.64978e-07 -0.258819 + -0.833865 0.504725 -0.223433 + -0.833865 0.504725 -0.223433 + -0.833865 0.504725 -0.223433 + -0.833865 0.504725 -0.223433 + -0.833865 0.504725 -0.223433 + -0.833865 0.504725 -0.223433 + -0.475067 0.870694 -0.127294 + -0.475067 0.870694 -0.127294 + -0.475067 0.870694 -0.127294 + -0.475067 0.870694 -0.127294 + -0.475067 0.870694 -0.127294 + -0.475067 0.870694 -0.127294 + 0.0104155 0.999942 0.00279075 + 0.0104155 0.999942 0.00279075 + 0.0104155 0.999942 0.00279075 + 0.0104155 0.999942 0.00279075 + 0.0104155 0.999942 0.00279075 + 0.0104155 0.999942 0.00279075 + 0.0104155 0.999942 0.00279075 + 0.0104155 0.999942 0.00279075 + 0.490689 0.861358 0.13148 + 0.490689 0.861358 0.13148 + 0.490689 0.861358 0.13148 + 0.490689 0.861358 0.13148 + 0.839073 0.495387 0.224829 + 0.839073 0.495387 0.224829 + 0.839073 0.495387 0.224829 + 0.839073 0.495387 0.224829 + 0.839073 0.495387 0.224829 + 0.839073 0.495387 0.224829 + 0.839073 0.495387 0.224829 + 0.92388 -3.43202e-07 0.382683 + 0.92388 -3.43202e-07 0.382683 + 0.92388 -3.43202e-07 0.382683 + 0.92388 -3.43202e-07 0.382683 + 0.802549 -0.495386 0.332426 + 0.802549 -0.495386 0.332426 + 0.802549 -0.495386 0.332426 + 0.802549 -0.495386 0.332426 + 0.802549 -0.495386 0.332426 + 0.802549 -0.495386 0.332426 + 0.802549 -0.495386 0.332426 + 0.802549 -0.495386 0.332426 + 0.469334 -0.861355 0.194404 + 0.469334 -0.861355 0.194404 + 0.469334 -0.861355 0.194404 + 0.469334 -0.861355 0.194404 + 0.469334 -0.861355 0.194404 + 0.00996268 -0.999942 0.00412655 + 0.00996268 -0.999942 0.00412655 + 0.00996268 -0.999942 0.00412655 + 0.00996268 -0.999942 0.00412655 + 0.00996268 -0.999942 0.00412655 + -0.454388 -0.870694 -0.188214 + -0.454388 -0.870694 -0.188214 + -0.454388 -0.870694 -0.188214 + -0.454388 -0.870694 -0.188214 + -0.454388 -0.870694 -0.188214 + -0.454388 -0.870694 -0.188214 + -0.454388 -0.870694 -0.188214 + -0.797567 -0.504725 -0.330363 + -0.797567 -0.504725 -0.330363 + -0.797567 -0.504725 -0.330363 + -0.797567 -0.504725 -0.330363 + -0.797567 -0.504725 -0.330363 + -0.797567 -0.504725 -0.330363 + -0.797567 -0.504725 -0.330363 + -0.92388 1.88387e-06 -0.382683 + -0.92388 1.88387e-06 -0.382683 + -0.92388 1.88387e-06 -0.382683 + -0.92388 1.88387e-06 -0.382683 + -0.92388 1.88387e-06 -0.382683 + -0.797568 0.504724 -0.330363 + -0.797568 0.504724 -0.330363 + -0.797568 0.504724 -0.330363 + -0.797568 0.504724 -0.330363 + -0.797568 0.504724 -0.330363 + -0.797568 0.504724 -0.330363 + -0.454389 0.870693 -0.188214 + -0.454389 0.870693 -0.188214 + -0.454389 0.870693 -0.188214 + -0.454389 0.870693 -0.188214 + -0.454389 0.870693 -0.188214 + -0.454389 0.870693 -0.188214 + -0.454389 0.870693 -0.188214 + 0.00996327 0.999942 0.00412697 + 0.00996327 0.999942 0.00412697 + 0.00996327 0.999942 0.00412697 + 0.00996327 0.999942 0.00412697 + 0.00996327 0.999942 0.00412697 + 0.469331 0.861357 0.194403 + 0.469331 0.861357 0.194403 + 0.469331 0.861357 0.194403 + 0.469331 0.861357 0.194403 + 0.469331 0.861357 0.194403 + 0.469331 0.861357 0.194403 + 0.802548 0.495389 0.332426 + 0.802548 0.495389 0.332426 + 0.802548 0.495389 0.332426 + 0.802548 0.495389 0.332426 + 0.802548 0.495389 0.332426 + 0.802548 0.495389 0.332426 + 0.802548 0.495389 0.332426 + 0.866026 -6.51586e-07 0.5 + 0.866026 -6.51586e-07 0.5 + 0.866026 -6.51586e-07 0.5 + 0.866026 -6.51586e-07 0.5 + 0.866026 -6.51586e-07 0.5 + 0.866026 -6.51586e-07 0.5 + 0.752291 -0.495389 0.434336 + 0.752291 -0.495389 0.434336 + 0.752291 -0.495389 0.434336 + 0.752291 -0.495389 0.434336 + 0.752291 -0.495389 0.434336 + 0.439941 -0.861357 0.254 + 0.439941 -0.861357 0.254 + 0.439941 -0.861357 0.254 + 0.439941 -0.861357 0.254 + 0.439941 -0.861357 0.254 + 0.439941 -0.861357 0.254 + 0.439941 -0.861357 0.254 + 0.439941 -0.861357 0.254 + 0.00933743 -0.999942 0.00539088 + 0.00933743 -0.999942 0.00539088 + 0.00933743 -0.999942 0.00539088 + 0.00933743 -0.999942 0.00539088 + 0.00933743 -0.999942 0.00539088 + -0.425937 -0.870692 -0.245914 + -0.425937 -0.870692 -0.245914 + -0.425937 -0.870692 -0.245914 + -0.425937 -0.870692 -0.245914 + -0.425937 -0.870692 -0.245914 + -0.425937 -0.870692 -0.245914 + -0.747625 -0.50472 -0.431641 + -0.747625 -0.50472 -0.431641 + -0.747625 -0.50472 -0.431641 + -0.747625 -0.50472 -0.431641 + -0.747625 -0.50472 -0.431641 + -0.747625 -0.50472 -0.431641 + -0.866025 2.24713e-06 -0.5 + -0.866025 2.24713e-06 -0.5 + -0.866025 2.24713e-06 -0.5 + -0.866025 2.24713e-06 -0.5 + -0.866025 2.24713e-06 -0.5 + -0.866025 2.24713e-06 -0.5 + -0.866025 2.24713e-06 -0.5 + -0.747623 0.504724 -0.43164 + -0.747623 0.504724 -0.43164 + -0.747623 0.504724 -0.43164 + -0.747623 0.504724 -0.43164 + -0.747623 0.504724 -0.43164 + -0.425934 0.870693 -0.245913 + -0.425934 0.870693 -0.245913 + -0.425934 0.870693 -0.245913 + -0.425934 0.870693 -0.245913 + -0.425934 0.870693 -0.245913 + -0.425934 0.870693 -0.245913 + 0.00933784 0.999942 0.00539118 + 0.00933784 0.999942 0.00539118 + 0.00933784 0.999942 0.00539118 + 0.00933784 0.999942 0.00539118 + 0.00933784 0.999942 0.00539118 + 0.439941 0.861357 0.254 + 0.439941 0.861357 0.254 + 0.439941 0.861357 0.254 + 0.439941 0.861357 0.254 + 0.439941 0.861357 0.254 + 0.439941 0.861357 0.254 + 0.439941 0.861357 0.254 + 0.439941 0.861357 0.254 + 0.752292 0.495389 0.434336 + 0.752292 0.495389 0.434336 + 0.752292 0.495389 0.434336 + 0.752292 0.495389 0.434336 + 0.752292 0.495389 0.434336 + 0.793354 2.53671e-07 0.608761 + 0.793354 2.53671e-07 0.608761 + 0.793354 2.53671e-07 0.608761 + 0.793354 2.53671e-07 0.608761 + 0.793354 2.53671e-07 0.608761 + 0.793354 2.53671e-07 0.608761 + 0.689163 -0.495391 0.528813 + 0.689163 -0.495391 0.528813 + 0.689163 -0.495391 0.528813 + 0.689163 -0.495391 0.528813 + 0.689163 -0.495391 0.528813 + 0.689163 -0.495391 0.528813 + 0.689163 -0.495391 0.528813 + 0.403026 -0.861356 0.309252 + 0.403026 -0.861356 0.309252 + 0.403026 -0.861356 0.309252 + 0.403026 -0.861356 0.309252 + 0.403026 -0.861356 0.309252 + 0.00855619 -0.999942 0.00656545 + 0.00855619 -0.999942 0.00656545 + 0.00855619 -0.999942 0.00656545 + 0.00855619 -0.999942 0.00656545 + 0.00855619 -0.999942 0.00656545 + 0.00855619 -0.999942 0.00656545 + -0.390192 -0.870693 -0.299405 + -0.390192 -0.870693 -0.299405 + -0.390192 -0.870693 -0.299405 + -0.390192 -0.870693 -0.299405 + -0.390192 -0.870693 -0.299405 + -0.390192 -0.870693 -0.299405 + -0.684887 -0.504725 -0.525531 + -0.684887 -0.504725 -0.525531 + -0.684887 -0.504725 -0.525531 + -0.684887 -0.504725 -0.525531 + -0.684887 -0.504725 -0.525531 + -0.684887 -0.504725 -0.525531 + -0.793354 -1.12935e-06 -0.608761 + -0.793354 -1.12935e-06 -0.608761 + -0.793354 -1.12935e-06 -0.608761 + -0.793354 -1.12935e-06 -0.608761 + -0.793354 -1.12935e-06 -0.608761 + -0.684887 0.504724 -0.525532 + -0.684887 0.504724 -0.525532 + -0.684887 0.504724 -0.525532 + -0.684887 0.504724 -0.525532 + -0.684887 0.504724 -0.525532 + -0.684887 0.504724 -0.525532 + -0.684887 0.504724 -0.525532 + -0.390192 0.870693 -0.299405 + -0.390192 0.870693 -0.299405 + -0.390192 0.870693 -0.299405 + -0.390192 0.870693 -0.299405 + -0.390192 0.870693 -0.299405 + -0.390192 0.870693 -0.299405 + 0.00855571 0.999942 0.00656509 + 0.00855571 0.999942 0.00656509 + 0.00855571 0.999942 0.00656509 + 0.00855571 0.999942 0.00656509 + 0.00855571 0.999942 0.00656509 + 0.00855571 0.999942 0.00656509 + 0.403025 0.861356 0.309252 + 0.403025 0.861356 0.309252 + 0.403025 0.861356 0.309252 + 0.403025 0.861356 0.309252 + 0.403025 0.861356 0.309252 + 0.689162 0.495391 0.528813 + 0.689162 0.495391 0.528813 + 0.689162 0.495391 0.528813 + 0.689162 0.495391 0.528813 + 0.689162 0.495391 0.528813 + 0.689162 0.495391 0.528813 + 0.689162 0.495391 0.528813 + 0.707107 1.74088e-07 0.707106 + 0.707107 1.74088e-07 0.707106 + 0.707107 1.74088e-07 0.707106 + 0.707107 1.74088e-07 0.707106 + 0.707107 1.74088e-07 0.707106 + 0.707107 1.74088e-07 0.707106 + 0.614244 -0.495388 0.614244 + 0.614244 -0.495388 0.614244 + 0.614244 -0.495388 0.614244 + 0.614244 -0.495388 0.614244 + 0.614244 -0.495388 0.614244 + 0.614244 -0.495388 0.614244 + 0.359211 -0.861356 0.359211 + 0.359211 -0.861356 0.359211 + 0.359211 -0.861356 0.359211 + 0.359211 -0.861356 0.359211 + 0.359211 -0.861356 0.359211 + 0.00762433 -0.999942 0.00762468 + 0.00762433 -0.999942 0.00762468 + 0.00762433 -0.999942 0.00762468 + 0.00762433 -0.999942 0.00762468 + 0.00762433 -0.999942 0.00762468 + 0.00762433 -0.999942 0.00762468 + 0.00762433 -0.999942 0.00762468 + -0.347773 -0.870694 -0.347773 + -0.347773 -0.870694 -0.347773 + -0.347773 -0.870694 -0.347773 + -0.347773 -0.870694 -0.347773 + -0.347773 -0.870694 -0.347773 + -0.61043 -0.504729 -0.610429 + -0.61043 -0.504729 -0.610429 + -0.61043 -0.504729 -0.610429 + -0.61043 -0.504729 -0.610429 + -0.61043 -0.504729 -0.610429 + -0.61043 -0.504729 -0.610429 + -0.61043 -0.504729 -0.610429 + -0.707107 -1.17803e-06 -0.707106 + -0.707107 -1.17803e-06 -0.707106 + -0.707107 -1.17803e-06 -0.707106 + -0.707107 -1.17803e-06 -0.707106 + -0.707107 -1.17803e-06 -0.707106 + -0.707107 -1.17803e-06 -0.707106 + -0.61043 0.504728 -0.61043 + -0.61043 0.504728 -0.61043 + -0.61043 0.504728 -0.61043 + -0.61043 0.504728 -0.61043 + -0.61043 0.504728 -0.61043 + -0.61043 0.504728 -0.61043 + -0.61043 0.504728 -0.61043 + -0.347774 0.870694 -0.347773 + -0.347774 0.870694 -0.347773 + -0.347774 0.870694 -0.347773 + -0.347774 0.870694 -0.347773 + -0.347774 0.870694 -0.347773 + 0.00762445 0.999942 0.0076248 + 0.00762445 0.999942 0.0076248 + 0.00762445 0.999942 0.0076248 + 0.00762445 0.999942 0.0076248 + 0.00762445 0.999942 0.0076248 + 0.00762445 0.999942 0.0076248 + 0.00762445 0.999942 0.0076248 + 0.359212 0.861356 0.359212 + 0.359212 0.861356 0.359212 + 0.359212 0.861356 0.359212 + 0.359212 0.861356 0.359212 + 0.359212 0.861356 0.359212 + 0.614244 0.495388 0.614244 + 0.614244 0.495388 0.614244 + 0.614244 0.495388 0.614244 + 0.614244 0.495388 0.614244 + 0.614244 0.495388 0.614244 + 0.614244 0.495388 0.614244 + 0.608761 -1.29323e-07 0.793353 + 0.608761 -1.29323e-07 0.793353 + 0.608761 -1.29323e-07 0.793353 + 0.608761 -1.29323e-07 0.793353 + 0.608761 -1.29323e-07 0.793353 + 0.608761 -1.29323e-07 0.793353 + 0.528813 -0.495389 0.689163 + 0.528813 -0.495389 0.689163 + 0.528813 -0.495389 0.689163 + 0.528813 -0.495389 0.689163 + 0.528813 -0.495389 0.689163 + 0.528813 -0.495389 0.689163 + 0.309252 -0.861357 0.403024 + 0.309252 -0.861357 0.403024 + 0.309252 -0.861357 0.403024 + 0.309252 -0.861357 0.403024 + 0.309252 -0.861357 0.403024 + 0.309252 -0.861357 0.403024 + 0.00656521 -0.999942 0.00855589 + 0.00656521 -0.999942 0.00855589 + 0.00656521 -0.999942 0.00855589 + 0.00656521 -0.999942 0.00855589 + 0.00656521 -0.999942 0.00855589 + 0.00656521 -0.999942 0.00855589 + 0.00656521 -0.999942 0.00855589 + -0.299406 -0.870692 -0.390194 + -0.299406 -0.870692 -0.390194 + -0.299406 -0.870692 -0.390194 + -0.299406 -0.870692 -0.390194 + -0.299406 -0.870692 -0.390194 + -0.525532 -0.504723 -0.684887 + -0.525532 -0.504723 -0.684887 + -0.525532 -0.504723 -0.684887 + -0.525532 -0.504723 -0.684887 + -0.525532 -0.504723 -0.684887 + -0.608761 -5.59806e-07 -0.793354 + -0.608761 -5.59806e-07 -0.793354 + -0.608761 -5.59806e-07 -0.793354 + -0.608761 -5.59806e-07 -0.793354 + -0.608761 -5.59806e-07 -0.793354 + -0.608761 -5.59806e-07 -0.793354 + -0.608761 -5.59806e-07 -0.793354 + -0.608761 -5.59806e-07 -0.793354 + -0.525532 0.504723 -0.684887 + -0.525532 0.504723 -0.684887 + -0.525532 0.504723 -0.684887 + -0.525532 0.504723 -0.684887 + -0.525532 0.504723 -0.684887 + -0.299406 0.870692 -0.390194 + -0.299406 0.870692 -0.390194 + -0.299406 0.870692 -0.390194 + -0.299406 0.870692 -0.390194 + -0.299406 0.870692 -0.390194 + 0.00656515 0.999942 0.00855577 + 0.00656515 0.999942 0.00855577 + 0.00656515 0.999942 0.00855577 + 0.00656515 0.999942 0.00855577 + 0.00656515 0.999942 0.00855577 + 0.00656515 0.999942 0.00855577 + 0.00656515 0.999942 0.00855577 + 0.309251 0.861357 0.403024 + 0.309251 0.861357 0.403024 + 0.309251 0.861357 0.403024 + 0.309251 0.861357 0.403024 + 0.309251 0.861357 0.403024 + 0.309251 0.861357 0.403024 + 0.528813 0.495389 0.689163 + 0.528813 0.495389 0.689163 + 0.528813 0.495389 0.689163 + 0.528813 0.495389 0.689163 + 0.528813 0.495389 0.689163 + 0.528813 0.495389 0.689163 + 0.500001 -8.65465e-07 0.866025 + 0.500001 -8.65465e-07 0.866025 + 0.500001 -8.65465e-07 0.866025 + 0.500001 -8.65465e-07 0.866025 + 0.500001 -8.65465e-07 0.866025 + 0.500001 -8.65465e-07 0.866025 + 0.434336 -0.49539 0.75229 + 0.434336 -0.49539 0.75229 + 0.434336 -0.49539 0.75229 + 0.434336 -0.49539 0.75229 + 0.434336 -0.49539 0.75229 + 0.434336 -0.49539 0.75229 + 0.253999 -0.861359 0.439939 + 0.253999 -0.861359 0.439939 + 0.253999 -0.861359 0.439939 + 0.253999 -0.861359 0.439939 + 0.253999 -0.861359 0.439939 + 0.253999 -0.861359 0.439939 + 0.005391 -0.999942 0.0093376 + 0.005391 -0.999942 0.0093376 + 0.005391 -0.999942 0.0093376 + 0.005391 -0.999942 0.0093376 + 0.005391 -0.999942 0.0093376 + 0.005391 -0.999942 0.0093376 + -0.245913 -0.870693 -0.425934 + -0.245913 -0.870693 -0.425934 + -0.245913 -0.870693 -0.425934 + -0.245913 -0.870693 -0.425934 + -0.245913 -0.870693 -0.425934 + -0.245913 -0.870693 -0.425934 + -0.245913 -0.870693 -0.425934 + -0.43164 -0.504726 -0.747622 + -0.43164 -0.504726 -0.747622 + -0.43164 -0.504726 -0.747622 + -0.43164 -0.504726 -0.747622 + -0.43164 -0.504726 -0.747622 + -0.5 0 -0.866025 + -0.5 0 -0.866025 + -0.5 0 -0.866025 + -0.5 0 -0.866025 + -0.5 0 -0.866025 + -0.43164 0.504726 -0.747622 + -0.43164 0.504726 -0.747622 + -0.43164 0.504726 -0.747622 + -0.43164 0.504726 -0.747622 + -0.43164 0.504726 -0.747622 + -0.43164 0.504726 -0.747622 + -0.245913 0.870694 -0.425934 + -0.245913 0.870694 -0.425934 + -0.245913 0.870694 -0.425934 + -0.245913 0.870694 -0.425934 + -0.245913 0.870694 -0.425934 + -0.245913 0.870694 -0.425934 + -0.245913 0.870694 -0.425934 + 0.005391 0.999942 0.00933754 + 0.005391 0.999942 0.00933754 + 0.005391 0.999942 0.00933754 + 0.005391 0.999942 0.00933754 + 0.005391 0.999942 0.00933754 + 0.005391 0.999942 0.00933754 + 0.253999 0.861359 0.439939 + 0.253999 0.861359 0.439939 + 0.253999 0.861359 0.439939 + 0.253999 0.861359 0.439939 + 0.253999 0.861359 0.439939 + 0.253999 0.861359 0.439939 + 0.434336 0.49539 0.752291 + 0.434336 0.49539 0.752291 + 0.434336 0.49539 0.752291 + 0.434336 0.49539 0.752291 + 0.434336 0.49539 0.752291 + 0.434336 0.49539 0.752291 + 0.382683 -7.46091e-07 0.92388 + 0.382683 -7.46091e-07 0.92388 + 0.382683 -7.46091e-07 0.92388 + 0.382683 -7.46091e-07 0.92388 + 0.382683 -7.46091e-07 0.92388 + 0.382683 -7.46091e-07 0.92388 + 0.332426 -0.495388 0.802548 + 0.332426 -0.495388 0.802548 + 0.332426 -0.495388 0.802548 + 0.332426 -0.495388 0.802548 + 0.332426 -0.495388 0.802548 + 0.194404 -0.861356 0.469332 + 0.194404 -0.861356 0.469332 + 0.194404 -0.861356 0.469332 + 0.194404 -0.861356 0.469332 + 0.194404 -0.861356 0.469332 + 0.194404 -0.861356 0.469332 + 0.194404 -0.861356 0.469332 + 0.00412685 -0.999942 0.0099628 + 0.00412685 -0.999942 0.0099628 + 0.00412685 -0.999942 0.0099628 + 0.00412685 -0.999942 0.0099628 + 0.00412685 -0.999942 0.0099628 + 0.00412685 -0.999942 0.0099628 + -0.188214 -0.870693 -0.454389 + -0.188214 -0.870693 -0.454389 + -0.188214 -0.870693 -0.454389 + -0.188214 -0.870693 -0.454389 + -0.188214 -0.870693 -0.454389 + -0.188214 -0.870693 -0.454389 + -0.330364 -0.504722 -0.797569 + -0.330364 -0.504722 -0.797569 + -0.330364 -0.504722 -0.797569 + -0.330364 -0.504722 -0.797569 + -0.330364 -0.504722 -0.797569 + -0.330364 -0.504722 -0.797569 + -0.330364 -0.504722 -0.797569 + -0.382684 -8.42142e-07 -0.92388 + -0.382684 -8.42142e-07 -0.92388 + -0.382684 -8.42142e-07 -0.92388 + -0.382684 -8.42142e-07 -0.92388 + -0.382684 -8.42142e-07 -0.92388 + -0.330364 0.504721 -0.797569 + -0.330364 0.504721 -0.797569 + -0.330364 0.504721 -0.797569 + -0.330364 0.504721 -0.797569 + -0.330364 0.504721 -0.797569 + -0.330364 0.504721 -0.797569 + -0.188214 0.870693 -0.454389 + -0.188214 0.870693 -0.454389 + -0.188214 0.870693 -0.454389 + -0.188214 0.870693 -0.454389 + -0.188214 0.870693 -0.454389 + -0.188214 0.870693 -0.454389 + 0.00412673 0.999942 0.00996286 + 0.00412673 0.999942 0.00996286 + 0.00412673 0.999942 0.00996286 + 0.00412673 0.999942 0.00996286 + 0.00412673 0.999942 0.00996286 + 0.00412673 0.999942 0.00996286 + 0.194404 0.861356 0.469333 + 0.194404 0.861356 0.469333 + 0.194404 0.861356 0.469333 + 0.194404 0.861356 0.469333 + 0.194404 0.861356 0.469333 + 0.194404 0.861356 0.469333 + 0.332426 0.495387 0.802549 + 0.332426 0.495387 0.802549 + 0.332426 0.495387 0.802549 + 0.332426 0.495387 0.802549 + 0.332426 0.495387 0.802549 + 0.332426 0.495387 0.802549 + 0.258819 4.57603e-07 0.965926 + 0.258819 4.57603e-07 0.965926 + 0.258819 4.57603e-07 0.965926 + 0.258819 4.57603e-07 0.965926 + 0.258819 4.57603e-07 0.965926 + 0.258819 4.57603e-07 0.965926 + 0.224829 -0.495387 0.839073 + 0.224829 -0.495387 0.839073 + 0.224829 -0.495387 0.839073 + 0.224829 -0.495387 0.839073 + 0.224829 -0.495387 0.839073 + 0.224829 -0.495387 0.839073 + 0.224829 -0.495387 0.839073 + 0.131481 -0.861355 0.490694 + 0.131481 -0.861355 0.490694 + 0.131481 -0.861355 0.490694 + 0.131481 -0.861355 0.490694 + 0.131481 -0.861355 0.490694 + 0.00279081 -0.999942 0.0104154 + 0.00279081 -0.999942 0.0104154 + 0.00279081 -0.999942 0.0104154 + 0.00279081 -0.999942 0.0104154 + 0.00279081 -0.999942 0.0104154 + 0.00279081 -0.999942 0.0104154 + -0.127294 -0.870693 -0.475068 + -0.127294 -0.870693 -0.475068 + -0.127294 -0.870693 -0.475068 + -0.127294 -0.870693 -0.475068 + -0.127294 -0.870693 -0.475068 + -0.127294 -0.870693 -0.475068 + -0.223433 -0.504726 -0.833865 + -0.223433 -0.504726 -0.833865 + -0.223433 -0.504726 -0.833865 + -0.223433 -0.504726 -0.833865 + -0.223433 -0.504726 -0.833865 + -0.223433 -0.504726 -0.833865 + -0.258819 -5.69542e-07 -0.965926 + -0.258819 -5.69542e-07 -0.965926 + -0.258819 -5.69542e-07 -0.965926 + -0.258819 -5.69542e-07 -0.965926 + -0.258819 -5.69542e-07 -0.965926 + -0.258819 -5.69542e-07 -0.965926 + -0.223433 0.504725 -0.833865 + -0.223433 0.504725 -0.833865 + -0.223433 0.504725 -0.833865 + -0.223433 0.504725 -0.833865 + -0.223433 0.504725 -0.833865 + -0.223433 0.504725 -0.833865 + -0.127294 0.870693 -0.475069 + -0.127294 0.870693 -0.475069 + -0.127294 0.870693 -0.475069 + -0.127294 0.870693 -0.475069 + -0.127294 0.870693 -0.475069 + -0.127294 0.870693 -0.475069 + 0.00279063 0.999942 0.0104148 + 0.00279063 0.999942 0.0104148 + 0.00279063 0.999942 0.0104148 + 0.00279063 0.999942 0.0104148 + 0.00279063 0.999942 0.0104148 + 0.00279063 0.999942 0.0104148 + 0.13148 0.861356 0.490692 + 0.13148 0.861356 0.490692 + 0.13148 0.861356 0.490692 + 0.13148 0.861356 0.490692 + 0.13148 0.861356 0.490692 + 0.13148 0.861356 0.490692 + 0.224828 0.495389 0.839072 + 0.224828 0.495389 0.839072 + 0.224828 0.495389 0.839072 + 0.224828 0.495389 0.839072 + 0.224828 0.495389 0.839072 + 0.224828 0.495389 0.839072 + 0.130526 1.74088e-07 0.991445 + 0.130526 1.74088e-07 0.991445 + 0.130526 1.74088e-07 0.991445 + 0.130526 1.74088e-07 0.991445 + 0.130526 1.74088e-07 0.991445 + 0.130526 1.74088e-07 0.991445 + 0.130526 1.74088e-07 0.991445 + 0.113384 -0.495387 0.861241 + 0.113384 -0.495387 0.861241 + 0.113384 -0.495387 0.861241 + 0.113384 -0.495387 0.861241 + 0.113384 -0.495387 0.861241 + 0.113384 -0.495387 0.861241 + 0.0663072 -0.861358 0.503653 + 0.0663072 -0.861358 0.503653 + 0.0663072 -0.861358 0.503653 + 0.0663072 -0.861358 0.503653 + 0.0663072 -0.861358 0.503653 + 0.0663072 -0.861358 0.503653 + 0.00140721 -0.999942 0.0106885 + 0.00140721 -0.999942 0.0106885 + 0.00140721 -0.999942 0.0106885 + 0.00140721 -0.999942 0.0106885 + 0.00140721 -0.999942 0.0106885 + 0.00140721 -0.999942 0.0106885 + -0.0641961 -0.870694 -0.487618 + -0.0641961 -0.870694 -0.487618 + -0.0641961 -0.870694 -0.487618 + -0.0641961 -0.870694 -0.487618 + -0.0641961 -0.870694 -0.487618 + -0.112681 -0.504724 -0.855895 + -0.112681 -0.504724 -0.855895 + -0.112681 -0.504724 -0.855895 + -0.112681 -0.504724 -0.855895 + -0.112681 -0.504724 -0.855895 + -0.112681 -0.504724 -0.855895 + -0.130527 0 -0.991445 + -0.130527 0 -0.991445 + -0.130527 0 -0.991445 + -0.130527 0 -0.991445 + -0.130527 0 -0.991445 + -0.130527 0 -0.991445 + -0.130527 0 -0.991445 + -0.130527 0 -0.991445 + -0.112681 0.504721 -0.855897 + -0.112681 0.504721 -0.855897 + -0.112681 0.504721 -0.855897 + -0.112681 0.504721 -0.855897 + -0.112681 0.504721 -0.855897 + -0.112681 0.504721 -0.855897 + -0.0641966 0.870692 -0.487621 + -0.0641966 0.870692 -0.487621 + -0.0641966 0.870692 -0.487621 + -0.0641966 0.870692 -0.487621 + -0.0641966 0.870692 -0.487621 + 0.0014075 0.999942 0.0106913 + 0.0014075 0.999942 0.0106913 + 0.0014075 0.999942 0.0106913 + 0.0014075 0.999942 0.0106913 + 0.0014075 0.999942 0.0106913 + 0.0014075 0.999942 0.0106913 + 0.0663073 0.861358 0.503652 + 0.0663073 0.861358 0.503652 + 0.0663073 0.861358 0.503652 + 0.0663073 0.861358 0.503652 + 0.0663073 0.861358 0.503652 + 0.0663073 0.861358 0.503652 + 0.113385 0.49539 0.861239 + 0.113385 0.49539 0.861239 + 0.113385 0.49539 0.861239 + 0.113385 0.49539 0.861239 + 0.113385 0.49539 0.861239 + } + } + } + } + } + } + } + } + osg::MatrixTransform { + UniqueID 201 + Name "Z_Axis_Rot" + UserDataContainer TRUE { + osg::DefaultUserDataContainer { + UniqueID 202 + UDC_UserObjects 1 { + osg::StringValueObject { + UniqueID 203 + Name "dae_node_id" + Value "Z_Axis_Rot" + } + } + } + } + Children 1 { + osg::Geode { + UniqueID 204 + Drawables 1 { + osg::Geometry { + UniqueID 205 + Name "blue-material" + DataVariance STATIC + StateSet TRUE { + osg::StateSet { + UniqueID 29 + } + } + PrimitiveSetList 1 { + osg::DrawElementsUInt { + UniqueID 206 + BufferObject TRUE { + osg::ElementBufferObject { + UniqueID 207 + Target 34963 + } + } + Mode TRIANGLES + vector 3456 { + 0 78 8 79 + 12 9 13 90 + 20 91 24 21 + 96 30 25 31 + 108 38 109 42 + 39 43 120 50 + 51 126 56 127 + 60 57 61 138 + 68 139 1 69 + 72 150 80 151 + 84 81 85 162 + 92 163 97 93 + 168 102 98 103 + 180 110 181 114 + 111 115 191 121 + 122 198 128 199 + 132 129 133 210 + 140 211 73 141 + 144 222 152 223 + 156 153 157 234 + 164 235 169 165 + 240 174 170 175 + 252 182 253 186 + 183 258 192 187 + 193 270 200 271 + 204 201 205 282 + 212 283 145 213 + 216 294 224 295 + 228 225 229 306 + 236 307 241 237 + 242 317 247 248 + 323 254 324 259 + 255 331 264 260 + 265 341 272 342 + 276 273 277 354 + 284 355 217 285 + 288 366 296 367 + 300 297 301 378 + 308 309 384 313 + 385 318 314 390 + 325 319 326 402 + 332 333 408 337 + 409 343 338 414 + 348 344 349 426 + 356 427 289 357 + 360 438 368 439 + 372 369 373 449 + 379 380 456 386 + 457 391 387 463 + 396 392 397 474 + 403 404 479 410 + 480 415 411 486 + 420 416 421 497 + 428 498 361 429 + 432 510 440 511 + 444 441 517 450 + 445 451 528 458 + 459 534 464 535 + 468 465 469 546 + 475 547 481 476 + 552 487 482 488 + 564 493 565 499 + 494 570 433 500 + 504 582 512 513 + 588 518 589 522 + 519 523 599 529 + 530 605 536 606 + 540 537 541 618 + 548 619 553 549 + 624 558 554 559 + 636 566 637 571 + 567 642 505 572 + 576 652 583 584 + 659 590 660 594 + 591 665 600 595 + 671 607 601 678 + 612 608 613 689 + 620 690 625 621 + 626 700 631 632 + 707 638 708 643 + 639 713 577 644 + 720 653 648 654 + 732 661 733 666 + 662 738 672 667 + 673 750 679 751 + 683 680 684 762 + 691 763 695 692 + 768 701 696 702 + 780 709 781 714 + 710 715 721 649 + 792 726 722 727 + 804 734 805 739 + 735 740 816 745 + 746 822 752 823 + 756 753 757 833 + 764 834 769 765 + 840 774 770 775 + 852 782 853 786 + 783 787 793 723 + 864 798 794 799 + 875 806 876 810 + 807 811 887 817 + 818 893 824 825 + 899 829 900 835 + 830 906 841 836 + 913 846 842 847 + 923 854 924 858 + 855 859 865 795 + 936 870 866 943 + 877 871 949 882 + 878 955 888 883 + 962 894 889 968 + 901 895 973 907 + 902 908 984 914 + 915 990 919 991 + 925 920 997 930 + 926 931 937 867 + 1008 944 938 1015 + 950 945 1020 956 + 951 957 1031 963 + 964 1038 969 1039 + 974 970 975 1050 + 980 1051 985 981 + 1056 992 986 1062 + 998 993 999 1074 + 1004 1075 939 1005 + 1009 1086 1016 1087 + 1021 1017 1093 1026 + 1022 1098 1032 1027 + 1033 1110 1040 1111 + 1044 1041 1045 1122 + 1052 1123 1057 1053 + 1128 1063 1058 1064 + 1140 1069 1070 1145 + 1076 1146 1010 1077 + 1080 1158 1088 1089 + 1163 1094 1164 1099 + 1095 1100 1176 1105 + 1106 1181 1112 1182 + 1116 1113 1117 1193 + 1124 1194 1129 1125 + 1201 1134 1130 1135 + 1211 1141 1212 1147 + 1142 1219 1081 1148 + 1152 1230 1159 1231 + 1165 1160 1166 1242 + 1171 1172 1248 1177 + 1249 1183 1178 1184 + 1260 1189 1261 1195 + 1190 1196 1272 1202 + 1273 1206 1203 1278 + 1213 1207 1214 1290 + 1220 1291 1153 1221 + 1224 1302 1232 1303 + 1236 1233 1237 1313 + 1243 1244 1319 1250 + 1320 1254 1251 1255 + 1331 1262 1332 1266 + 1263 1267 1343 1274 + 1344 1279 1275 1351 + 1284 1280 1285 1361 + 1292 1362 1225 1293 + 1296 1372 1304 1305 + 1379 1309 1380 1314 + 1310 1385 1321 1315 + 1322 1397 1327 1398 + 1333 1328 1334 1409 + 1339 1410 1345 1340 + 1346 1421 1352 1353 + 1427 1357 1428 1363 + 1358 1433 1297 1364 + 1440 1373 1368 1374 + 1452 1381 1453 1386 + 1382 1458 1391 1387 + 1392 1470 1399 1471 + 1403 1400 1404 1481 + 1411 1482 1415 1412 + 1416 1493 1422 1423 + 1500 1429 1501 1434 + 1430 1435 1441 1369 + 1512 1446 1442 1447 + 1524 1454 1525 1459 + 1455 1531 1464 1460 + 1465 1541 1472 1542 + 1476 1473 1549 1483 + 1477 1554 1488 1484 + 1561 1494 1489 1495 + 1571 1502 1572 1506 + 1503 1507 1513 1443 + 1584 1518 1514 1519 + 1596 1526 1527 1601 + 1532 1602 1536 1533 + 1608 1543 1537 1544 + 1620 1550 1621 1555 + 1551 1556 1632 1562 + 1633 1566 1563 1639 + 1573 1567 1644 1578 + 1574 1579 1585 1515 + 1656 1590 1586 1591 + 1668 1597 1669 1603 + 1598 1674 1609 1604 + 1681 1614 1610 1615 + 1691 1622 1692 1626 + 1623 1627 1703 1634 + 1635 1709 1640 1710 + 1645 1641 1716 1650 + 1646 1651 1657 1587 + 1728 1662 1658 1663 + 1740 1670 1741 1675 + 1671 1676 1752 1682 + 1683 1758 1687 1759 + 1693 1688 1765 1698 + 1694 1771 1704 1699 + 1778 1711 1705 1784 + 1717 1712 1789 1722 + 1718 1723 1729 1659 + 1730 1806 1736 1807 + 1742 1737 1812 1747 + 1743 1818 1753 1748 + 1825 1760 1754 1831 + 1766 1761 1836 1772 + 1767 1773 1847 1779 + 1780 1853 1785 1854 + 1790 1786 1791 1866 + 1796 1867 1731 1797 + 1800 1878 1808 1879 + 1813 1809 1884 1819 + 1814 1820 1895 1826 + 1827 1901 1832 1902 + 1837 1833 1838 1913 + 1843 1914 1848 1844 + 1921 1855 1849 1927 + 1860 1856 1861 1938 + 1868 1939 1801 1869 + 1872 1950 1880 1951 + 1885 1881 1956 1890 + 1886 1963 1896 1891 + 1968 1903 1897 1904 + 1980 1909 1981 1915 + 1910 1916 1992 1922 + 1923 1998 1928 1929 + 2003 1933 1934 2009 + 1940 2010 1873 1941 + 1944 2022 1952 2023 + 1957 1953 1958 2034 + 1964 2035 1969 1965 + 2041 1974 1970 1975 + 2052 1982 2053 1986 + 1983 1987 2064 1993 + 1994 2069 1999 2070 + 2004 2000 2076 2011 + 2005 2083 1945 2012 + 2016 2092 2024 2093 + 2028 2025 2029 2105 + 2036 2037 2111 2042 + 2112 2046 2043 2047 + 2123 2054 2124 2058 + 2055 2059 2135 2065 + 2136 2071 2066 2141 + 2077 2072 2078 2153 + 2084 2154 2017 2085 + 2160 2094 2088 2166 + 2099 2095 2100 2178 + 2106 2107 2183 2113 + 2184 2117 2114 2118 + 2196 2125 2197 2129 + 2126 2130 2207 2137 + 2208 2142 2138 2215 + 2147 2143 2148 2225 + 2155 2156 2161 2089 + 2232 2167 2162 2168 + 2243 2173 2174 2250 + 2179 2251 2185 2180 + 2256 2190 2186 2191 + 2268 2198 2269 2202 + 2199 2274 2209 2203 + 2210 2286 2216 2287 + 2220 2217 2292 2226 + 2221 2227 2233 2163 + 2304 2238 2234 2310 + 2244 2239 2245 2322 + 2252 2323 2257 2253 + 2258 2333 2263 2264 + 2340 2270 2341 2275 + 2271 2346 2280 2276 + 2281 2358 2288 2359 + 2293 2289 2364 2298 + 2294 2299 2305 2235 + 2376 2311 2306 2382 + 2316 2312 2317 2393 + 2324 2394 2328 2325 + 2401 2334 2329 2335 + 2411 2342 2412 2347 + 2343 2348 2423 2353 + 2354 2429 2360 2430 + 2365 2361 2366 2441 + 2371 2372 2377 2307 + 2448 2383 2378 2384 + 2461 2389 2462 2395 + 2390 2396 2472 2402 + 2403 2479 2407 2480 + 2413 2408 2414 2491 + 2419 2492 2424 2420 + 2497 2431 2425 2503 + 2436 2432 2510 2442 + 2437 2443 2449 2379 + 2520 2455 2450 2456 + 2531 2463 2532 2467 + 2464 2537 2473 2468 + 2474 2549 2481 2550 + 2485 2482 2486 2561 + 2493 2562 2498 2494 + 2567 2504 2499 2505 + 2578 2511 2579 2515 + 2512 2585 2451 2516 + 2592 2525 2521 2526 + 2604 2533 2605 2538 + 2534 2539 2616 2544 + 2545 2622 2551 2623 + 2555 2552 2556 2635 + 2563 2636 2568 2564 + 2642 2573 2569 2648 + 2580 2574 2653 2586 + 2581 2587 2593 2522 + 2594 2670 2600 2671 + 2606 2601 2607 2682 + 2612 2683 2617 2613 + 2688 2624 2618 2694 + 2629 2625 2630 2706 + 2637 2638 2712 2643 + 2644 2718 2649 2719 + 2654 2650 2655 2730 + 2660 2731 2595 2661 + 2664 2742 2672 2743 + 2676 2673 2677 2754 + 2684 2755 2689 2685 + 2761 2695 2690 2766 + 2700 2696 2701 2778 + 2707 2708 2784 2713 + 2714 2789 2720 2790 + 2724 2721 2725 2802 + 2732 2803 2665 2733 + 2736 2812 2744 2813 + 2748 2745 2749 2825 + 2756 2757 2831 2762 + 2832 2767 2763 2837 + 2772 2768 2773 2848 + 2779 2780 2854 2785 + 2855 2791 2786 2861 + 2796 2792 2797 2873 + 2804 2874 2737 2805 + 2880 2814 2808 2886 + 2819 2815 2820 2898 + 2826 2827 2903 2833 + 2904 2838 2834 2839 + 2915 2844 2916 2849 + 2845 2923 2856 2850 + 2929 2862 2857 2935 + 2867 2863 2868 2946 + 2875 2876 2881 2809 + 2952 2887 2882 2960 + 2892 2888 2893 2970 + 2899 2971 2905 2900 + 2977 2910 2906 2984 + 2917 2911 2918 2995 + 2924 2925 3000 2930 + 2931 3007 2936 3008 + 2940 2937 2941 3019 + 2947 2948 2953 2883 + 2954 3028 2961 3029 + 2965 2962 3036 2972 + 2966 3041 2978 2973 + 2979 3053 2985 3054 + 2989 2986 2990 3064 + 2996 3065 3001 2997 + 3002 3076 3009 3077 + 3013 3010 3014 3088 + 3020 3089 2955 3021 + 3096 3030 3024 3031 + 3108 3037 3109 3042 + 3038 3114 3047 3043 + 3048 3126 3055 3056 + 3132 3060 3133 3066 + 3061 3138 3071 3067 + 3144 3078 3072 3079 + 3156 3084 3157 3090 + 3085 3091 3097 3025 + 3168 3102 3098 3103 + 3180 3110 3181 3115 + 3111 3186 3120 3116 + 3121 3198 3127 3128 + 3203 3134 3204 3139 + 3135 3211 3145 3140 + 3146 3221 3151 3152 + 3228 3158 3229 3162 + 3159 3163 3169 3099 + 3240 3174 3170 3175 + 3252 3182 3253 3187 + 3183 3188 3265 3193 + 3194 3270 3199 3271 + 3205 3200 3206 3282 + 3212 3283 3216 3213 + 3289 3222 3217 3223 + 3301 3230 3302 3234 + 3231 3235 3241 3171 + 3312 3247 3242 3319 + 3254 3248 3325 3259 + 3255 3260 3336 3266 + 3337 3272 3267 3342 + 3277 3273 3348 3284 + 3278 3355 3290 3285 + 3360 3295 3291 3296 + 3372 3303 3304 3377 + 3308 3378 3243 3309 + 3313 3388 3320 3321 + 3395 3326 3396 3330 + 3327 3331 3407 3338 + 3408 3343 3339 3414 + 3349 3344 3350 3425 + 3356 3426 3361 3357 + 3431 3366 3362 3367 + 3443 3373 3444 3379 + 3374 3449 3314 3380 + 2 3389 3384 3390 + 14 3397 15 3401 + 3398 3402 26 3409 + 3410 32 3415 33 + 3419 3416 3420 44 + 3427 45 3432 3428 + 52 3437 3433 3438 + 62 3445 63 3450 + 3446 3451 3 3385 + 4 74 82 83 + 86 16 17 87 + 94 95 99 27 + 100 104 34 35 + 105 112 113 116 + 46 47 117 123 + 53 124 130 131 + 134 64 65 135 + 142 143 75 5 + 76 146 154 155 + 158 88 89 159 + 166 167 171 101 + 172 176 106 107 + 177 184 185 188 + 118 119 189 194 + 125 195 202 203 + 206 136 137 207 + 214 215 147 77 + 148 218 226 227 + 230 160 161 231 + 238 239 243 173 + 244 249 178 179 + 250 256 257 261 + 190 262 266 196 + 197 267 274 275 + 278 208 209 279 + 286 287 219 149 + 220 290 298 299 + 302 232 233 303 + 310 311 315 245 + 246 316 320 251 + 321 327 328 334 + 263 335 339 268 + 269 340 345 346 + 350 280 281 351 + 358 359 291 221 + 292 362 370 371 + 374 304 305 375 + 381 312 382 388 + 389 393 322 394 + 398 329 330 399 + 405 336 406 412 + 413 417 347 418 + 422 352 353 423 + 430 431 363 293 + 364 434 442 443 + 446 376 377 447 + 452 383 453 460 + 461 466 395 467 + 470 400 401 471 + 477 407 478 483 + 484 489 419 490 + 495 424 425 496 + 501 502 435 365 + 436 506 514 515 + 520 448 521 524 + 454 455 525 531 + 462 532 538 539 + 542 472 473 543 + 550 551 555 485 + 556 560 491 492 + 561 568 569 573 + 503 574 507 437 + 508 578 585 516 + 586 592 593 596 + 526 527 597 602 + 533 603 609 610 + 614 544 545 615 + 622 623 627 557 + 628 633 562 563 + 634 640 641 645 + 575 646 579 509 + 580 650 655 587 + 656 663 664 668 + 598 669 674 604 + 675 681 611 682 + 685 616 617 686 + 693 694 697 629 + 630 698 703 635 + 704 711 712 716 + 647 717 651 581 + 724 728 657 658 + 729 736 737 741 + 670 742 747 676 + 677 748 754 755 + 758 687 688 759 + 766 767 771 699 + 772 776 705 706 + 777 784 785 788 + 718 719 789 725 + 796 800 730 731 + 801 808 809 812 + 743 744 813 819 + 749 820 826 827 + 831 760 761 832 + 837 838 843 773 + 844 848 778 779 + 849 856 857 860 + 790 791 861 797 + 868 872 802 803 + 873 879 880 884 + 814 815 885 890 + 821 891 896 828 + 897 903 904 909 + 839 910 916 845 + 917 921 850 851 + 922 927 928 932 + 862 863 933 869 + 940 946 874 947 + 952 881 953 958 + 886 959 965 892 + 966 971 898 972 + 976 905 977 982 + 911 912 983 987 + 918 988 994 995 + 1000 929 1001 1006 + 934 935 1007 941 + 1011 1018 948 1019 + 1023 954 1024 1028 + 960 961 1029 1034 + 967 1035 1042 1043 + 1046 978 979 1047 + 1054 1055 1059 989 + 1060 1065 996 1066 + 1071 1002 1003 1072 + 1078 1079 1012 942 + 1013 1082 1090 1091 + 1096 1025 1097 1101 + 1030 1102 1107 1036 + 1037 1108 1114 1115 + 1118 1048 1049 1119 + 1126 1127 1131 1061 + 1132 1136 1067 1068 + 1137 1143 1073 1144 + 1149 1150 1083 1014 + 1084 1154 1161 1092 + 1162 1167 1168 1173 + 1103 1104 1174 1179 + 1109 1180 1185 1186 + 1191 1120 1121 1192 + 1197 1198 1204 1133 + 1205 1208 1138 1139 + 1209 1215 1216 1222 + 1151 1223 1155 1085 + 1156 1226 1234 1235 + 1238 1169 1170 1239 + 1245 1175 1246 1252 + 1253 1256 1187 1188 + 1257 1264 1265 1268 + 1199 1200 1269 1276 + 1277 1281 1210 1282 + 1286 1217 1218 1287 + 1294 1295 1227 1157 + 1228 1298 1306 1307 + 1311 1240 1241 1312 + 1316 1247 1317 1323 + 1324 1329 1258 1259 + 1330 1335 1336 1341 + 1270 1271 1342 1347 + 1348 1354 1283 1355 + 1359 1288 1289 1360 + 1365 1366 1299 1229 + 1300 1370 1375 1308 + 1376 1383 1384 1388 + 1318 1389 1393 1325 + 1326 1394 1401 1402 + 1405 1337 1338 1406 + 1413 1414 1417 1349 + 1350 1418 1424 1356 + 1425 1431 1432 1436 + 1367 1437 1371 1301 + 1444 1448 1377 1378 + 1449 1456 1457 1461 + 1390 1462 1466 1395 + 1396 1467 1474 1475 + 1478 1407 1408 1479 + 1485 1486 1490 1419 + 1420 1491 1496 1426 + 1497 1504 1505 1508 + 1438 1439 1509 1445 + 1516 1520 1450 1451 + 1521 1528 1529 1534 + 1463 1535 1538 1468 + 1469 1539 1545 1546 + 1552 1480 1553 1557 + 1487 1558 1564 1492 + 1565 1568 1498 1499 + 1569 1575 1576 1580 + 1510 1511 1581 1517 + 1588 1592 1522 1523 + 1593 1599 1530 1600 + 1605 1606 1611 1540 + 1612 1616 1547 1548 + 1617 1624 1625 1628 + 1559 1560 1629 1636 + 1637 1642 1570 1643 + 1647 1577 1648 1652 + 1582 1583 1653 1589 + 1660 1664 1594 1595 + 1665 1672 1673 1677 + 1607 1678 1684 1613 + 1685 1689 1618 1619 + 1690 1695 1696 1700 + 1630 1631 1701 1706 + 1638 1707 1713 1714 + 1719 1649 1720 1724 + 1654 1655 1725 1661 + 1732 1738 1666 1667 + 1739 1744 1745 1749 + 1679 1680 1750 1755 + 1686 1756 1762 1763 + 1768 1697 1769 1774 + 1702 1775 1781 1708 + 1782 1787 1715 1788 + 1792 1721 1793 1798 + 1726 1727 1799 1733 + 1734 1802 1810 1811 + 1815 1746 1816 1821 + 1751 1822 1828 1757 + 1829 1834 1764 1835 + 1839 1770 1840 1845 + 1776 1777 1846 1850 + 1783 1851 1857 1858 + 1862 1794 1795 1863 + 1870 1871 1803 1735 + 1804 1874 1882 1883 + 1887 1817 1888 1892 + 1823 1824 1893 1898 + 1830 1899 1905 1906 + 1911 1841 1842 1912 + 1917 1918 1924 1852 + 1925 1930 1859 1931 + 1935 1864 1865 1936 + 1942 1943 1875 1805 + 1876 1946 1954 1955 + 1959 1889 1960 1966 + 1894 1967 1971 1900 + 1972 1976 1907 1908 + 1977 1984 1985 1988 + 1919 1920 1989 1995 + 1926 1996 2001 1932 + 2002 2006 1937 2007 + 2013 2014 1947 1877 + 1948 2018 2026 2027 + 2030 1961 1962 2031 + 2038 2039 2044 1973 + 2045 2048 1978 1979 + 2049 2056 2057 2060 + 1990 1991 2061 2067 + 1997 2068 2073 2074 + 2079 2008 2080 2086 + 2015 2087 2019 1949 + 2020 2090 2096 2097 + 2101 2032 2033 2102 + 2108 2040 2109 2115 + 2116 2119 2050 2051 + 2120 2127 2128 2131 + 2062 2063 2132 2139 + 2140 2144 2075 2145 + 2149 2081 2082 2150 + 2157 2158 2091 2021 + 2164 2169 2098 2170 + 2175 2103 2104 2176 + 2181 2110 2182 2187 + 2188 2192 2121 2122 + 2193 2200 2201 2204 + 2133 2134 2205 2211 + 2212 2218 2146 2219 + 2222 2151 2152 2223 + 2228 2159 2229 2165 + 2236 2240 2171 2172 + 2241 2246 2177 2247 + 2254 2255 2259 2189 + 2260 2265 2194 2195 + 2266 2272 2273 2277 + 2206 2278 2282 2213 + 2214 2283 2290 2291 + 2295 2224 2296 2300 + 2230 2231 2301 2237 + 2308 2313 2242 2314 + 2318 2248 2249 2319 + 2326 2327 2330 2261 + 2262 2331 2336 2267 + 2337 2344 2345 2349 + 2279 2350 2355 2284 + 2285 2356 2362 2363 + 2367 2297 2368 2373 + 2302 2303 2374 2309 + 2380 2385 2315 2386 + 2391 2320 2321 2392 + 2397 2398 2404 2332 + 2405 2409 2338 2339 + 2410 2415 2416 2421 + 2351 2352 2422 2426 + 2357 2427 2433 2434 + 2438 2369 2370 2439 + 2444 2375 2445 2381 + 2452 2457 2387 2388 + 2458 2465 2466 2469 + 2399 2400 2470 2475 + 2406 2476 2483 2484 + 2487 2417 2418 2488 + 2495 2496 2500 2428 + 2501 2506 2435 2507 + 2513 2440 2514 2517 + 2446 2447 2518 2453 + 2523 2527 2459 2460 + 2528 2535 2536 2540 + 2471 2541 2546 2477 + 2478 2547 2553 2554 + 2557 2489 2490 2558 + 2565 2566 2570 2502 + 2571 2575 2508 2509 + 2576 2582 2583 2588 + 2519 2589 2524 2454 + 2596 2602 2529 2530 + 2603 2608 2609 2614 + 2542 2543 2615 2619 + 2548 2620 2626 2627 + 2631 2559 2560 2632 + 2639 2640 2645 2572 + 2646 2651 2577 2652 + 2656 2584 2657 2662 + 2590 2591 2663 2597 + 2598 2666 2674 2675 + 2678 2610 2611 2679 + 2686 2687 2691 2621 + 2692 2697 2628 2698 + 2702 2633 2634 2703 + 2709 2641 2710 2715 + 2647 2716 2722 2723 + 2726 2658 2659 2727 + 2734 2735 2667 2599 + 2668 2738 2746 2747 + 2750 2680 2681 2751 + 2758 2759 2764 2693 + 2765 2769 2699 2770 + 2774 2704 2705 2775 + 2781 2711 2782 2787 + 2717 2788 2793 2794 + 2798 2728 2729 2799 + 2806 2807 2739 2669 + 2740 2810 2816 2817 + 2821 2752 2753 2822 + 2828 2760 2829 2835 + 2836 2840 2771 2841 + 2846 2776 2777 2847 + 2851 2783 2852 2858 + 2859 2864 2795 2865 + 2869 2800 2801 2870 + 2877 2878 2811 2741 + 2884 2889 2818 2890 + 2894 2823 2824 2895 + 2901 2830 2902 2907 + 2908 2912 2842 2843 + 2913 2919 2920 2926 + 2853 2927 2932 2860 + 2933 2938 2866 2939 + 2942 2871 2872 2943 + 2949 2879 2950 2885 + 2956 2963 2891 2964 + 2967 2896 2897 2968 + 2974 2975 2980 2909 + 2981 2987 2914 2988 + 2991 2921 2922 2992 + 2998 2928 2999 3003 + 2934 3004 3011 3012 + 3015 2944 2945 3016 + 3022 2951 3023 2957 + 2958 3026 3032 3033 + 3039 2969 3040 3044 + 2976 3045 3049 2982 + 2983 3050 3057 3058 + 3062 2993 2994 3063 + 3068 3069 3073 3005 + 3006 3074 3080 3081 + 3086 3017 3018 3087 + 3092 3093 3027 2959 + 3100 3104 3034 3035 + 3105 3112 3113 3117 + 3046 3118 3122 3051 + 3052 3123 3129 3059 + 3130 3136 3137 3141 + 3070 3142 3147 3075 + 3148 3153 3082 3083 + 3154 3160 3161 3164 + 3094 3095 3165 3101 + 3172 3176 3106 3107 + 3177 3184 3185 3189 + 3119 3190 3195 3124 + 3125 3196 3201 3131 + 3202 3207 3208 3214 + 3143 3215 3218 3149 + 3150 3219 3224 3155 + 3225 3232 3233 3236 + 3166 3167 3237 3173 + 3244 3249 3178 3179 + 3250 3256 3257 3261 + 3191 3192 3262 3268 + 3197 3269 3274 3275 + 3279 3209 3210 3280 + 3286 3287 3292 3220 + 3293 3297 3226 3227 + 3298 3305 3306 3310 + 3238 3239 3311 3245 + 3315 3322 3251 3323 + 3328 3258 3329 3332 + 3263 3264 3333 3340 + 3341 3345 3276 3346 + 3351 3281 3352 3358 + 3288 3359 3363 3294 + 3364 3368 3299 3300 + 3369 3375 3307 3376 + 3381 3382 3316 3246 + 3317 3386 3391 3324 + 3392 3399 3400 3403 + 3334 3335 3404 3411 + 3412 3417 3347 3418 + 3421 3353 3354 3422 + 3429 3430 3434 3365 + 3435 3439 3370 3371 + 3440 3447 3448 3452 + 3383 3453 3387 3318 + 6 10 3393 3394 + 11 18 19 22 + 3405 3406 23 28 + 3413 29 36 37 + 40 3423 3424 41 + 48 49 54 3436 + 55 58 3441 3442 + 59 66 67 70 + 3454 3455 71 7 + + } + } + } + VertexArray TRUE { + osg::Vec3Array { + UniqueID 208 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 209 + } + } + Binding BIND_PER_VERTEX + vector 3456 { + 1.998 0 0 + 1.998 0 0 + 1.998 0 0 + 1.998 0 0 + 1.998 0 0 + 1.998 0 0 + 1.998 0 0 + 1.998 0 0 + 1.99144 0 0.0245 + 1.99144 0 0.0245 + 1.99144 0 0.0245 + 1.99144 0 0.0245 + 1.9735 0 0.0424352 + 1.9735 0 0.0424352 + 1.9735 0 0.0424352 + 1.9735 0 0.0424352 + 1.9735 0 0.0424352 + 1.9735 0 0.0424352 + 1.9735 0 0.0424352 + 1.9735 0 0.0424352 + 1.949 0 0.049 + 1.949 0 0.049 + 1.949 0 0.049 + 1.949 0 0.049 + 1.9245 0 0.0424352 + 1.9245 0 0.0424352 + 1.9245 0 0.0424352 + 1.9245 0 0.0424352 + 1.9245 0 0.0424352 + 1.9245 0 0.0424352 + 1.90656 0 0.0245 + 1.90656 0 0.0245 + 1.90656 0 0.0245 + 1.90656 0 0.0245 + 1.90656 0 0.0245 + 1.90656 0 0.0245 + 1.90656 0 0.0245 + 1.90656 0 0.0245 + 1.9 0 0 + 1.9 0 0 + 1.9 0 0 + 1.9 0 0 + 1.90656 0 -0.0245 + 1.90656 0 -0.0245 + 1.90656 0 -0.0245 + 1.90656 0 -0.0245 + 1.90656 0 -0.0245 + 1.90656 0 -0.0245 + 1.90656 0 -0.0245 + 1.90656 0 -0.0245 + 1.9245 0 -0.0424352 + 1.9245 0 -0.0424352 + 1.9245 0 -0.0424352 + 1.9245 0 -0.0424352 + 1.9245 0 -0.0424352 + 1.9245 0 -0.0424352 + 1.949 0 -0.049 + 1.949 0 -0.049 + 1.949 0 -0.049 + 1.949 0 -0.049 + 1.9735 0 -0.0424352 + 1.9735 0 -0.0424352 + 1.9735 0 -0.0424352 + 1.9735 0 -0.0424352 + 1.9735 0 -0.0424352 + 1.9735 0 -0.0424352 + 1.9735 0 -0.0424352 + 1.9735 0 -0.0424352 + 1.99144 0 -0.0245 + 1.99144 0 -0.0245 + 1.99144 0 -0.0245 + 1.99144 0 -0.0245 + 1.98091 0.260791 0 + 1.98091 0.260791 0 + 1.98091 0.260791 0 + 1.98091 0.260791 0 + 1.98091 0.260791 0 + 1.98091 0.260791 0 + 1.9744 0.259934 0.0245 + 1.9744 0.259934 0.0245 + 1.9744 0.259934 0.0245 + 1.9744 0.259934 0.0245 + 1.9744 0.259934 0.0245 + 1.9744 0.259934 0.0245 + 1.95662 0.257593 0.0424352 + 1.95662 0.257593 0.0424352 + 1.95662 0.257593 0.0424352 + 1.95662 0.257593 0.0424352 + 1.95662 0.257593 0.0424352 + 1.95662 0.257593 0.0424352 + 1.93233 0.254395 0.049 + 1.93233 0.254395 0.049 + 1.93233 0.254395 0.049 + 1.93233 0.254395 0.049 + 1.93233 0.254395 0.049 + 1.93233 0.254395 0.049 + 1.90804 0.251198 0.0424352 + 1.90804 0.251198 0.0424352 + 1.90804 0.251198 0.0424352 + 1.90804 0.251198 0.0424352 + 1.90804 0.251198 0.0424352 + 1.90804 0.251198 0.0424352 + 1.89025 0.248857 0.0245 + 1.89025 0.248857 0.0245 + 1.89025 0.248857 0.0245 + 1.89025 0.248857 0.0245 + 1.89025 0.248857 0.0245 + 1.89025 0.248857 0.0245 + 1.88374 0.248 0 + 1.88374 0.248 0 + 1.88374 0.248 0 + 1.88374 0.248 0 + 1.88374 0.248 0 + 1.88374 0.248 0 + 1.89025 0.248857 -0.0245 + 1.89025 0.248857 -0.0245 + 1.89025 0.248857 -0.0245 + 1.89025 0.248857 -0.0245 + 1.89025 0.248857 -0.0245 + 1.89025 0.248857 -0.0245 + 1.90804 0.251198 -0.0424352 + 1.90804 0.251198 -0.0424352 + 1.90804 0.251198 -0.0424352 + 1.90804 0.251198 -0.0424352 + 1.90804 0.251198 -0.0424352 + 1.90804 0.251198 -0.0424352 + 1.93233 0.254395 -0.049 + 1.93233 0.254395 -0.049 + 1.93233 0.254395 -0.049 + 1.93233 0.254395 -0.049 + 1.93233 0.254395 -0.049 + 1.93233 0.254395 -0.049 + 1.95662 0.257593 -0.0424352 + 1.95662 0.257593 -0.0424352 + 1.95662 0.257593 -0.0424352 + 1.95662 0.257593 -0.0424352 + 1.95662 0.257593 -0.0424352 + 1.95662 0.257593 -0.0424352 + 1.9744 0.259934 -0.0245 + 1.9744 0.259934 -0.0245 + 1.9744 0.259934 -0.0245 + 1.9744 0.259934 -0.0245 + 1.9744 0.259934 -0.0245 + 1.9744 0.259934 -0.0245 + 1.92992 0.51712 0 + 1.92992 0.51712 0 + 1.92992 0.51712 0 + 1.92992 0.51712 0 + 1.92992 0.51712 0 + 1.92992 0.51712 0 + 1.92358 0.515421 0.0245 + 1.92358 0.515421 0.0245 + 1.92358 0.515421 0.0245 + 1.92358 0.515421 0.0245 + 1.92358 0.515421 0.0245 + 1.92358 0.515421 0.0245 + 1.90625 0.510779 0.0424352 + 1.90625 0.510779 0.0424352 + 1.90625 0.510779 0.0424352 + 1.90625 0.510779 0.0424352 + 1.90625 0.510779 0.0424352 + 1.90625 0.510779 0.0424352 + 1.88259 0.504438 0.049 + 1.88259 0.504438 0.049 + 1.88259 0.504438 0.049 + 1.88259 0.504438 0.049 + 1.88259 0.504438 0.049 + 1.88259 0.504438 0.049 + 1.85892 0.498097 0.0424352 + 1.85892 0.498097 0.0424352 + 1.85892 0.498097 0.0424352 + 1.85892 0.498097 0.0424352 + 1.85892 0.498097 0.0424352 + 1.85892 0.498097 0.0424352 + 1.8416 0.493455 0.0245 + 1.8416 0.493455 0.0245 + 1.8416 0.493455 0.0245 + 1.8416 0.493455 0.0245 + 1.8416 0.493455 0.0245 + 1.8416 0.493455 0.0245 + 1.83526 0.491756 0 + 1.83526 0.491756 0 + 1.83526 0.491756 0 + 1.83526 0.491756 0 + 1.83526 0.491756 0 + 1.83526 0.491756 0 + 1.8416 0.493455 -0.0245 + 1.8416 0.493455 -0.0245 + 1.8416 0.493455 -0.0245 + 1.8416 0.493455 -0.0245 + 1.8416 0.493455 -0.0245 + 1.85892 0.498097 -0.0424352 + 1.85892 0.498097 -0.0424352 + 1.85892 0.498097 -0.0424352 + 1.85892 0.498097 -0.0424352 + 1.85892 0.498097 -0.0424352 + 1.85892 0.498097 -0.0424352 + 1.85892 0.498097 -0.0424352 + 1.88259 0.504438 -0.049 + 1.88259 0.504438 -0.049 + 1.88259 0.504438 -0.049 + 1.88259 0.504438 -0.049 + 1.88259 0.504438 -0.049 + 1.88259 0.504438 -0.049 + 1.90625 0.510779 -0.0424352 + 1.90625 0.510779 -0.0424352 + 1.90625 0.510779 -0.0424352 + 1.90625 0.510779 -0.0424352 + 1.90625 0.510779 -0.0424352 + 1.90625 0.510779 -0.0424352 + 1.92358 0.515421 -0.0245 + 1.92358 0.515421 -0.0245 + 1.92358 0.515421 -0.0245 + 1.92358 0.515421 -0.0245 + 1.92358 0.515421 -0.0245 + 1.92358 0.515421 -0.0245 + 1.84591 0.764601 0 + 1.84591 0.764601 0 + 1.84591 0.764601 0 + 1.84591 0.764601 0 + 1.84591 0.764601 0 + 1.84591 0.764601 0 + 1.83985 0.762089 0.0245 + 1.83985 0.762089 0.0245 + 1.83985 0.762089 0.0245 + 1.83985 0.762089 0.0245 + 1.83985 0.762089 0.0245 + 1.83985 0.762089 0.0245 + 1.82328 0.755225 0.0424352 + 1.82328 0.755225 0.0424352 + 1.82328 0.755225 0.0424352 + 1.82328 0.755225 0.0424352 + 1.82328 0.755225 0.0424352 + 1.82328 0.755225 0.0424352 + 1.80064 0.74585 0.049 + 1.80064 0.74585 0.049 + 1.80064 0.74585 0.049 + 1.80064 0.74585 0.049 + 1.80064 0.74585 0.049 + 1.80064 0.74585 0.049 + 1.77801 0.736474 0.0424352 + 1.77801 0.736474 0.0424352 + 1.77801 0.736474 0.0424352 + 1.77801 0.736474 0.0424352 + 1.77801 0.736474 0.0424352 + 1.77801 0.736474 0.0424352 + 1.77801 0.736474 0.0424352 + 1.76144 0.729611 0.0245 + 1.76144 0.729611 0.0245 + 1.76144 0.729611 0.0245 + 1.76144 0.729611 0.0245 + 1.76144 0.729611 0.0245 + 1.75537 0.727098 0 + 1.75537 0.727098 0 + 1.75537 0.727098 0 + 1.75537 0.727098 0 + 1.75537 0.727098 0 + 1.75537 0.727098 0 + 1.76144 0.729611 -0.0245 + 1.76144 0.729611 -0.0245 + 1.76144 0.729611 -0.0245 + 1.76144 0.729611 -0.0245 + 1.76144 0.729611 -0.0245 + 1.76144 0.729611 -0.0245 + 1.77801 0.736474 -0.0424352 + 1.77801 0.736474 -0.0424352 + 1.77801 0.736474 -0.0424352 + 1.77801 0.736474 -0.0424352 + 1.77801 0.736474 -0.0424352 + 1.77801 0.736474 -0.0424352 + 1.80064 0.74585 -0.049 + 1.80064 0.74585 -0.049 + 1.80064 0.74585 -0.049 + 1.80064 0.74585 -0.049 + 1.80064 0.74585 -0.049 + 1.80064 0.74585 -0.049 + 1.82328 0.755225 -0.0424352 + 1.82328 0.755225 -0.0424352 + 1.82328 0.755225 -0.0424352 + 1.82328 0.755225 -0.0424352 + 1.82328 0.755225 -0.0424352 + 1.82328 0.755225 -0.0424352 + 1.83985 0.762089 -0.0245 + 1.83985 0.762089 -0.0245 + 1.83985 0.762089 -0.0245 + 1.83985 0.762089 -0.0245 + 1.83985 0.762089 -0.0245 + 1.83985 0.762089 -0.0245 + 1.73032 0.999 0 + 1.73032 0.999 0 + 1.73032 0.999 0 + 1.73032 0.999 0 + 1.73032 0.999 0 + 1.73032 0.999 0 + 1.72463 0.995718 0.0245 + 1.72463 0.995718 0.0245 + 1.72463 0.995718 0.0245 + 1.72463 0.995718 0.0245 + 1.72463 0.995718 0.0245 + 1.72463 0.995718 0.0245 + 1.7091 0.98675 0.0424352 + 1.7091 0.98675 0.0424352 + 1.7091 0.98675 0.0424352 + 1.7091 0.98675 0.0424352 + 1.7091 0.98675 0.0424352 + 1.7091 0.98675 0.0424352 + 1.68788 0.9745 0.049 + 1.68788 0.9745 0.049 + 1.68788 0.9745 0.049 + 1.68788 0.9745 0.049 + 1.68788 0.9745 0.049 + 1.68788 0.9745 0.049 + 1.68788 0.9745 0.049 + 1.66667 0.96225 0.0424352 + 1.66667 0.96225 0.0424352 + 1.66667 0.96225 0.0424352 + 1.66667 0.96225 0.0424352 + 1.65113 0.953282 0.0245 + 1.65113 0.953282 0.0245 + 1.65113 0.953282 0.0245 + 1.65113 0.953282 0.0245 + 1.65113 0.953282 0.0245 + 1.65113 0.953282 0.0245 + 1.64545 0.95 0 + 1.64545 0.95 0 + 1.64545 0.95 0 + 1.64545 0.95 0 + 1.64545 0.95 0 + 1.64545 0.95 0 + 1.64545 0.95 0 + 1.64545 0.95 0 + 1.65113 0.953282 -0.0245 + 1.65113 0.953282 -0.0245 + 1.65113 0.953282 -0.0245 + 1.65113 0.953282 -0.0245 + 1.65113 0.953282 -0.0245 + 1.65113 0.953282 -0.0245 + 1.66667 0.96225 -0.0424352 + 1.66667 0.96225 -0.0424352 + 1.66667 0.96225 -0.0424352 + 1.66667 0.96225 -0.0424352 + 1.68788 0.9745 -0.049 + 1.68788 0.9745 -0.049 + 1.68788 0.9745 -0.049 + 1.68788 0.9745 -0.049 + 1.68788 0.9745 -0.049 + 1.68788 0.9745 -0.049 + 1.68788 0.9745 -0.049 + 1.7091 0.98675 -0.0424352 + 1.7091 0.98675 -0.0424352 + 1.7091 0.98675 -0.0424352 + 1.7091 0.98675 -0.0424352 + 1.7091 0.98675 -0.0424352 + 1.7091 0.98675 -0.0424352 + 1.72463 0.995718 -0.0245 + 1.72463 0.995718 -0.0245 + 1.72463 0.995718 -0.0245 + 1.72463 0.995718 -0.0245 + 1.72463 0.995718 -0.0245 + 1.72463 0.995718 -0.0245 + 1.58512 1.21631 0 + 1.58512 1.21631 0 + 1.58512 1.21631 0 + 1.58512 1.21631 0 + 1.58512 1.21631 0 + 1.58512 1.21631 0 + 1.57991 1.21231 0.0245 + 1.57991 1.21231 0.0245 + 1.57991 1.21231 0.0245 + 1.57991 1.21231 0.0245 + 1.57991 1.21231 0.0245 + 1.57991 1.21231 0.0245 + 1.56568 1.20139 0.0424352 + 1.56568 1.20139 0.0424352 + 1.56568 1.20139 0.0424352 + 1.56568 1.20139 0.0424352 + 1.56568 1.20139 0.0424352 + 1.56568 1.20139 0.0424352 + 1.54625 1.18648 0.049 + 1.54625 1.18648 0.049 + 1.54625 1.18648 0.049 + 1.54625 1.18648 0.049 + 1.54625 1.18648 0.049 + 1.54625 1.18648 0.049 + 1.52681 1.17156 0.0424352 + 1.52681 1.17156 0.0424352 + 1.52681 1.17156 0.0424352 + 1.52681 1.17156 0.0424352 + 1.52681 1.17156 0.0424352 + 1.52681 1.17156 0.0424352 + 1.51258 1.16064 0.0245 + 1.51258 1.16064 0.0245 + 1.51258 1.16064 0.0245 + 1.51258 1.16064 0.0245 + 1.51258 1.16064 0.0245 + 1.51258 1.16064 0.0245 + 1.50737 1.15665 0 + 1.50737 1.15665 0 + 1.50737 1.15665 0 + 1.50737 1.15665 0 + 1.50737 1.15665 0 + 1.50737 1.15665 0 + 1.51258 1.16064 -0.0245 + 1.51258 1.16064 -0.0245 + 1.51258 1.16064 -0.0245 + 1.51258 1.16064 -0.0245 + 1.51258 1.16064 -0.0245 + 1.51258 1.16064 -0.0245 + 1.52681 1.17156 -0.0424352 + 1.52681 1.17156 -0.0424352 + 1.52681 1.17156 -0.0424352 + 1.52681 1.17156 -0.0424352 + 1.52681 1.17156 -0.0424352 + 1.52681 1.17156 -0.0424352 + 1.54625 1.18648 -0.049 + 1.54625 1.18648 -0.049 + 1.54625 1.18648 -0.049 + 1.54625 1.18648 -0.049 + 1.54625 1.18648 -0.049 + 1.54625 1.18648 -0.049 + 1.56568 1.20139 -0.0424352 + 1.56568 1.20139 -0.0424352 + 1.56568 1.20139 -0.0424352 + 1.56568 1.20139 -0.0424352 + 1.56568 1.20139 -0.0424352 + 1.56568 1.20139 -0.0424352 + 1.57991 1.21231 -0.0245 + 1.57991 1.21231 -0.0245 + 1.57991 1.21231 -0.0245 + 1.57991 1.21231 -0.0245 + 1.57991 1.21231 -0.0245 + 1.57991 1.21231 -0.0245 + 1.4128 1.4128 0 + 1.4128 1.4128 0 + 1.4128 1.4128 0 + 1.4128 1.4128 0 + 1.4128 1.4128 0 + 1.4128 1.4128 0 + 1.40816 1.40816 0.0245 + 1.40816 1.40816 0.0245 + 1.40816 1.40816 0.0245 + 1.40816 1.40816 0.0245 + 1.40816 1.40816 0.0245 + 1.40816 1.40816 0.0245 + 1.39548 1.39548 0.0424352 + 1.39548 1.39548 0.0424352 + 1.39548 1.39548 0.0424352 + 1.39548 1.39548 0.0424352 + 1.39548 1.39548 0.0424352 + 1.37815 1.37815 0.049 + 1.37815 1.37815 0.049 + 1.37815 1.37815 0.049 + 1.37815 1.37815 0.049 + 1.37815 1.37815 0.049 + 1.37815 1.37815 0.049 + 1.37815 1.37815 0.049 + 1.36083 1.36083 0.0424352 + 1.36083 1.36083 0.0424352 + 1.36083 1.36083 0.0424352 + 1.36083 1.36083 0.0424352 + 1.36083 1.36083 0.0424352 + 1.36083 1.36083 0.0424352 + 1.36083 1.36083 0.0424352 + 1.34815 1.34815 0.0245 + 1.34815 1.34815 0.0245 + 1.34815 1.34815 0.0245 + 1.34815 1.34815 0.0245 + 1.34815 1.34815 0.0245 + 1.3435 1.3435 0 + 1.3435 1.3435 0 + 1.3435 1.3435 0 + 1.3435 1.3435 0 + 1.3435 1.3435 0 + 1.3435 1.3435 0 + 1.34815 1.34815 -0.0245 + 1.34815 1.34815 -0.0245 + 1.34815 1.34815 -0.0245 + 1.34815 1.34815 -0.0245 + 1.34815 1.34815 -0.0245 + 1.36083 1.36083 -0.0424352 + 1.36083 1.36083 -0.0424352 + 1.36083 1.36083 -0.0424352 + 1.36083 1.36083 -0.0424352 + 1.36083 1.36083 -0.0424352 + 1.36083 1.36083 -0.0424352 + 1.36083 1.36083 -0.0424352 + 1.37815 1.37815 -0.049 + 1.37815 1.37815 -0.049 + 1.37815 1.37815 -0.049 + 1.37815 1.37815 -0.049 + 1.37815 1.37815 -0.049 + 1.37815 1.37815 -0.049 + 1.37815 1.37815 -0.049 + 1.39548 1.39548 -0.0424352 + 1.39548 1.39548 -0.0424352 + 1.39548 1.39548 -0.0424352 + 1.39548 1.39548 -0.0424352 + 1.40816 1.40816 -0.0245 + 1.40816 1.40816 -0.0245 + 1.40816 1.40816 -0.0245 + 1.40816 1.40816 -0.0245 + 1.40816 1.40816 -0.0245 + 1.40816 1.40816 -0.0245 + 1.40816 1.40816 -0.0245 + 1.21631 1.58512 0 + 1.21631 1.58512 0 + 1.21631 1.58512 0 + 1.21631 1.58512 0 + 1.21631 1.58512 0 + 1.21631 1.58512 0 + 1.21231 1.57991 0.0245 + 1.21231 1.57991 0.0245 + 1.21231 1.57991 0.0245 + 1.21231 1.57991 0.0245 + 1.21231 1.57991 0.0245 + 1.21231 1.57991 0.0245 + 1.21231 1.57991 0.0245 + 1.20139 1.56568 0.0424352 + 1.20139 1.56568 0.0424352 + 1.20139 1.56568 0.0424352 + 1.20139 1.56568 0.0424352 + 1.20139 1.56568 0.0424352 + 1.18648 1.54624 0.049 + 1.18648 1.54624 0.049 + 1.18648 1.54624 0.049 + 1.18648 1.54624 0.049 + 1.18648 1.54624 0.049 + 1.18648 1.54624 0.049 + 1.17156 1.52681 0.0424352 + 1.17156 1.52681 0.0424352 + 1.17156 1.52681 0.0424352 + 1.17156 1.52681 0.0424352 + 1.17156 1.52681 0.0424352 + 1.17156 1.52681 0.0424352 + 1.16064 1.51258 0.0245 + 1.16064 1.51258 0.0245 + 1.16064 1.51258 0.0245 + 1.16064 1.51258 0.0245 + 1.16064 1.51258 0.0245 + 1.16064 1.51258 0.0245 + 1.15665 1.50737 0 + 1.15665 1.50737 0 + 1.15665 1.50737 0 + 1.15665 1.50737 0 + 1.15665 1.50737 0 + 1.15665 1.50737 0 + 1.16064 1.51258 -0.0245 + 1.16064 1.51258 -0.0245 + 1.16064 1.51258 -0.0245 + 1.16064 1.51258 -0.0245 + 1.16064 1.51258 -0.0245 + 1.16064 1.51258 -0.0245 + 1.17156 1.52681 -0.0424352 + 1.17156 1.52681 -0.0424352 + 1.17156 1.52681 -0.0424352 + 1.17156 1.52681 -0.0424352 + 1.17156 1.52681 -0.0424352 + 1.17156 1.52681 -0.0424352 + 1.18648 1.54624 -0.049 + 1.18648 1.54624 -0.049 + 1.18648 1.54624 -0.049 + 1.18648 1.54624 -0.049 + 1.18648 1.54624 -0.049 + 1.18648 1.54624 -0.049 + 1.20139 1.56568 -0.0424352 + 1.20139 1.56568 -0.0424352 + 1.20139 1.56568 -0.0424352 + 1.20139 1.56568 -0.0424352 + 1.20139 1.56568 -0.0424352 + 1.20139 1.56568 -0.0424352 + 1.21231 1.57991 -0.0245 + 1.21231 1.57991 -0.0245 + 1.21231 1.57991 -0.0245 + 1.21231 1.57991 -0.0245 + 1.21231 1.57991 -0.0245 + 1.21231 1.57991 -0.0245 + 0.999 1.73032 0 + 0.999 1.73032 0 + 0.999 1.73032 0 + 0.999 1.73032 0 + 0.999 1.73032 0 + 0.999 1.73032 0 + 0.995718 1.72463 0.0245 + 0.995718 1.72463 0.0245 + 0.995718 1.72463 0.0245 + 0.995718 1.72463 0.0245 + 0.995718 1.72463 0.0245 + 0.995718 1.72463 0.0245 + 0.98675 1.7091 0.0424352 + 0.98675 1.7091 0.0424352 + 0.98675 1.7091 0.0424352 + 0.98675 1.7091 0.0424352 + 0.98675 1.7091 0.0424352 + 0.98675 1.7091 0.0424352 + 0.9745 1.68788 0.049 + 0.9745 1.68788 0.049 + 0.9745 1.68788 0.049 + 0.9745 1.68788 0.049 + 0.9745 1.68788 0.049 + 0.96225 1.66667 0.0424352 + 0.96225 1.66667 0.0424352 + 0.96225 1.66667 0.0424352 + 0.96225 1.66667 0.0424352 + 0.96225 1.66667 0.0424352 + 0.96225 1.66667 0.0424352 + 0.953282 1.65113 0.0245 + 0.953282 1.65113 0.0245 + 0.953282 1.65113 0.0245 + 0.953282 1.65113 0.0245 + 0.953282 1.65113 0.0245 + 0.953282 1.65113 0.0245 + 0.953282 1.65113 0.0245 + 0.95 1.64545 0 + 0.95 1.64545 0 + 0.95 1.64545 0 + 0.95 1.64545 0 + 0.95 1.64545 0 + 0.95 1.64545 0 + 0.953282 1.65113 -0.0245 + 0.953282 1.65113 -0.0245 + 0.953282 1.65113 -0.0245 + 0.953282 1.65113 -0.0245 + 0.953282 1.65113 -0.0245 + 0.953282 1.65113 -0.0245 + 0.96225 1.66667 -0.0424352 + 0.96225 1.66667 -0.0424352 + 0.96225 1.66667 -0.0424352 + 0.96225 1.66667 -0.0424352 + 0.96225 1.66667 -0.0424352 + 0.96225 1.66667 -0.0424352 + 0.96225 1.66667 -0.0424352 + 0.9745 1.68788 -0.049 + 0.9745 1.68788 -0.049 + 0.9745 1.68788 -0.049 + 0.9745 1.68788 -0.049 + 0.9745 1.68788 -0.049 + 0.98675 1.7091 -0.0424352 + 0.98675 1.7091 -0.0424352 + 0.98675 1.7091 -0.0424352 + 0.98675 1.7091 -0.0424352 + 0.98675 1.7091 -0.0424352 + 0.98675 1.7091 -0.0424352 + 0.995718 1.72463 -0.0245 + 0.995718 1.72463 -0.0245 + 0.995718 1.72463 -0.0245 + 0.995718 1.72463 -0.0245 + 0.995718 1.72463 -0.0245 + 0.995718 1.72463 -0.0245 + 0.764602 1.84591 0 + 0.764602 1.84591 0 + 0.764602 1.84591 0 + 0.764602 1.84591 0 + 0.76209 1.83985 0.0245 + 0.76209 1.83985 0.0245 + 0.76209 1.83985 0.0245 + 0.76209 1.83985 0.0245 + 0.76209 1.83985 0.0245 + 0.76209 1.83985 0.0245 + 0.76209 1.83985 0.0245 + 0.755226 1.82328 0.0424352 + 0.755226 1.82328 0.0424352 + 0.755226 1.82328 0.0424352 + 0.755226 1.82328 0.0424352 + 0.755226 1.82328 0.0424352 + 0.755226 1.82328 0.0424352 + 0.74585 1.80064 0.049 + 0.74585 1.80064 0.049 + 0.74585 1.80064 0.049 + 0.74585 1.80064 0.049 + 0.74585 1.80064 0.049 + 0.74585 1.80064 0.049 + 0.736475 1.77801 0.0424352 + 0.736475 1.77801 0.0424352 + 0.736475 1.77801 0.0424352 + 0.736475 1.77801 0.0424352 + 0.736475 1.77801 0.0424352 + 0.736475 1.77801 0.0424352 + 0.736475 1.77801 0.0424352 + 0.729611 1.76144 0.0245 + 0.729611 1.76144 0.0245 + 0.729611 1.76144 0.0245 + 0.729611 1.76144 0.0245 + 0.729611 1.76144 0.0245 + 0.727099 1.75537 0 + 0.727099 1.75537 0 + 0.727099 1.75537 0 + 0.727099 1.75537 0 + 0.727099 1.75537 0 + 0.727099 1.75537 0 + 0.729611 1.76144 -0.0245 + 0.729611 1.76144 -0.0245 + 0.729611 1.76144 -0.0245 + 0.729611 1.76144 -0.0245 + 0.729611 1.76144 -0.0245 + 0.729611 1.76144 -0.0245 + 0.736475 1.77801 -0.0424352 + 0.736475 1.77801 -0.0424352 + 0.736475 1.77801 -0.0424352 + 0.736475 1.77801 -0.0424352 + 0.736475 1.77801 -0.0424352 + 0.74585 1.80064 -0.049 + 0.74585 1.80064 -0.049 + 0.74585 1.80064 -0.049 + 0.74585 1.80064 -0.049 + 0.74585 1.80064 -0.049 + 0.74585 1.80064 -0.049 + 0.74585 1.80064 -0.049 + 0.755226 1.82328 -0.0424352 + 0.755226 1.82328 -0.0424352 + 0.755226 1.82328 -0.0424352 + 0.755226 1.82328 -0.0424352 + 0.755226 1.82328 -0.0424352 + 0.755226 1.82328 -0.0424352 + 0.76209 1.83985 -0.0245 + 0.76209 1.83985 -0.0245 + 0.76209 1.83985 -0.0245 + 0.76209 1.83985 -0.0245 + 0.76209 1.83985 -0.0245 + 0.76209 1.83985 -0.0245 + 0.76209 1.83985 -0.0245 + 0.51712 1.92992 0 + 0.51712 1.92992 0 + 0.51712 1.92992 0 + 0.51712 1.92992 0 + 0.51712 1.92992 0 + 0.51712 1.92992 0 + 0.515421 1.92358 0.0245 + 0.515421 1.92358 0.0245 + 0.515421 1.92358 0.0245 + 0.515421 1.92358 0.0245 + 0.515421 1.92358 0.0245 + 0.515421 1.92358 0.0245 + 0.51078 1.90625 0.0424352 + 0.51078 1.90625 0.0424352 + 0.51078 1.90625 0.0424352 + 0.51078 1.90625 0.0424352 + 0.51078 1.90625 0.0424352 + 0.51078 1.90625 0.0424352 + 0.504438 1.88259 0.049 + 0.504438 1.88259 0.049 + 0.504438 1.88259 0.049 + 0.504438 1.88259 0.049 + 0.504438 1.88259 0.049 + 0.504438 1.88259 0.049 + 0.504438 1.88259 0.049 + 0.498097 1.85892 0.0424352 + 0.498097 1.85892 0.0424352 + 0.498097 1.85892 0.0424352 + 0.498097 1.85892 0.0424352 + 0.498097 1.85892 0.0424352 + 0.493455 1.8416 0.0245 + 0.493455 1.8416 0.0245 + 0.493455 1.8416 0.0245 + 0.493455 1.8416 0.0245 + 0.493455 1.8416 0.0245 + 0.493455 1.8416 0.0245 + 0.491756 1.83526 0 + 0.491756 1.83526 0 + 0.491756 1.83526 0 + 0.491756 1.83526 0 + 0.491756 1.83526 0 + 0.491756 1.83526 0 + 0.493455 1.8416 -0.0245 + 0.493455 1.8416 -0.0245 + 0.493455 1.8416 -0.0245 + 0.493455 1.8416 -0.0245 + 0.493455 1.8416 -0.0245 + 0.493455 1.8416 -0.0245 + 0.498097 1.85892 -0.0424352 + 0.498097 1.85892 -0.0424352 + 0.498097 1.85892 -0.0424352 + 0.498097 1.85892 -0.0424352 + 0.498097 1.85892 -0.0424352 + 0.498097 1.85892 -0.0424352 + 0.504438 1.88259 -0.049 + 0.504438 1.88259 -0.049 + 0.504438 1.88259 -0.049 + 0.504438 1.88259 -0.049 + 0.504438 1.88259 -0.049 + 0.504438 1.88259 -0.049 + 0.51078 1.90625 -0.0424352 + 0.51078 1.90625 -0.0424352 + 0.51078 1.90625 -0.0424352 + 0.51078 1.90625 -0.0424352 + 0.51078 1.90625 -0.0424352 + 0.51078 1.90625 -0.0424352 + 0.515421 1.92358 -0.0245 + 0.515421 1.92358 -0.0245 + 0.515421 1.92358 -0.0245 + 0.515421 1.92358 -0.0245 + 0.515421 1.92358 -0.0245 + 0.515421 1.92358 -0.0245 + 0.260791 1.98091 0 + 0.260791 1.98091 0 + 0.260791 1.98091 0 + 0.260791 1.98091 0 + 0.260791 1.98091 0 + 0.260791 1.98091 0 + 0.259934 1.9744 0.0245 + 0.259934 1.9744 0.0245 + 0.259934 1.9744 0.0245 + 0.259934 1.9744 0.0245 + 0.259934 1.9744 0.0245 + 0.259934 1.9744 0.0245 + 0.257593 1.95662 0.0424352 + 0.257593 1.95662 0.0424352 + 0.257593 1.95662 0.0424352 + 0.257593 1.95662 0.0424352 + 0.257593 1.95662 0.0424352 + 0.257593 1.95662 0.0424352 + 0.254395 1.93233 0.049 + 0.254395 1.93233 0.049 + 0.254395 1.93233 0.049 + 0.254395 1.93233 0.049 + 0.254395 1.93233 0.049 + 0.254395 1.93233 0.049 + 0.251197 1.90804 0.0424352 + 0.251197 1.90804 0.0424352 + 0.251197 1.90804 0.0424352 + 0.251197 1.90804 0.0424352 + 0.251197 1.90804 0.0424352 + 0.251197 1.90804 0.0424352 + 0.248856 1.89025 0.0245 + 0.248856 1.89025 0.0245 + 0.248856 1.89025 0.0245 + 0.248856 1.89025 0.0245 + 0.248856 1.89025 0.0245 + 0.248856 1.89025 0.0245 + 0.248856 1.89025 0.0245 + 0.247999 1.88374 0 + 0.247999 1.88374 0 + 0.247999 1.88374 0 + 0.247999 1.88374 0 + 0.248856 1.89025 -0.0245 + 0.248856 1.89025 -0.0245 + 0.248856 1.89025 -0.0245 + 0.248856 1.89025 -0.0245 + 0.248856 1.89025 -0.0245 + 0.248856 1.89025 -0.0245 + 0.248856 1.89025 -0.0245 + 0.251197 1.90804 -0.0424352 + 0.251197 1.90804 -0.0424352 + 0.251197 1.90804 -0.0424352 + 0.251197 1.90804 -0.0424352 + 0.251197 1.90804 -0.0424352 + 0.251197 1.90804 -0.0424352 + 0.254395 1.93233 -0.049 + 0.254395 1.93233 -0.049 + 0.254395 1.93233 -0.049 + 0.254395 1.93233 -0.049 + 0.254395 1.93233 -0.049 + 0.254395 1.93233 -0.049 + 0.257593 1.95662 -0.0424352 + 0.257593 1.95662 -0.0424352 + 0.257593 1.95662 -0.0424352 + 0.257593 1.95662 -0.0424352 + 0.257593 1.95662 -0.0424352 + 0.257593 1.95662 -0.0424352 + 0.259934 1.9744 -0.0245 + 0.259934 1.9744 -0.0245 + 0.259934 1.9744 -0.0245 + 0.259934 1.9744 -0.0245 + 0.259934 1.9744 -0.0245 + 0.259934 1.9744 -0.0245 + 1.50845e-07 1.998 0 + 1.50845e-07 1.998 0 + 1.50845e-07 1.998 0 + 1.50845e-07 1.998 0 + 1.50845e-07 1.998 0 + 1.50845e-07 1.998 0 + 1.50349e-07 1.99144 0.0245 + 1.50349e-07 1.99144 0.0245 + 1.50349e-07 1.99144 0.0245 + 1.50349e-07 1.99144 0.0245 + 1.50349e-07 1.99144 0.0245 + 1.48995e-07 1.9735 0.0424352 + 1.48995e-07 1.9735 0.0424352 + 1.48995e-07 1.9735 0.0424352 + 1.48995e-07 1.9735 0.0424352 + 1.48995e-07 1.9735 0.0424352 + 1.48995e-07 1.9735 0.0424352 + 1.48995e-07 1.9735 0.0424352 + 1.47145e-07 1.949 0.049 + 1.47145e-07 1.949 0.049 + 1.47145e-07 1.949 0.049 + 1.47145e-07 1.949 0.049 + 1.47145e-07 1.949 0.049 + 1.45296e-07 1.9245 0.0424352 + 1.45296e-07 1.9245 0.0424352 + 1.45296e-07 1.9245 0.0424352 + 1.45296e-07 1.9245 0.0424352 + 1.45296e-07 1.9245 0.0424352 + 1.45296e-07 1.9245 0.0424352 + 1.43942e-07 1.90656 0.0245 + 1.43942e-07 1.90656 0.0245 + 1.43942e-07 1.90656 0.0245 + 1.43942e-07 1.90656 0.0245 + 1.43942e-07 1.90656 0.0245 + 1.43942e-07 1.90656 0.0245 + 1.43446e-07 1.9 0 + 1.43446e-07 1.9 0 + 1.43446e-07 1.9 0 + 1.43446e-07 1.9 0 + 1.43446e-07 1.9 0 + 1.43446e-07 1.9 0 + 1.43446e-07 1.9 0 + 1.43942e-07 1.90656 -0.0245 + 1.43942e-07 1.90656 -0.0245 + 1.43942e-07 1.90656 -0.0245 + 1.43942e-07 1.90656 -0.0245 + 1.43942e-07 1.90656 -0.0245 + 1.43942e-07 1.90656 -0.0245 + 1.43942e-07 1.90656 -0.0245 + 1.45296e-07 1.9245 -0.0424352 + 1.45296e-07 1.9245 -0.0424352 + 1.45296e-07 1.9245 -0.0424352 + 1.45296e-07 1.9245 -0.0424352 + 1.45296e-07 1.9245 -0.0424352 + 1.45296e-07 1.9245 -0.0424352 + 1.47145e-07 1.949 -0.049 + 1.47145e-07 1.949 -0.049 + 1.47145e-07 1.949 -0.049 + 1.47145e-07 1.949 -0.049 + 1.48995e-07 1.9735 -0.0424352 + 1.48995e-07 1.9735 -0.0424352 + 1.48995e-07 1.9735 -0.0424352 + 1.48995e-07 1.9735 -0.0424352 + 1.48995e-07 1.9735 -0.0424352 + 1.48995e-07 1.9735 -0.0424352 + 1.48995e-07 1.9735 -0.0424352 + 1.50349e-07 1.99144 -0.0245 + 1.50349e-07 1.99144 -0.0245 + 1.50349e-07 1.99144 -0.0245 + 1.50349e-07 1.99144 -0.0245 + 1.50349e-07 1.99144 -0.0245 + 1.50349e-07 1.99144 -0.0245 + -0.260792 1.98091 0 + -0.260792 1.98091 0 + -0.260792 1.98091 0 + -0.260792 1.98091 0 + -0.260792 1.98091 0 + -0.260792 1.98091 0 + -0.260792 1.98091 0 + -0.259935 1.9744 0.0245 + -0.259935 1.9744 0.0245 + -0.259935 1.9744 0.0245 + -0.259935 1.9744 0.0245 + -0.259935 1.9744 0.0245 + -0.259935 1.9744 0.0245 + -0.257594 1.95662 0.0424352 + -0.257594 1.95662 0.0424352 + -0.257594 1.95662 0.0424352 + -0.257594 1.95662 0.0424352 + -0.257594 1.95662 0.0424352 + -0.257594 1.95662 0.0424352 + -0.254396 1.93233 0.049 + -0.254396 1.93233 0.049 + -0.254396 1.93233 0.049 + -0.254396 1.93233 0.049 + -0.254396 1.93233 0.049 + -0.254396 1.93233 0.049 + -0.254396 1.93233 0.049 + -0.251198 1.90804 0.0424352 + -0.251198 1.90804 0.0424352 + -0.251198 1.90804 0.0424352 + -0.251198 1.90804 0.0424352 + -0.251198 1.90804 0.0424352 + -0.251198 1.90804 0.0424352 + -0.248857 1.89025 0.0245 + -0.248857 1.89025 0.0245 + -0.248857 1.89025 0.0245 + -0.248857 1.89025 0.0245 + -0.248857 1.89025 0.0245 + -0.248 1.88374 0 + -0.248 1.88374 0 + -0.248 1.88374 0 + -0.248 1.88374 0 + -0.248 1.88374 0 + -0.248 1.88374 0 + -0.248 1.88374 0 + -0.248857 1.89025 -0.0245 + -0.248857 1.89025 -0.0245 + -0.248857 1.89025 -0.0245 + -0.248857 1.89025 -0.0245 + -0.251198 1.90804 -0.0424352 + -0.251198 1.90804 -0.0424352 + -0.251198 1.90804 -0.0424352 + -0.251198 1.90804 -0.0424352 + -0.251198 1.90804 -0.0424352 + -0.251198 1.90804 -0.0424352 + -0.254396 1.93233 -0.049 + -0.254396 1.93233 -0.049 + -0.254396 1.93233 -0.049 + -0.254396 1.93233 -0.049 + -0.254396 1.93233 -0.049 + -0.254396 1.93233 -0.049 + -0.254396 1.93233 -0.049 + -0.257594 1.95662 -0.0424352 + -0.257594 1.95662 -0.0424352 + -0.257594 1.95662 -0.0424352 + -0.257594 1.95662 -0.0424352 + -0.257594 1.95662 -0.0424352 + -0.257594 1.95662 -0.0424352 + -0.257594 1.95662 -0.0424352 + -0.259935 1.9744 -0.0245 + -0.259935 1.9744 -0.0245 + -0.259935 1.9744 -0.0245 + -0.259935 1.9744 -0.0245 + -0.51712 1.92992 0 + -0.51712 1.92992 0 + -0.51712 1.92992 0 + -0.51712 1.92992 0 + -0.51712 1.92992 0 + -0.51712 1.92992 0 + -0.51712 1.92992 0 + -0.515421 1.92358 0.0245 + -0.515421 1.92358 0.0245 + -0.515421 1.92358 0.0245 + -0.515421 1.92358 0.0245 + -0.515421 1.92358 0.0245 + -0.510779 1.90626 0.0424352 + -0.510779 1.90626 0.0424352 + -0.510779 1.90626 0.0424352 + -0.510779 1.90626 0.0424352 + -0.510779 1.90626 0.0424352 + -0.510779 1.90626 0.0424352 + -0.504438 1.88259 0.049 + -0.504438 1.88259 0.049 + -0.504438 1.88259 0.049 + -0.504438 1.88259 0.049 + -0.504438 1.88259 0.049 + -0.498097 1.85892 0.0424352 + -0.498097 1.85892 0.0424352 + -0.498097 1.85892 0.0424352 + -0.498097 1.85892 0.0424352 + -0.498097 1.85892 0.0424352 + -0.498097 1.85892 0.0424352 + -0.498097 1.85892 0.0424352 + -0.493455 1.8416 0.0245 + -0.493455 1.8416 0.0245 + -0.493455 1.8416 0.0245 + -0.493455 1.8416 0.0245 + -0.493455 1.8416 0.0245 + -0.493455 1.8416 0.0245 + -0.491756 1.83526 0 + -0.491756 1.83526 0 + -0.491756 1.83526 0 + -0.491756 1.83526 0 + -0.491756 1.83526 0 + -0.491756 1.83526 0 + -0.493455 1.8416 -0.0245 + -0.493455 1.8416 -0.0245 + -0.493455 1.8416 -0.0245 + -0.493455 1.8416 -0.0245 + -0.493455 1.8416 -0.0245 + -0.493455 1.8416 -0.0245 + -0.498097 1.85892 -0.0424352 + -0.498097 1.85892 -0.0424352 + -0.498097 1.85892 -0.0424352 + -0.498097 1.85892 -0.0424352 + -0.498097 1.85892 -0.0424352 + -0.498097 1.85892 -0.0424352 + -0.504438 1.88259 -0.049 + -0.504438 1.88259 -0.049 + -0.504438 1.88259 -0.049 + -0.504438 1.88259 -0.049 + -0.504438 1.88259 -0.049 + -0.504438 1.88259 -0.049 + -0.504438 1.88259 -0.049 + -0.510779 1.90626 -0.0424352 + -0.510779 1.90626 -0.0424352 + -0.510779 1.90626 -0.0424352 + -0.510779 1.90626 -0.0424352 + -0.510779 1.90626 -0.0424352 + -0.515421 1.92358 -0.0245 + -0.515421 1.92358 -0.0245 + -0.515421 1.92358 -0.0245 + -0.515421 1.92358 -0.0245 + -0.515421 1.92358 -0.0245 + -0.515421 1.92358 -0.0245 + -0.764602 1.84591 0 + -0.764602 1.84591 0 + -0.764602 1.84591 0 + -0.764602 1.84591 0 + -0.764602 1.84591 0 + -0.764602 1.84591 0 + -0.762089 1.83985 0.0245 + -0.762089 1.83985 0.0245 + -0.762089 1.83985 0.0245 + -0.762089 1.83985 0.0245 + -0.762089 1.83985 0.0245 + -0.762089 1.83985 0.0245 + -0.762089 1.83985 0.0245 + -0.755226 1.82328 0.0424352 + -0.755226 1.82328 0.0424352 + -0.755226 1.82328 0.0424352 + -0.755226 1.82328 0.0424352 + -0.755226 1.82328 0.0424352 + -0.74585 1.80064 0.049 + -0.74585 1.80064 0.049 + -0.74585 1.80064 0.049 + -0.74585 1.80064 0.049 + -0.74585 1.80064 0.049 + -0.74585 1.80064 0.049 + -0.74585 1.80064 0.049 + -0.736474 1.77801 0.0424352 + -0.736474 1.77801 0.0424352 + -0.736474 1.77801 0.0424352 + -0.736474 1.77801 0.0424352 + -0.736474 1.77801 0.0424352 + -0.729611 1.76144 0.0245 + -0.729611 1.76144 0.0245 + -0.729611 1.76144 0.0245 + -0.729611 1.76144 0.0245 + -0.729611 1.76144 0.0245 + -0.729611 1.76144 0.0245 + -0.727099 1.75537 0 + -0.727099 1.75537 0 + -0.727099 1.75537 0 + -0.727099 1.75537 0 + -0.727099 1.75537 0 + -0.727099 1.75537 0 + -0.729611 1.76144 -0.0245 + -0.729611 1.76144 -0.0245 + -0.729611 1.76144 -0.0245 + -0.729611 1.76144 -0.0245 + -0.729611 1.76144 -0.0245 + -0.729611 1.76144 -0.0245 + -0.736474 1.77801 -0.0424352 + -0.736474 1.77801 -0.0424352 + -0.736474 1.77801 -0.0424352 + -0.736474 1.77801 -0.0424352 + -0.736474 1.77801 -0.0424352 + -0.736474 1.77801 -0.0424352 + -0.74585 1.80064 -0.049 + -0.74585 1.80064 -0.049 + -0.74585 1.80064 -0.049 + -0.74585 1.80064 -0.049 + -0.74585 1.80064 -0.049 + -0.74585 1.80064 -0.049 + -0.755226 1.82328 -0.0424352 + -0.755226 1.82328 -0.0424352 + -0.755226 1.82328 -0.0424352 + -0.755226 1.82328 -0.0424352 + -0.755226 1.82328 -0.0424352 + -0.762089 1.83985 -0.0245 + -0.762089 1.83985 -0.0245 + -0.762089 1.83985 -0.0245 + -0.762089 1.83985 -0.0245 + -0.762089 1.83985 -0.0245 + -0.762089 1.83985 -0.0245 + -0.762089 1.83985 -0.0245 + -0.999 1.73032 0 + -0.999 1.73032 0 + -0.999 1.73032 0 + -0.999 1.73032 0 + -0.999 1.73032 0 + -0.999 1.73032 0 + -0.995717 1.72463 0.0245 + -0.995717 1.72463 0.0245 + -0.995717 1.72463 0.0245 + -0.995717 1.72463 0.0245 + -0.995717 1.72463 0.0245 + -0.986749 1.7091 0.0424352 + -0.986749 1.7091 0.0424352 + -0.986749 1.7091 0.0424352 + -0.986749 1.7091 0.0424352 + -0.986749 1.7091 0.0424352 + -0.986749 1.7091 0.0424352 + -0.986749 1.7091 0.0424352 + -0.986749 1.7091 0.0424352 + -0.9745 1.68788 0.049 + -0.9745 1.68788 0.049 + -0.9745 1.68788 0.049 + -0.9745 1.68788 0.049 + -0.9745 1.68788 0.049 + -0.96225 1.66667 0.0424352 + -0.96225 1.66667 0.0424352 + -0.96225 1.66667 0.0424352 + -0.96225 1.66667 0.0424352 + -0.96225 1.66667 0.0424352 + -0.953282 1.65113 0.0245 + -0.953282 1.65113 0.0245 + -0.953282 1.65113 0.0245 + -0.953282 1.65113 0.0245 + -0.953282 1.65113 0.0245 + -0.953282 1.65113 0.0245 + -0.953282 1.65113 0.0245 + -0.953282 1.65113 0.0245 + -0.95 1.64545 0 + -0.95 1.64545 0 + -0.95 1.64545 0 + -0.95 1.64545 0 + -0.953282 1.65113 -0.0245 + -0.953282 1.65113 -0.0245 + -0.953282 1.65113 -0.0245 + -0.953282 1.65113 -0.0245 + -0.953282 1.65113 -0.0245 + -0.953282 1.65113 -0.0245 + -0.953282 1.65113 -0.0245 + -0.953282 1.65113 -0.0245 + -0.96225 1.66667 -0.0424352 + -0.96225 1.66667 -0.0424352 + -0.96225 1.66667 -0.0424352 + -0.96225 1.66667 -0.0424352 + -0.96225 1.66667 -0.0424352 + -0.9745 1.68788 -0.049 + -0.9745 1.68788 -0.049 + -0.9745 1.68788 -0.049 + -0.9745 1.68788 -0.049 + -0.9745 1.68788 -0.049 + -0.986749 1.7091 -0.0424352 + -0.986749 1.7091 -0.0424352 + -0.986749 1.7091 -0.0424352 + -0.986749 1.7091 -0.0424352 + -0.986749 1.7091 -0.0424352 + -0.986749 1.7091 -0.0424352 + -0.986749 1.7091 -0.0424352 + -0.986749 1.7091 -0.0424352 + -0.995717 1.72463 -0.0245 + -0.995717 1.72463 -0.0245 + -0.995717 1.72463 -0.0245 + -0.995717 1.72463 -0.0245 + -0.995717 1.72463 -0.0245 + -1.21631 1.58512 0 + -1.21631 1.58512 0 + -1.21631 1.58512 0 + -1.21631 1.58512 0 + -1.21631 1.58512 0 + -1.21631 1.58512 0 + -1.21231 1.57991 0.0245 + -1.21231 1.57991 0.0245 + -1.21231 1.57991 0.0245 + -1.21231 1.57991 0.0245 + -1.21231 1.57991 0.0245 + -1.21231 1.57991 0.0245 + -1.20139 1.56568 0.0424352 + -1.20139 1.56568 0.0424352 + -1.20139 1.56568 0.0424352 + -1.20139 1.56568 0.0424352 + -1.20139 1.56568 0.0424352 + -1.20139 1.56568 0.0424352 + -1.18648 1.54624 0.049 + -1.18648 1.54624 0.049 + -1.18648 1.54624 0.049 + -1.18648 1.54624 0.049 + -1.18648 1.54624 0.049 + -1.18648 1.54624 0.049 + -1.17156 1.52681 0.0424352 + -1.17156 1.52681 0.0424352 + -1.17156 1.52681 0.0424352 + -1.17156 1.52681 0.0424352 + -1.17156 1.52681 0.0424352 + -1.17156 1.52681 0.0424352 + -1.16064 1.51258 0.0245 + -1.16064 1.51258 0.0245 + -1.16064 1.51258 0.0245 + -1.16064 1.51258 0.0245 + -1.16064 1.51258 0.0245 + -1.16064 1.51258 0.0245 + -1.15665 1.50737 0 + -1.15665 1.50737 0 + -1.15665 1.50737 0 + -1.15665 1.50737 0 + -1.15665 1.50737 0 + -1.15665 1.50737 0 + -1.16064 1.51258 -0.0245 + -1.16064 1.51258 -0.0245 + -1.16064 1.51258 -0.0245 + -1.16064 1.51258 -0.0245 + -1.16064 1.51258 -0.0245 + -1.16064 1.51258 -0.0245 + -1.17156 1.52681 -0.0424352 + -1.17156 1.52681 -0.0424352 + -1.17156 1.52681 -0.0424352 + -1.17156 1.52681 -0.0424352 + -1.17156 1.52681 -0.0424352 + -1.17156 1.52681 -0.0424352 + -1.18648 1.54624 -0.049 + -1.18648 1.54624 -0.049 + -1.18648 1.54624 -0.049 + -1.18648 1.54624 -0.049 + -1.18648 1.54624 -0.049 + -1.18648 1.54624 -0.049 + -1.20139 1.56568 -0.0424352 + -1.20139 1.56568 -0.0424352 + -1.20139 1.56568 -0.0424352 + -1.20139 1.56568 -0.0424352 + -1.20139 1.56568 -0.0424352 + -1.20139 1.56568 -0.0424352 + -1.21231 1.57991 -0.0245 + -1.21231 1.57991 -0.0245 + -1.21231 1.57991 -0.0245 + -1.21231 1.57991 -0.0245 + -1.21231 1.57991 -0.0245 + -1.21231 1.57991 -0.0245 + -1.4128 1.4128 0 + -1.4128 1.4128 0 + -1.4128 1.4128 0 + -1.4128 1.4128 0 + -1.4128 1.4128 0 + -1.4128 1.4128 0 + -1.40816 1.40816 0.0245 + -1.40816 1.40816 0.0245 + -1.40816 1.40816 0.0245 + -1.40816 1.40816 0.0245 + -1.40816 1.40816 0.0245 + -1.40816 1.40816 0.0245 + -1.40816 1.40816 0.0245 + -1.39548 1.39548 0.0424352 + -1.39548 1.39548 0.0424352 + -1.39548 1.39548 0.0424352 + -1.39548 1.39548 0.0424352 + -1.37815 1.37815 0.049 + -1.37815 1.37815 0.049 + -1.37815 1.37815 0.049 + -1.37815 1.37815 0.049 + -1.37815 1.37815 0.049 + -1.37815 1.37815 0.049 + -1.36083 1.36083 0.0424352 + -1.36083 1.36083 0.0424352 + -1.36083 1.36083 0.0424352 + -1.36083 1.36083 0.0424352 + -1.36083 1.36083 0.0424352 + -1.36083 1.36083 0.0424352 + -1.36083 1.36083 0.0424352 + -1.36083 1.36083 0.0424352 + -1.34815 1.34814 0.0245 + -1.34815 1.34814 0.0245 + -1.34815 1.34814 0.0245 + -1.34815 1.34814 0.0245 + -1.3435 1.3435 0 + -1.3435 1.3435 0 + -1.3435 1.3435 0 + -1.3435 1.3435 0 + -1.3435 1.3435 0 + -1.3435 1.3435 0 + -1.3435 1.3435 0 + -1.3435 1.3435 0 + -1.34815 1.34814 -0.0245 + -1.34815 1.34814 -0.0245 + -1.34815 1.34814 -0.0245 + -1.34815 1.34814 -0.0245 + -1.36083 1.36083 -0.0424352 + -1.36083 1.36083 -0.0424352 + -1.36083 1.36083 -0.0424352 + -1.36083 1.36083 -0.0424352 + -1.36083 1.36083 -0.0424352 + -1.36083 1.36083 -0.0424352 + -1.36083 1.36083 -0.0424352 + -1.36083 1.36083 -0.0424352 + -1.37815 1.37815 -0.049 + -1.37815 1.37815 -0.049 + -1.37815 1.37815 -0.049 + -1.37815 1.37815 -0.049 + -1.37815 1.37815 -0.049 + -1.37815 1.37815 -0.049 + -1.39548 1.39548 -0.0424352 + -1.39548 1.39548 -0.0424352 + -1.39548 1.39548 -0.0424352 + -1.39548 1.39548 -0.0424352 + -1.40816 1.40816 -0.0245 + -1.40816 1.40816 -0.0245 + -1.40816 1.40816 -0.0245 + -1.40816 1.40816 -0.0245 + -1.40816 1.40816 -0.0245 + -1.40816 1.40816 -0.0245 + -1.40816 1.40816 -0.0245 + -1.58512 1.21631 0 + -1.58512 1.21631 0 + -1.58512 1.21631 0 + -1.58512 1.21631 0 + -1.57991 1.21231 0.0245 + -1.57991 1.21231 0.0245 + -1.57991 1.21231 0.0245 + -1.57991 1.21231 0.0245 + -1.57991 1.21231 0.0245 + -1.57991 1.21231 0.0245 + -1.57991 1.21231 0.0245 + -1.56568 1.20139 0.0424352 + -1.56568 1.20139 0.0424352 + -1.56568 1.20139 0.0424352 + -1.56568 1.20139 0.0424352 + -1.56568 1.20139 0.0424352 + -1.56568 1.20139 0.0424352 + -1.54624 1.18648 0.049 + -1.54624 1.18648 0.049 + -1.54624 1.18648 0.049 + -1.54624 1.18648 0.049 + -1.54624 1.18648 0.049 + -1.54624 1.18648 0.049 + -1.52681 1.17156 0.0424352 + -1.52681 1.17156 0.0424352 + -1.52681 1.17156 0.0424352 + -1.52681 1.17156 0.0424352 + -1.52681 1.17156 0.0424352 + -1.52681 1.17156 0.0424352 + -1.51258 1.16064 0.0245 + -1.51258 1.16064 0.0245 + -1.51258 1.16064 0.0245 + -1.51258 1.16064 0.0245 + -1.51258 1.16064 0.0245 + -1.51258 1.16064 0.0245 + -1.50737 1.15665 0 + -1.50737 1.15665 0 + -1.50737 1.15665 0 + -1.50737 1.15665 0 + -1.50737 1.15665 0 + -1.50737 1.15665 0 + -1.51258 1.16064 -0.0245 + -1.51258 1.16064 -0.0245 + -1.51258 1.16064 -0.0245 + -1.51258 1.16064 -0.0245 + -1.51258 1.16064 -0.0245 + -1.51258 1.16064 -0.0245 + -1.52681 1.17156 -0.0424352 + -1.52681 1.17156 -0.0424352 + -1.52681 1.17156 -0.0424352 + -1.52681 1.17156 -0.0424352 + -1.52681 1.17156 -0.0424352 + -1.52681 1.17156 -0.0424352 + -1.54624 1.18648 -0.049 + -1.54624 1.18648 -0.049 + -1.54624 1.18648 -0.049 + -1.54624 1.18648 -0.049 + -1.54624 1.18648 -0.049 + -1.54624 1.18648 -0.049 + -1.56568 1.20139 -0.0424352 + -1.56568 1.20139 -0.0424352 + -1.56568 1.20139 -0.0424352 + -1.56568 1.20139 -0.0424352 + -1.56568 1.20139 -0.0424352 + -1.56568 1.20139 -0.0424352 + -1.57991 1.21231 -0.0245 + -1.57991 1.21231 -0.0245 + -1.57991 1.21231 -0.0245 + -1.57991 1.21231 -0.0245 + -1.57991 1.21231 -0.0245 + -1.57991 1.21231 -0.0245 + -1.57991 1.21231 -0.0245 + -1.73032 0.999 0 + -1.73032 0.999 0 + -1.73032 0.999 0 + -1.73032 0.999 0 + -1.73032 0.999 0 + -1.73032 0.999 0 + -1.72463 0.995718 0.0245 + -1.72463 0.995718 0.0245 + -1.72463 0.995718 0.0245 + -1.72463 0.995718 0.0245 + -1.72463 0.995718 0.0245 + -1.72463 0.995718 0.0245 + -1.7091 0.98675 0.0424352 + -1.7091 0.98675 0.0424352 + -1.7091 0.98675 0.0424352 + -1.7091 0.98675 0.0424352 + -1.7091 0.98675 0.0424352 + -1.7091 0.98675 0.0424352 + -1.68788 0.9745 0.049 + -1.68788 0.9745 0.049 + -1.68788 0.9745 0.049 + -1.68788 0.9745 0.049 + -1.68788 0.9745 0.049 + -1.68788 0.9745 0.049 + -1.66666 0.96225 0.0424352 + -1.66666 0.96225 0.0424352 + -1.66666 0.96225 0.0424352 + -1.66666 0.96225 0.0424352 + -1.66666 0.96225 0.0424352 + -1.66666 0.96225 0.0424352 + -1.65113 0.953283 0.0245 + -1.65113 0.953283 0.0245 + -1.65113 0.953283 0.0245 + -1.65113 0.953283 0.0245 + -1.65113 0.953283 0.0245 + -1.65113 0.953283 0.0245 + -1.64545 0.95 0 + -1.64545 0.95 0 + -1.64545 0.95 0 + -1.64545 0.95 0 + -1.64545 0.95 0 + -1.65113 0.953283 -0.0245 + -1.65113 0.953283 -0.0245 + -1.65113 0.953283 -0.0245 + -1.65113 0.953283 -0.0245 + -1.65113 0.953283 -0.0245 + -1.65113 0.953283 -0.0245 + -1.65113 0.953283 -0.0245 + -1.66666 0.96225 -0.0424352 + -1.66666 0.96225 -0.0424352 + -1.66666 0.96225 -0.0424352 + -1.66666 0.96225 -0.0424352 + -1.66666 0.96225 -0.0424352 + -1.68788 0.9745 -0.049 + -1.68788 0.9745 -0.049 + -1.68788 0.9745 -0.049 + -1.68788 0.9745 -0.049 + -1.68788 0.9745 -0.049 + -1.68788 0.9745 -0.049 + -1.68788 0.9745 -0.049 + -1.7091 0.98675 -0.0424352 + -1.7091 0.98675 -0.0424352 + -1.7091 0.98675 -0.0424352 + -1.7091 0.98675 -0.0424352 + -1.7091 0.98675 -0.0424352 + -1.7091 0.98675 -0.0424352 + -1.72463 0.995718 -0.0245 + -1.72463 0.995718 -0.0245 + -1.72463 0.995718 -0.0245 + -1.72463 0.995718 -0.0245 + -1.72463 0.995718 -0.0245 + -1.72463 0.995718 -0.0245 + -1.84591 0.764602 0 + -1.84591 0.764602 0 + -1.84591 0.764602 0 + -1.84591 0.764602 0 + -1.84591 0.764602 0 + -1.84591 0.764602 0 + -1.83985 0.762089 0.0245 + -1.83985 0.762089 0.0245 + -1.83985 0.762089 0.0245 + -1.83985 0.762089 0.0245 + -1.83985 0.762089 0.0245 + -1.83985 0.762089 0.0245 + -1.82328 0.755226 0.0424352 + -1.82328 0.755226 0.0424352 + -1.82328 0.755226 0.0424352 + -1.82328 0.755226 0.0424352 + -1.82328 0.755226 0.0424352 + -1.82328 0.755226 0.0424352 + -1.82328 0.755226 0.0424352 + -1.80064 0.74585 0.049 + -1.80064 0.74585 0.049 + -1.80064 0.74585 0.049 + -1.80064 0.74585 0.049 + -1.80064 0.74585 0.049 + -1.77801 0.736474 0.0424352 + -1.77801 0.736474 0.0424352 + -1.77801 0.736474 0.0424352 + -1.77801 0.736474 0.0424352 + -1.77801 0.736474 0.0424352 + -1.76144 0.729611 0.0245 + -1.76144 0.729611 0.0245 + -1.76144 0.729611 0.0245 + -1.76144 0.729611 0.0245 + -1.76144 0.729611 0.0245 + -1.76144 0.729611 0.0245 + -1.76144 0.729611 0.0245 + -1.76144 0.729611 0.0245 + -1.75537 0.727099 0 + -1.75537 0.727099 0 + -1.75537 0.727099 0 + -1.75537 0.727099 0 + -1.75537 0.727099 0 + -1.76144 0.729611 -0.0245 + -1.76144 0.729611 -0.0245 + -1.76144 0.729611 -0.0245 + -1.76144 0.729611 -0.0245 + -1.76144 0.729611 -0.0245 + -1.76144 0.729611 -0.0245 + -1.76144 0.729611 -0.0245 + -1.77801 0.736474 -0.0424352 + -1.77801 0.736474 -0.0424352 + -1.77801 0.736474 -0.0424352 + -1.77801 0.736474 -0.0424352 + -1.77801 0.736474 -0.0424352 + -1.80064 0.74585 -0.049 + -1.80064 0.74585 -0.049 + -1.80064 0.74585 -0.049 + -1.80064 0.74585 -0.049 + -1.80064 0.74585 -0.049 + -1.82328 0.755226 -0.0424352 + -1.82328 0.755226 -0.0424352 + -1.82328 0.755226 -0.0424352 + -1.82328 0.755226 -0.0424352 + -1.82328 0.755226 -0.0424352 + -1.82328 0.755226 -0.0424352 + -1.82328 0.755226 -0.0424352 + -1.83985 0.762089 -0.0245 + -1.83985 0.762089 -0.0245 + -1.83985 0.762089 -0.0245 + -1.83985 0.762089 -0.0245 + -1.83985 0.762089 -0.0245 + -1.83985 0.762089 -0.0245 + -1.92992 0.51712 0 + -1.92992 0.51712 0 + -1.92992 0.51712 0 + -1.92992 0.51712 0 + -1.92992 0.51712 0 + -1.92992 0.51712 0 + -1.92358 0.515421 0.0245 + -1.92358 0.515421 0.0245 + -1.92358 0.515421 0.0245 + -1.92358 0.515421 0.0245 + -1.92358 0.515421 0.0245 + -1.92358 0.515421 0.0245 + -1.90626 0.510779 0.0424352 + -1.90626 0.510779 0.0424352 + -1.90626 0.510779 0.0424352 + -1.90626 0.510779 0.0424352 + -1.90626 0.510779 0.0424352 + -1.88259 0.504438 0.049 + -1.88259 0.504438 0.049 + -1.88259 0.504438 0.049 + -1.88259 0.504438 0.049 + -1.88259 0.504438 0.049 + -1.88259 0.504438 0.049 + -1.88259 0.504438 0.049 + -1.85892 0.498097 0.0424352 + -1.85892 0.498097 0.0424352 + -1.85892 0.498097 0.0424352 + -1.85892 0.498097 0.0424352 + -1.85892 0.498097 0.0424352 + -1.85892 0.498097 0.0424352 + -1.8416 0.493455 0.0245 + -1.8416 0.493455 0.0245 + -1.8416 0.493455 0.0245 + -1.8416 0.493455 0.0245 + -1.8416 0.493455 0.0245 + -1.8416 0.493455 0.0245 + -1.83526 0.491756 0 + -1.83526 0.491756 0 + -1.83526 0.491756 0 + -1.83526 0.491756 0 + -1.83526 0.491756 0 + -1.83526 0.491756 0 + -1.8416 0.493455 -0.0245 + -1.8416 0.493455 -0.0245 + -1.8416 0.493455 -0.0245 + -1.8416 0.493455 -0.0245 + -1.8416 0.493455 -0.0245 + -1.8416 0.493455 -0.0245 + -1.85892 0.498097 -0.0424352 + -1.85892 0.498097 -0.0424352 + -1.85892 0.498097 -0.0424352 + -1.85892 0.498097 -0.0424352 + -1.85892 0.498097 -0.0424352 + -1.85892 0.498097 -0.0424352 + -1.85892 0.498097 -0.0424352 + -1.88259 0.504438 -0.049 + -1.88259 0.504438 -0.049 + -1.88259 0.504438 -0.049 + -1.88259 0.504438 -0.049 + -1.88259 0.504438 -0.049 + -1.90626 0.510779 -0.0424352 + -1.90626 0.510779 -0.0424352 + -1.90626 0.510779 -0.0424352 + -1.90626 0.510779 -0.0424352 + -1.90626 0.510779 -0.0424352 + -1.90626 0.510779 -0.0424352 + -1.92358 0.515421 -0.0245 + -1.92358 0.515421 -0.0245 + -1.92358 0.515421 -0.0245 + -1.92358 0.515421 -0.0245 + -1.92358 0.515421 -0.0245 + -1.92358 0.515421 -0.0245 + -1.98091 0.260792 0 + -1.98091 0.260792 0 + -1.98091 0.260792 0 + -1.98091 0.260792 0 + -1.98091 0.260792 0 + -1.98091 0.260792 0 + -1.9744 0.259935 0.0245 + -1.9744 0.259935 0.0245 + -1.9744 0.259935 0.0245 + -1.9744 0.259935 0.0245 + -1.9744 0.259935 0.0245 + -1.9744 0.259935 0.0245 + -1.95662 0.257594 0.0424352 + -1.95662 0.257594 0.0424352 + -1.95662 0.257594 0.0424352 + -1.95662 0.257594 0.0424352 + -1.95662 0.257594 0.0424352 + -1.95662 0.257594 0.0424352 + -1.93233 0.254396 0.049 + -1.93233 0.254396 0.049 + -1.93233 0.254396 0.049 + -1.93233 0.254396 0.049 + -1.93233 0.254396 0.049 + -1.93233 0.254396 0.049 + -1.93233 0.254396 0.049 + -1.90804 0.251198 0.0424352 + -1.90804 0.251198 0.0424352 + -1.90804 0.251198 0.0424352 + -1.90804 0.251198 0.0424352 + -1.90804 0.251198 0.0424352 + -1.90804 0.251198 0.0424352 + -1.89025 0.248857 0.0245 + -1.89025 0.248857 0.0245 + -1.89025 0.248857 0.0245 + -1.89025 0.248857 0.0245 + -1.88374 0.248 0 + -1.88374 0.248 0 + -1.88374 0.248 0 + -1.88374 0.248 0 + -1.88374 0.248 0 + -1.88374 0.248 0 + -1.88374 0.248 0 + -1.89025 0.248857 -0.0245 + -1.89025 0.248857 -0.0245 + -1.89025 0.248857 -0.0245 + -1.89025 0.248857 -0.0245 + -1.89025 0.248857 -0.0245 + -1.90804 0.251198 -0.0424352 + -1.90804 0.251198 -0.0424352 + -1.90804 0.251198 -0.0424352 + -1.90804 0.251198 -0.0424352 + -1.90804 0.251198 -0.0424352 + -1.90804 0.251198 -0.0424352 + -1.93233 0.254396 -0.049 + -1.93233 0.254396 -0.049 + -1.93233 0.254396 -0.049 + -1.93233 0.254396 -0.049 + -1.93233 0.254396 -0.049 + -1.93233 0.254396 -0.049 + -1.93233 0.254396 -0.049 + -1.95662 0.257594 -0.0424352 + -1.95662 0.257594 -0.0424352 + -1.95662 0.257594 -0.0424352 + -1.95662 0.257594 -0.0424352 + -1.95662 0.257594 -0.0424352 + -1.95662 0.257594 -0.0424352 + -1.9744 0.259935 -0.0245 + -1.9744 0.259935 -0.0245 + -1.9744 0.259935 -0.0245 + -1.9744 0.259935 -0.0245 + -1.9744 0.259935 -0.0245 + -1.9744 0.259935 -0.0245 + -1.998 1.74671e-07 0 + -1.998 1.74671e-07 0 + -1.998 1.74671e-07 0 + -1.998 1.74671e-07 0 + -1.998 1.74671e-07 0 + -1.998 1.74671e-07 0 + -1.998 1.74671e-07 0 + -1.998 1.74671e-07 0 + -1.99144 1.74097e-07 0.0245 + -1.99144 1.74097e-07 0.0245 + -1.99144 1.74097e-07 0.0245 + -1.99144 1.74097e-07 0.0245 + -1.9735 1.72529e-07 0.0424352 + -1.9735 1.72529e-07 0.0424352 + -1.9735 1.72529e-07 0.0424352 + -1.9735 1.72529e-07 0.0424352 + -1.9735 1.72529e-07 0.0424352 + -1.9735 1.72529e-07 0.0424352 + -1.9735 1.72529e-07 0.0424352 + -1.949 1.70387e-07 0.049 + -1.949 1.70387e-07 0.049 + -1.949 1.70387e-07 0.049 + -1.949 1.70387e-07 0.049 + -1.949 1.70387e-07 0.049 + -1.9245 1.68245e-07 0.0424352 + -1.9245 1.68245e-07 0.0424352 + -1.9245 1.68245e-07 0.0424352 + -1.9245 1.68245e-07 0.0424352 + -1.9245 1.68245e-07 0.0424352 + -1.9245 1.68245e-07 0.0424352 + -1.90656 1.66677e-07 0.0245 + -1.90656 1.66677e-07 0.0245 + -1.90656 1.66677e-07 0.0245 + -1.90656 1.66677e-07 0.0245 + -1.90656 1.66677e-07 0.0245 + -1.90656 1.66677e-07 0.0245 + -1.90656 1.66677e-07 0.0245 + -1.9 1.66103e-07 0 + -1.9 1.66103e-07 0 + -1.9 1.66103e-07 0 + -1.9 1.66103e-07 0 + -1.9 1.66103e-07 0 + -1.9 1.66103e-07 0 + -1.90656 1.66677e-07 -0.0245 + -1.90656 1.66677e-07 -0.0245 + -1.90656 1.66677e-07 -0.0245 + -1.90656 1.66677e-07 -0.0245 + -1.90656 1.66677e-07 -0.0245 + -1.90656 1.66677e-07 -0.0245 + -1.90656 1.66677e-07 -0.0245 + -1.9245 1.68245e-07 -0.0424352 + -1.9245 1.68245e-07 -0.0424352 + -1.9245 1.68245e-07 -0.0424352 + -1.9245 1.68245e-07 -0.0424352 + -1.9245 1.68245e-07 -0.0424352 + -1.9245 1.68245e-07 -0.0424352 + -1.949 1.70387e-07 -0.049 + -1.949 1.70387e-07 -0.049 + -1.949 1.70387e-07 -0.049 + -1.949 1.70387e-07 -0.049 + -1.949 1.70387e-07 -0.049 + -1.9735 1.72529e-07 -0.0424352 + -1.9735 1.72529e-07 -0.0424352 + -1.9735 1.72529e-07 -0.0424352 + -1.9735 1.72529e-07 -0.0424352 + -1.9735 1.72529e-07 -0.0424352 + -1.9735 1.72529e-07 -0.0424352 + -1.9735 1.72529e-07 -0.0424352 + -1.99144 1.74097e-07 -0.0245 + -1.99144 1.74097e-07 -0.0245 + -1.99144 1.74097e-07 -0.0245 + -1.99144 1.74097e-07 -0.0245 + -1.98091 -0.260792 0 + -1.98091 -0.260792 0 + -1.98091 -0.260792 0 + -1.98091 -0.260792 0 + -1.98091 -0.260792 0 + -1.98091 -0.260792 0 + -1.9744 -0.259935 0.0245 + -1.9744 -0.259935 0.0245 + -1.9744 -0.259935 0.0245 + -1.9744 -0.259935 0.0245 + -1.9744 -0.259935 0.0245 + -1.9744 -0.259935 0.0245 + -1.95662 -0.257594 0.0424352 + -1.95662 -0.257594 0.0424352 + -1.95662 -0.257594 0.0424352 + -1.95662 -0.257594 0.0424352 + -1.95662 -0.257594 0.0424352 + -1.95662 -0.257594 0.0424352 + -1.93233 -0.254396 0.049 + -1.93233 -0.254396 0.049 + -1.93233 -0.254396 0.049 + -1.93233 -0.254396 0.049 + -1.93233 -0.254396 0.049 + -1.93233 -0.254396 0.049 + -1.93233 -0.254396 0.049 + -1.90804 -0.251198 0.0424352 + -1.90804 -0.251198 0.0424352 + -1.90804 -0.251198 0.0424352 + -1.90804 -0.251198 0.0424352 + -1.90804 -0.251198 0.0424352 + -1.90804 -0.251198 0.0424352 + -1.89025 -0.248857 0.0245 + -1.89025 -0.248857 0.0245 + -1.89025 -0.248857 0.0245 + -1.89025 -0.248857 0.0245 + -1.89025 -0.248857 0.0245 + -1.88374 -0.248 0 + -1.88374 -0.248 0 + -1.88374 -0.248 0 + -1.88374 -0.248 0 + -1.88374 -0.248 0 + -1.88374 -0.248 0 + -1.88374 -0.248 0 + -1.89025 -0.248857 -0.0245 + -1.89025 -0.248857 -0.0245 + -1.89025 -0.248857 -0.0245 + -1.89025 -0.248857 -0.0245 + -1.90804 -0.251198 -0.0424352 + -1.90804 -0.251198 -0.0424352 + -1.90804 -0.251198 -0.0424352 + -1.90804 -0.251198 -0.0424352 + -1.90804 -0.251198 -0.0424352 + -1.90804 -0.251198 -0.0424352 + -1.93233 -0.254396 -0.049 + -1.93233 -0.254396 -0.049 + -1.93233 -0.254396 -0.049 + -1.93233 -0.254396 -0.049 + -1.93233 -0.254396 -0.049 + -1.93233 -0.254396 -0.049 + -1.93233 -0.254396 -0.049 + -1.95662 -0.257594 -0.0424352 + -1.95662 -0.257594 -0.0424352 + -1.95662 -0.257594 -0.0424352 + -1.95662 -0.257594 -0.0424352 + -1.95662 -0.257594 -0.0424352 + -1.95662 -0.257594 -0.0424352 + -1.9744 -0.259935 -0.0245 + -1.9744 -0.259935 -0.0245 + -1.9744 -0.259935 -0.0245 + -1.9744 -0.259935 -0.0245 + -1.9744 -0.259935 -0.0245 + -1.9744 -0.259935 -0.0245 + -1.92992 -0.51712 0 + -1.92992 -0.51712 0 + -1.92992 -0.51712 0 + -1.92992 -0.51712 0 + -1.92992 -0.51712 0 + -1.92992 -0.51712 0 + -1.92358 -0.515421 0.0245 + -1.92358 -0.515421 0.0245 + -1.92358 -0.515421 0.0245 + -1.92358 -0.515421 0.0245 + -1.92358 -0.515421 0.0245 + -1.92358 -0.515421 0.0245 + -1.90626 -0.510779 0.0424352 + -1.90626 -0.510779 0.0424352 + -1.90626 -0.510779 0.0424352 + -1.90626 -0.510779 0.0424352 + -1.90626 -0.510779 0.0424352 + -1.90626 -0.510779 0.0424352 + -1.88259 -0.504438 0.049 + -1.88259 -0.504438 0.049 + -1.88259 -0.504438 0.049 + -1.88259 -0.504438 0.049 + -1.88259 -0.504438 0.049 + -1.85892 -0.498097 0.0424352 + -1.85892 -0.498097 0.0424352 + -1.85892 -0.498097 0.0424352 + -1.85892 -0.498097 0.0424352 + -1.85892 -0.498097 0.0424352 + -1.85892 -0.498097 0.0424352 + -1.8416 -0.493455 0.0245 + -1.8416 -0.493455 0.0245 + -1.8416 -0.493455 0.0245 + -1.8416 -0.493455 0.0245 + -1.8416 -0.493455 0.0245 + -1.8416 -0.493455 0.0245 + -1.8416 -0.493455 0.0245 + -1.8416 -0.493455 0.0245 + -1.83526 -0.491756 0 + -1.83526 -0.491756 0 + -1.83526 -0.491756 0 + -1.83526 -0.491756 0 + -1.8416 -0.493455 -0.0245 + -1.8416 -0.493455 -0.0245 + -1.8416 -0.493455 -0.0245 + -1.8416 -0.493455 -0.0245 + -1.8416 -0.493455 -0.0245 + -1.8416 -0.493455 -0.0245 + -1.8416 -0.493455 -0.0245 + -1.8416 -0.493455 -0.0245 + -1.85892 -0.498097 -0.0424352 + -1.85892 -0.498097 -0.0424352 + -1.85892 -0.498097 -0.0424352 + -1.85892 -0.498097 -0.0424352 + -1.85892 -0.498097 -0.0424352 + -1.85892 -0.498097 -0.0424352 + -1.88259 -0.504438 -0.049 + -1.88259 -0.504438 -0.049 + -1.88259 -0.504438 -0.049 + -1.88259 -0.504438 -0.049 + -1.88259 -0.504438 -0.049 + -1.88259 -0.504438 -0.049 + -1.90626 -0.510779 -0.0424352 + -1.90626 -0.510779 -0.0424352 + -1.90626 -0.510779 -0.0424352 + -1.90626 -0.510779 -0.0424352 + -1.90626 -0.510779 -0.0424352 + -1.92358 -0.515421 -0.0245 + -1.92358 -0.515421 -0.0245 + -1.92358 -0.515421 -0.0245 + -1.92358 -0.515421 -0.0245 + -1.92358 -0.515421 -0.0245 + -1.92358 -0.515421 -0.0245 + -1.84591 -0.764601 0 + -1.84591 -0.764601 0 + -1.84591 -0.764601 0 + -1.84591 -0.764601 0 + -1.84591 -0.764601 0 + -1.84591 -0.764601 0 + -1.83985 -0.762088 0.0245 + -1.83985 -0.762088 0.0245 + -1.83985 -0.762088 0.0245 + -1.83985 -0.762088 0.0245 + -1.83985 -0.762088 0.0245 + -1.83985 -0.762088 0.0245 + -1.82328 -0.755225 0.0424352 + -1.82328 -0.755225 0.0424352 + -1.82328 -0.755225 0.0424352 + -1.82328 -0.755225 0.0424352 + -1.82328 -0.755225 0.0424352 + -1.82328 -0.755225 0.0424352 + -1.82328 -0.755225 0.0424352 + -1.80064 -0.745849 0.049 + -1.80064 -0.745849 0.049 + -1.80064 -0.745849 0.049 + -1.80064 -0.745849 0.049 + -1.80064 -0.745849 0.049 + -1.77801 -0.736474 0.0424352 + -1.77801 -0.736474 0.0424352 + -1.77801 -0.736474 0.0424352 + -1.77801 -0.736474 0.0424352 + -1.77801 -0.736474 0.0424352 + -1.77801 -0.736474 0.0424352 + -1.76144 -0.72961 0.0245 + -1.76144 -0.72961 0.0245 + -1.76144 -0.72961 0.0245 + -1.76144 -0.72961 0.0245 + -1.76144 -0.72961 0.0245 + -1.76144 -0.72961 0.0245 + -1.75537 -0.727098 0 + -1.75537 -0.727098 0 + -1.75537 -0.727098 0 + -1.75537 -0.727098 0 + -1.75537 -0.727098 0 + -1.75537 -0.727098 0 + -1.76144 -0.72961 -0.0245 + -1.76144 -0.72961 -0.0245 + -1.76144 -0.72961 -0.0245 + -1.76144 -0.72961 -0.0245 + -1.76144 -0.72961 -0.0245 + -1.76144 -0.72961 -0.0245 + -1.77801 -0.736474 -0.0424352 + -1.77801 -0.736474 -0.0424352 + -1.77801 -0.736474 -0.0424352 + -1.77801 -0.736474 -0.0424352 + -1.77801 -0.736474 -0.0424352 + -1.77801 -0.736474 -0.0424352 + -1.80064 -0.745849 -0.049 + -1.80064 -0.745849 -0.049 + -1.80064 -0.745849 -0.049 + -1.80064 -0.745849 -0.049 + -1.80064 -0.745849 -0.049 + -1.82328 -0.755225 -0.0424352 + -1.82328 -0.755225 -0.0424352 + -1.82328 -0.755225 -0.0424352 + -1.82328 -0.755225 -0.0424352 + -1.82328 -0.755225 -0.0424352 + -1.82328 -0.755225 -0.0424352 + -1.83985 -0.762088 -0.0245 + -1.83985 -0.762088 -0.0245 + -1.83985 -0.762088 -0.0245 + -1.83985 -0.762088 -0.0245 + -1.83985 -0.762088 -0.0245 + -1.83985 -0.762088 -0.0245 + -1.83985 -0.762088 -0.0245 + -1.73032 -0.998999 0 + -1.73032 -0.998999 0 + -1.73032 -0.998999 0 + -1.73032 -0.998999 0 + -1.73032 -0.998999 0 + -1.73032 -0.998999 0 + -1.72463 -0.995717 0.0245 + -1.72463 -0.995717 0.0245 + -1.72463 -0.995717 0.0245 + -1.72463 -0.995717 0.0245 + -1.72463 -0.995717 0.0245 + -1.72463 -0.995717 0.0245 + -1.7091 -0.986749 0.0424352 + -1.7091 -0.986749 0.0424352 + -1.7091 -0.986749 0.0424352 + -1.7091 -0.986749 0.0424352 + -1.7091 -0.986749 0.0424352 + -1.7091 -0.986749 0.0424352 + -1.68788 -0.9745 0.049 + -1.68788 -0.9745 0.049 + -1.68788 -0.9745 0.049 + -1.68788 -0.9745 0.049 + -1.68788 -0.9745 0.049 + -1.68788 -0.9745 0.049 + -1.68788 -0.9745 0.049 + -1.66667 -0.96225 0.0424352 + -1.66667 -0.96225 0.0424352 + -1.66667 -0.96225 0.0424352 + -1.66667 -0.96225 0.0424352 + -1.66667 -0.96225 0.0424352 + -1.65113 -0.953282 0.0245 + -1.65113 -0.953282 0.0245 + -1.65113 -0.953282 0.0245 + -1.65113 -0.953282 0.0245 + -1.65113 -0.953282 0.0245 + -1.65113 -0.953282 0.0245 + -1.64545 -0.95 0 + -1.64545 -0.95 0 + -1.64545 -0.95 0 + -1.64545 -0.95 0 + -1.64545 -0.95 0 + -1.64545 -0.95 0 + -1.65113 -0.953282 -0.0245 + -1.65113 -0.953282 -0.0245 + -1.65113 -0.953282 -0.0245 + -1.65113 -0.953282 -0.0245 + -1.65113 -0.953282 -0.0245 + -1.65113 -0.953282 -0.0245 + -1.66667 -0.96225 -0.0424352 + -1.66667 -0.96225 -0.0424352 + -1.66667 -0.96225 -0.0424352 + -1.66667 -0.96225 -0.0424352 + -1.66667 -0.96225 -0.0424352 + -1.68788 -0.9745 -0.049 + -1.68788 -0.9745 -0.049 + -1.68788 -0.9745 -0.049 + -1.68788 -0.9745 -0.049 + -1.68788 -0.9745 -0.049 + -1.68788 -0.9745 -0.049 + -1.68788 -0.9745 -0.049 + -1.7091 -0.986749 -0.0424352 + -1.7091 -0.986749 -0.0424352 + -1.7091 -0.986749 -0.0424352 + -1.7091 -0.986749 -0.0424352 + -1.7091 -0.986749 -0.0424352 + -1.7091 -0.986749 -0.0424352 + -1.7091 -0.986749 -0.0424352 + -1.72463 -0.995717 -0.0245 + -1.72463 -0.995717 -0.0245 + -1.72463 -0.995717 -0.0245 + -1.72463 -0.995717 -0.0245 + -1.72463 -0.995717 -0.0245 + -1.58512 -1.21631 0 + -1.58512 -1.21631 0 + -1.58512 -1.21631 0 + -1.58512 -1.21631 0 + -1.57991 -1.21231 0.0245 + -1.57991 -1.21231 0.0245 + -1.57991 -1.21231 0.0245 + -1.57991 -1.21231 0.0245 + -1.57991 -1.21231 0.0245 + -1.57991 -1.21231 0.0245 + -1.57991 -1.21231 0.0245 + -1.56568 -1.20139 0.0424352 + -1.56568 -1.20139 0.0424352 + -1.56568 -1.20139 0.0424352 + -1.56568 -1.20139 0.0424352 + -1.56568 -1.20139 0.0424352 + -1.56568 -1.20139 0.0424352 + -1.54624 -1.18648 0.049 + -1.54624 -1.18648 0.049 + -1.54624 -1.18648 0.049 + -1.54624 -1.18648 0.049 + -1.54624 -1.18648 0.049 + -1.54624 -1.18648 0.049 + -1.52681 -1.17156 0.0424352 + -1.52681 -1.17156 0.0424352 + -1.52681 -1.17156 0.0424352 + -1.52681 -1.17156 0.0424352 + -1.52681 -1.17156 0.0424352 + -1.52681 -1.17156 0.0424352 + -1.51258 -1.16064 0.0245 + -1.51258 -1.16064 0.0245 + -1.51258 -1.16064 0.0245 + -1.51258 -1.16064 0.0245 + -1.51258 -1.16064 0.0245 + -1.51258 -1.16064 0.0245 + -1.50737 -1.15665 0 + -1.50737 -1.15665 0 + -1.50737 -1.15665 0 + -1.50737 -1.15665 0 + -1.50737 -1.15665 0 + -1.50737 -1.15665 0 + -1.51258 -1.16064 -0.0245 + -1.51258 -1.16064 -0.0245 + -1.51258 -1.16064 -0.0245 + -1.51258 -1.16064 -0.0245 + -1.51258 -1.16064 -0.0245 + -1.51258 -1.16064 -0.0245 + -1.52681 -1.17156 -0.0424352 + -1.52681 -1.17156 -0.0424352 + -1.52681 -1.17156 -0.0424352 + -1.52681 -1.17156 -0.0424352 + -1.52681 -1.17156 -0.0424352 + -1.52681 -1.17156 -0.0424352 + -1.54624 -1.18648 -0.049 + -1.54624 -1.18648 -0.049 + -1.54624 -1.18648 -0.049 + -1.54624 -1.18648 -0.049 + -1.54624 -1.18648 -0.049 + -1.54624 -1.18648 -0.049 + -1.56568 -1.20139 -0.0424352 + -1.56568 -1.20139 -0.0424352 + -1.56568 -1.20139 -0.0424352 + -1.56568 -1.20139 -0.0424352 + -1.56568 -1.20139 -0.0424352 + -1.56568 -1.20139 -0.0424352 + -1.57991 -1.21231 -0.0245 + -1.57991 -1.21231 -0.0245 + -1.57991 -1.21231 -0.0245 + -1.57991 -1.21231 -0.0245 + -1.57991 -1.21231 -0.0245 + -1.57991 -1.21231 -0.0245 + -1.57991 -1.21231 -0.0245 + -1.4128 -1.4128 0 + -1.4128 -1.4128 0 + -1.4128 -1.4128 0 + -1.4128 -1.4128 0 + -1.4128 -1.4128 0 + -1.4128 -1.4128 0 + -1.40816 -1.40816 0.0245 + -1.40816 -1.40816 0.0245 + -1.40816 -1.40816 0.0245 + -1.40816 -1.40816 0.0245 + -1.40816 -1.40816 0.0245 + -1.40816 -1.40816 0.0245 + -1.40816 -1.40816 0.0245 + -1.39548 -1.39548 0.0424352 + -1.39548 -1.39548 0.0424352 + -1.39548 -1.39548 0.0424352 + -1.39548 -1.39548 0.0424352 + -1.39548 -1.39548 0.0424352 + -1.37815 -1.37815 0.049 + -1.37815 -1.37815 0.049 + -1.37815 -1.37815 0.049 + -1.37815 -1.37815 0.049 + -1.37815 -1.37815 0.049 + -1.36083 -1.36083 0.0424352 + -1.36083 -1.36083 0.0424352 + -1.36083 -1.36083 0.0424352 + -1.36083 -1.36083 0.0424352 + -1.36083 -1.36083 0.0424352 + -1.36083 -1.36083 0.0424352 + -1.36083 -1.36083 0.0424352 + -1.34815 -1.34814 0.0245 + -1.34815 -1.34814 0.0245 + -1.34815 -1.34814 0.0245 + -1.34815 -1.34814 0.0245 + -1.34815 -1.34814 0.0245 + -1.34815 -1.34814 0.0245 + -1.3435 -1.3435 0 + -1.3435 -1.3435 0 + -1.3435 -1.3435 0 + -1.3435 -1.3435 0 + -1.3435 -1.3435 0 + -1.3435 -1.3435 0 + -1.34815 -1.34814 -0.0245 + -1.34815 -1.34814 -0.0245 + -1.34815 -1.34814 -0.0245 + -1.34815 -1.34814 -0.0245 + -1.34815 -1.34814 -0.0245 + -1.36083 -1.36083 -0.0424352 + -1.36083 -1.36083 -0.0424352 + -1.36083 -1.36083 -0.0424352 + -1.36083 -1.36083 -0.0424352 + -1.36083 -1.36083 -0.0424352 + -1.36083 -1.36083 -0.0424352 + -1.36083 -1.36083 -0.0424352 + -1.36083 -1.36083 -0.0424352 + -1.37815 -1.37815 -0.049 + -1.37815 -1.37815 -0.049 + -1.37815 -1.37815 -0.049 + -1.37815 -1.37815 -0.049 + -1.37815 -1.37815 -0.049 + -1.39548 -1.39548 -0.0424352 + -1.39548 -1.39548 -0.0424352 + -1.39548 -1.39548 -0.0424352 + -1.39548 -1.39548 -0.0424352 + -1.39548 -1.39548 -0.0424352 + -1.40816 -1.40816 -0.0245 + -1.40816 -1.40816 -0.0245 + -1.40816 -1.40816 -0.0245 + -1.40816 -1.40816 -0.0245 + -1.40816 -1.40816 -0.0245 + -1.40816 -1.40816 -0.0245 + -1.40816 -1.40816 -0.0245 + -1.21631 -1.58512 0 + -1.21631 -1.58512 0 + -1.21631 -1.58512 0 + -1.21631 -1.58512 0 + -1.21631 -1.58512 0 + -1.21631 -1.58512 0 + -1.21231 -1.57991 0.0245 + -1.21231 -1.57991 0.0245 + -1.21231 -1.57991 0.0245 + -1.21231 -1.57991 0.0245 + -1.21231 -1.57991 0.0245 + -1.20139 -1.56568 0.0424352 + -1.20139 -1.56568 0.0424352 + -1.20139 -1.56568 0.0424352 + -1.20139 -1.56568 0.0424352 + -1.20139 -1.56568 0.0424352 + -1.20139 -1.56568 0.0424352 + -1.20139 -1.56568 0.0424352 + -1.18648 -1.54624 0.049 + -1.18648 -1.54624 0.049 + -1.18648 -1.54624 0.049 + -1.18648 -1.54624 0.049 + -1.18648 -1.54624 0.049 + -1.18648 -1.54624 0.049 + -1.17156 -1.52681 0.0424352 + -1.17156 -1.52681 0.0424352 + -1.17156 -1.52681 0.0424352 + -1.17156 -1.52681 0.0424352 + -1.17156 -1.52681 0.0424352 + -1.17156 -1.52681 0.0424352 + -1.17156 -1.52681 0.0424352 + -1.16064 -1.51258 0.0245 + -1.16064 -1.51258 0.0245 + -1.16064 -1.51258 0.0245 + -1.16064 -1.51258 0.0245 + -1.16064 -1.51258 0.0245 + -1.15665 -1.50737 0 + -1.15665 -1.50737 0 + -1.15665 -1.50737 0 + -1.15665 -1.50737 0 + -1.15665 -1.50737 0 + -1.15665 -1.50737 0 + -1.16064 -1.51258 -0.0245 + -1.16064 -1.51258 -0.0245 + -1.16064 -1.51258 -0.0245 + -1.16064 -1.51258 -0.0245 + -1.16064 -1.51258 -0.0245 + -1.16064 -1.51258 -0.0245 + -1.17156 -1.52681 -0.0424352 + -1.17156 -1.52681 -0.0424352 + -1.17156 -1.52681 -0.0424352 + -1.17156 -1.52681 -0.0424352 + -1.17156 -1.52681 -0.0424352 + -1.17156 -1.52681 -0.0424352 + -1.18648 -1.54624 -0.049 + -1.18648 -1.54624 -0.049 + -1.18648 -1.54624 -0.049 + -1.18648 -1.54624 -0.049 + -1.18648 -1.54624 -0.049 + -1.18648 -1.54624 -0.049 + -1.20139 -1.56568 -0.0424352 + -1.20139 -1.56568 -0.0424352 + -1.20139 -1.56568 -0.0424352 + -1.20139 -1.56568 -0.0424352 + -1.20139 -1.56568 -0.0424352 + -1.20139 -1.56568 -0.0424352 + -1.21231 -1.57991 -0.0245 + -1.21231 -1.57991 -0.0245 + -1.21231 -1.57991 -0.0245 + -1.21231 -1.57991 -0.0245 + -1.21231 -1.57991 -0.0245 + -1.21231 -1.57991 -0.0245 + -0.999 -1.73032 0 + -0.999 -1.73032 0 + -0.999 -1.73032 0 + -0.999 -1.73032 0 + -0.999 -1.73032 0 + -0.999 -1.73032 0 + -0.995717 -1.72463 0.0245 + -0.995717 -1.72463 0.0245 + -0.995717 -1.72463 0.0245 + -0.995717 -1.72463 0.0245 + -0.995717 -1.72463 0.0245 + -0.995717 -1.72463 0.0245 + -0.986749 -1.7091 0.0424352 + -0.986749 -1.7091 0.0424352 + -0.986749 -1.7091 0.0424352 + -0.986749 -1.7091 0.0424352 + -0.986749 -1.7091 0.0424352 + -0.986749 -1.7091 0.0424352 + -0.9745 -1.68788 0.049 + -0.9745 -1.68788 0.049 + -0.9745 -1.68788 0.049 + -0.9745 -1.68788 0.049 + -0.9745 -1.68788 0.049 + -0.9745 -1.68788 0.049 + -0.96225 -1.66667 0.0424352 + -0.96225 -1.66667 0.0424352 + -0.96225 -1.66667 0.0424352 + -0.96225 -1.66667 0.0424352 + -0.96225 -1.66667 0.0424352 + -0.953282 -1.65113 0.0245 + -0.953282 -1.65113 0.0245 + -0.953282 -1.65113 0.0245 + -0.953282 -1.65113 0.0245 + -0.953282 -1.65113 0.0245 + -0.953282 -1.65113 0.0245 + -0.953282 -1.65113 0.0245 + -0.95 -1.64545 0 + -0.95 -1.64545 0 + -0.95 -1.64545 0 + -0.95 -1.64545 0 + -0.95 -1.64545 0 + -0.95 -1.64545 0 + -0.953282 -1.65113 -0.0245 + -0.953282 -1.65113 -0.0245 + -0.953282 -1.65113 -0.0245 + -0.953282 -1.65113 -0.0245 + -0.953282 -1.65113 -0.0245 + -0.953282 -1.65113 -0.0245 + -0.953282 -1.65113 -0.0245 + -0.96225 -1.66667 -0.0424352 + -0.96225 -1.66667 -0.0424352 + -0.96225 -1.66667 -0.0424352 + -0.96225 -1.66667 -0.0424352 + -0.96225 -1.66667 -0.0424352 + -0.9745 -1.68788 -0.049 + -0.9745 -1.68788 -0.049 + -0.9745 -1.68788 -0.049 + -0.9745 -1.68788 -0.049 + -0.9745 -1.68788 -0.049 + -0.9745 -1.68788 -0.049 + -0.986749 -1.7091 -0.0424352 + -0.986749 -1.7091 -0.0424352 + -0.986749 -1.7091 -0.0424352 + -0.986749 -1.7091 -0.0424352 + -0.986749 -1.7091 -0.0424352 + -0.986749 -1.7091 -0.0424352 + -0.986749 -1.7091 -0.0424352 + -0.995717 -1.72463 -0.0245 + -0.995717 -1.72463 -0.0245 + -0.995717 -1.72463 -0.0245 + -0.995717 -1.72463 -0.0245 + -0.995717 -1.72463 -0.0245 + -0.764602 -1.84591 0 + -0.764602 -1.84591 0 + -0.764602 -1.84591 0 + -0.764602 -1.84591 0 + -0.764602 -1.84591 0 + -0.764602 -1.84591 0 + -0.762089 -1.83985 0.0245 + -0.762089 -1.83985 0.0245 + -0.762089 -1.83985 0.0245 + -0.762089 -1.83985 0.0245 + -0.762089 -1.83985 0.0245 + -0.762089 -1.83985 0.0245 + -0.762089 -1.83985 0.0245 + -0.755226 -1.82328 0.0424352 + -0.755226 -1.82328 0.0424352 + -0.755226 -1.82328 0.0424352 + -0.755226 -1.82328 0.0424352 + -0.74585 -1.80064 0.049 + -0.74585 -1.80064 0.049 + -0.74585 -1.80064 0.049 + -0.74585 -1.80064 0.049 + -0.74585 -1.80064 0.049 + -0.74585 -1.80064 0.049 + -0.74585 -1.80064 0.049 + -0.74585 -1.80064 0.049 + -0.736474 -1.77801 0.0424352 + -0.736474 -1.77801 0.0424352 + -0.736474 -1.77801 0.0424352 + -0.736474 -1.77801 0.0424352 + -0.736474 -1.77801 0.0424352 + -0.736474 -1.77801 0.0424352 + -0.729611 -1.76144 0.0245 + -0.729611 -1.76144 0.0245 + -0.729611 -1.76144 0.0245 + -0.729611 -1.76144 0.0245 + -0.727099 -1.75537 0 + -0.727099 -1.75537 0 + -0.727099 -1.75537 0 + -0.727099 -1.75537 0 + -0.727099 -1.75537 0 + -0.727099 -1.75537 0 + -0.727099 -1.75537 0 + -0.727099 -1.75537 0 + -0.729611 -1.76144 -0.0245 + -0.729611 -1.76144 -0.0245 + -0.729611 -1.76144 -0.0245 + -0.729611 -1.76144 -0.0245 + -0.736474 -1.77801 -0.0424352 + -0.736474 -1.77801 -0.0424352 + -0.736474 -1.77801 -0.0424352 + -0.736474 -1.77801 -0.0424352 + -0.736474 -1.77801 -0.0424352 + -0.736474 -1.77801 -0.0424352 + -0.74585 -1.80064 -0.049 + -0.74585 -1.80064 -0.049 + -0.74585 -1.80064 -0.049 + -0.74585 -1.80064 -0.049 + -0.74585 -1.80064 -0.049 + -0.74585 -1.80064 -0.049 + -0.74585 -1.80064 -0.049 + -0.755226 -1.82328 -0.0424352 + -0.755226 -1.82328 -0.0424352 + -0.755226 -1.82328 -0.0424352 + -0.755226 -1.82328 -0.0424352 + -0.755226 -1.82328 -0.0424352 + -0.762089 -1.83985 -0.0245 + -0.762089 -1.83985 -0.0245 + -0.762089 -1.83985 -0.0245 + -0.762089 -1.83985 -0.0245 + -0.762089 -1.83985 -0.0245 + -0.762089 -1.83985 -0.0245 + -0.762089 -1.83985 -0.0245 + -0.517121 -1.92992 0 + -0.517121 -1.92992 0 + -0.517121 -1.92992 0 + -0.517121 -1.92992 0 + -0.517121 -1.92992 0 + -0.517121 -1.92992 0 + -0.517121 -1.92992 0 + -0.515422 -1.92358 0.0245 + -0.515422 -1.92358 0.0245 + -0.515422 -1.92358 0.0245 + -0.515422 -1.92358 0.0245 + -0.515422 -1.92358 0.0245 + -0.515422 -1.92358 0.0245 + -0.51078 -1.90625 0.0424352 + -0.51078 -1.90625 0.0424352 + -0.51078 -1.90625 0.0424352 + -0.51078 -1.90625 0.0424352 + -0.51078 -1.90625 0.0424352 + -0.51078 -1.90625 0.0424352 + -0.504439 -1.88259 0.049 + -0.504439 -1.88259 0.049 + -0.504439 -1.88259 0.049 + -0.504439 -1.88259 0.049 + -0.504439 -1.88259 0.049 + -0.498098 -1.85892 0.0424352 + -0.498098 -1.85892 0.0424352 + -0.498098 -1.85892 0.0424352 + -0.498098 -1.85892 0.0424352 + -0.498098 -1.85892 0.0424352 + -0.498098 -1.85892 0.0424352 + -0.498098 -1.85892 0.0424352 + -0.493456 -1.8416 0.0245 + -0.493456 -1.8416 0.0245 + -0.493456 -1.8416 0.0245 + -0.493456 -1.8416 0.0245 + -0.493456 -1.8416 0.0245 + -0.493456 -1.8416 0.0245 + -0.491757 -1.83526 0 + -0.491757 -1.83526 0 + -0.491757 -1.83526 0 + -0.491757 -1.83526 0 + -0.491757 -1.83526 0 + -0.491757 -1.83526 0 + -0.493456 -1.8416 -0.0245 + -0.493456 -1.8416 -0.0245 + -0.493456 -1.8416 -0.0245 + -0.493456 -1.8416 -0.0245 + -0.493456 -1.8416 -0.0245 + -0.493456 -1.8416 -0.0245 + -0.498098 -1.85892 -0.0424352 + -0.498098 -1.85892 -0.0424352 + -0.498098 -1.85892 -0.0424352 + -0.498098 -1.85892 -0.0424352 + -0.498098 -1.85892 -0.0424352 + -0.498098 -1.85892 -0.0424352 + -0.504439 -1.88259 -0.049 + -0.504439 -1.88259 -0.049 + -0.504439 -1.88259 -0.049 + -0.504439 -1.88259 -0.049 + -0.504439 -1.88259 -0.049 + -0.504439 -1.88259 -0.049 + -0.504439 -1.88259 -0.049 + -0.51078 -1.90625 -0.0424352 + -0.51078 -1.90625 -0.0424352 + -0.51078 -1.90625 -0.0424352 + -0.51078 -1.90625 -0.0424352 + -0.51078 -1.90625 -0.0424352 + -0.515422 -1.92358 -0.0245 + -0.515422 -1.92358 -0.0245 + -0.515422 -1.92358 -0.0245 + -0.515422 -1.92358 -0.0245 + -0.515422 -1.92358 -0.0245 + -0.260792 -1.98091 0 + -0.260792 -1.98091 0 + -0.260792 -1.98091 0 + -0.260792 -1.98091 0 + -0.260792 -1.98091 0 + -0.259936 -1.9744 0.0245 + -0.259936 -1.9744 0.0245 + -0.259936 -1.9744 0.0245 + -0.259936 -1.9744 0.0245 + -0.259936 -1.9744 0.0245 + -0.259936 -1.9744 0.0245 + -0.257595 -1.95662 0.0424352 + -0.257595 -1.95662 0.0424352 + -0.257595 -1.95662 0.0424352 + -0.257595 -1.95662 0.0424352 + -0.257595 -1.95662 0.0424352 + -0.257595 -1.95662 0.0424352 + -0.254397 -1.93233 0.049 + -0.254397 -1.93233 0.049 + -0.254397 -1.93233 0.049 + -0.254397 -1.93233 0.049 + -0.254397 -1.93233 0.049 + -0.254397 -1.93233 0.049 + -0.254397 -1.93233 0.049 + -0.251199 -1.90804 0.0424352 + -0.251199 -1.90804 0.0424352 + -0.251199 -1.90804 0.0424352 + -0.251199 -1.90804 0.0424352 + -0.251199 -1.90804 0.0424352 + -0.248858 -1.89025 0.0245 + -0.248858 -1.89025 0.0245 + -0.248858 -1.89025 0.0245 + -0.248858 -1.89025 0.0245 + -0.248858 -1.89025 0.0245 + -0.248858 -1.89025 0.0245 + -0.248001 -1.88374 0 + -0.248001 -1.88374 0 + -0.248001 -1.88374 0 + -0.248001 -1.88374 0 + -0.248001 -1.88374 0 + -0.248001 -1.88374 0 + -0.248858 -1.89025 -0.0245 + -0.248858 -1.89025 -0.0245 + -0.248858 -1.89025 -0.0245 + -0.248858 -1.89025 -0.0245 + -0.248858 -1.89025 -0.0245 + -0.248858 -1.89025 -0.0245 + -0.251199 -1.90804 -0.0424352 + -0.251199 -1.90804 -0.0424352 + -0.251199 -1.90804 -0.0424352 + -0.251199 -1.90804 -0.0424352 + -0.251199 -1.90804 -0.0424352 + -0.251199 -1.90804 -0.0424352 + -0.254397 -1.93233 -0.049 + -0.254397 -1.93233 -0.049 + -0.254397 -1.93233 -0.049 + -0.254397 -1.93233 -0.049 + -0.254397 -1.93233 -0.049 + -0.257595 -1.95662 -0.0424352 + -0.257595 -1.95662 -0.0424352 + -0.257595 -1.95662 -0.0424352 + -0.257595 -1.95662 -0.0424352 + -0.257595 -1.95662 -0.0424352 + -0.257595 -1.95662 -0.0424352 + -0.257595 -1.95662 -0.0424352 + -0.259936 -1.9744 -0.0245 + -0.259936 -1.9744 -0.0245 + -0.259936 -1.9744 -0.0245 + -0.259936 -1.9744 -0.0245 + -0.259936 -1.9744 -0.0245 + -0.259936 -1.9744 -0.0245 + -0.259936 -1.9744 -0.0245 + 1.50845e-07 -1.998 0 + 1.50845e-07 -1.998 0 + 1.50845e-07 -1.998 0 + 1.50845e-07 -1.998 0 + 1.50845e-07 -1.998 0 + 1.50845e-07 -1.998 0 + 1.50845e-07 -1.998 0 + 1.50845e-07 -1.998 0 + 1.50349e-07 -1.99144 0.0245 + 1.50349e-07 -1.99144 0.0245 + 1.50349e-07 -1.99144 0.0245 + 1.50349e-07 -1.99144 0.0245 + 1.48995e-07 -1.9735 0.0424352 + 1.48995e-07 -1.9735 0.0424352 + 1.48995e-07 -1.9735 0.0424352 + 1.48995e-07 -1.9735 0.0424352 + 1.48995e-07 -1.9735 0.0424352 + 1.48995e-07 -1.9735 0.0424352 + 1.48995e-07 -1.9735 0.0424352 + 1.48995e-07 -1.9735 0.0424352 + 1.47145e-07 -1.949 0.049 + 1.47145e-07 -1.949 0.049 + 1.47145e-07 -1.949 0.049 + 1.47145e-07 -1.949 0.049 + 1.45296e-07 -1.9245 0.0424352 + 1.45296e-07 -1.9245 0.0424352 + 1.45296e-07 -1.9245 0.0424352 + 1.45296e-07 -1.9245 0.0424352 + 1.45296e-07 -1.9245 0.0424352 + 1.45296e-07 -1.9245 0.0424352 + 1.43942e-07 -1.90656 0.0245 + 1.43942e-07 -1.90656 0.0245 + 1.43942e-07 -1.90656 0.0245 + 1.43942e-07 -1.90656 0.0245 + 1.43942e-07 -1.90656 0.0245 + 1.43942e-07 -1.90656 0.0245 + 1.43942e-07 -1.90656 0.0245 + 1.43446e-07 -1.9 0 + 1.43446e-07 -1.9 0 + 1.43446e-07 -1.9 0 + 1.43446e-07 -1.9 0 + 1.43446e-07 -1.9 0 + 1.43446e-07 -1.9 0 + 1.43942e-07 -1.90656 -0.0245 + 1.43942e-07 -1.90656 -0.0245 + 1.43942e-07 -1.90656 -0.0245 + 1.43942e-07 -1.90656 -0.0245 + 1.43942e-07 -1.90656 -0.0245 + 1.43942e-07 -1.90656 -0.0245 + 1.43942e-07 -1.90656 -0.0245 + 1.45296e-07 -1.9245 -0.0424352 + 1.45296e-07 -1.9245 -0.0424352 + 1.45296e-07 -1.9245 -0.0424352 + 1.45296e-07 -1.9245 -0.0424352 + 1.45296e-07 -1.9245 -0.0424352 + 1.45296e-07 -1.9245 -0.0424352 + 1.47145e-07 -1.949 -0.049 + 1.47145e-07 -1.949 -0.049 + 1.47145e-07 -1.949 -0.049 + 1.47145e-07 -1.949 -0.049 + 1.47145e-07 -1.949 -0.049 + 1.48995e-07 -1.9735 -0.0424352 + 1.48995e-07 -1.9735 -0.0424352 + 1.48995e-07 -1.9735 -0.0424352 + 1.48995e-07 -1.9735 -0.0424352 + 1.48995e-07 -1.9735 -0.0424352 + 1.48995e-07 -1.9735 -0.0424352 + 1.48995e-07 -1.9735 -0.0424352 + 1.50349e-07 -1.99144 -0.0245 + 1.50349e-07 -1.99144 -0.0245 + 1.50349e-07 -1.99144 -0.0245 + 1.50349e-07 -1.99144 -0.0245 + 0.260791 -1.98091 0 + 0.260791 -1.98091 0 + 0.260791 -1.98091 0 + 0.260791 -1.98091 0 + 0.260791 -1.98091 0 + 0.260791 -1.98091 0 + 0.259934 -1.9744 0.0245 + 0.259934 -1.9744 0.0245 + 0.259934 -1.9744 0.0245 + 0.259934 -1.9744 0.0245 + 0.259934 -1.9744 0.0245 + 0.259934 -1.9744 0.0245 + 0.257593 -1.95662 0.0424352 + 0.257593 -1.95662 0.0424352 + 0.257593 -1.95662 0.0424352 + 0.257593 -1.95662 0.0424352 + 0.257593 -1.95662 0.0424352 + 0.257593 -1.95662 0.0424352 + 0.254395 -1.93233 0.049 + 0.254395 -1.93233 0.049 + 0.254395 -1.93233 0.049 + 0.254395 -1.93233 0.049 + 0.254395 -1.93233 0.049 + 0.254395 -1.93233 0.049 + 0.251197 -1.90804 0.0424352 + 0.251197 -1.90804 0.0424352 + 0.251197 -1.90804 0.0424352 + 0.251197 -1.90804 0.0424352 + 0.251197 -1.90804 0.0424352 + 0.251197 -1.90804 0.0424352 + 0.248856 -1.89025 0.0245 + 0.248856 -1.89025 0.0245 + 0.248856 -1.89025 0.0245 + 0.248856 -1.89025 0.0245 + 0.248856 -1.89025 0.0245 + 0.248856 -1.89025 0.0245 + 0.247999 -1.88374 0 + 0.247999 -1.88374 0 + 0.247999 -1.88374 0 + 0.247999 -1.88374 0 + 0.247999 -1.88374 0 + 0.247999 -1.88374 0 + 0.248856 -1.89025 -0.0245 + 0.248856 -1.89025 -0.0245 + 0.248856 -1.89025 -0.0245 + 0.248856 -1.89025 -0.0245 + 0.248856 -1.89025 -0.0245 + 0.248856 -1.89025 -0.0245 + 0.251197 -1.90804 -0.0424352 + 0.251197 -1.90804 -0.0424352 + 0.251197 -1.90804 -0.0424352 + 0.251197 -1.90804 -0.0424352 + 0.251197 -1.90804 -0.0424352 + 0.251197 -1.90804 -0.0424352 + 0.254395 -1.93233 -0.049 + 0.254395 -1.93233 -0.049 + 0.254395 -1.93233 -0.049 + 0.254395 -1.93233 -0.049 + 0.254395 -1.93233 -0.049 + 0.254395 -1.93233 -0.049 + 0.257593 -1.95662 -0.0424352 + 0.257593 -1.95662 -0.0424352 + 0.257593 -1.95662 -0.0424352 + 0.257593 -1.95662 -0.0424352 + 0.257593 -1.95662 -0.0424352 + 0.257593 -1.95662 -0.0424352 + 0.259934 -1.9744 -0.0245 + 0.259934 -1.9744 -0.0245 + 0.259934 -1.9744 -0.0245 + 0.259934 -1.9744 -0.0245 + 0.259934 -1.9744 -0.0245 + 0.259934 -1.9744 -0.0245 + 0.51712 -1.92992 0 + 0.51712 -1.92992 0 + 0.51712 -1.92992 0 + 0.51712 -1.92992 0 + 0.51712 -1.92992 0 + 0.51712 -1.92992 0 + 0.51542 -1.92358 0.0245 + 0.51542 -1.92358 0.0245 + 0.51542 -1.92358 0.0245 + 0.51542 -1.92358 0.0245 + 0.51542 -1.92358 0.0245 + 0.51542 -1.92358 0.0245 + 0.510778 -1.90626 0.0424352 + 0.510778 -1.90626 0.0424352 + 0.510778 -1.90626 0.0424352 + 0.510778 -1.90626 0.0424352 + 0.510778 -1.90626 0.0424352 + 0.510778 -1.90626 0.0424352 + 0.504437 -1.88259 0.049 + 0.504437 -1.88259 0.049 + 0.504437 -1.88259 0.049 + 0.504437 -1.88259 0.049 + 0.504437 -1.88259 0.049 + 0.504437 -1.88259 0.049 + 0.504437 -1.88259 0.049 + 0.498096 -1.85892 0.0424352 + 0.498096 -1.85892 0.0424352 + 0.498096 -1.85892 0.0424352 + 0.498096 -1.85892 0.0424352 + 0.498096 -1.85892 0.0424352 + 0.493454 -1.8416 0.0245 + 0.493454 -1.8416 0.0245 + 0.493454 -1.8416 0.0245 + 0.493454 -1.8416 0.0245 + 0.493454 -1.8416 0.0245 + 0.493454 -1.8416 0.0245 + 0.491755 -1.83526 0 + 0.491755 -1.83526 0 + 0.491755 -1.83526 0 + 0.491755 -1.83526 0 + 0.491755 -1.83526 0 + 0.491755 -1.83526 0 + 0.493454 -1.8416 -0.0245 + 0.493454 -1.8416 -0.0245 + 0.493454 -1.8416 -0.0245 + 0.493454 -1.8416 -0.0245 + 0.493454 -1.8416 -0.0245 + 0.493454 -1.8416 -0.0245 + 0.498096 -1.85892 -0.0424352 + 0.498096 -1.85892 -0.0424352 + 0.498096 -1.85892 -0.0424352 + 0.498096 -1.85892 -0.0424352 + 0.498096 -1.85892 -0.0424352 + 0.504437 -1.88259 -0.049 + 0.504437 -1.88259 -0.049 + 0.504437 -1.88259 -0.049 + 0.504437 -1.88259 -0.049 + 0.504437 -1.88259 -0.049 + 0.504437 -1.88259 -0.049 + 0.504437 -1.88259 -0.049 + 0.510778 -1.90626 -0.0424352 + 0.510778 -1.90626 -0.0424352 + 0.510778 -1.90626 -0.0424352 + 0.510778 -1.90626 -0.0424352 + 0.510778 -1.90626 -0.0424352 + 0.510778 -1.90626 -0.0424352 + 0.51542 -1.92358 -0.0245 + 0.51542 -1.92358 -0.0245 + 0.51542 -1.92358 -0.0245 + 0.51542 -1.92358 -0.0245 + 0.51542 -1.92358 -0.0245 + 0.51542 -1.92358 -0.0245 + 0.764602 -1.84591 0 + 0.764602 -1.84591 0 + 0.764602 -1.84591 0 + 0.764602 -1.84591 0 + 0.76209 -1.83985 0.0245 + 0.76209 -1.83985 0.0245 + 0.76209 -1.83985 0.0245 + 0.76209 -1.83985 0.0245 + 0.76209 -1.83985 0.0245 + 0.76209 -1.83985 0.0245 + 0.76209 -1.83985 0.0245 + 0.755226 -1.82328 0.0424352 + 0.755226 -1.82328 0.0424352 + 0.755226 -1.82328 0.0424352 + 0.755226 -1.82328 0.0424352 + 0.755226 -1.82328 0.0424352 + 0.755226 -1.82328 0.0424352 + 0.74585 -1.80064 0.049 + 0.74585 -1.80064 0.049 + 0.74585 -1.80064 0.049 + 0.74585 -1.80064 0.049 + 0.74585 -1.80064 0.049 + 0.74585 -1.80064 0.049 + 0.736475 -1.77801 0.0424352 + 0.736475 -1.77801 0.0424352 + 0.736475 -1.77801 0.0424352 + 0.736475 -1.77801 0.0424352 + 0.736475 -1.77801 0.0424352 + 0.736475 -1.77801 0.0424352 + 0.729611 -1.76144 0.0245 + 0.729611 -1.76144 0.0245 + 0.729611 -1.76144 0.0245 + 0.729611 -1.76144 0.0245 + 0.729611 -1.76144 0.0245 + 0.729611 -1.76144 0.0245 + 0.729611 -1.76144 0.0245 + 0.727099 -1.75537 0 + 0.727099 -1.75537 0 + 0.727099 -1.75537 0 + 0.727099 -1.75537 0 + 0.729611 -1.76144 -0.0245 + 0.729611 -1.76144 -0.0245 + 0.729611 -1.76144 -0.0245 + 0.729611 -1.76144 -0.0245 + 0.729611 -1.76144 -0.0245 + 0.729611 -1.76144 -0.0245 + 0.736475 -1.77801 -0.0424352 + 0.736475 -1.77801 -0.0424352 + 0.736475 -1.77801 -0.0424352 + 0.736475 -1.77801 -0.0424352 + 0.736475 -1.77801 -0.0424352 + 0.736475 -1.77801 -0.0424352 + 0.736475 -1.77801 -0.0424352 + 0.74585 -1.80064 -0.049 + 0.74585 -1.80064 -0.049 + 0.74585 -1.80064 -0.049 + 0.74585 -1.80064 -0.049 + 0.74585 -1.80064 -0.049 + 0.74585 -1.80064 -0.049 + 0.755226 -1.82328 -0.0424352 + 0.755226 -1.82328 -0.0424352 + 0.755226 -1.82328 -0.0424352 + 0.755226 -1.82328 -0.0424352 + 0.755226 -1.82328 -0.0424352 + 0.755226 -1.82328 -0.0424352 + 0.76209 -1.83985 -0.0245 + 0.76209 -1.83985 -0.0245 + 0.76209 -1.83985 -0.0245 + 0.76209 -1.83985 -0.0245 + 0.76209 -1.83985 -0.0245 + 0.76209 -1.83985 -0.0245 + 0.76209 -1.83985 -0.0245 + 0.999 -1.73032 0 + 0.999 -1.73032 0 + 0.999 -1.73032 0 + 0.999 -1.73032 0 + 0.999 -1.73032 0 + 0.999 -1.73032 0 + 0.995718 -1.72463 0.0245 + 0.995718 -1.72463 0.0245 + 0.995718 -1.72463 0.0245 + 0.995718 -1.72463 0.0245 + 0.995718 -1.72463 0.0245 + 0.995718 -1.72463 0.0245 + 0.98675 -1.7091 0.0424352 + 0.98675 -1.7091 0.0424352 + 0.98675 -1.7091 0.0424352 + 0.98675 -1.7091 0.0424352 + 0.98675 -1.7091 0.0424352 + 0.98675 -1.7091 0.0424352 + 0.9745 -1.68788 0.049 + 0.9745 -1.68788 0.049 + 0.9745 -1.68788 0.049 + 0.9745 -1.68788 0.049 + 0.9745 -1.68788 0.049 + 0.96225 -1.66667 0.0424352 + 0.96225 -1.66667 0.0424352 + 0.96225 -1.66667 0.0424352 + 0.96225 -1.66667 0.0424352 + 0.96225 -1.66667 0.0424352 + 0.96225 -1.66667 0.0424352 + 0.96225 -1.66667 0.0424352 + 0.953282 -1.65113 0.0245 + 0.953282 -1.65113 0.0245 + 0.953282 -1.65113 0.0245 + 0.953282 -1.65113 0.0245 + 0.953282 -1.65113 0.0245 + 0.95 -1.64545 0 + 0.95 -1.64545 0 + 0.95 -1.64545 0 + 0.95 -1.64545 0 + 0.95 -1.64545 0 + 0.95 -1.64545 0 + 0.95 -1.64545 0 + 0.95 -1.64545 0 + 0.953282 -1.65113 -0.0245 + 0.953282 -1.65113 -0.0245 + 0.953282 -1.65113 -0.0245 + 0.953282 -1.65113 -0.0245 + 0.953282 -1.65113 -0.0245 + 0.953282 -1.65113 -0.0245 + 0.96225 -1.66667 -0.0424352 + 0.96225 -1.66667 -0.0424352 + 0.96225 -1.66667 -0.0424352 + 0.96225 -1.66667 -0.0424352 + 0.96225 -1.66667 -0.0424352 + 0.96225 -1.66667 -0.0424352 + 0.9745 -1.68788 -0.049 + 0.9745 -1.68788 -0.049 + 0.9745 -1.68788 -0.049 + 0.9745 -1.68788 -0.049 + 0.9745 -1.68788 -0.049 + 0.98675 -1.7091 -0.0424352 + 0.98675 -1.7091 -0.0424352 + 0.98675 -1.7091 -0.0424352 + 0.98675 -1.7091 -0.0424352 + 0.98675 -1.7091 -0.0424352 + 0.98675 -1.7091 -0.0424352 + 0.995718 -1.72463 -0.0245 + 0.995718 -1.72463 -0.0245 + 0.995718 -1.72463 -0.0245 + 0.995718 -1.72463 -0.0245 + 0.995718 -1.72463 -0.0245 + 0.995718 -1.72463 -0.0245 + 1.21631 -1.58512 0 + 1.21631 -1.58512 0 + 1.21631 -1.58512 0 + 1.21631 -1.58512 0 + 1.21631 -1.58512 0 + 1.21631 -1.58512 0 + 1.21631 -1.58512 0 + 1.21631 -1.58512 0 + 1.21231 -1.57991 0.0245 + 1.21231 -1.57991 0.0245 + 1.21231 -1.57991 0.0245 + 1.21231 -1.57991 0.0245 + 1.21231 -1.57991 0.0245 + 1.20139 -1.56568 0.0424352 + 1.20139 -1.56568 0.0424352 + 1.20139 -1.56568 0.0424352 + 1.20139 -1.56568 0.0424352 + 1.20139 -1.56568 0.0424352 + 1.18648 -1.54625 0.049 + 1.18648 -1.54625 0.049 + 1.18648 -1.54625 0.049 + 1.18648 -1.54625 0.049 + 1.18648 -1.54625 0.049 + 1.18648 -1.54625 0.049 + 1.18648 -1.54625 0.049 + 1.17156 -1.52681 0.0424352 + 1.17156 -1.52681 0.0424352 + 1.17156 -1.52681 0.0424352 + 1.17156 -1.52681 0.0424352 + 1.17156 -1.52681 0.0424352 + 1.17156 -1.52681 0.0424352 + 1.17156 -1.52681 0.0424352 + 1.16064 -1.51258 0.0245 + 1.16064 -1.51258 0.0245 + 1.16064 -1.51258 0.0245 + 1.16064 -1.51258 0.0245 + 1.16064 -1.51258 0.0245 + 1.15665 -1.50737 0 + 1.15665 -1.50737 0 + 1.15665 -1.50737 0 + 1.15665 -1.50737 0 + 1.15665 -1.50737 0 + 1.15665 -1.50737 0 + 1.16064 -1.51258 -0.0245 + 1.16064 -1.51258 -0.0245 + 1.16064 -1.51258 -0.0245 + 1.16064 -1.51258 -0.0245 + 1.16064 -1.51258 -0.0245 + 1.17156 -1.52681 -0.0424352 + 1.17156 -1.52681 -0.0424352 + 1.17156 -1.52681 -0.0424352 + 1.17156 -1.52681 -0.0424352 + 1.17156 -1.52681 -0.0424352 + 1.17156 -1.52681 -0.0424352 + 1.17156 -1.52681 -0.0424352 + 1.18648 -1.54625 -0.049 + 1.18648 -1.54625 -0.049 + 1.18648 -1.54625 -0.049 + 1.18648 -1.54625 -0.049 + 1.18648 -1.54625 -0.049 + 1.18648 -1.54625 -0.049 + 1.20139 -1.56568 -0.0424352 + 1.20139 -1.56568 -0.0424352 + 1.20139 -1.56568 -0.0424352 + 1.20139 -1.56568 -0.0424352 + 1.20139 -1.56568 -0.0424352 + 1.20139 -1.56568 -0.0424352 + 1.21231 -1.57991 -0.0245 + 1.21231 -1.57991 -0.0245 + 1.21231 -1.57991 -0.0245 + 1.21231 -1.57991 -0.0245 + 1.21231 -1.57991 -0.0245 + 1.4128 -1.4128 0 + 1.4128 -1.4128 0 + 1.4128 -1.4128 0 + 1.4128 -1.4128 0 + 1.40816 -1.40816 0.0245 + 1.40816 -1.40816 0.0245 + 1.40816 -1.40816 0.0245 + 1.40816 -1.40816 0.0245 + 1.40816 -1.40816 0.0245 + 1.40816 -1.40816 0.0245 + 1.40816 -1.40816 0.0245 + 1.40816 -1.40816 0.0245 + 1.39547 -1.39548 0.0424352 + 1.39547 -1.39548 0.0424352 + 1.39547 -1.39548 0.0424352 + 1.39547 -1.39548 0.0424352 + 1.39547 -1.39548 0.0424352 + 1.37815 -1.37815 0.049 + 1.37815 -1.37815 0.049 + 1.37815 -1.37815 0.049 + 1.37815 -1.37815 0.049 + 1.37815 -1.37815 0.049 + 1.37815 -1.37815 0.049 + 1.36083 -1.36083 0.0424352 + 1.36083 -1.36083 0.0424352 + 1.36083 -1.36083 0.0424352 + 1.36083 -1.36083 0.0424352 + 1.36083 -1.36083 0.0424352 + 1.36083 -1.36083 0.0424352 + 1.34814 -1.34815 0.0245 + 1.34814 -1.34815 0.0245 + 1.34814 -1.34815 0.0245 + 1.34814 -1.34815 0.0245 + 1.34814 -1.34815 0.0245 + 1.34814 -1.34815 0.0245 + 1.34814 -1.34815 0.0245 + 1.3435 -1.3435 0 + 1.3435 -1.3435 0 + 1.3435 -1.3435 0 + 1.3435 -1.3435 0 + 1.34814 -1.34815 -0.0245 + 1.34814 -1.34815 -0.0245 + 1.34814 -1.34815 -0.0245 + 1.34814 -1.34815 -0.0245 + 1.34814 -1.34815 -0.0245 + 1.34814 -1.34815 -0.0245 + 1.34814 -1.34815 -0.0245 + 1.36083 -1.36083 -0.0424352 + 1.36083 -1.36083 -0.0424352 + 1.36083 -1.36083 -0.0424352 + 1.36083 -1.36083 -0.0424352 + 1.36083 -1.36083 -0.0424352 + 1.37815 -1.37815 -0.049 + 1.37815 -1.37815 -0.049 + 1.37815 -1.37815 -0.049 + 1.37815 -1.37815 -0.049 + 1.37815 -1.37815 -0.049 + 1.37815 -1.37815 -0.049 + 1.37815 -1.37815 -0.049 + 1.37815 -1.37815 -0.049 + 1.39547 -1.39548 -0.0424352 + 1.39547 -1.39548 -0.0424352 + 1.39547 -1.39548 -0.0424352 + 1.39547 -1.39548 -0.0424352 + 1.40816 -1.40816 -0.0245 + 1.40816 -1.40816 -0.0245 + 1.40816 -1.40816 -0.0245 + 1.40816 -1.40816 -0.0245 + 1.40816 -1.40816 -0.0245 + 1.40816 -1.40816 -0.0245 + 1.40816 -1.40816 -0.0245 + 1.40816 -1.40816 -0.0245 + 1.58512 -1.21631 0 + 1.58512 -1.21631 0 + 1.58512 -1.21631 0 + 1.58512 -1.21631 0 + 1.58512 -1.21631 0 + 1.58512 -1.21631 0 + 1.57991 -1.21231 0.0245 + 1.57991 -1.21231 0.0245 + 1.57991 -1.21231 0.0245 + 1.57991 -1.21231 0.0245 + 1.57991 -1.21231 0.0245 + 1.57991 -1.21231 0.0245 + 1.56568 -1.20139 0.0424352 + 1.56568 -1.20139 0.0424352 + 1.56568 -1.20139 0.0424352 + 1.56568 -1.20139 0.0424352 + 1.56568 -1.20139 0.0424352 + 1.56568 -1.20139 0.0424352 + 1.54625 -1.18648 0.049 + 1.54625 -1.18648 0.049 + 1.54625 -1.18648 0.049 + 1.54625 -1.18648 0.049 + 1.54625 -1.18648 0.049 + 1.54625 -1.18648 0.049 + 1.52681 -1.17156 0.0424352 + 1.52681 -1.17156 0.0424352 + 1.52681 -1.17156 0.0424352 + 1.52681 -1.17156 0.0424352 + 1.52681 -1.17156 0.0424352 + 1.52681 -1.17156 0.0424352 + 1.51258 -1.16064 0.0245 + 1.51258 -1.16064 0.0245 + 1.51258 -1.16064 0.0245 + 1.51258 -1.16064 0.0245 + 1.51258 -1.16064 0.0245 + 1.51258 -1.16064 0.0245 + 1.50737 -1.15665 0 + 1.50737 -1.15665 0 + 1.50737 -1.15665 0 + 1.50737 -1.15665 0 + 1.50737 -1.15665 0 + 1.50737 -1.15665 0 + 1.51258 -1.16064 -0.0245 + 1.51258 -1.16064 -0.0245 + 1.51258 -1.16064 -0.0245 + 1.51258 -1.16064 -0.0245 + 1.51258 -1.16064 -0.0245 + 1.51258 -1.16064 -0.0245 + 1.52681 -1.17156 -0.0424352 + 1.52681 -1.17156 -0.0424352 + 1.52681 -1.17156 -0.0424352 + 1.52681 -1.17156 -0.0424352 + 1.52681 -1.17156 -0.0424352 + 1.52681 -1.17156 -0.0424352 + 1.52681 -1.17156 -0.0424352 + 1.54625 -1.18648 -0.049 + 1.54625 -1.18648 -0.049 + 1.54625 -1.18648 -0.049 + 1.54625 -1.18648 -0.049 + 1.54625 -1.18648 -0.049 + 1.56568 -1.20139 -0.0424352 + 1.56568 -1.20139 -0.0424352 + 1.56568 -1.20139 -0.0424352 + 1.56568 -1.20139 -0.0424352 + 1.56568 -1.20139 -0.0424352 + 1.56568 -1.20139 -0.0424352 + 1.57991 -1.21231 -0.0245 + 1.57991 -1.21231 -0.0245 + 1.57991 -1.21231 -0.0245 + 1.57991 -1.21231 -0.0245 + 1.57991 -1.21231 -0.0245 + 1.57991 -1.21231 -0.0245 + 1.73032 -0.999 0 + 1.73032 -0.999 0 + 1.73032 -0.999 0 + 1.73032 -0.999 0 + 1.73032 -0.999 0 + 1.73032 -0.999 0 + 1.72463 -0.995718 0.0245 + 1.72463 -0.995718 0.0245 + 1.72463 -0.995718 0.0245 + 1.72463 -0.995718 0.0245 + 1.72463 -0.995718 0.0245 + 1.72463 -0.995718 0.0245 + 1.7091 -0.98675 0.0424352 + 1.7091 -0.98675 0.0424352 + 1.7091 -0.98675 0.0424352 + 1.7091 -0.98675 0.0424352 + 1.7091 -0.98675 0.0424352 + 1.7091 -0.98675 0.0424352 + 1.68788 -0.9745 0.049 + 1.68788 -0.9745 0.049 + 1.68788 -0.9745 0.049 + 1.68788 -0.9745 0.049 + 1.68788 -0.9745 0.049 + 1.68788 -0.9745 0.049 + 1.68788 -0.9745 0.049 + 1.66667 -0.96225 0.0424352 + 1.66667 -0.96225 0.0424352 + 1.66667 -0.96225 0.0424352 + 1.66667 -0.96225 0.0424352 + 1.66667 -0.96225 0.0424352 + 1.65113 -0.953282 0.0245 + 1.65113 -0.953282 0.0245 + 1.65113 -0.953282 0.0245 + 1.65113 -0.953282 0.0245 + 1.65113 -0.953282 0.0245 + 1.64545 -0.95 0 + 1.64545 -0.95 0 + 1.64545 -0.95 0 + 1.64545 -0.95 0 + 1.64545 -0.95 0 + 1.64545 -0.95 0 + 1.64545 -0.95 0 + 1.64545 -0.95 0 + 1.65113 -0.953282 -0.0245 + 1.65113 -0.953282 -0.0245 + 1.65113 -0.953282 -0.0245 + 1.65113 -0.953282 -0.0245 + 1.65113 -0.953282 -0.0245 + 1.66667 -0.96225 -0.0424352 + 1.66667 -0.96225 -0.0424352 + 1.66667 -0.96225 -0.0424352 + 1.66667 -0.96225 -0.0424352 + 1.66667 -0.96225 -0.0424352 + 1.68788 -0.9745 -0.049 + 1.68788 -0.9745 -0.049 + 1.68788 -0.9745 -0.049 + 1.68788 -0.9745 -0.049 + 1.68788 -0.9745 -0.049 + 1.68788 -0.9745 -0.049 + 1.68788 -0.9745 -0.049 + 1.7091 -0.98675 -0.0424352 + 1.7091 -0.98675 -0.0424352 + 1.7091 -0.98675 -0.0424352 + 1.7091 -0.98675 -0.0424352 + 1.7091 -0.98675 -0.0424352 + 1.7091 -0.98675 -0.0424352 + 1.72463 -0.995718 -0.0245 + 1.72463 -0.995718 -0.0245 + 1.72463 -0.995718 -0.0245 + 1.72463 -0.995718 -0.0245 + 1.72463 -0.995718 -0.0245 + 1.72463 -0.995718 -0.0245 + 1.84591 -0.764602 0 + 1.84591 -0.764602 0 + 1.84591 -0.764602 0 + 1.84591 -0.764602 0 + 1.84591 -0.764602 0 + 1.84591 -0.764602 0 + 1.84591 -0.764602 0 + 1.83985 -0.76209 0.0245 + 1.83985 -0.76209 0.0245 + 1.83985 -0.76209 0.0245 + 1.83985 -0.76209 0.0245 + 1.83985 -0.76209 0.0245 + 1.82328 -0.755226 0.0424352 + 1.82328 -0.755226 0.0424352 + 1.82328 -0.755226 0.0424352 + 1.82328 -0.755226 0.0424352 + 1.82328 -0.755226 0.0424352 + 1.82328 -0.755226 0.0424352 + 1.82328 -0.755226 0.0424352 + 1.80064 -0.745851 0.049 + 1.80064 -0.745851 0.049 + 1.80064 -0.745851 0.049 + 1.80064 -0.745851 0.049 + 1.80064 -0.745851 0.049 + 1.80064 -0.745851 0.049 + 1.77801 -0.736475 0.0424352 + 1.77801 -0.736475 0.0424352 + 1.77801 -0.736475 0.0424352 + 1.77801 -0.736475 0.0424352 + 1.77801 -0.736475 0.0424352 + 1.76144 -0.729611 0.0245 + 1.76144 -0.729611 0.0245 + 1.76144 -0.729611 0.0245 + 1.76144 -0.729611 0.0245 + 1.76144 -0.729611 0.0245 + 1.76144 -0.729611 0.0245 + 1.76144 -0.729611 0.0245 + 1.75537 -0.727099 0 + 1.75537 -0.727099 0 + 1.75537 -0.727099 0 + 1.75537 -0.727099 0 + 1.75537 -0.727099 0 + 1.76144 -0.729611 -0.0245 + 1.76144 -0.729611 -0.0245 + 1.76144 -0.729611 -0.0245 + 1.76144 -0.729611 -0.0245 + 1.76144 -0.729611 -0.0245 + 1.76144 -0.729611 -0.0245 + 1.76144 -0.729611 -0.0245 + 1.77801 -0.736475 -0.0424352 + 1.77801 -0.736475 -0.0424352 + 1.77801 -0.736475 -0.0424352 + 1.77801 -0.736475 -0.0424352 + 1.77801 -0.736475 -0.0424352 + 1.77801 -0.736475 -0.0424352 + 1.80064 -0.745851 -0.049 + 1.80064 -0.745851 -0.049 + 1.80064 -0.745851 -0.049 + 1.80064 -0.745851 -0.049 + 1.80064 -0.745851 -0.049 + 1.80064 -0.745851 -0.049 + 1.82328 -0.755226 -0.0424352 + 1.82328 -0.755226 -0.0424352 + 1.82328 -0.755226 -0.0424352 + 1.82328 -0.755226 -0.0424352 + 1.82328 -0.755226 -0.0424352 + 1.82328 -0.755226 -0.0424352 + 1.82328 -0.755226 -0.0424352 + 1.83985 -0.76209 -0.0245 + 1.83985 -0.76209 -0.0245 + 1.83985 -0.76209 -0.0245 + 1.83985 -0.76209 -0.0245 + 1.92992 -0.51712 0 + 1.92992 -0.51712 0 + 1.92992 -0.51712 0 + 1.92992 -0.51712 0 + 1.92992 -0.51712 0 + 1.92992 -0.51712 0 + 1.92992 -0.51712 0 + 1.92358 -0.515421 0.0245 + 1.92358 -0.515421 0.0245 + 1.92358 -0.515421 0.0245 + 1.92358 -0.515421 0.0245 + 1.92358 -0.515421 0.0245 + 1.92358 -0.515421 0.0245 + 1.90626 -0.510779 0.0424352 + 1.90626 -0.510779 0.0424352 + 1.90626 -0.510779 0.0424352 + 1.90626 -0.510779 0.0424352 + 1.90626 -0.510779 0.0424352 + 1.88259 -0.504438 0.049 + 1.88259 -0.504438 0.049 + 1.88259 -0.504438 0.049 + 1.88259 -0.504438 0.049 + 1.88259 -0.504438 0.049 + 1.88259 -0.504438 0.049 + 1.85892 -0.498097 0.0424352 + 1.85892 -0.498097 0.0424352 + 1.85892 -0.498097 0.0424352 + 1.85892 -0.498097 0.0424352 + 1.85892 -0.498097 0.0424352 + 1.85892 -0.498097 0.0424352 + 1.8416 -0.493455 0.0245 + 1.8416 -0.493455 0.0245 + 1.8416 -0.493455 0.0245 + 1.8416 -0.493455 0.0245 + 1.8416 -0.493455 0.0245 + 1.8416 -0.493455 0.0245 + 1.83526 -0.491756 0 + 1.83526 -0.491756 0 + 1.83526 -0.491756 0 + 1.83526 -0.491756 0 + 1.83526 -0.491756 0 + 1.83526 -0.491756 0 + 1.83526 -0.491756 0 + 1.8416 -0.493455 -0.0245 + 1.8416 -0.493455 -0.0245 + 1.8416 -0.493455 -0.0245 + 1.8416 -0.493455 -0.0245 + 1.8416 -0.493455 -0.0245 + 1.85892 -0.498097 -0.0424352 + 1.85892 -0.498097 -0.0424352 + 1.85892 -0.498097 -0.0424352 + 1.85892 -0.498097 -0.0424352 + 1.85892 -0.498097 -0.0424352 + 1.85892 -0.498097 -0.0424352 + 1.88259 -0.504438 -0.049 + 1.88259 -0.504438 -0.049 + 1.88259 -0.504438 -0.049 + 1.88259 -0.504438 -0.049 + 1.88259 -0.504438 -0.049 + 1.88259 -0.504438 -0.049 + 1.90626 -0.510779 -0.0424352 + 1.90626 -0.510779 -0.0424352 + 1.90626 -0.510779 -0.0424352 + 1.90626 -0.510779 -0.0424352 + 1.90626 -0.510779 -0.0424352 + 1.92358 -0.515421 -0.0245 + 1.92358 -0.515421 -0.0245 + 1.92358 -0.515421 -0.0245 + 1.92358 -0.515421 -0.0245 + 1.92358 -0.515421 -0.0245 + 1.92358 -0.515421 -0.0245 + 1.92358 -0.515421 -0.0245 + 1.98091 -0.260791 0 + 1.98091 -0.260791 0 + 1.98091 -0.260791 0 + 1.98091 -0.260791 0 + 1.9744 -0.259934 0.0245 + 1.9744 -0.259934 0.0245 + 1.9744 -0.259934 0.0245 + 1.9744 -0.259934 0.0245 + 1.9744 -0.259934 0.0245 + 1.9744 -0.259934 0.0245 + 1.9744 -0.259934 0.0245 + 1.95662 -0.257593 0.0424352 + 1.95662 -0.257593 0.0424352 + 1.95662 -0.257593 0.0424352 + 1.95662 -0.257593 0.0424352 + 1.95662 -0.257593 0.0424352 + 1.95662 -0.257593 0.0424352 + 1.93233 -0.254395 0.049 + 1.93233 -0.254395 0.049 + 1.93233 -0.254395 0.049 + 1.93233 -0.254395 0.049 + 1.93233 -0.254395 0.049 + 1.93233 -0.254395 0.049 + 1.90804 -0.251198 0.0424352 + 1.90804 -0.251198 0.0424352 + 1.90804 -0.251198 0.0424352 + 1.90804 -0.251198 0.0424352 + 1.90804 -0.251198 0.0424352 + 1.90804 -0.251198 0.0424352 + 1.90804 -0.251198 0.0424352 + 1.89025 -0.248857 0.0245 + 1.89025 -0.248857 0.0245 + 1.89025 -0.248857 0.0245 + 1.89025 -0.248857 0.0245 + 1.89025 -0.248857 0.0245 + 1.88374 -0.248 0 + 1.88374 -0.248 0 + 1.88374 -0.248 0 + 1.88374 -0.248 0 + 1.88374 -0.248 0 + 1.88374 -0.248 0 + 1.89025 -0.248857 -0.0245 + 1.89025 -0.248857 -0.0245 + 1.89025 -0.248857 -0.0245 + 1.89025 -0.248857 -0.0245 + 1.89025 -0.248857 -0.0245 + 1.89025 -0.248857 -0.0245 + 1.90804 -0.251198 -0.0424352 + 1.90804 -0.251198 -0.0424352 + 1.90804 -0.251198 -0.0424352 + 1.90804 -0.251198 -0.0424352 + 1.90804 -0.251198 -0.0424352 + 1.90804 -0.251198 -0.0424352 + 1.93233 -0.254395 -0.049 + 1.93233 -0.254395 -0.049 + 1.93233 -0.254395 -0.049 + 1.93233 -0.254395 -0.049 + 1.93233 -0.254395 -0.049 + 1.93233 -0.254395 -0.049 + 1.95662 -0.257593 -0.0424352 + 1.95662 -0.257593 -0.0424352 + 1.95662 -0.257593 -0.0424352 + 1.95662 -0.257593 -0.0424352 + 1.95662 -0.257593 -0.0424352 + 1.95662 -0.257593 -0.0424352 + 1.9744 -0.259934 -0.0245 + 1.9744 -0.259934 -0.0245 + 1.9744 -0.259934 -0.0245 + 1.9744 -0.259934 -0.0245 + 1.9744 -0.259934 -0.0245 + 1.9744 -0.259934 -0.0245 + 1.9744 -0.259934 -0.0245 + } + } + } + NormalArray TRUE { + osg::Vec3Array { + UniqueID 210 + BufferObject TRUE { + osg::VertexBufferObject { + UniqueID 209 + } + } + Binding BIND_PER_VERTEX + vector 3456 { + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 0.868672 0 0.495387 + 0.868672 0 0.495387 + 0.868672 0 0.495387 + 0.868672 0 0.495387 + 0.508001 0 0.861357 + 0.508001 0 0.861357 + 0.508001 0 0.861357 + 0.508001 0 0.861357 + 0.508001 0 0.861357 + 0.508001 0 0.861357 + 0.508001 0 0.861357 + 0.508001 0 0.861357 + 0.0107829 0 0.999942 + 0.0107829 0 0.999942 + 0.0107829 0 0.999942 + 0.0107829 0 0.999942 + -0.491827 0 0.870693 + -0.491827 0 0.870693 + -0.491827 0 0.870693 + -0.491827 0 0.870693 + -0.491827 0 0.870693 + -0.491827 0 0.870693 + -0.86328 0 0.504725 + -0.86328 0 0.504725 + -0.86328 0 0.504725 + -0.86328 0 0.504725 + -0.86328 0 0.504725 + -0.86328 0 0.504725 + -0.86328 0 0.504725 + -0.86328 0 0.504725 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -0.863281 0 -0.504725 + -0.863281 0 -0.504725 + -0.863281 0 -0.504725 + -0.863281 0 -0.504725 + -0.863281 0 -0.504725 + -0.863281 0 -0.504725 + -0.863281 0 -0.504725 + -0.863281 0 -0.504725 + -0.491827 0 -0.870693 + -0.491827 0 -0.870693 + -0.491827 0 -0.870693 + -0.491827 0 -0.870693 + -0.491827 0 -0.870693 + -0.491827 0 -0.870693 + 0.0107829 0 -0.999942 + 0.0107829 0 -0.999942 + 0.0107829 0 -0.999942 + 0.0107829 0 -0.999942 + 0.508001 0 -0.861357 + 0.508001 0 -0.861357 + 0.508001 0 -0.861357 + 0.508001 0 -0.861357 + 0.508001 0 -0.861357 + 0.508001 0 -0.861357 + 0.508001 0 -0.861357 + 0.508001 0 -0.861357 + 0.868672 0 -0.495387 + 0.868672 0 -0.495387 + 0.868672 0 -0.495387 + 0.868672 0 -0.495387 + 0.991445 0.130526 0 + 0.991445 0.130526 0 + 0.991445 0.130526 0 + 0.991445 0.130526 0 + 0.991445 0.130526 0 + 0.991445 0.130526 0 + 0.861239 0.113384 0.495389 + 0.861239 0.113384 0.495389 + 0.861239 0.113384 0.495389 + 0.861239 0.113384 0.495389 + 0.861239 0.113384 0.495389 + 0.861239 0.113384 0.495389 + 0.503654 0.0663074 0.861357 + 0.503654 0.0663074 0.861357 + 0.503654 0.0663074 0.861357 + 0.503654 0.0663074 0.861357 + 0.503654 0.0663074 0.861357 + 0.503654 0.0663074 0.861357 + 0.0106911 0.0014075 0.999942 + 0.0106911 0.0014075 0.999942 + 0.0106911 0.0014075 0.999942 + 0.0106911 0.0014075 0.999942 + 0.0106911 0.0014075 0.999942 + 0.0106911 0.0014075 0.999942 + -0.48762 -0.0641963 0.870693 + -0.48762 -0.0641963 0.870693 + -0.48762 -0.0641963 0.870693 + -0.48762 -0.0641963 0.870693 + -0.48762 -0.0641963 0.870693 + -0.48762 -0.0641963 0.870693 + -0.855897 -0.112681 0.504722 + -0.855897 -0.112681 0.504722 + -0.855897 -0.112681 0.504722 + -0.855897 -0.112681 0.504722 + -0.855897 -0.112681 0.504722 + -0.855897 -0.112681 0.504722 + -0.991445 -0.130526 0 + -0.991445 -0.130526 0 + -0.991445 -0.130526 0 + -0.991445 -0.130526 0 + -0.991445 -0.130526 0 + -0.991445 -0.130526 0 + -0.855897 -0.112681 -0.504722 + -0.855897 -0.112681 -0.504722 + -0.855897 -0.112681 -0.504722 + -0.855897 -0.112681 -0.504722 + -0.855897 -0.112681 -0.504722 + -0.855897 -0.112681 -0.504722 + -0.48762 -0.0641963 -0.870693 + -0.48762 -0.0641963 -0.870693 + -0.48762 -0.0641963 -0.870693 + -0.48762 -0.0641963 -0.870693 + -0.48762 -0.0641963 -0.870693 + -0.48762 -0.0641963 -0.870693 + 0.0106912 0.0014075 -0.999942 + 0.0106912 0.0014075 -0.999942 + 0.0106912 0.0014075 -0.999942 + 0.0106912 0.0014075 -0.999942 + 0.0106912 0.0014075 -0.999942 + 0.0106912 0.0014075 -0.999942 + 0.503654 0.0663074 -0.861357 + 0.503654 0.0663074 -0.861357 + 0.503654 0.0663074 -0.861357 + 0.503654 0.0663074 -0.861357 + 0.503654 0.0663074 -0.861357 + 0.503654 0.0663074 -0.861357 + 0.86124 0.113384 -0.495389 + 0.86124 0.113384 -0.495389 + 0.86124 0.113384 -0.495389 + 0.86124 0.113384 -0.495389 + 0.86124 0.113384 -0.495389 + 0.86124 0.113384 -0.495389 + 0.965926 0.25882 0 + 0.965926 0.25882 0 + 0.965926 0.25882 0 + 0.965926 0.25882 0 + 0.965926 0.25882 0 + 0.965926 0.25882 0 + 0.839073 0.224829 0.495388 + 0.839073 0.224829 0.495388 + 0.839073 0.224829 0.495388 + 0.839073 0.224829 0.495388 + 0.839073 0.224829 0.495388 + 0.839073 0.224829 0.495388 + 0.490692 0.13148 0.861356 + 0.490692 0.13148 0.861356 + 0.490692 0.13148 0.861356 + 0.490692 0.13148 0.861356 + 0.490692 0.13148 0.861356 + 0.490692 0.13148 0.861356 + 0.0104154 0.00279081 0.999942 + 0.0104154 0.00279081 0.999942 + 0.0104154 0.00279081 0.999942 + 0.0104154 0.00279081 0.999942 + 0.0104154 0.00279081 0.999942 + 0.0104154 0.00279081 0.999942 + -0.475066 -0.127294 0.870694 + -0.475066 -0.127294 0.870694 + -0.475066 -0.127294 0.870694 + -0.475066 -0.127294 0.870694 + -0.475066 -0.127294 0.870694 + -0.475066 -0.127294 0.870694 + -0.833865 -0.223434 0.504724 + -0.833865 -0.223434 0.504724 + -0.833865 -0.223434 0.504724 + -0.833865 -0.223434 0.504724 + -0.833865 -0.223434 0.504724 + -0.833865 -0.223434 0.504724 + -0.965926 -0.258819 0 + -0.965926 -0.258819 0 + -0.965926 -0.258819 0 + -0.965926 -0.258819 0 + -0.965926 -0.258819 0 + -0.965926 -0.258819 0 + -0.833865 -0.223433 -0.504724 + -0.833865 -0.223433 -0.504724 + -0.833865 -0.223433 -0.504724 + -0.833865 -0.223433 -0.504724 + -0.833865 -0.223433 -0.504724 + -0.475066 -0.127293 -0.870694 + -0.475066 -0.127293 -0.870694 + -0.475066 -0.127293 -0.870694 + -0.475066 -0.127293 -0.870694 + -0.475066 -0.127293 -0.870694 + -0.475066 -0.127293 -0.870694 + -0.475066 -0.127293 -0.870694 + 0.0104155 0.00279081 -0.999942 + 0.0104155 0.00279081 -0.999942 + 0.0104155 0.00279081 -0.999942 + 0.0104155 0.00279081 -0.999942 + 0.0104155 0.00279081 -0.999942 + 0.0104155 0.00279081 -0.999942 + 0.490692 0.13148 -0.861356 + 0.490692 0.13148 -0.861356 + 0.490692 0.13148 -0.861356 + 0.490692 0.13148 -0.861356 + 0.490692 0.13148 -0.861356 + 0.490692 0.13148 -0.861356 + 0.839073 0.224829 -0.495387 + 0.839073 0.224829 -0.495387 + 0.839073 0.224829 -0.495387 + 0.839073 0.224829 -0.495387 + 0.839073 0.224829 -0.495387 + 0.839073 0.224829 -0.495387 + 0.92388 0.382683 1.85279e-07 + 0.92388 0.382683 1.85279e-07 + 0.92388 0.382683 1.85279e-07 + 0.92388 0.382683 1.85279e-07 + 0.92388 0.382683 1.85279e-07 + 0.92388 0.382683 1.85279e-07 + 0.802549 0.332426 0.495387 + 0.802549 0.332426 0.495387 + 0.802549 0.332426 0.495387 + 0.802549 0.332426 0.495387 + 0.802549 0.332426 0.495387 + 0.802549 0.332426 0.495387 + 0.469331 0.194403 0.861357 + 0.469331 0.194403 0.861357 + 0.469331 0.194403 0.861357 + 0.469331 0.194403 0.861357 + 0.469331 0.194403 0.861357 + 0.469331 0.194403 0.861357 + 0.00996315 0.00412679 0.999942 + 0.00996315 0.00412679 0.999942 + 0.00996315 0.00412679 0.999942 + 0.00996315 0.00412679 0.999942 + 0.00996315 0.00412679 0.999942 + 0.00996315 0.00412679 0.999942 + -0.45439 -0.188214 0.870692 + -0.45439 -0.188214 0.870692 + -0.45439 -0.188214 0.870692 + -0.45439 -0.188214 0.870692 + -0.45439 -0.188214 0.870692 + -0.45439 -0.188214 0.870692 + -0.45439 -0.188214 0.870692 + -0.797569 -0.330363 0.504722 + -0.797569 -0.330363 0.504722 + -0.797569 -0.330363 0.504722 + -0.797569 -0.330363 0.504722 + -0.797569 -0.330363 0.504722 + -0.92388 -0.382683 -2.23922e-07 + -0.92388 -0.382683 -2.23922e-07 + -0.92388 -0.382683 -2.23922e-07 + -0.92388 -0.382683 -2.23922e-07 + -0.92388 -0.382683 -2.23922e-07 + -0.92388 -0.382683 -2.23922e-07 + -0.797568 -0.330364 -0.504722 + -0.797568 -0.330364 -0.504722 + -0.797568 -0.330364 -0.504722 + -0.797568 -0.330364 -0.504722 + -0.797568 -0.330364 -0.504722 + -0.797568 -0.330364 -0.504722 + -0.45439 -0.188215 -0.870692 + -0.45439 -0.188215 -0.870692 + -0.45439 -0.188215 -0.870692 + -0.45439 -0.188215 -0.870692 + -0.45439 -0.188215 -0.870692 + -0.45439 -0.188215 -0.870692 + 0.00996327 0.00412685 -0.999942 + 0.00996327 0.00412685 -0.999942 + 0.00996327 0.00412685 -0.999942 + 0.00996327 0.00412685 -0.999942 + 0.00996327 0.00412685 -0.999942 + 0.00996327 0.00412685 -0.999942 + 0.469331 0.194403 -0.861357 + 0.469331 0.194403 -0.861357 + 0.469331 0.194403 -0.861357 + 0.469331 0.194403 -0.861357 + 0.469331 0.194403 -0.861357 + 0.469331 0.194403 -0.861357 + 0.802549 0.332426 -0.495387 + 0.802549 0.332426 -0.495387 + 0.802549 0.332426 -0.495387 + 0.802549 0.332426 -0.495387 + 0.802549 0.332426 -0.495387 + 0.802549 0.332426 -0.495387 + 0.866026 0.5 2.18232e-07 + 0.866026 0.5 2.18232e-07 + 0.866026 0.5 2.18232e-07 + 0.866026 0.5 2.18232e-07 + 0.866026 0.5 2.18232e-07 + 0.866026 0.5 2.18232e-07 + 0.752291 0.434335 0.495389 + 0.752291 0.434335 0.495389 + 0.752291 0.434335 0.495389 + 0.752291 0.434335 0.495389 + 0.752291 0.434335 0.495389 + 0.752291 0.434335 0.495389 + 0.439941 0.254 0.861357 + 0.439941 0.254 0.861357 + 0.439941 0.254 0.861357 + 0.439941 0.254 0.861357 + 0.439941 0.254 0.861357 + 0.439941 0.254 0.861357 + 0.00933778 0.0053913 0.999942 + 0.00933778 0.0053913 0.999942 + 0.00933778 0.0053913 0.999942 + 0.00933778 0.0053913 0.999942 + 0.00933778 0.0053913 0.999942 + 0.00933778 0.0053913 0.999942 + 0.00933778 0.0053913 0.999942 + -0.425935 -0.245913 0.870693 + -0.425935 -0.245913 0.870693 + -0.425935 -0.245913 0.870693 + -0.425935 -0.245913 0.870693 + -0.747623 -0.43164 0.504725 + -0.747623 -0.43164 0.504725 + -0.747623 -0.43164 0.504725 + -0.747623 -0.43164 0.504725 + -0.747623 -0.43164 0.504725 + -0.747623 -0.43164 0.504725 + -0.866025 -0.5 0 + -0.866025 -0.5 0 + -0.866025 -0.5 0 + -0.866025 -0.5 0 + -0.866025 -0.5 0 + -0.866025 -0.5 0 + -0.866025 -0.5 0 + -0.866025 -0.5 0 + -0.747623 -0.43164 -0.504725 + -0.747623 -0.43164 -0.504725 + -0.747623 -0.43164 -0.504725 + -0.747623 -0.43164 -0.504725 + -0.747623 -0.43164 -0.504725 + -0.747623 -0.43164 -0.504725 + -0.425935 -0.245913 -0.870693 + -0.425935 -0.245913 -0.870693 + -0.425935 -0.245913 -0.870693 + -0.425935 -0.245913 -0.870693 + 0.00933802 0.00539142 -0.999942 + 0.00933802 0.00539142 -0.999942 + 0.00933802 0.00539142 -0.999942 + 0.00933802 0.00539142 -0.999942 + 0.00933802 0.00539142 -0.999942 + 0.00933802 0.00539142 -0.999942 + 0.00933802 0.00539142 -0.999942 + 0.439941 0.254 -0.861357 + 0.439941 0.254 -0.861357 + 0.439941 0.254 -0.861357 + 0.439941 0.254 -0.861357 + 0.439941 0.254 -0.861357 + 0.439941 0.254 -0.861357 + 0.752292 0.434336 -0.495389 + 0.752292 0.434336 -0.495389 + 0.752292 0.434336 -0.495389 + 0.752292 0.434336 -0.495389 + 0.752292 0.434336 -0.495389 + 0.752292 0.434336 -0.495389 + 0.793353 0.608762 -4.83716e-07 + 0.793353 0.608762 -4.83716e-07 + 0.793353 0.608762 -4.83716e-07 + 0.793353 0.608762 -4.83716e-07 + 0.793353 0.608762 -4.83716e-07 + 0.793353 0.608762 -4.83716e-07 + 0.689164 0.528814 0.495388 + 0.689164 0.528814 0.495388 + 0.689164 0.528814 0.495388 + 0.689164 0.528814 0.495388 + 0.689164 0.528814 0.495388 + 0.689164 0.528814 0.495388 + 0.403025 0.309252 0.861356 + 0.403025 0.309252 0.861356 + 0.403025 0.309252 0.861356 + 0.403025 0.309252 0.861356 + 0.403025 0.309252 0.861356 + 0.403025 0.309252 0.861356 + 0.00855523 0.00656456 0.999942 + 0.00855523 0.00656456 0.999942 + 0.00855523 0.00656456 0.999942 + 0.00855523 0.00656456 0.999942 + 0.00855523 0.00656456 0.999942 + 0.00855523 0.00656456 0.999942 + -0.390191 -0.299405 0.870694 + -0.390191 -0.299405 0.870694 + -0.390191 -0.299405 0.870694 + -0.390191 -0.299405 0.870694 + -0.390191 -0.299405 0.870694 + -0.390191 -0.299405 0.870694 + -0.684887 -0.525532 0.504724 + -0.684887 -0.525532 0.504724 + -0.684887 -0.525532 0.504724 + -0.684887 -0.525532 0.504724 + -0.684887 -0.525532 0.504724 + -0.684887 -0.525532 0.504724 + -0.793354 -0.608761 -2.65299e-07 + -0.793354 -0.608761 -2.65299e-07 + -0.793354 -0.608761 -2.65299e-07 + -0.793354 -0.608761 -2.65299e-07 + -0.793354 -0.608761 -2.65299e-07 + -0.793354 -0.608761 -2.65299e-07 + -0.684887 -0.525532 -0.504724 + -0.684887 -0.525532 -0.504724 + -0.684887 -0.525532 -0.504724 + -0.684887 -0.525532 -0.504724 + -0.684887 -0.525532 -0.504724 + -0.684887 -0.525532 -0.504724 + -0.390191 -0.299405 -0.870694 + -0.390191 -0.299405 -0.870694 + -0.390191 -0.299405 -0.870694 + -0.390191 -0.299405 -0.870694 + -0.390191 -0.299405 -0.870694 + -0.390191 -0.299405 -0.870694 + 0.00855511 0.00656456 -0.999942 + 0.00855511 0.00656456 -0.999942 + 0.00855511 0.00656456 -0.999942 + 0.00855511 0.00656456 -0.999942 + 0.00855511 0.00656456 -0.999942 + 0.00855511 0.00656456 -0.999942 + 0.403025 0.309252 -0.861356 + 0.403025 0.309252 -0.861356 + 0.403025 0.309252 -0.861356 + 0.403025 0.309252 -0.861356 + 0.403025 0.309252 -0.861356 + 0.403025 0.309252 -0.861356 + 0.689164 0.528814 -0.495388 + 0.689164 0.528814 -0.495388 + 0.689164 0.528814 -0.495388 + 0.689164 0.528814 -0.495388 + 0.689164 0.528814 -0.495388 + 0.689164 0.528814 -0.495388 + 0.707107 0.707107 7.76246e-07 + 0.707107 0.707107 7.76246e-07 + 0.707107 0.707107 7.76246e-07 + 0.707107 0.707107 7.76246e-07 + 0.707107 0.707107 7.76246e-07 + 0.707107 0.707107 7.76246e-07 + 0.614244 0.614243 0.495389 + 0.614244 0.614243 0.495389 + 0.614244 0.614243 0.495389 + 0.614244 0.614243 0.495389 + 0.614244 0.614243 0.495389 + 0.614244 0.614243 0.495389 + 0.359211 0.359211 0.861356 + 0.359211 0.359211 0.861356 + 0.359211 0.359211 0.861356 + 0.359211 0.359211 0.861356 + 0.359211 0.359211 0.861356 + 0.00762588 0.00762594 0.999942 + 0.00762588 0.00762594 0.999942 + 0.00762588 0.00762594 0.999942 + 0.00762588 0.00762594 0.999942 + 0.00762588 0.00762594 0.999942 + 0.00762588 0.00762594 0.999942 + 0.00762588 0.00762594 0.999942 + -0.347774 -0.347774 0.870693 + -0.347774 -0.347774 0.870693 + -0.347774 -0.347774 0.870693 + -0.347774 -0.347774 0.870693 + -0.347774 -0.347774 0.870693 + -0.347774 -0.347774 0.870693 + -0.347774 -0.347774 0.870693 + -0.610431 -0.610431 0.504726 + -0.610431 -0.610431 0.504726 + -0.610431 -0.610431 0.504726 + -0.610431 -0.610431 0.504726 + -0.610431 -0.610431 0.504726 + -0.707106 -0.707107 1.04051e-06 + -0.707106 -0.707107 1.04051e-06 + -0.707106 -0.707107 1.04051e-06 + -0.707106 -0.707107 1.04051e-06 + -0.707106 -0.707107 1.04051e-06 + -0.707106 -0.707107 1.04051e-06 + -0.610431 -0.610432 -0.504725 + -0.610431 -0.610432 -0.504725 + -0.610431 -0.610432 -0.504725 + -0.610431 -0.610432 -0.504725 + -0.610431 -0.610432 -0.504725 + -0.347774 -0.347774 -0.870693 + -0.347774 -0.347774 -0.870693 + -0.347774 -0.347774 -0.870693 + -0.347774 -0.347774 -0.870693 + -0.347774 -0.347774 -0.870693 + -0.347774 -0.347774 -0.870693 + -0.347774 -0.347774 -0.870693 + 0.00762564 0.00762558 -0.999942 + 0.00762564 0.00762558 -0.999942 + 0.00762564 0.00762558 -0.999942 + 0.00762564 0.00762558 -0.999942 + 0.00762564 0.00762558 -0.999942 + 0.00762564 0.00762558 -0.999942 + 0.00762564 0.00762558 -0.999942 + 0.35921 0.35921 -0.861357 + 0.35921 0.35921 -0.861357 + 0.35921 0.35921 -0.861357 + 0.35921 0.35921 -0.861357 + 0.614243 0.614243 -0.495389 + 0.614243 0.614243 -0.495389 + 0.614243 0.614243 -0.495389 + 0.614243 0.614243 -0.495389 + 0.614243 0.614243 -0.495389 + 0.614243 0.614243 -0.495389 + 0.614243 0.614243 -0.495389 + 0.608761 0.793354 -1.35042e-06 + 0.608761 0.793354 -1.35042e-06 + 0.608761 0.793354 -1.35042e-06 + 0.608761 0.793354 -1.35042e-06 + 0.608761 0.793354 -1.35042e-06 + 0.608761 0.793354 -1.35042e-06 + 0.528815 0.689165 0.495385 + 0.528815 0.689165 0.495385 + 0.528815 0.689165 0.495385 + 0.528815 0.689165 0.495385 + 0.528815 0.689165 0.495385 + 0.528815 0.689165 0.495385 + 0.528815 0.689165 0.495385 + 0.309251 0.403023 0.861358 + 0.309251 0.403023 0.861358 + 0.309251 0.403023 0.861358 + 0.309251 0.403023 0.861358 + 0.309251 0.403023 0.861358 + 0.00656509 0.00855577 0.999942 + 0.00656509 0.00855577 0.999942 + 0.00656509 0.00855577 0.999942 + 0.00656509 0.00855577 0.999942 + 0.00656509 0.00855577 0.999942 + 0.00656509 0.00855577 0.999942 + -0.299405 -0.390193 0.870693 + -0.299405 -0.390193 0.870693 + -0.299405 -0.390193 0.870693 + -0.299405 -0.390193 0.870693 + -0.299405 -0.390193 0.870693 + -0.299405 -0.390193 0.870693 + -0.525531 -0.684885 0.504727 + -0.525531 -0.684885 0.504727 + -0.525531 -0.684885 0.504727 + -0.525531 -0.684885 0.504727 + -0.525531 -0.684885 0.504727 + -0.525531 -0.684885 0.504727 + -0.608762 -0.793353 1.52274e-06 + -0.608762 -0.793353 1.52274e-06 + -0.608762 -0.793353 1.52274e-06 + -0.608762 -0.793353 1.52274e-06 + -0.608762 -0.793353 1.52274e-06 + -0.608762 -0.793353 1.52274e-06 + -0.525532 -0.684886 -0.504726 + -0.525532 -0.684886 -0.504726 + -0.525532 -0.684886 -0.504726 + -0.525532 -0.684886 -0.504726 + -0.525532 -0.684886 -0.504726 + -0.525532 -0.684886 -0.504726 + -0.299405 -0.390192 -0.870693 + -0.299405 -0.390192 -0.870693 + -0.299405 -0.390192 -0.870693 + -0.299405 -0.390192 -0.870693 + -0.299405 -0.390192 -0.870693 + -0.299405 -0.390192 -0.870693 + 0.00656486 0.00855553 -0.999942 + 0.00656486 0.00855553 -0.999942 + 0.00656486 0.00855553 -0.999942 + 0.00656486 0.00855553 -0.999942 + 0.00656486 0.00855553 -0.999942 + 0.00656486 0.00855553 -0.999942 + 0.309251 0.403023 -0.861358 + 0.309251 0.403023 -0.861358 + 0.309251 0.403023 -0.861358 + 0.309251 0.403023 -0.861358 + 0.309251 0.403023 -0.861358 + 0.309251 0.403023 -0.861358 + 0.528814 0.689165 -0.495386 + 0.528814 0.689165 -0.495386 + 0.528814 0.689165 -0.495386 + 0.528814 0.689165 -0.495386 + 0.528814 0.689165 -0.495386 + 0.528814 0.689165 -0.495386 + 0.5 0.866025 1.35385e-06 + 0.5 0.866025 1.35385e-06 + 0.5 0.866025 1.35385e-06 + 0.5 0.866025 1.35385e-06 + 0.5 0.866025 1.35385e-06 + 0.5 0.866025 1.35385e-06 + 0.434335 0.75229 0.495391 + 0.434335 0.75229 0.495391 + 0.434335 0.75229 0.495391 + 0.434335 0.75229 0.495391 + 0.434335 0.75229 0.495391 + 0.434335 0.75229 0.495391 + 0.254 0.439941 0.861357 + 0.254 0.439941 0.861357 + 0.254 0.439941 0.861357 + 0.254 0.439941 0.861357 + 0.254 0.439941 0.861357 + 0.254 0.439941 0.861357 + 0.00539184 0.00933885 0.999942 + 0.00539184 0.00933885 0.999942 + 0.00539184 0.00933885 0.999942 + 0.00539184 0.00933885 0.999942 + 0.00539184 0.00933885 0.999942 + -0.245913 -0.425933 0.870694 + -0.245913 -0.425933 0.870694 + -0.245913 -0.425933 0.870694 + -0.245913 -0.425933 0.870694 + -0.245913 -0.425933 0.870694 + -0.245913 -0.425933 0.870694 + -0.431641 -0.747623 0.504724 + -0.431641 -0.747623 0.504724 + -0.431641 -0.747623 0.504724 + -0.431641 -0.747623 0.504724 + -0.431641 -0.747623 0.504724 + -0.431641 -0.747623 0.504724 + -0.431641 -0.747623 0.504724 + -0.5 -0.866025 -1.99005e-06 + -0.5 -0.866025 -1.99005e-06 + -0.5 -0.866025 -1.99005e-06 + -0.5 -0.866025 -1.99005e-06 + -0.5 -0.866025 -1.99005e-06 + -0.5 -0.866025 -1.99005e-06 + -0.43164 -0.747622 -0.504726 + -0.43164 -0.747622 -0.504726 + -0.43164 -0.747622 -0.504726 + -0.43164 -0.747622 -0.504726 + -0.43164 -0.747622 -0.504726 + -0.43164 -0.747622 -0.504726 + -0.245913 -0.425933 -0.870694 + -0.245913 -0.425933 -0.870694 + -0.245913 -0.425933 -0.870694 + -0.245913 -0.425933 -0.870694 + -0.245913 -0.425933 -0.870694 + -0.245913 -0.425933 -0.870694 + -0.245913 -0.425933 -0.870694 + 0.00539201 0.00933927 -0.999942 + 0.00539201 0.00933927 -0.999942 + 0.00539201 0.00933927 -0.999942 + 0.00539201 0.00933927 -0.999942 + 0.00539201 0.00933927 -0.999942 + 0.254001 0.439942 -0.861357 + 0.254001 0.439942 -0.861357 + 0.254001 0.439942 -0.861357 + 0.254001 0.439942 -0.861357 + 0.254001 0.439942 -0.861357 + 0.254001 0.439942 -0.861357 + 0.434336 0.752291 -0.49539 + 0.434336 0.752291 -0.49539 + 0.434336 0.752291 -0.49539 + 0.434336 0.752291 -0.49539 + 0.434336 0.752291 -0.49539 + 0.434336 0.752291 -0.49539 + 0.382683 0.92388 0 + 0.382683 0.92388 0 + 0.382683 0.92388 0 + 0.382683 0.92388 0 + 0.332426 0.802548 0.495389 + 0.332426 0.802548 0.495389 + 0.332426 0.802548 0.495389 + 0.332426 0.802548 0.495389 + 0.332426 0.802548 0.495389 + 0.332426 0.802548 0.495389 + 0.332426 0.802548 0.495389 + 0.194403 0.469329 0.861358 + 0.194403 0.469329 0.861358 + 0.194403 0.469329 0.861358 + 0.194403 0.469329 0.861358 + 0.194403 0.469329 0.861358 + 0.194403 0.469329 0.861358 + 0.00412601 0.00996148 0.999942 + 0.00412601 0.00996148 0.999942 + 0.00412601 0.00996148 0.999942 + 0.00412601 0.00996148 0.999942 + 0.00412601 0.00996148 0.999942 + 0.00412601 0.00996148 0.999942 + -0.188214 -0.454389 0.870693 + -0.188214 -0.454389 0.870693 + -0.188214 -0.454389 0.870693 + -0.188214 -0.454389 0.870693 + -0.188214 -0.454389 0.870693 + -0.188214 -0.454389 0.870693 + -0.188214 -0.454389 0.870693 + -0.330363 -0.797568 0.504723 + -0.330363 -0.797568 0.504723 + -0.330363 -0.797568 0.504723 + -0.330363 -0.797568 0.504723 + -0.330363 -0.797568 0.504723 + -0.382683 -0.92388 -1.52152e-06 + -0.382683 -0.92388 -1.52152e-06 + -0.382683 -0.92388 -1.52152e-06 + -0.382683 -0.92388 -1.52152e-06 + -0.382683 -0.92388 -1.52152e-06 + -0.382683 -0.92388 -1.52152e-06 + -0.330363 -0.797568 -0.504723 + -0.330363 -0.797568 -0.504723 + -0.330363 -0.797568 -0.504723 + -0.330363 -0.797568 -0.504723 + -0.330363 -0.797568 -0.504723 + -0.330363 -0.797568 -0.504723 + -0.188214 -0.454389 -0.870693 + -0.188214 -0.454389 -0.870693 + -0.188214 -0.454389 -0.870693 + -0.188214 -0.454389 -0.870693 + -0.188214 -0.454389 -0.870693 + 0.00412613 0.00996178 -0.999942 + 0.00412613 0.00996178 -0.999942 + 0.00412613 0.00996178 -0.999942 + 0.00412613 0.00996178 -0.999942 + 0.00412613 0.00996178 -0.999942 + 0.00412613 0.00996178 -0.999942 + 0.00412613 0.00996178 -0.999942 + 0.194403 0.46933 -0.861358 + 0.194403 0.46933 -0.861358 + 0.194403 0.46933 -0.861358 + 0.194403 0.46933 -0.861358 + 0.194403 0.46933 -0.861358 + 0.194403 0.46933 -0.861358 + 0.332426 0.802548 -0.495387 + 0.332426 0.802548 -0.495387 + 0.332426 0.802548 -0.495387 + 0.332426 0.802548 -0.495387 + 0.332426 0.802548 -0.495387 + 0.332426 0.802548 -0.495387 + 0.332426 0.802548 -0.495387 + 0.258819 0.965926 7.61012e-07 + 0.258819 0.965926 7.61012e-07 + 0.258819 0.965926 7.61012e-07 + 0.258819 0.965926 7.61012e-07 + 0.258819 0.965926 7.61012e-07 + 0.258819 0.965926 7.61012e-07 + 0.224829 0.839074 0.495385 + 0.224829 0.839074 0.495385 + 0.224829 0.839074 0.495385 + 0.224829 0.839074 0.495385 + 0.224829 0.839074 0.495385 + 0.224829 0.839074 0.495385 + 0.131481 0.490692 0.861356 + 0.131481 0.490692 0.861356 + 0.131481 0.490692 0.861356 + 0.131481 0.490692 0.861356 + 0.131481 0.490692 0.861356 + 0.131481 0.490692 0.861356 + 0.00279093 0.0104163 0.999942 + 0.00279093 0.0104163 0.999942 + 0.00279093 0.0104163 0.999942 + 0.00279093 0.0104163 0.999942 + 0.00279093 0.0104163 0.999942 + 0.00279093 0.0104163 0.999942 + 0.00279093 0.0104163 0.999942 + -0.127294 -0.475067 0.870694 + -0.127294 -0.475067 0.870694 + -0.127294 -0.475067 0.870694 + -0.127294 -0.475067 0.870694 + -0.127294 -0.475067 0.870694 + -0.223434 -0.833865 0.504724 + -0.223434 -0.833865 0.504724 + -0.223434 -0.833865 0.504724 + -0.223434 -0.833865 0.504724 + -0.223434 -0.833865 0.504724 + -0.223434 -0.833865 0.504724 + -0.258819 -0.965926 2.09532e-06 + -0.258819 -0.965926 2.09532e-06 + -0.258819 -0.965926 2.09532e-06 + -0.258819 -0.965926 2.09532e-06 + -0.258819 -0.965926 2.09532e-06 + -0.258819 -0.965926 2.09532e-06 + -0.223434 -0.833866 -0.504722 + -0.223434 -0.833866 -0.504722 + -0.223434 -0.833866 -0.504722 + -0.223434 -0.833866 -0.504722 + -0.223434 -0.833866 -0.504722 + -0.223434 -0.833866 -0.504722 + -0.127294 -0.475067 -0.870694 + -0.127294 -0.475067 -0.870694 + -0.127294 -0.475067 -0.870694 + -0.127294 -0.475067 -0.870694 + -0.127294 -0.475067 -0.870694 + -0.127294 -0.475067 -0.870694 + 0.00279099 0.0104164 -0.999942 + 0.00279099 0.0104164 -0.999942 + 0.00279099 0.0104164 -0.999942 + 0.00279099 0.0104164 -0.999942 + 0.00279099 0.0104164 -0.999942 + 0.00279099 0.0104164 -0.999942 + 0.13148 0.490691 -0.861356 + 0.13148 0.490691 -0.861356 + 0.13148 0.490691 -0.861356 + 0.13148 0.490691 -0.861356 + 0.13148 0.490691 -0.861356 + 0.13148 0.490691 -0.861356 + 0.224829 0.839074 -0.495385 + 0.224829 0.839074 -0.495385 + 0.224829 0.839074 -0.495385 + 0.224829 0.839074 -0.495385 + 0.224829 0.839074 -0.495385 + 0.224829 0.839074 -0.495385 + 0.130526 0.991445 3.2828e-07 + 0.130526 0.991445 3.2828e-07 + 0.130526 0.991445 3.2828e-07 + 0.130526 0.991445 3.2828e-07 + 0.130526 0.991445 3.2828e-07 + 0.130526 0.991445 3.2828e-07 + 0.113384 0.861241 0.495386 + 0.113384 0.861241 0.495386 + 0.113384 0.861241 0.495386 + 0.113384 0.861241 0.495386 + 0.113384 0.861241 0.495386 + 0.113384 0.861241 0.495386 + 0.0663073 0.503655 0.861357 + 0.0663073 0.503655 0.861357 + 0.0663073 0.503655 0.861357 + 0.0663073 0.503655 0.861357 + 0.0663073 0.503655 0.861357 + 0.0663073 0.503655 0.861357 + 0.00140738 0.0106904 0.999942 + 0.00140738 0.0106904 0.999942 + 0.00140738 0.0106904 0.999942 + 0.00140738 0.0106904 0.999942 + 0.00140738 0.0106904 0.999942 + 0.00140738 0.0106904 0.999942 + -0.0641963 -0.487621 0.870692 + -0.0641963 -0.487621 0.870692 + -0.0641963 -0.487621 0.870692 + -0.0641963 -0.487621 0.870692 + -0.0641963 -0.487621 0.870692 + -0.0641963 -0.487621 0.870692 + -0.112681 -0.855898 0.50472 + -0.112681 -0.855898 0.50472 + -0.112681 -0.855898 0.50472 + -0.112681 -0.855898 0.50472 + -0.112681 -0.855898 0.50472 + -0.112681 -0.855898 0.50472 + -0.112681 -0.855898 0.50472 + -0.130526 -0.991445 0 + -0.130526 -0.991445 0 + -0.130526 -0.991445 0 + -0.130526 -0.991445 0 + -0.112681 -0.855897 -0.504721 + -0.112681 -0.855897 -0.504721 + -0.112681 -0.855897 -0.504721 + -0.112681 -0.855897 -0.504721 + -0.112681 -0.855897 -0.504721 + -0.112681 -0.855897 -0.504721 + -0.112681 -0.855897 -0.504721 + -0.0641963 -0.48762 -0.870693 + -0.0641963 -0.48762 -0.870693 + -0.0641963 -0.48762 -0.870693 + -0.0641963 -0.48762 -0.870693 + -0.0641963 -0.48762 -0.870693 + -0.0641963 -0.48762 -0.870693 + 0.00140744 0.0106908 -0.999942 + 0.00140744 0.0106908 -0.999942 + 0.00140744 0.0106908 -0.999942 + 0.00140744 0.0106908 -0.999942 + 0.00140744 0.0106908 -0.999942 + 0.00140744 0.0106908 -0.999942 + 0.0663073 0.503655 -0.861356 + 0.0663073 0.503655 -0.861356 + 0.0663073 0.503655 -0.861356 + 0.0663073 0.503655 -0.861356 + 0.0663073 0.503655 -0.861356 + 0.0663073 0.503655 -0.861356 + 0.113384 0.861242 -0.495386 + 0.113384 0.861242 -0.495386 + 0.113384 0.861242 -0.495386 + 0.113384 0.861242 -0.495386 + 0.113384 0.861242 -0.495386 + 0.113384 0.861242 -0.495386 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 1 0 + 0 0.868672 0.495387 + 0 0.868672 0.495387 + 0 0.868672 0.495387 + 0 0.868672 0.495387 + 0 0.868672 0.495387 + 0 0.507999 0.861358 + 0 0.507999 0.861358 + 0 0.507999 0.861358 + 0 0.507999 0.861358 + 0 0.507999 0.861358 + 0 0.507999 0.861358 + 0 0.507999 0.861358 + 0 0.0107834 0.999942 + 0 0.0107834 0.999942 + 0 0.0107834 0.999942 + 0 0.0107834 0.999942 + 0 0.0107834 0.999942 + 1.50327e-07 -0.491826 0.870694 + 1.50327e-07 -0.491826 0.870694 + 1.50327e-07 -0.491826 0.870694 + 1.50327e-07 -0.491826 0.870694 + 1.50327e-07 -0.491826 0.870694 + 1.50327e-07 -0.491826 0.870694 + 2.62427e-07 -0.86328 0.504725 + 2.62427e-07 -0.86328 0.504725 + 2.62427e-07 -0.86328 0.504725 + 2.62427e-07 -0.86328 0.504725 + 2.62427e-07 -0.86328 0.504725 + 2.62427e-07 -0.86328 0.504725 + 1.96313e-07 -1 -2.99709e-06 + 1.96313e-07 -1 -2.99709e-06 + 1.96313e-07 -1 -2.99709e-06 + 1.96313e-07 -1 -2.99709e-06 + 1.96313e-07 -1 -2.99709e-06 + 1.96313e-07 -1 -2.99709e-06 + 1.96313e-07 -1 -2.99709e-06 + 2.01521e-07 -0.863279 -0.504727 + 2.01521e-07 -0.863279 -0.504727 + 2.01521e-07 -0.863279 -0.504727 + 2.01521e-07 -0.863279 -0.504727 + 2.01521e-07 -0.863279 -0.504727 + 2.01521e-07 -0.863279 -0.504727 + 2.01521e-07 -0.863279 -0.504727 + 1.3183e-07 -0.491826 -0.870694 + 1.3183e-07 -0.491826 -0.870694 + 1.3183e-07 -0.491826 -0.870694 + 1.3183e-07 -0.491826 -0.870694 + 1.3183e-07 -0.491826 -0.870694 + 1.3183e-07 -0.491826 -0.870694 + 0 0.0107836 -0.999942 + 0 0.0107836 -0.999942 + 0 0.0107836 -0.999942 + 0 0.0107836 -0.999942 + -2.38105e-07 0.508001 -0.861356 + -2.38105e-07 0.508001 -0.861356 + -2.38105e-07 0.508001 -0.861356 + -2.38105e-07 0.508001 -0.861356 + -2.38105e-07 0.508001 -0.861356 + -2.38105e-07 0.508001 -0.861356 + -2.38105e-07 0.508001 -0.861356 + -1.25273e-07 0.868673 -0.495386 + -1.25273e-07 0.868673 -0.495386 + -1.25273e-07 0.868673 -0.495386 + -1.25273e-07 0.868673 -0.495386 + -1.25273e-07 0.868673 -0.495386 + -1.25273e-07 0.868673 -0.495386 + -0.130526 0.991445 1.50461e-07 + -0.130526 0.991445 1.50461e-07 + -0.130526 0.991445 1.50461e-07 + -0.130526 0.991445 1.50461e-07 + -0.130526 0.991445 1.50461e-07 + -0.130526 0.991445 1.50461e-07 + -0.130526 0.991445 1.50461e-07 + -0.113385 0.861242 0.495385 + -0.113385 0.861242 0.495385 + -0.113385 0.861242 0.495385 + -0.113385 0.861242 0.495385 + -0.113385 0.861242 0.495385 + -0.113385 0.861242 0.495385 + -0.0663073 0.503654 0.861357 + -0.0663073 0.503654 0.861357 + -0.0663073 0.503654 0.861357 + -0.0663073 0.503654 0.861357 + -0.0663073 0.503654 0.861357 + -0.0663073 0.503654 0.861357 + -0.00140744 0.0106912 0.999942 + -0.00140744 0.0106912 0.999942 + -0.00140744 0.0106912 0.999942 + -0.00140744 0.0106912 0.999942 + -0.00140744 0.0106912 0.999942 + -0.00140744 0.0106912 0.999942 + -0.00140744 0.0106912 0.999942 + 0.0641962 -0.487619 0.870693 + 0.0641962 -0.487619 0.870693 + 0.0641962 -0.487619 0.870693 + 0.0641962 -0.487619 0.870693 + 0.0641962 -0.487619 0.870693 + 0.0641962 -0.487619 0.870693 + 0.11268 -0.855893 0.504727 + 0.11268 -0.855893 0.504727 + 0.11268 -0.855893 0.504727 + 0.11268 -0.855893 0.504727 + 0.11268 -0.855893 0.504727 + 0.130526 -0.991445 2.74062e-06 + 0.130526 -0.991445 2.74062e-06 + 0.130526 -0.991445 2.74062e-06 + 0.130526 -0.991445 2.74062e-06 + 0.130526 -0.991445 2.74062e-06 + 0.130526 -0.991445 2.74062e-06 + 0.130526 -0.991445 2.74062e-06 + 0.112681 -0.855895 -0.504725 + 0.112681 -0.855895 -0.504725 + 0.112681 -0.855895 -0.504725 + 0.112681 -0.855895 -0.504725 + 0.0641962 -0.487619 -0.870694 + 0.0641962 -0.487619 -0.870694 + 0.0641962 -0.487619 -0.870694 + 0.0641962 -0.487619 -0.870694 + 0.0641962 -0.487619 -0.870694 + 0.0641962 -0.487619 -0.870694 + -0.00140756 0.0106919 -0.999942 + -0.00140756 0.0106919 -0.999942 + -0.00140756 0.0106919 -0.999942 + -0.00140756 0.0106919 -0.999942 + -0.00140756 0.0106919 -0.999942 + -0.00140756 0.0106919 -0.999942 + -0.00140756 0.0106919 -0.999942 + -0.0663072 0.503652 -0.861359 + -0.0663072 0.503652 -0.861359 + -0.0663072 0.503652 -0.861359 + -0.0663072 0.503652 -0.861359 + -0.0663072 0.503652 -0.861359 + -0.0663072 0.503652 -0.861359 + -0.0663072 0.503652 -0.861359 + -0.113385 0.86124 -0.495388 + -0.113385 0.86124 -0.495388 + -0.113385 0.86124 -0.495388 + -0.113385 0.86124 -0.495388 + -0.258819 0.965926 -3.07203e-06 + -0.258819 0.965926 -3.07203e-06 + -0.258819 0.965926 -3.07203e-06 + -0.258819 0.965926 -3.07203e-06 + -0.258819 0.965926 -3.07203e-06 + -0.258819 0.965926 -3.07203e-06 + -0.258819 0.965926 -3.07203e-06 + -0.224829 0.839074 0.495386 + -0.224829 0.839074 0.495386 + -0.224829 0.839074 0.495386 + -0.224829 0.839074 0.495386 + -0.224829 0.839074 0.495386 + -0.13148 0.490692 0.861356 + -0.13148 0.490692 0.861356 + -0.13148 0.490692 0.861356 + -0.13148 0.490692 0.861356 + -0.13148 0.490692 0.861356 + -0.13148 0.490692 0.861356 + -0.00279129 0.0104175 0.999942 + -0.00279129 0.0104175 0.999942 + -0.00279129 0.0104175 0.999942 + -0.00279129 0.0104175 0.999942 + -0.00279129 0.0104175 0.999942 + 0.127294 -0.475068 0.870693 + 0.127294 -0.475068 0.870693 + 0.127294 -0.475068 0.870693 + 0.127294 -0.475068 0.870693 + 0.127294 -0.475068 0.870693 + 0.127294 -0.475068 0.870693 + 0.127294 -0.475068 0.870693 + 0.223433 -0.833867 0.504722 + 0.223433 -0.833867 0.504722 + 0.223433 -0.833867 0.504722 + 0.223433 -0.833867 0.504722 + 0.223433 -0.833867 0.504722 + 0.223433 -0.833867 0.504722 + 0.258819 -0.965926 -1.27082e-06 + 0.258819 -0.965926 -1.27082e-06 + 0.258819 -0.965926 -1.27082e-06 + 0.258819 -0.965926 -1.27082e-06 + 0.258819 -0.965926 -1.27082e-06 + 0.258819 -0.965926 -1.27082e-06 + 0.223433 -0.833866 -0.504722 + 0.223433 -0.833866 -0.504722 + 0.223433 -0.833866 -0.504722 + 0.223433 -0.833866 -0.504722 + 0.223433 -0.833866 -0.504722 + 0.223433 -0.833866 -0.504722 + 0.127294 -0.47507 -0.870692 + 0.127294 -0.47507 -0.870692 + 0.127294 -0.47507 -0.870692 + 0.127294 -0.47507 -0.870692 + 0.127294 -0.47507 -0.870692 + 0.127294 -0.47507 -0.870692 + -0.00279081 0.0104157 -0.999942 + -0.00279081 0.0104157 -0.999942 + -0.00279081 0.0104157 -0.999942 + -0.00279081 0.0104157 -0.999942 + -0.00279081 0.0104157 -0.999942 + -0.00279081 0.0104157 -0.999942 + -0.00279081 0.0104157 -0.999942 + -0.13148 0.49069 -0.861357 + -0.13148 0.49069 -0.861357 + -0.13148 0.49069 -0.861357 + -0.13148 0.49069 -0.861357 + -0.13148 0.49069 -0.861357 + -0.224829 0.839072 -0.495389 + -0.224829 0.839072 -0.495389 + -0.224829 0.839072 -0.495389 + -0.224829 0.839072 -0.495389 + -0.224829 0.839072 -0.495389 + -0.224829 0.839072 -0.495389 + -0.382683 0.92388 -1.16732e-06 + -0.382683 0.92388 -1.16732e-06 + -0.382683 0.92388 -1.16732e-06 + -0.382683 0.92388 -1.16732e-06 + -0.382683 0.92388 -1.16732e-06 + -0.382683 0.92388 -1.16732e-06 + -0.332427 0.802549 0.495386 + -0.332427 0.802549 0.495386 + -0.332427 0.802549 0.495386 + -0.332427 0.802549 0.495386 + -0.332427 0.802549 0.495386 + -0.332427 0.802549 0.495386 + -0.332427 0.802549 0.495386 + -0.194404 0.469333 0.861356 + -0.194404 0.469333 0.861356 + -0.194404 0.469333 0.861356 + -0.194404 0.469333 0.861356 + -0.194404 0.469333 0.861356 + -0.00412667 0.00996274 0.999942 + -0.00412667 0.00996274 0.999942 + -0.00412667 0.00996274 0.999942 + -0.00412667 0.00996274 0.999942 + -0.00412667 0.00996274 0.999942 + -0.00412667 0.00996274 0.999942 + -0.00412667 0.00996274 0.999942 + 0.188215 -0.45439 0.870693 + 0.188215 -0.45439 0.870693 + 0.188215 -0.45439 0.870693 + 0.188215 -0.45439 0.870693 + 0.188215 -0.45439 0.870693 + 0.330363 -0.797567 0.504725 + 0.330363 -0.797567 0.504725 + 0.330363 -0.797567 0.504725 + 0.330363 -0.797567 0.504725 + 0.330363 -0.797567 0.504725 + 0.330363 -0.797567 0.504725 + 0.382683 -0.92388 1.61979e-06 + 0.382683 -0.92388 1.61979e-06 + 0.382683 -0.92388 1.61979e-06 + 0.382683 -0.92388 1.61979e-06 + 0.382683 -0.92388 1.61979e-06 + 0.382683 -0.92388 1.61979e-06 + 0.330363 -0.797567 -0.504724 + 0.330363 -0.797567 -0.504724 + 0.330363 -0.797567 -0.504724 + 0.330363 -0.797567 -0.504724 + 0.330363 -0.797567 -0.504724 + 0.330363 -0.797567 -0.504724 + 0.188214 -0.454388 -0.870693 + 0.188214 -0.454388 -0.870693 + 0.188214 -0.454388 -0.870693 + 0.188214 -0.454388 -0.870693 + 0.188214 -0.454388 -0.870693 + 0.188214 -0.454388 -0.870693 + -0.00412667 0.00996286 -0.999942 + -0.00412667 0.00996286 -0.999942 + -0.00412667 0.00996286 -0.999942 + -0.00412667 0.00996286 -0.999942 + -0.00412667 0.00996286 -0.999942 + -0.00412667 0.00996286 -0.999942 + -0.194404 0.469332 -0.861356 + -0.194404 0.469332 -0.861356 + -0.194404 0.469332 -0.861356 + -0.194404 0.469332 -0.861356 + -0.194404 0.469332 -0.861356 + -0.332426 0.802549 -0.495387 + -0.332426 0.802549 -0.495387 + -0.332426 0.802549 -0.495387 + -0.332426 0.802549 -0.495387 + -0.332426 0.802549 -0.495387 + -0.332426 0.802549 -0.495387 + -0.332426 0.802549 -0.495387 + -0.5 0.866026 9.76136e-07 + -0.5 0.866026 9.76136e-07 + -0.5 0.866026 9.76136e-07 + -0.5 0.866026 9.76136e-07 + -0.5 0.866026 9.76136e-07 + -0.5 0.866026 9.76136e-07 + -0.434336 0.752292 0.495389 + -0.434336 0.752292 0.495389 + -0.434336 0.752292 0.495389 + -0.434336 0.752292 0.495389 + -0.434336 0.752292 0.495389 + -0.254 0.439941 0.861357 + -0.254 0.439941 0.861357 + -0.254 0.439941 0.861357 + -0.254 0.439941 0.861357 + -0.254 0.439941 0.861357 + -0.254 0.439941 0.861357 + -0.254 0.439941 0.861357 + -0.254 0.439941 0.861357 + -0.00539148 0.00933856 0.999942 + -0.00539148 0.00933856 0.999942 + -0.00539148 0.00933856 0.999942 + -0.00539148 0.00933856 0.999942 + -0.00539148 0.00933856 0.999942 + 0.245913 -0.425934 0.870694 + 0.245913 -0.425934 0.870694 + 0.245913 -0.425934 0.870694 + 0.245913 -0.425934 0.870694 + 0.245913 -0.425934 0.870694 + 0.43164 -0.747622 0.504726 + 0.43164 -0.747622 0.504726 + 0.43164 -0.747622 0.504726 + 0.43164 -0.747622 0.504726 + 0.43164 -0.747622 0.504726 + 0.43164 -0.747622 0.504726 + 0.43164 -0.747622 0.504726 + 0.43164 -0.747622 0.504726 + 0.5 -0.866025 0 + 0.5 -0.866025 0 + 0.5 -0.866025 0 + 0.5 -0.866025 0 + 0.43164 -0.747622 -0.504726 + 0.43164 -0.747622 -0.504726 + 0.43164 -0.747622 -0.504726 + 0.43164 -0.747622 -0.504726 + 0.43164 -0.747622 -0.504726 + 0.43164 -0.747622 -0.504726 + 0.43164 -0.747622 -0.504726 + 0.43164 -0.747622 -0.504726 + 0.245913 -0.425933 -0.870694 + 0.245913 -0.425933 -0.870694 + 0.245913 -0.425933 -0.870694 + 0.245913 -0.425933 -0.870694 + 0.245913 -0.425933 -0.870694 + -0.00539166 0.00933892 -0.999942 + -0.00539166 0.00933892 -0.999942 + -0.00539166 0.00933892 -0.999942 + -0.00539166 0.00933892 -0.999942 + -0.00539166 0.00933892 -0.999942 + -0.254 0.439941 -0.861357 + -0.254 0.439941 -0.861357 + -0.254 0.439941 -0.861357 + -0.254 0.439941 -0.861357 + -0.254 0.439941 -0.861357 + -0.254 0.439941 -0.861357 + -0.254 0.439941 -0.861357 + -0.254 0.439941 -0.861357 + -0.434336 0.752292 -0.495388 + -0.434336 0.752292 -0.495388 + -0.434336 0.752292 -0.495388 + -0.434336 0.752292 -0.495388 + -0.434336 0.752292 -0.495388 + -0.608762 0.793353 -1.23727e-07 + -0.608762 0.793353 -1.23727e-07 + -0.608762 0.793353 -1.23727e-07 + -0.608762 0.793353 -1.23727e-07 + -0.608762 0.793353 -1.23727e-07 + -0.608762 0.793353 -1.23727e-07 + -0.528814 0.689164 0.495389 + -0.528814 0.689164 0.495389 + -0.528814 0.689164 0.495389 + -0.528814 0.689164 0.495389 + -0.528814 0.689164 0.495389 + -0.528814 0.689164 0.495389 + -0.30925 0.403023 0.861358 + -0.30925 0.403023 0.861358 + -0.30925 0.403023 0.861358 + -0.30925 0.403023 0.861358 + -0.30925 0.403023 0.861358 + -0.30925 0.403023 0.861358 + -0.00656426 0.008555 0.999942 + -0.00656426 0.008555 0.999942 + -0.00656426 0.008555 0.999942 + -0.00656426 0.008555 0.999942 + -0.00656426 0.008555 0.999942 + -0.00656426 0.008555 0.999942 + 0.299404 -0.390191 0.870694 + 0.299404 -0.390191 0.870694 + 0.299404 -0.390191 0.870694 + 0.299404 -0.390191 0.870694 + 0.299404 -0.390191 0.870694 + 0.299404 -0.390191 0.870694 + 0.525531 -0.684885 0.504727 + 0.525531 -0.684885 0.504727 + 0.525531 -0.684885 0.504727 + 0.525531 -0.684885 0.504727 + 0.525531 -0.684885 0.504727 + 0.525531 -0.684885 0.504727 + 0.608761 -0.793354 1.42629e-06 + 0.608761 -0.793354 1.42629e-06 + 0.608761 -0.793354 1.42629e-06 + 0.608761 -0.793354 1.42629e-06 + 0.608761 -0.793354 1.42629e-06 + 0.608761 -0.793354 1.42629e-06 + 0.525531 -0.684886 -0.504726 + 0.525531 -0.684886 -0.504726 + 0.525531 -0.684886 -0.504726 + 0.525531 -0.684886 -0.504726 + 0.525531 -0.684886 -0.504726 + 0.525531 -0.684886 -0.504726 + 0.299404 -0.39019 -0.870695 + 0.299404 -0.39019 -0.870695 + 0.299404 -0.39019 -0.870695 + 0.299404 -0.39019 -0.870695 + 0.299404 -0.39019 -0.870695 + 0.299404 -0.39019 -0.870695 + -0.00656468 0.00855559 -0.999942 + -0.00656468 0.00855559 -0.999942 + -0.00656468 0.00855559 -0.999942 + -0.00656468 0.00855559 -0.999942 + -0.00656468 0.00855559 -0.999942 + -0.00656468 0.00855559 -0.999942 + -0.309251 0.403024 -0.861357 + -0.309251 0.403024 -0.861357 + -0.309251 0.403024 -0.861357 + -0.309251 0.403024 -0.861357 + -0.309251 0.403024 -0.861357 + -0.309251 0.403024 -0.861357 + -0.528814 0.689164 -0.495388 + -0.528814 0.689164 -0.495388 + -0.528814 0.689164 -0.495388 + -0.528814 0.689164 -0.495388 + -0.528814 0.689164 -0.495388 + -0.528814 0.689164 -0.495388 + -0.707107 0.707107 -1.23727e-07 + -0.707107 0.707107 -1.23727e-07 + -0.707107 0.707107 -1.23727e-07 + -0.707107 0.707107 -1.23727e-07 + -0.707107 0.707107 -1.23727e-07 + -0.707107 0.707107 -1.23727e-07 + -0.614244 0.614244 0.495387 + -0.614244 0.614244 0.495387 + -0.614244 0.614244 0.495387 + -0.614244 0.614244 0.495387 + -0.614244 0.614244 0.495387 + -0.614244 0.614244 0.495387 + -0.614244 0.614244 0.495387 + -0.359212 0.359212 0.861356 + -0.359212 0.359212 0.861356 + -0.359212 0.359212 0.861356 + -0.359212 0.359212 0.861356 + -0.00762552 0.00762522 0.999942 + -0.00762552 0.00762522 0.999942 + -0.00762552 0.00762522 0.999942 + -0.00762552 0.00762522 0.999942 + -0.00762552 0.00762522 0.999942 + -0.00762552 0.00762522 0.999942 + 0.347775 -0.347775 0.870692 + 0.347775 -0.347775 0.870692 + 0.347775 -0.347775 0.870692 + 0.347775 -0.347775 0.870692 + 0.347775 -0.347775 0.870692 + 0.347775 -0.347775 0.870692 + 0.347775 -0.347775 0.870692 + 0.347775 -0.347775 0.870692 + 0.610432 -0.610432 0.504724 + 0.610432 -0.610432 0.504724 + 0.610432 -0.610432 0.504724 + 0.610432 -0.610432 0.504724 + 0.707107 -0.707106 -9.96395e-07 + 0.707107 -0.707106 -9.96395e-07 + 0.707107 -0.707106 -9.96395e-07 + 0.707107 -0.707106 -9.96395e-07 + 0.707107 -0.707106 -9.96395e-07 + 0.707107 -0.707106 -9.96395e-07 + 0.707107 -0.707106 -9.96395e-07 + 0.707107 -0.707106 -9.96395e-07 + 0.610431 -0.610431 -0.504725 + 0.610431 -0.610431 -0.504725 + 0.610431 -0.610431 -0.504725 + 0.610431 -0.610431 -0.504725 + 0.347775 -0.347775 -0.870692 + 0.347775 -0.347775 -0.870692 + 0.347775 -0.347775 -0.870692 + 0.347775 -0.347775 -0.870692 + 0.347775 -0.347775 -0.870692 + 0.347775 -0.347775 -0.870692 + 0.347775 -0.347775 -0.870692 + 0.347775 -0.347775 -0.870692 + -0.00762552 0.00762522 -0.999942 + -0.00762552 0.00762522 -0.999942 + -0.00762552 0.00762522 -0.999942 + -0.00762552 0.00762522 -0.999942 + -0.00762552 0.00762522 -0.999942 + -0.00762552 0.00762522 -0.999942 + -0.359211 0.359211 -0.861356 + -0.359211 0.359211 -0.861356 + -0.359211 0.359211 -0.861356 + -0.359211 0.359211 -0.861356 + -0.614244 0.614244 -0.495387 + -0.614244 0.614244 -0.495387 + -0.614244 0.614244 -0.495387 + -0.614244 0.614244 -0.495387 + -0.614244 0.614244 -0.495387 + -0.614244 0.614244 -0.495387 + -0.614244 0.614244 -0.495387 + -0.793353 0.608761 0 + -0.793353 0.608761 0 + -0.793353 0.608761 0 + -0.793353 0.608761 0 + -0.689164 0.528814 0.495389 + -0.689164 0.528814 0.495389 + -0.689164 0.528814 0.495389 + -0.689164 0.528814 0.495389 + -0.689164 0.528814 0.495389 + -0.689164 0.528814 0.495389 + -0.689164 0.528814 0.495389 + -0.403025 0.309252 0.861356 + -0.403025 0.309252 0.861356 + -0.403025 0.309252 0.861356 + -0.403025 0.309252 0.861356 + -0.403025 0.309252 0.861356 + -0.403025 0.309252 0.861356 + -0.00855553 0.00656486 0.999942 + -0.00855553 0.00656486 0.999942 + -0.00855553 0.00656486 0.999942 + -0.00855553 0.00656486 0.999942 + -0.00855553 0.00656486 0.999942 + -0.00855553 0.00656486 0.999942 + 0.390193 -0.299405 0.870693 + 0.390193 -0.299405 0.870693 + 0.390193 -0.299405 0.870693 + 0.390193 -0.299405 0.870693 + 0.390193 -0.299405 0.870693 + 0.390193 -0.299405 0.870693 + 0.684886 -0.525532 0.504725 + 0.684886 -0.525532 0.504725 + 0.684886 -0.525532 0.504725 + 0.684886 -0.525532 0.504725 + 0.684886 -0.525532 0.504725 + 0.684886 -0.525532 0.504725 + 0.793353 -0.608761 4.84658e-07 + 0.793353 -0.608761 4.84658e-07 + 0.793353 -0.608761 4.84658e-07 + 0.793353 -0.608761 4.84658e-07 + 0.793353 -0.608761 4.84658e-07 + 0.793353 -0.608761 4.84658e-07 + 0.684886 -0.525532 -0.504725 + 0.684886 -0.525532 -0.504725 + 0.684886 -0.525532 -0.504725 + 0.684886 -0.525532 -0.504725 + 0.684886 -0.525532 -0.504725 + 0.684886 -0.525532 -0.504725 + 0.390193 -0.299405 -0.870693 + 0.390193 -0.299405 -0.870693 + 0.390193 -0.299405 -0.870693 + 0.390193 -0.299405 -0.870693 + 0.390193 -0.299405 -0.870693 + 0.390193 -0.299405 -0.870693 + -0.00855547 0.0065648 -0.999942 + -0.00855547 0.0065648 -0.999942 + -0.00855547 0.0065648 -0.999942 + -0.00855547 0.0065648 -0.999942 + -0.00855547 0.0065648 -0.999942 + -0.00855547 0.0065648 -0.999942 + -0.403025 0.309252 -0.861356 + -0.403025 0.309252 -0.861356 + -0.403025 0.309252 -0.861356 + -0.403025 0.309252 -0.861356 + -0.403025 0.309252 -0.861356 + -0.403025 0.309252 -0.861356 + -0.689164 0.528814 -0.495389 + -0.689164 0.528814 -0.495389 + -0.689164 0.528814 -0.495389 + -0.689164 0.528814 -0.495389 + -0.689164 0.528814 -0.495389 + -0.689164 0.528814 -0.495389 + -0.689164 0.528814 -0.495389 + -0.866025 0.5 3.68072e-07 + -0.866025 0.5 3.68072e-07 + -0.866025 0.5 3.68072e-07 + -0.866025 0.5 3.68072e-07 + -0.866025 0.5 3.68072e-07 + -0.866025 0.5 3.68072e-07 + -0.75229 0.434335 0.495391 + -0.75229 0.434335 0.495391 + -0.75229 0.434335 0.495391 + -0.75229 0.434335 0.495391 + -0.75229 0.434335 0.495391 + -0.75229 0.434335 0.495391 + -0.439941 0.254001 0.861357 + -0.439941 0.254001 0.861357 + -0.439941 0.254001 0.861357 + -0.439941 0.254001 0.861357 + -0.439941 0.254001 0.861357 + -0.439941 0.254001 0.861357 + -0.00933802 0.00539118 0.999942 + -0.00933802 0.00539118 0.999942 + -0.00933802 0.00539118 0.999942 + -0.00933802 0.00539118 0.999942 + -0.00933802 0.00539118 0.999942 + -0.00933802 0.00539118 0.999942 + 0.425934 -0.245913 0.870693 + 0.425934 -0.245913 0.870693 + 0.425934 -0.245913 0.870693 + 0.425934 -0.245913 0.870693 + 0.425934 -0.245913 0.870693 + 0.425934 -0.245913 0.870693 + 0.747622 -0.431641 0.504725 + 0.747622 -0.431641 0.504725 + 0.747622 -0.431641 0.504725 + 0.747622 -0.431641 0.504725 + 0.747622 -0.431641 0.504725 + 0.747622 -0.431641 0.504725 + 0.866025 -0.5 -3.78782e-07 + 0.866025 -0.5 -3.78782e-07 + 0.866025 -0.5 -3.78782e-07 + 0.866025 -0.5 -3.78782e-07 + 0.866025 -0.5 -3.78782e-07 + 0.747622 -0.43164 -0.504725 + 0.747622 -0.43164 -0.504725 + 0.747622 -0.43164 -0.504725 + 0.747622 -0.43164 -0.504725 + 0.747622 -0.43164 -0.504725 + 0.747622 -0.43164 -0.504725 + 0.747622 -0.43164 -0.504725 + 0.425934 -0.245913 -0.870694 + 0.425934 -0.245913 -0.870694 + 0.425934 -0.245913 -0.870694 + 0.425934 -0.245913 -0.870694 + 0.425934 -0.245913 -0.870694 + -0.00933808 0.00539124 -0.999942 + -0.00933808 0.00539124 -0.999942 + -0.00933808 0.00539124 -0.999942 + -0.00933808 0.00539124 -0.999942 + -0.00933808 0.00539124 -0.999942 + -0.00933808 0.00539124 -0.999942 + -0.00933808 0.00539124 -0.999942 + -0.439941 0.254001 -0.861357 + -0.439941 0.254001 -0.861357 + -0.439941 0.254001 -0.861357 + -0.439941 0.254001 -0.861357 + -0.439941 0.254001 -0.861357 + -0.439941 0.254001 -0.861357 + -0.75229 0.434336 -0.495391 + -0.75229 0.434336 -0.495391 + -0.75229 0.434336 -0.495391 + -0.75229 0.434336 -0.495391 + -0.75229 0.434336 -0.495391 + -0.75229 0.434336 -0.495391 + -0.92388 0.382683 0 + -0.92388 0.382683 0 + -0.92388 0.382683 0 + -0.92388 0.382683 0 + -0.92388 0.382683 0 + -0.92388 0.382683 0 + -0.802549 0.332426 0.495387 + -0.802549 0.332426 0.495387 + -0.802549 0.332426 0.495387 + -0.802549 0.332426 0.495387 + -0.802549 0.332426 0.495387 + -0.802549 0.332426 0.495387 + -0.469331 0.194403 0.861357 + -0.469331 0.194403 0.861357 + -0.469331 0.194403 0.861357 + -0.469331 0.194403 0.861357 + -0.469331 0.194403 0.861357 + -0.469331 0.194403 0.861357 + -0.469331 0.194403 0.861357 + -0.00996214 0.00412643 0.999942 + -0.00996214 0.00412643 0.999942 + -0.00996214 0.00412643 0.999942 + -0.00996214 0.00412643 0.999942 + -0.00996214 0.00412643 0.999942 + 0.454389 -0.188214 0.870693 + 0.454389 -0.188214 0.870693 + 0.454389 -0.188214 0.870693 + 0.454389 -0.188214 0.870693 + 0.454389 -0.188214 0.870693 + 0.797568 -0.330363 0.504724 + 0.797568 -0.330363 0.504724 + 0.797568 -0.330363 0.504724 + 0.797568 -0.330363 0.504724 + 0.797568 -0.330363 0.504724 + 0.797568 -0.330363 0.504724 + 0.797568 -0.330363 0.504724 + 0.797568 -0.330363 0.504724 + 0.92388 -0.382683 3.11544e-07 + 0.92388 -0.382683 3.11544e-07 + 0.92388 -0.382683 3.11544e-07 + 0.92388 -0.382683 3.11544e-07 + 0.92388 -0.382683 3.11544e-07 + 0.797568 -0.330364 -0.504724 + 0.797568 -0.330364 -0.504724 + 0.797568 -0.330364 -0.504724 + 0.797568 -0.330364 -0.504724 + 0.797568 -0.330364 -0.504724 + 0.797568 -0.330364 -0.504724 + 0.797568 -0.330364 -0.504724 + 0.454389 -0.188214 -0.870693 + 0.454389 -0.188214 -0.870693 + 0.454389 -0.188214 -0.870693 + 0.454389 -0.188214 -0.870693 + 0.454389 -0.188214 -0.870693 + -0.00996184 0.00412637 -0.999942 + -0.00996184 0.00412637 -0.999942 + -0.00996184 0.00412637 -0.999942 + -0.00996184 0.00412637 -0.999942 + -0.00996184 0.00412637 -0.999942 + -0.469332 0.194403 -0.861357 + -0.469332 0.194403 -0.861357 + -0.469332 0.194403 -0.861357 + -0.469332 0.194403 -0.861357 + -0.469332 0.194403 -0.861357 + -0.469332 0.194403 -0.861357 + -0.469332 0.194403 -0.861357 + -0.802549 0.332426 -0.495387 + -0.802549 0.332426 -0.495387 + -0.802549 0.332426 -0.495387 + -0.802549 0.332426 -0.495387 + -0.802549 0.332426 -0.495387 + -0.802549 0.332426 -0.495387 + -0.965926 0.25882 0 + -0.965926 0.25882 0 + -0.965926 0.25882 0 + -0.965926 0.25882 0 + -0.965926 0.25882 0 + -0.965926 0.25882 0 + -0.839073 0.224829 0.495387 + -0.839073 0.224829 0.495387 + -0.839073 0.224829 0.495387 + -0.839073 0.224829 0.495387 + -0.839073 0.224829 0.495387 + -0.839073 0.224829 0.495387 + -0.490692 0.13148 0.861356 + -0.490692 0.13148 0.861356 + -0.490692 0.13148 0.861356 + -0.490692 0.13148 0.861356 + -0.490692 0.13148 0.861356 + -0.0104158 0.00279093 0.999942 + -0.0104158 0.00279093 0.999942 + -0.0104158 0.00279093 0.999942 + -0.0104158 0.00279093 0.999942 + -0.0104158 0.00279093 0.999942 + -0.0104158 0.00279093 0.999942 + -0.0104158 0.00279093 0.999942 + 0.475067 -0.127294 0.870694 + 0.475067 -0.127294 0.870694 + 0.475067 -0.127294 0.870694 + 0.475067 -0.127294 0.870694 + 0.475067 -0.127294 0.870694 + 0.475067 -0.127294 0.870694 + 0.833864 -0.223433 0.504726 + 0.833864 -0.223433 0.504726 + 0.833864 -0.223433 0.504726 + 0.833864 -0.223433 0.504726 + 0.833864 -0.223433 0.504726 + 0.833864 -0.223433 0.504726 + 0.965926 -0.258819 0 + 0.965926 -0.258819 0 + 0.965926 -0.258819 0 + 0.965926 -0.258819 0 + 0.965926 -0.258819 0 + 0.965926 -0.258819 0 + 0.833864 -0.223433 -0.504726 + 0.833864 -0.223433 -0.504726 + 0.833864 -0.223433 -0.504726 + 0.833864 -0.223433 -0.504726 + 0.833864 -0.223433 -0.504726 + 0.833864 -0.223433 -0.504726 + 0.475067 -0.127294 -0.870694 + 0.475067 -0.127294 -0.870694 + 0.475067 -0.127294 -0.870694 + 0.475067 -0.127294 -0.870694 + 0.475067 -0.127294 -0.870694 + 0.475067 -0.127294 -0.870694 + 0.475067 -0.127294 -0.870694 + -0.0104157 0.00279087 -0.999942 + -0.0104157 0.00279087 -0.999942 + -0.0104157 0.00279087 -0.999942 + -0.0104157 0.00279087 -0.999942 + -0.0104157 0.00279087 -0.999942 + -0.490692 0.13148 -0.861356 + -0.490692 0.13148 -0.861356 + -0.490692 0.13148 -0.861356 + -0.490692 0.13148 -0.861356 + -0.490692 0.13148 -0.861356 + -0.490692 0.13148 -0.861356 + -0.839073 0.224829 -0.495387 + -0.839073 0.224829 -0.495387 + -0.839073 0.224829 -0.495387 + -0.839073 0.224829 -0.495387 + -0.839073 0.224829 -0.495387 + -0.839073 0.224829 -0.495387 + -0.991445 0.130526 0 + -0.991445 0.130526 0 + -0.991445 0.130526 0 + -0.991445 0.130526 0 + -0.991445 0.130526 0 + -0.991445 0.130526 0 + -0.861239 0.113384 0.495389 + -0.861239 0.113384 0.495389 + -0.861239 0.113384 0.495389 + -0.861239 0.113384 0.495389 + -0.861239 0.113384 0.495389 + -0.861239 0.113384 0.495389 + -0.503654 0.0663075 0.861357 + -0.503654 0.0663075 0.861357 + -0.503654 0.0663075 0.861357 + -0.503654 0.0663075 0.861357 + -0.503654 0.0663075 0.861357 + -0.503654 0.0663075 0.861357 + -0.0106911 0.00140744 0.999942 + -0.0106911 0.00140744 0.999942 + -0.0106911 0.00140744 0.999942 + -0.0106911 0.00140744 0.999942 + -0.0106911 0.00140744 0.999942 + -0.0106911 0.00140744 0.999942 + -0.0106911 0.00140744 0.999942 + 0.48762 -0.0641963 0.870693 + 0.48762 -0.0641963 0.870693 + 0.48762 -0.0641963 0.870693 + 0.48762 -0.0641963 0.870693 + 0.48762 -0.0641963 0.870693 + 0.48762 -0.0641963 0.870693 + 0.855896 -0.112681 0.504723 + 0.855896 -0.112681 0.504723 + 0.855896 -0.112681 0.504723 + 0.855896 -0.112681 0.504723 + 0.991445 -0.130526 0 + 0.991445 -0.130526 0 + 0.991445 -0.130526 0 + 0.991445 -0.130526 0 + 0.991445 -0.130526 0 + 0.991445 -0.130526 0 + 0.991445 -0.130526 0 + 0.855896 -0.112681 -0.504723 + 0.855896 -0.112681 -0.504723 + 0.855896 -0.112681 -0.504723 + 0.855896 -0.112681 -0.504723 + 0.855896 -0.112681 -0.504723 + 0.48762 -0.0641963 -0.870693 + 0.48762 -0.0641963 -0.870693 + 0.48762 -0.0641963 -0.870693 + 0.48762 -0.0641963 -0.870693 + 0.48762 -0.0641963 -0.870693 + 0.48762 -0.0641963 -0.870693 + -0.0106911 0.00140744 -0.999942 + -0.0106911 0.00140744 -0.999942 + -0.0106911 0.00140744 -0.999942 + -0.0106911 0.00140744 -0.999942 + -0.0106911 0.00140744 -0.999942 + -0.0106911 0.00140744 -0.999942 + -0.0106911 0.00140744 -0.999942 + -0.503654 0.0663075 -0.861357 + -0.503654 0.0663075 -0.861357 + -0.503654 0.0663075 -0.861357 + -0.503654 0.0663075 -0.861357 + -0.503654 0.0663075 -0.861357 + -0.503654 0.0663075 -0.861357 + -0.861239 0.113384 -0.495389 + -0.861239 0.113384 -0.495389 + -0.861239 0.113384 -0.495389 + -0.861239 0.113384 -0.495389 + -0.861239 0.113384 -0.495389 + -0.861239 0.113384 -0.495389 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -1 0 0 + -0.868672 0 0.495387 + -0.868672 0 0.495387 + -0.868672 0 0.495387 + -0.868672 0 0.495387 + -0.508001 0 0.861357 + -0.508001 0 0.861357 + -0.508001 0 0.861357 + -0.508001 0 0.861357 + -0.508001 0 0.861357 + -0.508001 0 0.861357 + -0.508001 0 0.861357 + -0.0107831 0 0.999942 + -0.0107831 0 0.999942 + -0.0107831 0 0.999942 + -0.0107831 0 0.999942 + -0.0107831 0 0.999942 + 0.491827 0 0.870693 + 0.491827 0 0.870693 + 0.491827 0 0.870693 + 0.491827 0 0.870693 + 0.491827 0 0.870693 + 0.491827 0 0.870693 + 0.86328 0 0.504725 + 0.86328 0 0.504725 + 0.86328 0 0.504725 + 0.86328 0 0.504725 + 0.86328 0 0.504725 + 0.86328 0 0.504725 + 0.86328 0 0.504725 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 1 0 0 + 0.86328 -1.42519e-07 -0.504725 + 0.86328 -1.42519e-07 -0.504725 + 0.86328 -1.42519e-07 -0.504725 + 0.86328 -1.42519e-07 -0.504725 + 0.86328 -1.42519e-07 -0.504725 + 0.86328 -1.42519e-07 -0.504725 + 0.86328 -1.42519e-07 -0.504725 + 0.491827 0 -0.870693 + 0.491827 0 -0.870693 + 0.491827 0 -0.870693 + 0.491827 0 -0.870693 + 0.491827 0 -0.870693 + 0.491827 0 -0.870693 + -0.010783 0 -0.999942 + -0.010783 0 -0.999942 + -0.010783 0 -0.999942 + -0.010783 0 -0.999942 + -0.010783 0 -0.999942 + -0.508001 0 -0.861357 + -0.508001 0 -0.861357 + -0.508001 0 -0.861357 + -0.508001 0 -0.861357 + -0.508001 0 -0.861357 + -0.508001 0 -0.861357 + -0.508001 0 -0.861357 + -0.868672 0 -0.495387 + -0.868672 0 -0.495387 + -0.868672 0 -0.495387 + -0.868672 0 -0.495387 + -0.991445 -0.130526 0 + -0.991445 -0.130526 0 + -0.991445 -0.130526 0 + -0.991445 -0.130526 0 + -0.991445 -0.130526 0 + -0.991445 -0.130526 0 + -0.861239 -0.113384 0.495389 + -0.861239 -0.113384 0.495389 + -0.861239 -0.113384 0.495389 + -0.861239 -0.113384 0.495389 + -0.861239 -0.113384 0.495389 + -0.861239 -0.113384 0.495389 + -0.503654 -0.0663074 0.861357 + -0.503654 -0.0663074 0.861357 + -0.503654 -0.0663074 0.861357 + -0.503654 -0.0663074 0.861357 + -0.503654 -0.0663074 0.861357 + -0.503654 -0.0663074 0.861357 + -0.0106912 -0.00140744 0.999942 + -0.0106912 -0.00140744 0.999942 + -0.0106912 -0.00140744 0.999942 + -0.0106912 -0.00140744 0.999942 + -0.0106912 -0.00140744 0.999942 + -0.0106912 -0.00140744 0.999942 + -0.0106912 -0.00140744 0.999942 + 0.48762 0.0641963 0.870693 + 0.48762 0.0641963 0.870693 + 0.48762 0.0641963 0.870693 + 0.48762 0.0641963 0.870693 + 0.48762 0.0641963 0.870693 + 0.48762 0.0641963 0.870693 + 0.855896 0.112681 0.504723 + 0.855896 0.112681 0.504723 + 0.855896 0.112681 0.504723 + 0.855896 0.112681 0.504723 + 0.855896 0.112681 0.504723 + 0.991445 0.130526 0 + 0.991445 0.130526 0 + 0.991445 0.130526 0 + 0.991445 0.130526 0 + 0.991445 0.130526 0 + 0.991445 0.130526 0 + 0.991445 0.130526 0 + 0.855896 0.112681 -0.504723 + 0.855896 0.112681 -0.504723 + 0.855896 0.112681 -0.504723 + 0.855896 0.112681 -0.504723 + 0.48762 0.0641963 -0.870693 + 0.48762 0.0641963 -0.870693 + 0.48762 0.0641963 -0.870693 + 0.48762 0.0641963 -0.870693 + 0.48762 0.0641963 -0.870693 + 0.48762 0.0641963 -0.870693 + -0.0106912 -0.00140744 -0.999942 + -0.0106912 -0.00140744 -0.999942 + -0.0106912 -0.00140744 -0.999942 + -0.0106912 -0.00140744 -0.999942 + -0.0106912 -0.00140744 -0.999942 + -0.0106912 -0.00140744 -0.999942 + -0.0106912 -0.00140744 -0.999942 + -0.503654 -0.0663074 -0.861357 + -0.503654 -0.0663074 -0.861357 + -0.503654 -0.0663074 -0.861357 + -0.503654 -0.0663074 -0.861357 + -0.503654 -0.0663074 -0.861357 + -0.503654 -0.0663074 -0.861357 + -0.861239 -0.113384 -0.495389 + -0.861239 -0.113384 -0.495389 + -0.861239 -0.113384 -0.495389 + -0.861239 -0.113384 -0.495389 + -0.861239 -0.113384 -0.495389 + -0.861239 -0.113384 -0.495389 + -0.965926 -0.25882 0 + -0.965926 -0.25882 0 + -0.965926 -0.25882 0 + -0.965926 -0.25882 0 + -0.965926 -0.25882 0 + -0.965926 -0.25882 0 + -0.839073 -0.224829 0.495387 + -0.839073 -0.224829 0.495387 + -0.839073 -0.224829 0.495387 + -0.839073 -0.224829 0.495387 + -0.839073 -0.224829 0.495387 + -0.839073 -0.224829 0.495387 + -0.490692 -0.13148 0.861356 + -0.490692 -0.13148 0.861356 + -0.490692 -0.13148 0.861356 + -0.490692 -0.13148 0.861356 + -0.490692 -0.13148 0.861356 + -0.490692 -0.13148 0.861356 + -0.0104157 -0.00279093 0.999942 + -0.0104157 -0.00279093 0.999942 + -0.0104157 -0.00279093 0.999942 + -0.0104157 -0.00279093 0.999942 + -0.0104157 -0.00279093 0.999942 + 0.475067 0.127294 0.870694 + 0.475067 0.127294 0.870694 + 0.475067 0.127294 0.870694 + 0.475067 0.127294 0.870694 + 0.475067 0.127294 0.870694 + 0.475067 0.127294 0.870694 + 0.833864 0.223433 0.504726 + 0.833864 0.223433 0.504726 + 0.833864 0.223433 0.504726 + 0.833864 0.223433 0.504726 + 0.833864 0.223433 0.504726 + 0.833864 0.223433 0.504726 + 0.833864 0.223433 0.504726 + 0.833864 0.223433 0.504726 + 0.965926 0.258819 0 + 0.965926 0.258819 0 + 0.965926 0.258819 0 + 0.965926 0.258819 0 + 0.833864 0.223433 -0.504726 + 0.833864 0.223433 -0.504726 + 0.833864 0.223433 -0.504726 + 0.833864 0.223433 -0.504726 + 0.833864 0.223433 -0.504726 + 0.833864 0.223433 -0.504726 + 0.833864 0.223433 -0.504726 + 0.833864 0.223433 -0.504726 + 0.475067 0.127294 -0.870694 + 0.475067 0.127294 -0.870694 + 0.475067 0.127294 -0.870694 + 0.475067 0.127294 -0.870694 + 0.475067 0.127294 -0.870694 + 0.475067 0.127294 -0.870694 + -0.0104159 -0.00279099 -0.999942 + -0.0104159 -0.00279099 -0.999942 + -0.0104159 -0.00279099 -0.999942 + -0.0104159 -0.00279099 -0.999942 + -0.0104159 -0.00279099 -0.999942 + -0.0104159 -0.00279099 -0.999942 + -0.490692 -0.13148 -0.861356 + -0.490692 -0.13148 -0.861356 + -0.490692 -0.13148 -0.861356 + -0.490692 -0.13148 -0.861356 + -0.490692 -0.13148 -0.861356 + -0.839073 -0.224829 -0.495387 + -0.839073 -0.224829 -0.495387 + -0.839073 -0.224829 -0.495387 + -0.839073 -0.224829 -0.495387 + -0.839073 -0.224829 -0.495387 + -0.839073 -0.224829 -0.495387 + -0.92388 -0.382683 0 + -0.92388 -0.382683 0 + -0.92388 -0.382683 0 + -0.92388 -0.382683 0 + -0.92388 -0.382683 0 + -0.92388 -0.382683 0 + -0.802549 -0.332426 0.495387 + -0.802549 -0.332426 0.495387 + -0.802549 -0.332426 0.495387 + -0.802549 -0.332426 0.495387 + -0.802549 -0.332426 0.495387 + -0.802549 -0.332426 0.495387 + -0.469331 -0.194403 0.861357 + -0.469331 -0.194403 0.861357 + -0.469331 -0.194403 0.861357 + -0.469331 -0.194403 0.861357 + -0.469331 -0.194403 0.861357 + -0.469331 -0.194403 0.861357 + -0.469331 -0.194403 0.861357 + -0.00996298 -0.00412661 0.999942 + -0.00996298 -0.00412661 0.999942 + -0.00996298 -0.00412661 0.999942 + -0.00996298 -0.00412661 0.999942 + -0.00996298 -0.00412661 0.999942 + 0.454389 0.188214 0.870693 + 0.454389 0.188214 0.870693 + 0.454389 0.188214 0.870693 + 0.454389 0.188214 0.870693 + 0.454389 0.188214 0.870693 + 0.454389 0.188214 0.870693 + 0.797568 0.330363 0.504724 + 0.797568 0.330363 0.504724 + 0.797568 0.330363 0.504724 + 0.797568 0.330363 0.504724 + 0.797568 0.330363 0.504724 + 0.797568 0.330363 0.504724 + 0.92388 0.382683 1.46036e-07 + 0.92388 0.382683 1.46036e-07 + 0.92388 0.382683 1.46036e-07 + 0.92388 0.382683 1.46036e-07 + 0.92388 0.382683 1.46036e-07 + 0.92388 0.382683 1.46036e-07 + 0.797568 0.330363 -0.504724 + 0.797568 0.330363 -0.504724 + 0.797568 0.330363 -0.504724 + 0.797568 0.330363 -0.504724 + 0.797568 0.330363 -0.504724 + 0.797568 0.330363 -0.504724 + 0.454389 0.188214 -0.870693 + 0.454389 0.188214 -0.870693 + 0.454389 0.188214 -0.870693 + 0.454389 0.188214 -0.870693 + 0.454389 0.188214 -0.870693 + 0.454389 0.188214 -0.870693 + -0.00996292 -0.00412661 -0.999942 + -0.00996292 -0.00412661 -0.999942 + -0.00996292 -0.00412661 -0.999942 + -0.00996292 -0.00412661 -0.999942 + -0.00996292 -0.00412661 -0.999942 + -0.469331 -0.194403 -0.861357 + -0.469331 -0.194403 -0.861357 + -0.469331 -0.194403 -0.861357 + -0.469331 -0.194403 -0.861357 + -0.469331 -0.194403 -0.861357 + -0.469331 -0.194403 -0.861357 + -0.802548 -0.332426 -0.495388 + -0.802548 -0.332426 -0.495388 + -0.802548 -0.332426 -0.495388 + -0.802548 -0.332426 -0.495388 + -0.802548 -0.332426 -0.495388 + -0.802548 -0.332426 -0.495388 + -0.802548 -0.332426 -0.495388 + -0.866026 -0.5 2.64862e-07 + -0.866026 -0.5 2.64862e-07 + -0.866026 -0.5 2.64862e-07 + -0.866026 -0.5 2.64862e-07 + -0.866026 -0.5 2.64862e-07 + -0.866026 -0.5 2.64862e-07 + -0.752291 -0.434335 0.49539 + -0.752291 -0.434335 0.49539 + -0.752291 -0.434335 0.49539 + -0.752291 -0.434335 0.49539 + -0.752291 -0.434335 0.49539 + -0.752291 -0.434335 0.49539 + -0.439941 -0.254 0.861357 + -0.439941 -0.254 0.861357 + -0.439941 -0.254 0.861357 + -0.439941 -0.254 0.861357 + -0.439941 -0.254 0.861357 + -0.439941 -0.254 0.861357 + -0.00933832 -0.00539148 0.999942 + -0.00933832 -0.00539148 0.999942 + -0.00933832 -0.00539148 0.999942 + -0.00933832 -0.00539148 0.999942 + -0.00933832 -0.00539148 0.999942 + -0.00933832 -0.00539148 0.999942 + -0.00933832 -0.00539148 0.999942 + 0.425934 0.245913 0.870693 + 0.425934 0.245913 0.870693 + 0.425934 0.245913 0.870693 + 0.425934 0.245913 0.870693 + 0.425934 0.245913 0.870693 + 0.747623 0.43164 0.504724 + 0.747623 0.43164 0.504724 + 0.747623 0.43164 0.504724 + 0.747623 0.43164 0.504724 + 0.747623 0.43164 0.504724 + 0.747623 0.43164 0.504724 + 0.866026 0.499999 -3.55355e-07 + 0.866026 0.499999 -3.55355e-07 + 0.866026 0.499999 -3.55355e-07 + 0.866026 0.499999 -3.55355e-07 + 0.866026 0.499999 -3.55355e-07 + 0.866026 0.499999 -3.55355e-07 + 0.747623 0.43164 -0.504725 + 0.747623 0.43164 -0.504725 + 0.747623 0.43164 -0.504725 + 0.747623 0.43164 -0.504725 + 0.747623 0.43164 -0.504725 + 0.747623 0.43164 -0.504725 + 0.425934 0.245913 -0.870693 + 0.425934 0.245913 -0.870693 + 0.425934 0.245913 -0.870693 + 0.425934 0.245913 -0.870693 + 0.425934 0.245913 -0.870693 + -0.00933844 -0.00539154 -0.999942 + -0.00933844 -0.00539154 -0.999942 + -0.00933844 -0.00539154 -0.999942 + -0.00933844 -0.00539154 -0.999942 + -0.00933844 -0.00539154 -0.999942 + -0.00933844 -0.00539154 -0.999942 + -0.00933844 -0.00539154 -0.999942 + -0.439941 -0.254 -0.861357 + -0.439941 -0.254 -0.861357 + -0.439941 -0.254 -0.861357 + -0.439941 -0.254 -0.861357 + -0.439941 -0.254 -0.861357 + -0.439941 -0.254 -0.861357 + -0.439941 -0.254 -0.861357 + -0.752292 -0.434336 -0.495389 + -0.752292 -0.434336 -0.495389 + -0.752292 -0.434336 -0.495389 + -0.752292 -0.434336 -0.495389 + -0.752292 -0.434336 -0.495389 + -0.793353 -0.608761 0 + -0.793353 -0.608761 0 + -0.793353 -0.608761 0 + -0.793353 -0.608761 0 + -0.689163 -0.528813 0.495389 + -0.689163 -0.528813 0.495389 + -0.689163 -0.528813 0.495389 + -0.689163 -0.528813 0.495389 + -0.689163 -0.528813 0.495389 + -0.689163 -0.528813 0.495389 + -0.689163 -0.528813 0.495389 + -0.403024 -0.309252 0.861356 + -0.403024 -0.309252 0.861356 + -0.403024 -0.309252 0.861356 + -0.403024 -0.309252 0.861356 + -0.403024 -0.309252 0.861356 + -0.403024 -0.309252 0.861356 + -0.00855547 -0.00656486 0.999942 + -0.00855547 -0.00656486 0.999942 + -0.00855547 -0.00656486 0.999942 + -0.00855547 -0.00656486 0.999942 + -0.00855547 -0.00656486 0.999942 + -0.00855547 -0.00656486 0.999942 + 0.390193 0.299405 0.870693 + 0.390193 0.299405 0.870693 + 0.390193 0.299405 0.870693 + 0.390193 0.299405 0.870693 + 0.390193 0.299405 0.870693 + 0.390193 0.299405 0.870693 + 0.684887 0.525532 0.504724 + 0.684887 0.525532 0.504724 + 0.684887 0.525532 0.504724 + 0.684887 0.525532 0.504724 + 0.684887 0.525532 0.504724 + 0.684887 0.525532 0.504724 + 0.793353 0.608761 4.62449e-07 + 0.793353 0.608761 4.62449e-07 + 0.793353 0.608761 4.62449e-07 + 0.793353 0.608761 4.62449e-07 + 0.793353 0.608761 4.62449e-07 + 0.793353 0.608761 4.62449e-07 + 0.684887 0.525532 -0.504724 + 0.684887 0.525532 -0.504724 + 0.684887 0.525532 -0.504724 + 0.684887 0.525532 -0.504724 + 0.684887 0.525532 -0.504724 + 0.684887 0.525532 -0.504724 + 0.390193 0.299405 -0.870693 + 0.390193 0.299405 -0.870693 + 0.390193 0.299405 -0.870693 + 0.390193 0.299405 -0.870693 + 0.390193 0.299405 -0.870693 + 0.390193 0.299405 -0.870693 + -0.00855517 -0.00656462 -0.999942 + -0.00855517 -0.00656462 -0.999942 + -0.00855517 -0.00656462 -0.999942 + -0.00855517 -0.00656462 -0.999942 + -0.00855517 -0.00656462 -0.999942 + -0.00855517 -0.00656462 -0.999942 + -0.403024 -0.309251 -0.861357 + -0.403024 -0.309251 -0.861357 + -0.403024 -0.309251 -0.861357 + -0.403024 -0.309251 -0.861357 + -0.403024 -0.309251 -0.861357 + -0.403024 -0.309251 -0.861357 + -0.689163 -0.528813 -0.495389 + -0.689163 -0.528813 -0.495389 + -0.689163 -0.528813 -0.495389 + -0.689163 -0.528813 -0.495389 + -0.689163 -0.528813 -0.495389 + -0.689163 -0.528813 -0.495389 + -0.689163 -0.528813 -0.495389 + -0.707107 -0.707106 0 + -0.707107 -0.707106 0 + -0.707107 -0.707106 0 + -0.707107 -0.707106 0 + -0.707107 -0.707106 0 + -0.707107 -0.707106 0 + -0.614245 -0.614245 0.495385 + -0.614245 -0.614245 0.495385 + -0.614245 -0.614245 0.495385 + -0.614245 -0.614245 0.495385 + -0.614245 -0.614245 0.495385 + -0.614245 -0.614245 0.495385 + -0.614245 -0.614245 0.495385 + -0.359212 -0.359212 0.861356 + -0.359212 -0.359212 0.861356 + -0.359212 -0.359212 0.861356 + -0.359212 -0.359212 0.861356 + -0.359212 -0.359212 0.861356 + -0.00762624 -0.00762624 0.999942 + -0.00762624 -0.00762624 0.999942 + -0.00762624 -0.00762624 0.999942 + -0.00762624 -0.00762624 0.999942 + -0.00762624 -0.00762624 0.999942 + 0.347775 0.347775 0.870692 + 0.347775 0.347775 0.870692 + 0.347775 0.347775 0.870692 + 0.347775 0.347775 0.870692 + 0.347775 0.347775 0.870692 + 0.347775 0.347775 0.870692 + 0.347775 0.347775 0.870692 + 0.610431 0.61043 0.504727 + 0.610431 0.61043 0.504727 + 0.610431 0.61043 0.504727 + 0.610431 0.61043 0.504727 + 0.610431 0.61043 0.504727 + 0.610431 0.61043 0.504727 + 0.707107 0.707106 8.85956e-07 + 0.707107 0.707106 8.85956e-07 + 0.707107 0.707106 8.85956e-07 + 0.707107 0.707106 8.85956e-07 + 0.707107 0.707106 8.85956e-07 + 0.707107 0.707106 8.85956e-07 + 0.61043 0.61043 -0.504727 + 0.61043 0.61043 -0.504727 + 0.61043 0.61043 -0.504727 + 0.61043 0.61043 -0.504727 + 0.61043 0.61043 -0.504727 + 0.347774 0.347774 -0.870693 + 0.347774 0.347774 -0.870693 + 0.347774 0.347774 -0.870693 + 0.347774 0.347774 -0.870693 + 0.347774 0.347774 -0.870693 + 0.347774 0.347774 -0.870693 + 0.347774 0.347774 -0.870693 + 0.347774 0.347774 -0.870693 + -0.00762641 -0.00762641 -0.999942 + -0.00762641 -0.00762641 -0.999942 + -0.00762641 -0.00762641 -0.999942 + -0.00762641 -0.00762641 -0.999942 + -0.00762641 -0.00762641 -0.999942 + -0.359211 -0.359211 -0.861356 + -0.359211 -0.359211 -0.861356 + -0.359211 -0.359211 -0.861356 + -0.359211 -0.359211 -0.861356 + -0.359211 -0.359211 -0.861356 + -0.614245 -0.614244 -0.495386 + -0.614245 -0.614244 -0.495386 + -0.614245 -0.614244 -0.495386 + -0.614245 -0.614244 -0.495386 + -0.614245 -0.614244 -0.495386 + -0.614245 -0.614244 -0.495386 + -0.614245 -0.614244 -0.495386 + -0.608762 -0.793353 2.58645e-07 + -0.608762 -0.793353 2.58645e-07 + -0.608762 -0.793353 2.58645e-07 + -0.608762 -0.793353 2.58645e-07 + -0.608762 -0.793353 2.58645e-07 + -0.608762 -0.793353 2.58645e-07 + -0.528813 -0.689163 0.49539 + -0.528813 -0.689163 0.49539 + -0.528813 -0.689163 0.49539 + -0.528813 -0.689163 0.49539 + -0.528813 -0.689163 0.49539 + -0.309251 -0.403024 0.861357 + -0.309251 -0.403024 0.861357 + -0.309251 -0.403024 0.861357 + -0.309251 -0.403024 0.861357 + -0.309251 -0.403024 0.861357 + -0.309251 -0.403024 0.861357 + -0.309251 -0.403024 0.861357 + -0.00656396 -0.0085544 0.999942 + -0.00656396 -0.0085544 0.999942 + -0.00656396 -0.0085544 0.999942 + -0.00656396 -0.0085544 0.999942 + -0.00656396 -0.0085544 0.999942 + -0.00656396 -0.0085544 0.999942 + 0.299405 0.390192 0.870694 + 0.299405 0.390192 0.870694 + 0.299405 0.390192 0.870694 + 0.299405 0.390192 0.870694 + 0.299405 0.390192 0.870694 + 0.299405 0.390192 0.870694 + 0.299405 0.390192 0.870694 + 0.525532 0.684887 0.504723 + 0.525532 0.684887 0.504723 + 0.525532 0.684887 0.504723 + 0.525532 0.684887 0.504723 + 0.525532 0.684887 0.504723 + 0.608762 0.793353 -2.00556e-06 + 0.608762 0.793353 -2.00556e-06 + 0.608762 0.793353 -2.00556e-06 + 0.608762 0.793353 -2.00556e-06 + 0.608762 0.793353 -2.00556e-06 + 0.608762 0.793353 -2.00556e-06 + 0.525532 0.684886 -0.504725 + 0.525532 0.684886 -0.504725 + 0.525532 0.684886 -0.504725 + 0.525532 0.684886 -0.504725 + 0.525532 0.684886 -0.504725 + 0.525532 0.684886 -0.504725 + 0.299405 0.390192 -0.870693 + 0.299405 0.390192 -0.870693 + 0.299405 0.390192 -0.870693 + 0.299405 0.390192 -0.870693 + 0.299405 0.390192 -0.870693 + 0.299405 0.390192 -0.870693 + -0.00656384 -0.00855428 -0.999942 + -0.00656384 -0.00855428 -0.999942 + -0.00656384 -0.00855428 -0.999942 + -0.00656384 -0.00855428 -0.999942 + -0.00656384 -0.00855428 -0.999942 + -0.00656384 -0.00855428 -0.999942 + -0.309252 -0.403025 -0.861356 + -0.309252 -0.403025 -0.861356 + -0.309252 -0.403025 -0.861356 + -0.309252 -0.403025 -0.861356 + -0.309252 -0.403025 -0.861356 + -0.309252 -0.403025 -0.861356 + -0.528814 -0.689164 -0.495388 + -0.528814 -0.689164 -0.495388 + -0.528814 -0.689164 -0.495388 + -0.528814 -0.689164 -0.495388 + -0.528814 -0.689164 -0.495388 + -0.528814 -0.689164 -0.495388 + -0.5 -0.866026 9.89814e-07 + -0.5 -0.866026 9.89814e-07 + -0.5 -0.866026 9.89814e-07 + -0.5 -0.866026 9.89814e-07 + -0.5 -0.866026 9.89814e-07 + -0.5 -0.866026 9.89814e-07 + -0.434336 -0.752292 0.495389 + -0.434336 -0.752292 0.495389 + -0.434336 -0.752292 0.495389 + -0.434336 -0.752292 0.495389 + -0.434336 -0.752292 0.495389 + -0.434336 -0.752292 0.495389 + -0.254 -0.439941 0.861357 + -0.254 -0.439941 0.861357 + -0.254 -0.439941 0.861357 + -0.254 -0.439941 0.861357 + -0.254 -0.439941 0.861357 + -0.254 -0.439941 0.861357 + -0.00539184 -0.00933903 0.999942 + -0.00539184 -0.00933903 0.999942 + -0.00539184 -0.00933903 0.999942 + -0.00539184 -0.00933903 0.999942 + -0.00539184 -0.00933903 0.999942 + -0.00539184 -0.00933903 0.999942 + 0.245913 0.425933 0.870694 + 0.245913 0.425933 0.870694 + 0.245913 0.425933 0.870694 + 0.245913 0.425933 0.870694 + 0.245913 0.425933 0.870694 + 0.43164 0.747622 0.504726 + 0.43164 0.747622 0.504726 + 0.43164 0.747622 0.504726 + 0.43164 0.747622 0.504726 + 0.43164 0.747622 0.504726 + 0.43164 0.747622 0.504726 + 0.43164 0.747622 0.504726 + 0.5 0.866026 6.27957e-07 + 0.5 0.866026 6.27957e-07 + 0.5 0.866026 6.27957e-07 + 0.5 0.866026 6.27957e-07 + 0.5 0.866026 6.27957e-07 + 0.5 0.866026 6.27957e-07 + 0.43164 0.747622 -0.504726 + 0.43164 0.747622 -0.504726 + 0.43164 0.747622 -0.504726 + 0.43164 0.747622 -0.504726 + 0.43164 0.747622 -0.504726 + 0.43164 0.747622 -0.504726 + 0.43164 0.747622 -0.504726 + 0.245913 0.425933 -0.870694 + 0.245913 0.425933 -0.870694 + 0.245913 0.425933 -0.870694 + 0.245913 0.425933 -0.870694 + 0.245913 0.425933 -0.870694 + -0.00539219 -0.00933963 -0.999942 + -0.00539219 -0.00933963 -0.999942 + -0.00539219 -0.00933963 -0.999942 + -0.00539219 -0.00933963 -0.999942 + -0.00539219 -0.00933963 -0.999942 + -0.00539219 -0.00933963 -0.999942 + -0.254 -0.439941 -0.861357 + -0.254 -0.439941 -0.861357 + -0.254 -0.439941 -0.861357 + -0.254 -0.439941 -0.861357 + -0.254 -0.439941 -0.861357 + -0.254 -0.439941 -0.861357 + -0.254 -0.439941 -0.861357 + -0.434336 -0.752292 -0.495389 + -0.434336 -0.752292 -0.495389 + -0.434336 -0.752292 -0.495389 + -0.434336 -0.752292 -0.495389 + -0.434336 -0.752292 -0.495389 + -0.382684 -0.923879 -1.1639e-06 + -0.382684 -0.923879 -1.1639e-06 + -0.382684 -0.923879 -1.1639e-06 + -0.382684 -0.923879 -1.1639e-06 + -0.382684 -0.923879 -1.1639e-06 + -0.382684 -0.923879 -1.1639e-06 + -0.332427 -0.80255 0.495385 + -0.332427 -0.80255 0.495385 + -0.332427 -0.80255 0.495385 + -0.332427 -0.80255 0.495385 + -0.332427 -0.80255 0.495385 + -0.332427 -0.80255 0.495385 + -0.332427 -0.80255 0.495385 + -0.194404 -0.469332 0.861356 + -0.194404 -0.469332 0.861356 + -0.194404 -0.469332 0.861356 + -0.194404 -0.469332 0.861356 + -0.00412667 -0.0099625 0.999942 + -0.00412667 -0.0099625 0.999942 + -0.00412667 -0.0099625 0.999942 + -0.00412667 -0.0099625 0.999942 + -0.00412667 -0.0099625 0.999942 + -0.00412667 -0.0099625 0.999942 + -0.00412667 -0.0099625 0.999942 + -0.00412667 -0.0099625 0.999942 + 0.188214 0.454388 0.870694 + 0.188214 0.454388 0.870694 + 0.188214 0.454388 0.870694 + 0.188214 0.454388 0.870694 + 0.188214 0.454388 0.870694 + 0.188214 0.454388 0.870694 + 0.330364 0.797568 0.504723 + 0.330364 0.797568 0.504723 + 0.330364 0.797568 0.504723 + 0.330364 0.797568 0.504723 + 0.382683 0.92388 0 + 0.382683 0.92388 0 + 0.382683 0.92388 0 + 0.382683 0.92388 0 + 0.382683 0.92388 0 + 0.382683 0.92388 0 + 0.382683 0.92388 0 + 0.382683 0.92388 0 + 0.330364 0.797568 -0.504723 + 0.330364 0.797568 -0.504723 + 0.330364 0.797568 -0.504723 + 0.330364 0.797568 -0.504723 + 0.188214 0.454388 -0.870694 + 0.188214 0.454388 -0.870694 + 0.188214 0.454388 -0.870694 + 0.188214 0.454388 -0.870694 + 0.188214 0.454388 -0.870694 + 0.188214 0.454388 -0.870694 + -0.00412631 -0.00996148 -0.999942 + -0.00412631 -0.00996148 -0.999942 + -0.00412631 -0.00996148 -0.999942 + -0.00412631 -0.00996148 -0.999942 + -0.00412631 -0.00996148 -0.999942 + -0.00412631 -0.00996148 -0.999942 + -0.00412631 -0.00996148 -0.999942 + -0.194404 -0.469331 -0.861357 + -0.194404 -0.469331 -0.861357 + -0.194404 -0.469331 -0.861357 + -0.194404 -0.469331 -0.861357 + -0.194404 -0.469331 -0.861357 + -0.332427 -0.802549 -0.495386 + -0.332427 -0.802549 -0.495386 + -0.332427 -0.802549 -0.495386 + -0.332427 -0.802549 -0.495386 + -0.332427 -0.802549 -0.495386 + -0.332427 -0.802549 -0.495386 + -0.332427 -0.802549 -0.495386 + -0.258819 -0.965926 -2.81961e-07 + -0.258819 -0.965926 -2.81961e-07 + -0.258819 -0.965926 -2.81961e-07 + -0.258819 -0.965926 -2.81961e-07 + -0.258819 -0.965926 -2.81961e-07 + -0.258819 -0.965926 -2.81961e-07 + -0.258819 -0.965926 -2.81961e-07 + -0.224829 -0.839073 0.495388 + -0.224829 -0.839073 0.495388 + -0.224829 -0.839073 0.495388 + -0.224829 -0.839073 0.495388 + -0.224829 -0.839073 0.495388 + -0.224829 -0.839073 0.495388 + -0.131481 -0.490692 0.861356 + -0.131481 -0.490692 0.861356 + -0.131481 -0.490692 0.861356 + -0.131481 -0.490692 0.861356 + -0.131481 -0.490692 0.861356 + -0.131481 -0.490692 0.861356 + -0.00279075 -0.0104157 0.999942 + -0.00279075 -0.0104157 0.999942 + -0.00279075 -0.0104157 0.999942 + -0.00279075 -0.0104157 0.999942 + -0.00279075 -0.0104157 0.999942 + 0.127295 0.475069 0.870692 + 0.127295 0.475069 0.870692 + 0.127295 0.475069 0.870692 + 0.127295 0.475069 0.870692 + 0.127295 0.475069 0.870692 + 0.127295 0.475069 0.870692 + 0.127295 0.475069 0.870692 + 0.223434 0.833866 0.504723 + 0.223434 0.833866 0.504723 + 0.223434 0.833866 0.504723 + 0.223434 0.833866 0.504723 + 0.223434 0.833866 0.504723 + 0.223434 0.833866 0.504723 + 0.25882 0.965926 2.10201e-06 + 0.25882 0.965926 2.10201e-06 + 0.25882 0.965926 2.10201e-06 + 0.25882 0.965926 2.10201e-06 + 0.25882 0.965926 2.10201e-06 + 0.25882 0.965926 2.10201e-06 + 0.223435 0.833867 -0.504721 + 0.223435 0.833867 -0.504721 + 0.223435 0.833867 -0.504721 + 0.223435 0.833867 -0.504721 + 0.223435 0.833867 -0.504721 + 0.223435 0.833867 -0.504721 + 0.127295 0.47507 -0.870692 + 0.127295 0.47507 -0.870692 + 0.127295 0.47507 -0.870692 + 0.127295 0.47507 -0.870692 + 0.127295 0.47507 -0.870692 + 0.127295 0.47507 -0.870692 + -0.00279093 -0.010416 -0.999942 + -0.00279093 -0.010416 -0.999942 + -0.00279093 -0.010416 -0.999942 + -0.00279093 -0.010416 -0.999942 + -0.00279093 -0.010416 -0.999942 + -0.00279093 -0.010416 -0.999942 + -0.00279093 -0.010416 -0.999942 + -0.131481 -0.490692 -0.861356 + -0.131481 -0.490692 -0.861356 + -0.131481 -0.490692 -0.861356 + -0.131481 -0.490692 -0.861356 + -0.131481 -0.490692 -0.861356 + -0.224829 -0.839071 -0.49539 + -0.224829 -0.839071 -0.49539 + -0.224829 -0.839071 -0.49539 + -0.224829 -0.839071 -0.49539 + -0.224829 -0.839071 -0.49539 + -0.130526 -0.991445 0 + -0.130526 -0.991445 0 + -0.130526 -0.991445 0 + -0.130526 -0.991445 0 + -0.130526 -0.991445 0 + -0.113385 -0.861241 0.495386 + -0.113385 -0.861241 0.495386 + -0.113385 -0.861241 0.495386 + -0.113385 -0.861241 0.495386 + -0.113385 -0.861241 0.495386 + -0.113385 -0.861241 0.495386 + -0.0663074 -0.503653 0.861358 + -0.0663074 -0.503653 0.861358 + -0.0663074 -0.503653 0.861358 + -0.0663074 -0.503653 0.861358 + -0.0663074 -0.503653 0.861358 + -0.0663074 -0.503653 0.861358 + -0.00140733 -0.0106907 0.999942 + -0.00140733 -0.0106907 0.999942 + -0.00140733 -0.0106907 0.999942 + -0.00140733 -0.0106907 0.999942 + -0.00140733 -0.0106907 0.999942 + -0.00140733 -0.0106907 0.999942 + -0.00140733 -0.0106907 0.999942 + 0.0641966 0.48762 0.870692 + 0.0641966 0.48762 0.870692 + 0.0641966 0.48762 0.870692 + 0.0641966 0.48762 0.870692 + 0.0641966 0.48762 0.870692 + 0.112681 0.855897 0.504722 + 0.112681 0.855897 0.504722 + 0.112681 0.855897 0.504722 + 0.112681 0.855897 0.504722 + 0.112681 0.855897 0.504722 + 0.112681 0.855897 0.504722 + 0.130526 0.991445 2.67429e-07 + 0.130526 0.991445 2.67429e-07 + 0.130526 0.991445 2.67429e-07 + 0.130526 0.991445 2.67429e-07 + 0.130526 0.991445 2.67429e-07 + 0.130526 0.991445 2.67429e-07 + 0.112681 0.855896 -0.504723 + 0.112681 0.855896 -0.504723 + 0.112681 0.855896 -0.504723 + 0.112681 0.855896 -0.504723 + 0.112681 0.855896 -0.504723 + 0.112681 0.855896 -0.504723 + 0.0641963 0.487619 -0.870693 + 0.0641963 0.487619 -0.870693 + 0.0641963 0.487619 -0.870693 + 0.0641963 0.487619 -0.870693 + 0.0641963 0.487619 -0.870693 + 0.0641963 0.487619 -0.870693 + -0.00140744 -0.0106908 -0.999942 + -0.00140744 -0.0106908 -0.999942 + -0.00140744 -0.0106908 -0.999942 + -0.00140744 -0.0106908 -0.999942 + -0.00140744 -0.0106908 -0.999942 + -0.0663072 -0.503653 -0.861358 + -0.0663072 -0.503653 -0.861358 + -0.0663072 -0.503653 -0.861358 + -0.0663072 -0.503653 -0.861358 + -0.0663072 -0.503653 -0.861358 + -0.0663072 -0.503653 -0.861358 + -0.0663072 -0.503653 -0.861358 + -0.113385 -0.861241 -0.495387 + -0.113385 -0.861241 -0.495387 + -0.113385 -0.861241 -0.495387 + -0.113385 -0.861241 -0.495387 + -0.113385 -0.861241 -0.495387 + -0.113385 -0.861241 -0.495387 + -0.113385 -0.861241 -0.495387 + -2.48619e-07 -1 1.50462e-07 + -2.48619e-07 -1 1.50462e-07 + -2.48619e-07 -1 1.50462e-07 + -2.48619e-07 -1 1.50462e-07 + -2.48619e-07 -1 1.50462e-07 + -2.48619e-07 -1 1.50462e-07 + -2.48619e-07 -1 1.50462e-07 + -2.48619e-07 -1 1.50462e-07 + -2.50702e-07 -0.868672 0.495388 + -2.50702e-07 -0.868672 0.495388 + -2.50702e-07 -0.868672 0.495388 + -2.50702e-07 -0.868672 0.495388 + -1.57946e-07 -0.507999 0.861358 + -1.57946e-07 -0.507999 0.861358 + -1.57946e-07 -0.507999 0.861358 + -1.57946e-07 -0.507999 0.861358 + -1.57946e-07 -0.507999 0.861358 + -1.57946e-07 -0.507999 0.861358 + -1.57946e-07 -0.507999 0.861358 + -1.57946e-07 -0.507999 0.861358 + 0 -0.0107824 0.999942 + 0 -0.0107824 0.999942 + 0 -0.0107824 0.999942 + 0 -0.0107824 0.999942 + 1.25626e-07 0.491826 0.870694 + 1.25626e-07 0.491826 0.870694 + 1.25626e-07 0.491826 0.870694 + 1.25626e-07 0.491826 0.870694 + 1.25626e-07 0.491826 0.870694 + 1.25626e-07 0.491826 0.870694 + 1.89492e-07 0.863279 0.504728 + 1.89492e-07 0.863279 0.504728 + 1.89492e-07 0.863279 0.504728 + 1.89492e-07 0.863279 0.504728 + 1.89492e-07 0.863279 0.504728 + 1.89492e-07 0.863279 0.504728 + 1.89492e-07 0.863279 0.504728 + 2.85152e-07 1 1.48166e-07 + 2.85152e-07 1 1.48166e-07 + 2.85152e-07 1 1.48166e-07 + 2.85152e-07 1 1.48166e-07 + 2.85152e-07 1 1.48166e-07 + 2.85152e-07 1 1.48166e-07 + 1.72058e-07 0.863279 -0.504728 + 1.72058e-07 0.863279 -0.504728 + 1.72058e-07 0.863279 -0.504728 + 1.72058e-07 0.863279 -0.504728 + 1.72058e-07 0.863279 -0.504728 + 1.72058e-07 0.863279 -0.504728 + 1.72058e-07 0.863279 -0.504728 + 0 0.491826 -0.870694 + 0 0.491826 -0.870694 + 0 0.491826 -0.870694 + 0 0.491826 -0.870694 + 0 0.491826 -0.870694 + 0 0.491826 -0.870694 + 0 -0.0107826 -0.999942 + 0 -0.0107826 -0.999942 + 0 -0.0107826 -0.999942 + 0 -0.0107826 -0.999942 + 0 -0.0107826 -0.999942 + -1.68115e-07 -0.507999 -0.861358 + -1.68115e-07 -0.507999 -0.861358 + -1.68115e-07 -0.507999 -0.861358 + -1.68115e-07 -0.507999 -0.861358 + -1.68115e-07 -0.507999 -0.861358 + -1.68115e-07 -0.507999 -0.861358 + -1.68115e-07 -0.507999 -0.861358 + -2.39532e-07 -0.868672 -0.495388 + -2.39532e-07 -0.868672 -0.495388 + -2.39532e-07 -0.868672 -0.495388 + -2.39532e-07 -0.868672 -0.495388 + 0.130526 -0.991445 3.31389e-07 + 0.130526 -0.991445 3.31389e-07 + 0.130526 -0.991445 3.31389e-07 + 0.130526 -0.991445 3.31389e-07 + 0.130526 -0.991445 3.31389e-07 + 0.130526 -0.991445 3.31389e-07 + 0.113385 -0.861242 0.495384 + 0.113385 -0.861242 0.495384 + 0.113385 -0.861242 0.495384 + 0.113385 -0.861242 0.495384 + 0.113385 -0.861242 0.495384 + 0.113385 -0.861242 0.495384 + 0.0663077 -0.503657 0.861356 + 0.0663077 -0.503657 0.861356 + 0.0663077 -0.503657 0.861356 + 0.0663077 -0.503657 0.861356 + 0.0663077 -0.503657 0.861356 + 0.0663077 -0.503657 0.861356 + 0.00140738 -0.0106903 0.999942 + 0.00140738 -0.0106903 0.999942 + 0.00140738 -0.0106903 0.999942 + 0.00140738 -0.0106903 0.999942 + 0.00140738 -0.0106903 0.999942 + 0.00140738 -0.0106903 0.999942 + -0.0641962 0.48762 0.870692 + -0.0641962 0.48762 0.870692 + -0.0641962 0.48762 0.870692 + -0.0641962 0.48762 0.870692 + -0.0641962 0.48762 0.870692 + -0.0641962 0.48762 0.870692 + -0.112681 0.855898 0.50472 + -0.112681 0.855898 0.50472 + -0.112681 0.855898 0.50472 + -0.112681 0.855898 0.50472 + -0.112681 0.855898 0.50472 + -0.112681 0.855898 0.50472 + -0.130526 0.991445 4.77355e-07 + -0.130526 0.991445 4.77355e-07 + -0.130526 0.991445 4.77355e-07 + -0.130526 0.991445 4.77355e-07 + -0.130526 0.991445 4.77355e-07 + -0.130526 0.991445 4.77355e-07 + -0.112681 0.855897 -0.504721 + -0.112681 0.855897 -0.504721 + -0.112681 0.855897 -0.504721 + -0.112681 0.855897 -0.504721 + -0.112681 0.855897 -0.504721 + -0.112681 0.855897 -0.504721 + -0.0641962 0.487619 -0.870693 + -0.0641962 0.487619 -0.870693 + -0.0641962 0.487619 -0.870693 + -0.0641962 0.487619 -0.870693 + -0.0641962 0.487619 -0.870693 + -0.0641962 0.487619 -0.870693 + 0.00140744 -0.0106907 -0.999942 + 0.00140744 -0.0106907 -0.999942 + 0.00140744 -0.0106907 -0.999942 + 0.00140744 -0.0106907 -0.999942 + 0.00140744 -0.0106907 -0.999942 + 0.00140744 -0.0106907 -0.999942 + 0.0663077 -0.503657 -0.861355 + 0.0663077 -0.503657 -0.861355 + 0.0663077 -0.503657 -0.861355 + 0.0663077 -0.503657 -0.861355 + 0.0663077 -0.503657 -0.861355 + 0.0663077 -0.503657 -0.861355 + 0.113385 -0.861243 -0.495384 + 0.113385 -0.861243 -0.495384 + 0.113385 -0.861243 -0.495384 + 0.113385 -0.861243 -0.495384 + 0.113385 -0.861243 -0.495384 + 0.113385 -0.861243 -0.495384 + 0.258819 -0.965926 6.90445e-07 + 0.258819 -0.965926 6.90445e-07 + 0.258819 -0.965926 6.90445e-07 + 0.258819 -0.965926 6.90445e-07 + 0.258819 -0.965926 6.90445e-07 + 0.258819 -0.965926 6.90445e-07 + 0.224828 -0.839072 0.495389 + 0.224828 -0.839072 0.495389 + 0.224828 -0.839072 0.495389 + 0.224828 -0.839072 0.495389 + 0.224828 -0.839072 0.495389 + 0.224828 -0.839072 0.495389 + 0.13148 -0.490689 0.861358 + 0.13148 -0.490689 0.861358 + 0.13148 -0.490689 0.861358 + 0.13148 -0.490689 0.861358 + 0.13148 -0.490689 0.861358 + 0.13148 -0.490689 0.861358 + 0.00279075 -0.0104151 0.999942 + 0.00279075 -0.0104151 0.999942 + 0.00279075 -0.0104151 0.999942 + 0.00279075 -0.0104151 0.999942 + 0.00279075 -0.0104151 0.999942 + 0.00279075 -0.0104151 0.999942 + 0.00279075 -0.0104151 0.999942 + -0.127294 0.475068 0.870693 + -0.127294 0.475068 0.870693 + -0.127294 0.475068 0.870693 + -0.127294 0.475068 0.870693 + -0.127294 0.475068 0.870693 + -0.223433 0.833865 0.504725 + -0.223433 0.833865 0.504725 + -0.223433 0.833865 0.504725 + -0.223433 0.833865 0.504725 + -0.223433 0.833865 0.504725 + -0.223433 0.833865 0.504725 + -0.258819 0.965926 -1.25652e-06 + -0.258819 0.965926 -1.25652e-06 + -0.258819 0.965926 -1.25652e-06 + -0.258819 0.965926 -1.25652e-06 + -0.258819 0.965926 -1.25652e-06 + -0.258819 0.965926 -1.25652e-06 + -0.223433 0.833864 -0.504726 + -0.223433 0.833864 -0.504726 + -0.223433 0.833864 -0.504726 + -0.223433 0.833864 -0.504726 + -0.223433 0.833864 -0.504726 + -0.223433 0.833864 -0.504726 + -0.127294 0.475069 -0.870693 + -0.127294 0.475069 -0.870693 + -0.127294 0.475069 -0.870693 + -0.127294 0.475069 -0.870693 + -0.127294 0.475069 -0.870693 + 0.00279087 -0.0104154 -0.999942 + 0.00279087 -0.0104154 -0.999942 + 0.00279087 -0.0104154 -0.999942 + 0.00279087 -0.0104154 -0.999942 + 0.00279087 -0.0104154 -0.999942 + 0.00279087 -0.0104154 -0.999942 + 0.00279087 -0.0104154 -0.999942 + 0.13148 -0.490689 -0.861358 + 0.13148 -0.490689 -0.861358 + 0.13148 -0.490689 -0.861358 + 0.13148 -0.490689 -0.861358 + 0.13148 -0.490689 -0.861358 + 0.13148 -0.490689 -0.861358 + 0.224828 -0.839072 -0.495389 + 0.224828 -0.839072 -0.495389 + 0.224828 -0.839072 -0.495389 + 0.224828 -0.839072 -0.495389 + 0.224828 -0.839072 -0.495389 + 0.224828 -0.839072 -0.495389 + 0.382683 -0.92388 0 + 0.382683 -0.92388 0 + 0.382683 -0.92388 0 + 0.382683 -0.92388 0 + 0.332426 -0.802549 0.495387 + 0.332426 -0.802549 0.495387 + 0.332426 -0.802549 0.495387 + 0.332426 -0.802549 0.495387 + 0.332426 -0.802549 0.495387 + 0.332426 -0.802549 0.495387 + 0.332426 -0.802549 0.495387 + 0.194403 -0.469331 0.861357 + 0.194403 -0.469331 0.861357 + 0.194403 -0.469331 0.861357 + 0.194403 -0.469331 0.861357 + 0.194403 -0.469331 0.861357 + 0.194403 -0.469331 0.861357 + 0.00412583 -0.00996101 0.999942 + 0.00412583 -0.00996101 0.999942 + 0.00412583 -0.00996101 0.999942 + 0.00412583 -0.00996101 0.999942 + 0.00412583 -0.00996101 0.999942 + 0.00412583 -0.00996101 0.999942 + -0.188214 0.45439 0.870693 + -0.188214 0.45439 0.870693 + -0.188214 0.45439 0.870693 + -0.188214 0.45439 0.870693 + -0.188214 0.45439 0.870693 + -0.188214 0.45439 0.870693 + -0.330363 0.797567 0.504725 + -0.330363 0.797567 0.504725 + -0.330363 0.797567 0.504725 + -0.330363 0.797567 0.504725 + -0.330363 0.797567 0.504725 + -0.330363 0.797567 0.504725 + -0.330363 0.797567 0.504725 + -0.382683 0.92388 0 + -0.382683 0.92388 0 + -0.382683 0.92388 0 + -0.382683 0.92388 0 + -0.330363 0.797567 -0.504726 + -0.330363 0.797567 -0.504726 + -0.330363 0.797567 -0.504726 + -0.330363 0.797567 -0.504726 + -0.330363 0.797567 -0.504726 + -0.330363 0.797567 -0.504726 + -0.188214 0.454389 -0.870693 + -0.188214 0.454389 -0.870693 + -0.188214 0.454389 -0.870693 + -0.188214 0.454389 -0.870693 + -0.188214 0.454389 -0.870693 + -0.188214 0.454389 -0.870693 + -0.188214 0.454389 -0.870693 + 0.00412589 -0.00996107 -0.999942 + 0.00412589 -0.00996107 -0.999942 + 0.00412589 -0.00996107 -0.999942 + 0.00412589 -0.00996107 -0.999942 + 0.00412589 -0.00996107 -0.999942 + 0.00412589 -0.00996107 -0.999942 + 0.194403 -0.469332 -0.861356 + 0.194403 -0.469332 -0.861356 + 0.194403 -0.469332 -0.861356 + 0.194403 -0.469332 -0.861356 + 0.194403 -0.469332 -0.861356 + 0.194403 -0.469332 -0.861356 + 0.332427 -0.802549 -0.495386 + 0.332427 -0.802549 -0.495386 + 0.332427 -0.802549 -0.495386 + 0.332427 -0.802549 -0.495386 + 0.332427 -0.802549 -0.495386 + 0.332427 -0.802549 -0.495386 + 0.332427 -0.802549 -0.495386 + 0.5 -0.866025 1.35291e-06 + 0.5 -0.866025 1.35291e-06 + 0.5 -0.866025 1.35291e-06 + 0.5 -0.866025 1.35291e-06 + 0.5 -0.866025 1.35291e-06 + 0.5 -0.866025 1.35291e-06 + 0.434336 -0.752291 0.495389 + 0.434336 -0.752291 0.495389 + 0.434336 -0.752291 0.495389 + 0.434336 -0.752291 0.495389 + 0.434336 -0.752291 0.495389 + 0.434336 -0.752291 0.495389 + 0.254001 -0.439941 0.861357 + 0.254001 -0.439941 0.861357 + 0.254001 -0.439941 0.861357 + 0.254001 -0.439941 0.861357 + 0.254001 -0.439941 0.861357 + 0.254001 -0.439941 0.861357 + 0.00539184 -0.00933885 0.999942 + 0.00539184 -0.00933885 0.999942 + 0.00539184 -0.00933885 0.999942 + 0.00539184 -0.00933885 0.999942 + 0.00539184 -0.00933885 0.999942 + -0.245913 0.425933 0.870694 + -0.245913 0.425933 0.870694 + -0.245913 0.425933 0.870694 + -0.245913 0.425933 0.870694 + -0.245913 0.425933 0.870694 + -0.245913 0.425933 0.870694 + -0.245913 0.425933 0.870694 + -0.431639 0.747621 0.504729 + -0.431639 0.747621 0.504729 + -0.431639 0.747621 0.504729 + -0.431639 0.747621 0.504729 + -0.431639 0.747621 0.504729 + -0.5 0.866025 0 + -0.5 0.866025 0 + -0.5 0.866025 0 + -0.5 0.866025 0 + -0.5 0.866025 0 + -0.5 0.866025 0 + -0.5 0.866025 0 + -0.5 0.866025 0 + -0.43164 0.747621 -0.504727 + -0.43164 0.747621 -0.504727 + -0.43164 0.747621 -0.504727 + -0.43164 0.747621 -0.504727 + -0.43164 0.747621 -0.504727 + -0.43164 0.747621 -0.504727 + -0.245913 0.425934 -0.870694 + -0.245913 0.425934 -0.870694 + -0.245913 0.425934 -0.870694 + -0.245913 0.425934 -0.870694 + -0.245913 0.425934 -0.870694 + -0.245913 0.425934 -0.870694 + 0.00539201 -0.00933921 -0.999942 + 0.00539201 -0.00933921 -0.999942 + 0.00539201 -0.00933921 -0.999942 + 0.00539201 -0.00933921 -0.999942 + 0.00539201 -0.00933921 -0.999942 + 0.254001 -0.439942 -0.861356 + 0.254001 -0.439942 -0.861356 + 0.254001 -0.439942 -0.861356 + 0.254001 -0.439942 -0.861356 + 0.254001 -0.439942 -0.861356 + 0.254001 -0.439942 -0.861356 + 0.434336 -0.752292 -0.495387 + 0.434336 -0.752292 -0.495387 + 0.434336 -0.752292 -0.495387 + 0.434336 -0.752292 -0.495387 + 0.434336 -0.752292 -0.495387 + 0.434336 -0.752292 -0.495387 + 0.608761 -0.793354 0 + 0.608761 -0.793354 0 + 0.608761 -0.793354 0 + 0.608761 -0.793354 0 + 0.608761 -0.793354 0 + 0.608761 -0.793354 0 + 0.608761 -0.793354 0 + 0.608761 -0.793354 0 + 0.528813 -0.689164 0.495388 + 0.528813 -0.689164 0.495388 + 0.528813 -0.689164 0.495388 + 0.528813 -0.689164 0.495388 + 0.528813 -0.689164 0.495388 + 0.309251 -0.403025 0.861356 + 0.309251 -0.403025 0.861356 + 0.309251 -0.403025 0.861356 + 0.309251 -0.403025 0.861356 + 0.309251 -0.403025 0.861356 + 0.00656521 -0.00855577 0.999942 + 0.00656521 -0.00855577 0.999942 + 0.00656521 -0.00855577 0.999942 + 0.00656521 -0.00855577 0.999942 + 0.00656521 -0.00855577 0.999942 + 0.00656521 -0.00855577 0.999942 + 0.00656521 -0.00855577 0.999942 + -0.299405 0.390193 0.870693 + -0.299405 0.390193 0.870693 + -0.299405 0.390193 0.870693 + -0.299405 0.390193 0.870693 + -0.299405 0.390193 0.870693 + -0.299405 0.390193 0.870693 + -0.299405 0.390193 0.870693 + -0.525533 0.684889 0.50472 + -0.525533 0.684889 0.50472 + -0.525533 0.684889 0.50472 + -0.525533 0.684889 0.50472 + -0.525533 0.684889 0.50472 + -0.608761 0.793354 -1.63469e-06 + -0.608761 0.793354 -1.63469e-06 + -0.608761 0.793354 -1.63469e-06 + -0.608761 0.793354 -1.63469e-06 + -0.608761 0.793354 -1.63469e-06 + -0.608761 0.793354 -1.63469e-06 + -0.525533 0.684888 -0.504721 + -0.525533 0.684888 -0.504721 + -0.525533 0.684888 -0.504721 + -0.525533 0.684888 -0.504721 + -0.525533 0.684888 -0.504721 + -0.299405 0.390193 -0.870693 + -0.299405 0.390193 -0.870693 + -0.299405 0.390193 -0.870693 + -0.299405 0.390193 -0.870693 + -0.299405 0.390193 -0.870693 + -0.299405 0.390193 -0.870693 + -0.299405 0.390193 -0.870693 + 0.0065648 -0.00855529 -0.999942 + 0.0065648 -0.00855529 -0.999942 + 0.0065648 -0.00855529 -0.999942 + 0.0065648 -0.00855529 -0.999942 + 0.0065648 -0.00855529 -0.999942 + 0.0065648 -0.00855529 -0.999942 + 0.309251 -0.403024 -0.861357 + 0.309251 -0.403024 -0.861357 + 0.309251 -0.403024 -0.861357 + 0.309251 -0.403024 -0.861357 + 0.309251 -0.403024 -0.861357 + 0.309251 -0.403024 -0.861357 + 0.528813 -0.689164 -0.495389 + 0.528813 -0.689164 -0.495389 + 0.528813 -0.689164 -0.495389 + 0.528813 -0.689164 -0.495389 + 0.528813 -0.689164 -0.495389 + 0.707106 -0.707107 1.0694e-06 + 0.707106 -0.707107 1.0694e-06 + 0.707106 -0.707107 1.0694e-06 + 0.707106 -0.707107 1.0694e-06 + 0.614243 -0.614244 0.495388 + 0.614243 -0.614244 0.495388 + 0.614243 -0.614244 0.495388 + 0.614243 -0.614244 0.495388 + 0.614243 -0.614244 0.495388 + 0.614243 -0.614244 0.495388 + 0.614243 -0.614244 0.495388 + 0.614243 -0.614244 0.495388 + 0.35921 -0.35921 0.861358 + 0.35921 -0.35921 0.861358 + 0.35921 -0.35921 0.861358 + 0.35921 -0.35921 0.861358 + 0.35921 -0.35921 0.861358 + 0.00762439 -0.00762427 0.999942 + 0.00762439 -0.00762427 0.999942 + 0.00762439 -0.00762427 0.999942 + 0.00762439 -0.00762427 0.999942 + 0.00762439 -0.00762427 0.999942 + 0.00762439 -0.00762427 0.999942 + -0.347775 0.347775 0.870693 + -0.347775 0.347775 0.870693 + -0.347775 0.347775 0.870693 + -0.347775 0.347775 0.870693 + -0.347775 0.347775 0.870693 + -0.347775 0.347775 0.870693 + -0.610431 0.610431 0.504725 + -0.610431 0.610431 0.504725 + -0.610431 0.610431 0.504725 + -0.610431 0.610431 0.504725 + -0.610431 0.610431 0.504725 + -0.610431 0.610431 0.504725 + -0.610431 0.610431 0.504725 + -0.707107 0.707107 0 + -0.707107 0.707107 0 + -0.707107 0.707107 0 + -0.707107 0.707107 0 + -0.610431 0.610431 -0.504725 + -0.610431 0.610431 -0.504725 + -0.610431 0.610431 -0.504725 + -0.610431 0.610431 -0.504725 + -0.610431 0.610431 -0.504725 + -0.610431 0.610431 -0.504725 + -0.610431 0.610431 -0.504725 + -0.347775 0.347775 -0.870692 + -0.347775 0.347775 -0.870692 + -0.347775 0.347775 -0.870692 + -0.347775 0.347775 -0.870692 + -0.347775 0.347775 -0.870692 + 0.00762439 -0.00762427 -0.999942 + 0.00762439 -0.00762427 -0.999942 + 0.00762439 -0.00762427 -0.999942 + 0.00762439 -0.00762427 -0.999942 + 0.00762439 -0.00762427 -0.999942 + 0.00762439 -0.00762427 -0.999942 + 0.00762439 -0.00762427 -0.999942 + 0.00762439 -0.00762427 -0.999942 + 0.35921 -0.35921 -0.861358 + 0.35921 -0.35921 -0.861358 + 0.35921 -0.35921 -0.861358 + 0.35921 -0.35921 -0.861358 + 0.614244 -0.614244 -0.495387 + 0.614244 -0.614244 -0.495387 + 0.614244 -0.614244 -0.495387 + 0.614244 -0.614244 -0.495387 + 0.614244 -0.614244 -0.495387 + 0.614244 -0.614244 -0.495387 + 0.614244 -0.614244 -0.495387 + 0.614244 -0.614244 -0.495387 + 0.793353 -0.608761 -4.57603e-07 + 0.793353 -0.608761 -4.57603e-07 + 0.793353 -0.608761 -4.57603e-07 + 0.793353 -0.608761 -4.57603e-07 + 0.793353 -0.608761 -4.57603e-07 + 0.793353 -0.608761 -4.57603e-07 + 0.689164 -0.528813 0.495389 + 0.689164 -0.528813 0.495389 + 0.689164 -0.528813 0.495389 + 0.689164 -0.528813 0.495389 + 0.689164 -0.528813 0.495389 + 0.689164 -0.528813 0.495389 + 0.403024 -0.309251 0.861357 + 0.403024 -0.309251 0.861357 + 0.403024 -0.309251 0.861357 + 0.403024 -0.309251 0.861357 + 0.403024 -0.309251 0.861357 + 0.403024 -0.309251 0.861357 + 0.00855446 -0.00656408 0.999942 + 0.00855446 -0.00656408 0.999942 + 0.00855446 -0.00656408 0.999942 + 0.00855446 -0.00656408 0.999942 + 0.00855446 -0.00656408 0.999942 + 0.00855446 -0.00656408 0.999942 + -0.39019 0.299404 0.870695 + -0.39019 0.299404 0.870695 + -0.39019 0.299404 0.870695 + -0.39019 0.299404 0.870695 + -0.39019 0.299404 0.870695 + -0.39019 0.299404 0.870695 + -0.684885 0.525531 0.504727 + -0.684885 0.525531 0.504727 + -0.684885 0.525531 0.504727 + -0.684885 0.525531 0.504727 + -0.684885 0.525531 0.504727 + -0.684885 0.525531 0.504727 + -0.793354 0.608761 -3.01808e-07 + -0.793354 0.608761 -3.01808e-07 + -0.793354 0.608761 -3.01808e-07 + -0.793354 0.608761 -3.01808e-07 + -0.793354 0.608761 -3.01808e-07 + -0.793354 0.608761 -3.01808e-07 + -0.684885 0.525531 -0.504728 + -0.684885 0.525531 -0.504728 + -0.684885 0.525531 -0.504728 + -0.684885 0.525531 -0.504728 + -0.684885 0.525531 -0.504728 + -0.684885 0.525531 -0.504728 + -0.39019 0.299404 -0.870695 + -0.39019 0.299404 -0.870695 + -0.39019 0.299404 -0.870695 + -0.39019 0.299404 -0.870695 + -0.39019 0.299404 -0.870695 + -0.39019 0.299404 -0.870695 + -0.39019 0.299404 -0.870695 + 0.00855458 -0.00656414 -0.999942 + 0.00855458 -0.00656414 -0.999942 + 0.00855458 -0.00656414 -0.999942 + 0.00855458 -0.00656414 -0.999942 + 0.00855458 -0.00656414 -0.999942 + 0.403024 -0.309251 -0.861356 + 0.403024 -0.309251 -0.861356 + 0.403024 -0.309251 -0.861356 + 0.403024 -0.309251 -0.861356 + 0.403024 -0.309251 -0.861356 + 0.403024 -0.309251 -0.861356 + 0.689164 -0.528814 -0.495389 + 0.689164 -0.528814 -0.495389 + 0.689164 -0.528814 -0.495389 + 0.689164 -0.528814 -0.495389 + 0.689164 -0.528814 -0.495389 + 0.689164 -0.528814 -0.495389 + 0.866025 -0.5 2.18853e-07 + 0.866025 -0.5 2.18853e-07 + 0.866025 -0.5 2.18853e-07 + 0.866025 -0.5 2.18853e-07 + 0.866025 -0.5 2.18853e-07 + 0.866025 -0.5 2.18853e-07 + 0.752291 -0.434336 0.495389 + 0.752291 -0.434336 0.495389 + 0.752291 -0.434336 0.495389 + 0.752291 -0.434336 0.495389 + 0.752291 -0.434336 0.495389 + 0.752291 -0.434336 0.495389 + 0.439941 -0.254 0.861357 + 0.439941 -0.254 0.861357 + 0.439941 -0.254 0.861357 + 0.439941 -0.254 0.861357 + 0.439941 -0.254 0.861357 + 0.439941 -0.254 0.861357 + 0.00933772 -0.0053913 0.999942 + 0.00933772 -0.0053913 0.999942 + 0.00933772 -0.0053913 0.999942 + 0.00933772 -0.0053913 0.999942 + 0.00933772 -0.0053913 0.999942 + 0.00933772 -0.0053913 0.999942 + 0.00933772 -0.0053913 0.999942 + -0.425935 0.245913 0.870693 + -0.425935 0.245913 0.870693 + -0.425935 0.245913 0.870693 + -0.425935 0.245913 0.870693 + -0.425935 0.245913 0.870693 + -0.747623 0.431641 0.504724 + -0.747623 0.431641 0.504724 + -0.747623 0.431641 0.504724 + -0.747623 0.431641 0.504724 + -0.747623 0.431641 0.504724 + -0.866025 0.5 0 + -0.866025 0.5 0 + -0.866025 0.5 0 + -0.866025 0.5 0 + -0.866025 0.5 0 + -0.866025 0.5 0 + -0.866025 0.5 0 + -0.866025 0.5 0 + -0.747623 0.431641 -0.504724 + -0.747623 0.431641 -0.504724 + -0.747623 0.431641 -0.504724 + -0.747623 0.431641 -0.504724 + -0.747623 0.431641 -0.504724 + -0.425934 0.245913 -0.870693 + -0.425934 0.245913 -0.870693 + -0.425934 0.245913 -0.870693 + -0.425934 0.245913 -0.870693 + -0.425934 0.245913 -0.870693 + 0.00933796 -0.00539142 -0.999942 + 0.00933796 -0.00539142 -0.999942 + 0.00933796 -0.00539142 -0.999942 + 0.00933796 -0.00539142 -0.999942 + 0.00933796 -0.00539142 -0.999942 + 0.00933796 -0.00539142 -0.999942 + 0.00933796 -0.00539142 -0.999942 + 0.439941 -0.254 -0.861357 + 0.439941 -0.254 -0.861357 + 0.439941 -0.254 -0.861357 + 0.439941 -0.254 -0.861357 + 0.439941 -0.254 -0.861357 + 0.439941 -0.254 -0.861357 + 0.752292 -0.434336 -0.495389 + 0.752292 -0.434336 -0.495389 + 0.752292 -0.434336 -0.495389 + 0.752292 -0.434336 -0.495389 + 0.752292 -0.434336 -0.495389 + 0.752292 -0.434336 -0.495389 + 0.92388 -0.382684 -1.83725e-07 + 0.92388 -0.382684 -1.83725e-07 + 0.92388 -0.382684 -1.83725e-07 + 0.92388 -0.382684 -1.83725e-07 + 0.92388 -0.382684 -1.83725e-07 + 0.92388 -0.382684 -1.83725e-07 + 0.92388 -0.382684 -1.83725e-07 + 0.802548 -0.332426 0.495388 + 0.802548 -0.332426 0.495388 + 0.802548 -0.332426 0.495388 + 0.802548 -0.332426 0.495388 + 0.802548 -0.332426 0.495388 + 0.469332 -0.194403 0.861356 + 0.469332 -0.194403 0.861356 + 0.469332 -0.194403 0.861356 + 0.469332 -0.194403 0.861356 + 0.469332 -0.194403 0.861356 + 0.469332 -0.194403 0.861356 + 0.469332 -0.194403 0.861356 + 0.00996214 -0.00412631 0.999942 + 0.00996214 -0.00412631 0.999942 + 0.00996214 -0.00412631 0.999942 + 0.00996214 -0.00412631 0.999942 + 0.00996214 -0.00412631 0.999942 + 0.00996214 -0.00412631 0.999942 + -0.454389 0.188215 0.870693 + -0.454389 0.188215 0.870693 + -0.454389 0.188215 0.870693 + -0.454389 0.188215 0.870693 + -0.454389 0.188215 0.870693 + -0.797567 0.330364 0.504724 + -0.797567 0.330364 0.504724 + -0.797567 0.330364 0.504724 + -0.797567 0.330364 0.504724 + -0.797567 0.330364 0.504724 + -0.797567 0.330364 0.504724 + -0.797567 0.330364 0.504724 + -0.92388 0.382684 3.33754e-07 + -0.92388 0.382684 3.33754e-07 + -0.92388 0.382684 3.33754e-07 + -0.92388 0.382684 3.33754e-07 + -0.92388 0.382684 3.33754e-07 + -0.797567 0.330363 -0.504724 + -0.797567 0.330363 -0.504724 + -0.797567 0.330363 -0.504724 + -0.797567 0.330363 -0.504724 + -0.797567 0.330363 -0.504724 + -0.797567 0.330363 -0.504724 + -0.797567 0.330363 -0.504724 + -0.454389 0.188214 -0.870693 + -0.454389 0.188214 -0.870693 + -0.454389 0.188214 -0.870693 + -0.454389 0.188214 -0.870693 + -0.454389 0.188214 -0.870693 + -0.454389 0.188214 -0.870693 + 0.00996202 -0.00412631 -0.999942 + 0.00996202 -0.00412631 -0.999942 + 0.00996202 -0.00412631 -0.999942 + 0.00996202 -0.00412631 -0.999942 + 0.00996202 -0.00412631 -0.999942 + 0.00996202 -0.00412631 -0.999942 + 0.469332 -0.194404 -0.861356 + 0.469332 -0.194404 -0.861356 + 0.469332 -0.194404 -0.861356 + 0.469332 -0.194404 -0.861356 + 0.469332 -0.194404 -0.861356 + 0.469332 -0.194404 -0.861356 + 0.469332 -0.194404 -0.861356 + 0.802548 -0.332426 -0.495388 + 0.802548 -0.332426 -0.495388 + 0.802548 -0.332426 -0.495388 + 0.802548 -0.332426 -0.495388 + 0.965926 -0.258819 2.9253e-07 + 0.965926 -0.258819 2.9253e-07 + 0.965926 -0.258819 2.9253e-07 + 0.965926 -0.258819 2.9253e-07 + 0.965926 -0.258819 2.9253e-07 + 0.965926 -0.258819 2.9253e-07 + 0.965926 -0.258819 2.9253e-07 + 0.839073 -0.224829 0.495388 + 0.839073 -0.224829 0.495388 + 0.839073 -0.224829 0.495388 + 0.839073 -0.224829 0.495388 + 0.839073 -0.224829 0.495388 + 0.839073 -0.224829 0.495388 + 0.490691 -0.13148 0.861356 + 0.490691 -0.13148 0.861356 + 0.490691 -0.13148 0.861356 + 0.490691 -0.13148 0.861356 + 0.490691 -0.13148 0.861356 + 0.0104153 -0.00279087 0.999942 + 0.0104153 -0.00279087 0.999942 + 0.0104153 -0.00279087 0.999942 + 0.0104153 -0.00279087 0.999942 + 0.0104153 -0.00279087 0.999942 + 0.0104153 -0.00279087 0.999942 + -0.475068 0.127294 0.870693 + -0.475068 0.127294 0.870693 + -0.475068 0.127294 0.870693 + -0.475068 0.127294 0.870693 + -0.475068 0.127294 0.870693 + -0.475068 0.127294 0.870693 + -0.833864 0.223433 0.504726 + -0.833864 0.223433 0.504726 + -0.833864 0.223433 0.504726 + -0.833864 0.223433 0.504726 + -0.833864 0.223433 0.504726 + -0.833864 0.223433 0.504726 + -0.965926 0.258819 0 + -0.965926 0.258819 0 + -0.965926 0.258819 0 + -0.965926 0.258819 0 + -0.965926 0.258819 0 + -0.965926 0.258819 0 + -0.965926 0.258819 0 + -0.833864 0.223433 -0.504726 + -0.833864 0.223433 -0.504726 + -0.833864 0.223433 -0.504726 + -0.833864 0.223433 -0.504726 + -0.833864 0.223433 -0.504726 + -0.475067 0.127294 -0.870694 + -0.475067 0.127294 -0.870694 + -0.475067 0.127294 -0.870694 + -0.475067 0.127294 -0.870694 + -0.475067 0.127294 -0.870694 + -0.475067 0.127294 -0.870694 + 0.0104153 -0.00279087 -0.999942 + 0.0104153 -0.00279087 -0.999942 + 0.0104153 -0.00279087 -0.999942 + 0.0104153 -0.00279087 -0.999942 + 0.0104153 -0.00279087 -0.999942 + 0.0104153 -0.00279087 -0.999942 + 0.490691 -0.13148 -0.861356 + 0.490691 -0.13148 -0.861356 + 0.490691 -0.13148 -0.861356 + 0.490691 -0.13148 -0.861356 + 0.490691 -0.13148 -0.861356 + 0.839073 -0.224829 -0.495387 + 0.839073 -0.224829 -0.495387 + 0.839073 -0.224829 -0.495387 + 0.839073 -0.224829 -0.495387 + 0.839073 -0.224829 -0.495387 + 0.839073 -0.224829 -0.495387 + 0.839073 -0.224829 -0.495387 + 0.991445 -0.130526 0 + 0.991445 -0.130526 0 + 0.991445 -0.130526 0 + 0.991445 -0.130526 0 + 0.86124 -0.113384 0.495389 + 0.86124 -0.113384 0.495389 + 0.86124 -0.113384 0.495389 + 0.86124 -0.113384 0.495389 + 0.86124 -0.113384 0.495389 + 0.86124 -0.113384 0.495389 + 0.86124 -0.113384 0.495389 + 0.503654 -0.0663071 0.861357 + 0.503654 -0.0663071 0.861357 + 0.503654 -0.0663071 0.861357 + 0.503654 -0.0663071 0.861357 + 0.503654 -0.0663071 0.861357 + 0.503654 -0.0663071 0.861357 + 0.0106912 -0.00140738 0.999942 + 0.0106912 -0.00140738 0.999942 + 0.0106912 -0.00140738 0.999942 + 0.0106912 -0.00140738 0.999942 + 0.0106912 -0.00140738 0.999942 + 0.0106912 -0.00140738 0.999942 + -0.48762 0.0641962 0.870693 + -0.48762 0.0641962 0.870693 + -0.48762 0.0641962 0.870693 + -0.48762 0.0641962 0.870693 + -0.48762 0.0641962 0.870693 + -0.48762 0.0641962 0.870693 + -0.48762 0.0641962 0.870693 + -0.855897 0.112681 0.504722 + -0.855897 0.112681 0.504722 + -0.855897 0.112681 0.504722 + -0.855897 0.112681 0.504722 + -0.855897 0.112681 0.504722 + -0.991445 0.130526 0 + -0.991445 0.130526 0 + -0.991445 0.130526 0 + -0.991445 0.130526 0 + -0.991445 0.130526 0 + -0.991445 0.130526 0 + -0.855897 0.112681 -0.504722 + -0.855897 0.112681 -0.504722 + -0.855897 0.112681 -0.504722 + -0.855897 0.112681 -0.504722 + -0.855897 0.112681 -0.504722 + -0.855897 0.112681 -0.504722 + -0.48762 0.0641961 -0.870693 + -0.48762 0.0641961 -0.870693 + -0.48762 0.0641961 -0.870693 + -0.48762 0.0641961 -0.870693 + -0.48762 0.0641961 -0.870693 + -0.48762 0.0641961 -0.870693 + 0.0106912 -0.00140738 -0.999942 + 0.0106912 -0.00140738 -0.999942 + 0.0106912 -0.00140738 -0.999942 + 0.0106912 -0.00140738 -0.999942 + 0.0106912 -0.00140738 -0.999942 + 0.0106912 -0.00140738 -0.999942 + 0.503654 -0.0663071 -0.861357 + 0.503654 -0.0663071 -0.861357 + 0.503654 -0.0663071 -0.861357 + 0.503654 -0.0663071 -0.861357 + 0.503654 -0.0663071 -0.861357 + 0.503654 -0.0663071 -0.861357 + 0.86124 -0.113384 -0.495389 + 0.86124 -0.113384 -0.495389 + 0.86124 -0.113384 -0.495389 + 0.86124 -0.113384 -0.495389 + 0.86124 -0.113384 -0.495389 + 0.86124 -0.113384 -0.495389 + 0.86124 -0.113384 -0.495389 + } + } + } + } + } + } + } + } + } + Matrix { + 0.00394446 0 0 0 + 0 0.00394446 0 0 + 0 0 0.00394446 0 + 0 0 0 1 + } + + } + } + Matrix { + 253.52 0 0 0 + 0 253.52 0 0 + 0 0 253.52 0 + 0 0 0 1 + } + + } + } +} From 6f9b813bd1da8cbb9896e42fffb5a5db0644877d Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Mon, 14 Jul 2025 22:39:19 +0200 Subject: [PATCH 234/330] Mark scripts on newly scripted, active objects as active --- apps/openmw/mwlua/localscripts.cpp | 13 ++++++++----- apps/openmw/mwlua/localscripts.hpp | 2 +- apps/openmw/mwlua/luamanagerimp.cpp | 3 +++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwlua/localscripts.cpp b/apps/openmw/mwlua/localscripts.cpp index 4bdfb0d13a..d784328035 100644 --- a/apps/openmw/mwlua/localscripts.cpp +++ b/apps/openmw/mwlua/localscripts.cpp @@ -235,13 +235,16 @@ namespace MWLua &mOnSkillLevelUp }); } - void LocalScripts::setActive(bool active) + void LocalScripts::setActive(bool active, bool callHandlers) { mData.mIsActive = active; - if (active) - callEngineHandlers(mOnActiveHandlers); - else - callEngineHandlers(mOnInactiveHandlers); + if (callHandlers) + { + if (active) + callEngineHandlers(mOnActiveHandlers); + else + callEngineHandlers(mOnInactiveHandlers); + } } void LocalScripts::applyStatsCache() diff --git a/apps/openmw/mwlua/localscripts.hpp b/apps/openmw/mwlua/localscripts.hpp index adbf20292d..146eff95ba 100644 --- a/apps/openmw/mwlua/localscripts.hpp +++ b/apps/openmw/mwlua/localscripts.hpp @@ -67,7 +67,7 @@ namespace MWLua MWBase::LuaManager::ActorControls* getActorControls() { return &mData.mControls; } const MWWorld::Ptr& getPtrOrEmpty() const { return mData.ptrOrEmpty(); } - void setActive(bool active); + void setActive(bool active, bool callHandlers = true); bool isActive() const override { return mData.mIsActive; } void onConsume(const LObject& consumable) { callEngineHandlers(mOnConsumeHandlers, consumable); } void onActivated(const LObject& actor) { callEngineHandlers(mOnActivatedHandlers, actor); } diff --git a/apps/openmw/mwlua/luamanagerimp.cpp b/apps/openmw/mwlua/luamanagerimp.cpp index 5fa2d9867c..2fd7618ad7 100644 --- a/apps/openmw/mwlua/luamanagerimp.cpp +++ b/apps/openmw/mwlua/luamanagerimp.cpp @@ -540,7 +540,10 @@ namespace MWLua localScripts = createLocalScripts(ptr); localScripts->addAutoStartedScripts(); if (ptr.isInCell() && MWBase::Environment::get().getWorldScene()->isCellActive(*ptr.getCell())) + { + localScripts->setActive(true, false); mActiveLocalScripts.insert(localScripts); + } } localScripts->addCustomScript(scriptId, initData); } From 8826d5cb0e7dbb3ddbdad79601d2f0681a46222e Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Tue, 15 Jul 2025 15:04:39 +0300 Subject: [PATCH 235/330] Update project leader history --- AUTHORS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index e327bc29d6..51910dedaa 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -10,7 +10,8 @@ If you feel your name is missing from this list, please add it to `AUTHORS.md`. Programmers ----------- - Bret Curtis (psi29a) - Project leader 2019-present + Alexey Dobrokhotov (Capo) - Project leader 2025-present + Bret Curtis (psi29a) - Project leader 2019-2025 Marc Zinnschlag (Zini) - Project leader 2010-2018 Nicolay Korslund - Project leader 2008-2010 scrawl - Top contributor @@ -49,7 +50,6 @@ Programmers Berulacks Bo Svensson Britt Mathis (galdor557) - Capostrophic Carl Maxwell cc9cii Cédric Mocquillon From d602e9ff7a70175e23a4f8718450e3a89d573e59 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Tue, 15 Jul 2025 18:05:32 +0300 Subject: [PATCH 236/330] Don't build the engine, the editor and editor tests multiple times in Clang Tidy jobs --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1ca0d4251e..8d1e19d462 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -414,7 +414,7 @@ Ubuntu_Clang_Tidy_openmw: needs: - Ubuntu_Clang_Tidy_components variables: - BUILD_TARGETS: openmw + BUILD_TARGETS: openmw openmw-tests timeout: 3h Ubuntu_Clang_Tidy_openmw-cs: @@ -430,7 +430,7 @@ Ubuntu_Clang_Tidy_other: needs: - Ubuntu_Clang_Tidy_components variables: - BUILD_TARGETS: bsatool esmtool openmw-launcher openmw-iniimporter openmw-essimporter openmw-wizard niftest components-tests openmw-tests openmw-cs-tests openmw-navmeshtool openmw-bulletobjecttool + BUILD_TARGETS: components-tests bsatool esmtool openmw-launcher openmw-iniimporter openmw-essimporter openmw-wizard niftest openmw-navmeshtool openmw-bulletobjecttool timeout: 3h .Ubuntu_Clang_tests: From 931555c7ffdf6a39b47e2ea494893f044bf8045d Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Tue, 15 Jul 2025 21:57:12 +0200 Subject: [PATCH 237/330] Remove int conversions from pathfinding --- apps/openmw/mwmechanics/aicombat.cpp | 6 +++--- apps/openmw/mwmechanics/aiwander.cpp | 4 ++-- apps/openmw/mwmechanics/pathfinding.cpp | 14 +++++++------- apps/openmw/mwmechanics/pathfinding.hpp | 6 +++--- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 1b0b0e5a89..a6f9935194 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -393,13 +393,13 @@ namespace MWMechanics osg::Vec3f localPos = actor.getRefData().getPosition().asVec3(); coords.toLocal(localPos); - int closestPointIndex = PathFinder::getClosestPoint(pathgrid, localPos); - for (int i = 0; i < static_cast(pathgrid->mPoints.size()); i++) + size_t closestPointIndex = PathFinder::getClosestPoint(pathgrid, localPos); + for (size_t i = 0; i < pathgrid->mPoints.size(); i++) { if (i != closestPointIndex && getPathGridGraph(pathgrid).isPointConnected(closestPointIndex, i)) { - points.push_back(pathgrid->mPoints[static_cast(i)]); + points.push_back(pathgrid->mPoints[i]); } } diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 464d83ad46..3cc7aac838 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -827,7 +827,7 @@ namespace MWMechanics if (pathgrid == nullptr || pathgrid->mPoints.empty()) return; - int index = PathFinder::getClosestPoint(pathgrid, PathFinder::makeOsgVec3(dest)); + size_t index = PathFinder::getClosestPoint(pathgrid, PathFinder::makeOsgVec3(dest)); getPathGridGraph(pathgrid).getNeighbouringPoints(index, points); } @@ -860,7 +860,7 @@ namespace MWMechanics const osg::Vec3f npcPos = converter.toLocalVec3(mInitialActorPosition); // Find closest pathgrid point - int closestPointIndex = PathFinder::getClosestPoint(pathgrid, npcPos); + size_t closestPointIndex = PathFinder::getClosestPoint(pathgrid, npcPos); // mAllowedNodes for this actor with pathgrid point indexes based on mDistance // and if the point is connected to the closest current point diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 192cbdfe22..dc9d8e4061 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -25,15 +25,15 @@ namespace { // Chooses a reachable end pathgrid point. start is assumed reachable. - std::pair getClosestReachablePoint( - const ESM::Pathgrid* grid, const MWMechanics::PathgridGraph* graph, const osg::Vec3f& pos, int start) + std::pair getClosestReachablePoint( + const ESM::Pathgrid* grid, const MWMechanics::PathgridGraph* graph, const osg::Vec3f& pos, size_t start) { assert(grid && !grid->mPoints.empty()); float closestDistanceBetween = std::numeric_limits::max(); float closestDistanceReachable = std::numeric_limits::max(); - int closestIndex = 0; - int closestReachableIndex = 0; + size_t closestIndex = 0; + size_t closestReachableIndex = 0; // TODO: if this full scan causes performance problems mapping pathgrid // points to a quadtree may help for (size_t counter = 0; counter < grid->mPoints.size(); counter++) @@ -62,7 +62,7 @@ namespace // allowed nodes if not. Hence a path needs to be created even if the start // and the end points are the same. - return std::pair(closestReachableIndex, closestReachableIndex == closestIndex); + return { closestReachableIndex, closestReachableIndex == closestIndex }; } float sqrDistance(const osg::Vec2f& lhs, const osg::Vec2f& rhs) @@ -197,10 +197,10 @@ namespace MWMechanics // point right behind the wall that is closer than any pathgrid // point outside the wall osg::Vec3f startPointInLocalCoords(converter.toLocalVec3(startPoint)); - int startNode = getClosestPoint(pathgrid, startPointInLocalCoords); + size_t startNode = getClosestPoint(pathgrid, startPointInLocalCoords); osg::Vec3f endPointInLocalCoords(converter.toLocalVec3(endPoint)); - std::pair endNode + std::pair endNode = getClosestReachablePoint(pathgrid, &pathgridGraph, endPointInLocalCoords, startNode); // if it's shorter for actor to travel from start to end, than to travel from either diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 0f688686cd..94242404e4 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -178,16 +178,16 @@ namespace MWMechanics // // NOTE: pos is expected to be in local coordinates, as is grid->mPoints // - static int getClosestPoint(const ESM::Pathgrid* grid, const osg::Vec3f& pos) + static size_t getClosestPoint(const ESM::Pathgrid* grid, const osg::Vec3f& pos) { assert(grid && !grid->mPoints.empty()); float distanceBetween = distanceSquared(grid->mPoints[0], pos); - int closestIndex = 0; + size_t closestIndex = 0; // TODO: if this full scan causes performance problems mapping pathgrid // points to a quadtree may help - for (unsigned int counter = 1; counter < grid->mPoints.size(); counter++) + for (size_t counter = 1; counter < grid->mPoints.size(); counter++) { float potentialDistBetween = distanceSquared(grid->mPoints[counter], pos); if (potentialDistBetween < distanceBetween) From 400c5a6dbab6f5ccb4558f1b71876a77c85418ff Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Wed, 16 Jul 2025 01:03:09 +0300 Subject: [PATCH 238/330] Bump mac CI image to macos-15-xcode-16 and tweak trigger rules --- .gitlab-ci.yml | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1ca0d4251e..18872dfbc6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -502,7 +502,14 @@ Ubuntu_GCC_integration_tests_asan: .MacOS: stage: build rules: - - if: $CI_PROJECT_ID == "7107382" + - if: $CI_PROJECT_ID != "7107382" + when: never + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + when: manual + - if: $CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "schedule" + image: macos-15-xcode-16 + tags: + - saas-macos-medium-m1 cache: paths: - ccache/ @@ -537,11 +544,8 @@ Ubuntu_GCC_integration_tests_asan: macOS14_Xcode15_amd64: extends: .MacOS - image: macos-14-xcode-15 - tags: - - saas-macos-medium-m1 cache: - key: macOS14_Xcode15_amd64.v2 + key: macOS15_Xcode16_amd64.v1 variables: CCACHE_SIZE: 3G DMG_IDENTIFIER: amd64 @@ -549,11 +553,8 @@ macOS14_Xcode15_amd64: macOS14_Xcode15_arm64: extends: .MacOS - image: macos-14-xcode-15 - tags: - - saas-macos-medium-m1 cache: - key: macOS14_Xcode15_arm64.v1 + key: macOS15_Xcode16_arm64.v1 variables: DMG_IDENTIFIER: arm64 CCACHE_SIZE: 3G From 4f827b63366ec9e3de52e6623cd032c4d160913e Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Wed, 16 Jul 2025 11:30:21 +0300 Subject: [PATCH 239/330] Rename mac jobs, test caching --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 18872dfbc6..bde2d6a1b9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -542,7 +542,7 @@ Ubuntu_GCC_integration_tests_asan: paths: - build/OpenMW-*.dmg -macOS14_Xcode15_amd64: +macOS15_Xcode16_amd64: extends: .MacOS cache: key: macOS15_Xcode16_amd64.v1 @@ -551,7 +551,7 @@ macOS14_Xcode15_amd64: DMG_IDENTIFIER: amd64 MACOS_AMD64: true -macOS14_Xcode15_arm64: +macOS15_Xcode16_arm64: extends: .MacOS cache: key: macOS15_Xcode16_arm64.v1 From f9c7dc0b20037165e96a7b3e9c75675f084f440d Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Mon, 14 Jul 2025 19:42:00 +0300 Subject: [PATCH 240/330] Sync changelog for 0.50.0 --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e847ec69fd..5435835606 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,16 +6,21 @@ Bug #6039: Next Spell keybind fails while selected enchanted item has multiple copies Bug #6573: Editor: Selection behaves incorrectly on high-DPI displays Bug #6792: Birth sign info box has no line breaks + Bug #7371: Equipping item from inventory does not play a Down sound when equipping fails Bug #7622: Player's marksman weapons don't work on close actors underwater + Bug #7649: The sound and vfx of resisted enchanted items' magic still play Bug #7740: Magic items in the HUD aren't composited correctly Bug #7799: Picking up ingredients while object paging active grid is on may cause a hiccup + Bug #7871: Kwama Queen doesn't start combat with player Bug #8245: The console command ShowVars does not list global mwscripts Bug #8265: Topics are linked incorrectly Bug #8303: On target spells cast by non-actors should fire underwater Bug #8318: Missing global variables are not handled gracefully in dialogue conditions + Bug #8333: Quest status subrecords should not actually cause parsing to skip remaining data Bug #8340: Multi-effect enchantments are too expensive Bug #8341: Repeat shader visitor passes discard parallax Bug #8349: Travel to non-existent cell causes persistent black screen + Bug #8359: Some quick keys menu related issues Bug #8371: Silence affects powers Bug #8375: Moon phase cycle doesn't match Morrowind Bug #8383: Casting bound helm or boots on beast races doesn't cleanup properly @@ -38,12 +43,19 @@ Bug #8593: Render targets do not generate mipmaps Bug #8598: Post processing shaders don't interact with the vfs correctly Bug #8599: Non-ASCII paths in BSA files don't work + Bug #8609: The crosshair is too large + Bug #8610: Terrain normal maps using NormalGL format instead of NormalDX + Bug #8612: Using aiactivate on an ingredient when graphical herbalism is enabled triggers non-stop pickup sounds + Bug #8615: Rest/wait time progress speed is different from vanilla + Feature #2522: Support quick item transfer Feature #3769: Allow GetSpellEffects on enchantments Feature #8112: Expose landscape record data to Lua Feature #8113: Support extended selection in autodetected subdirectory dialog + Feature #8139: Editor: Redesign the selection markers Feature #8285: Expose list of active shaders in postprocessing API Feature #8313: Show the character name in the savegame details Feature #8320: Add access mwscript source text to lua api + Feature #8334: Lua: AddTopic equivalent Feature #8355: Lua: Window visibility checking in interfaces.UI Feature #8580: Sort characters in the save loading menu Feature #8597: Lua: Add more built-in event handlers From 183652e51d8e2e0a09f2c3212fb7be1db0f1a6c4 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Wed, 16 Jul 2025 20:18:17 +0200 Subject: [PATCH 241/330] Expose path grids to Lua --- CMakeLists.txt | 2 +- apps/openmw/mwlua/cellbindings.cpp | 42 ++++++++++++++++++++++++++++++ files/lua_api/openmw/core.lua | 20 +++++++++++++- 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a00dafc7ef..b7904ddab8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,7 +82,7 @@ message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) set(OPENMW_VERSION_MINOR 50) set(OPENMW_VERSION_RELEASE 0) -set(OPENMW_LUA_API_REVISION 81) +set(OPENMW_LUA_API_REVISION 82) set(OPENMW_POSTPROCESSING_API_REVISION 3) set(OPENMW_VERSION_COMMITHASH "") diff --git a/apps/openmw/mwlua/cellbindings.cpp b/apps/openmw/mwlua/cellbindings.cpp index 933dba3fda..202186d119 100644 --- a/apps/openmw/mwlua/cellbindings.cpp +++ b/apps/openmw/mwlua/cellbindings.cpp @@ -61,6 +61,10 @@ namespace sol struct is_automagical : std::false_type { }; + template <> + struct is_automagical : std::false_type + { + }; } namespace MWLua @@ -126,6 +130,14 @@ namespace MWLua return sol::nullopt; }); + cellT["pathGrid"] = sol::readonly_property([](const CellT& c) -> const ESM::Pathgrid* { + const ESM::Pathgrid* grid + = MWBase::Environment::get().getESMStore()->get().search(*c.mStore->getCell()); + if (grid && grid->mPoints.empty()) + return nullptr; + return grid; + }); + if constexpr (std::is_same_v) { // only for global scripts cellT["getAll"] = [ids = getPackageToTypeTable(view)](const CellT& cell, sol::optional type) { @@ -286,6 +298,36 @@ namespace MWLua return GObjectList{ std::move(res) }; }; } + + if (view["openmw_cellbindings"] != sol::nil) + return; // Only add the usertype once + + auto pathGridT = view.new_usertype("ESM3_PathGrid"); + pathGridT[sol::meta_function::to_string] = [](const ESM::Pathgrid& rec) -> std::string { + return "ESM3_PathGrid[" + rec.mCell.toDebugString() + "]"; + }; + pathGridT["getPoints"] = [](sol::this_state lua, const ESM::Pathgrid& rec) -> sol::table { + sol::table points(lua, sol::create); + for (const ESM::Pathgrid::Point& point : rec.mPoints) + { + sol::table table(lua, sol::create); + table["autoGenerated"] = point.mAutogenerated == 0; + table["relativePosition"] = osg::Vec3f(point.mX, point.mY, point.mZ); + sol::table edges(lua, sol::create); + table["connections"] = edges; + points.add(table); + } + for (const ESM::Pathgrid::Edge& edge : rec.mEdges) + { + sol::table p1 = points[edge.mV0 + 1]; + sol::table p2 = points[edge.mV1 + 1]; + p1.get("connections").add(p2); + p2.get("connections").add(p1); + } + return points; + }; + + view["openmw_cellbindings"] = true; } void initCellBindingsForLocalScripts(const Context& context) diff --git a/files/lua_api/openmw/core.lua b/files/lua_api/openmw/core.lua index 1ef2c806b0..94fefb2b6d 100644 --- a/files/lua_api/openmw/core.lua +++ b/files/lua_api/openmw/core.lua @@ -295,13 +295,14 @@ -- @field #string id Unique record ID of the cell, based on cell name for interiors and the worldspace for exteriors, or the formID of the cell for ESM4 cells. -- @field #string region Region of the cell. -- @field #boolean isExterior Whether the cell is an exterior cell. "Exterior" means grid of cells where the player can seamless walk from one cell to another without teleports. QuasiExterior (interior with sky) is not an exterior. --- @field #boolean isQuasiExterior (DEPRECATED, use `hasTag("QuasiExterior")`) Whether the cell is a quasi exterior (like interior but with the sky and the wheather). +-- @field #boolean isQuasiExterior (DEPRECATED, use `hasTag("QuasiExterior")`) Whether the cell is a quasi exterior (like interior but with the sky and the weather). -- @field #number gridX Index of the cell by X (only for exteriors). -- @field #number gridY Index of the cell by Y (only for exteriors). -- @field #string worldSpaceId Id of the world space. -- @field #boolean hasWater True if the cell contains water. -- @field #number waterLevel The water level of the cell. (nil if cell has no water). -- @field #boolean hasSky True if in this cell sky should be rendered. +-- @field #PathGrid pathGrid The cell's @{#PathGrid} if it has one. --- -- Returns true if the cell has given tag. @@ -334,6 +335,23 @@ -- local all = cell:getAll() -- local weapons = cell:getAll(types.Weapon) +--- +-- A cell's path grid marking traversable paths. +-- @type PathGrid + +--- +-- Get all points in this path grid. +-- @function [parent=#PathGrid] getPoints +-- @param self +-- @return #list<#PathGridPoint> A list of @{#PathGridPoint}s. + +--- +-- A point in a cell's path grid. +-- @type PathGridPoint +-- @field #boolean autoGenerated True if this node was automatically generated in the editor. +-- @field openmw.util#Vector3 relativePosition The point's position relative to the cell's origin. An exterior cell's origin is its southwest corner. +-- @field #list<#PathGridPoint> connections A list of points connected to this point. + --- -- @type ActiveSpell -- @field #string name The spell or item display name From bd6254b6dff5feb0196e08a5638d776577cb8d4e Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Thu, 17 Jul 2025 08:22:26 +0200 Subject: [PATCH 242/330] Ensure corpses of actors that have moved cells are cleaned up --- apps/openmw/mwworld/cellstore.cpp | 42 +++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 61618c001e..75ee14f627 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -1263,26 +1263,48 @@ namespace MWWorld } } - for (CellRefList::List::iterator it(get().mList.begin()); - it != get().mList.end(); ++it) + // Actors need to respawn here even if they've been moved to another cell + for (LiveCellRefBase& base : get().mList) { - Ptr ptr = getCurrentPtr(&*it); + Ptr ptr = getCurrentPtr(&base); clearCorpse(ptr, mStore); ptr.getClass().respawn(ptr); } - for (CellRefList::List::iterator it(get().mList.begin()); - it != get().mList.end(); ++it) + for (LiveCellRefBase& base : get().mList) { - Ptr ptr = getCurrentPtr(&*it); + Ptr ptr = getCurrentPtr(&base); clearCorpse(ptr, mStore); ptr.getClass().respawn(ptr); } - forEachType([](Ptr ptr) { - // no need to clearCorpse, handled as part of get() + for (LiveCellRefBase& base : get().mList) + { + Ptr ptr = getCurrentPtr(&base); if (!ptr.mRef->isDeleted()) ptr.getClass().respawn(ptr); - return true; - }); + } + for (const auto& [base, _] : mMovedHere) + { + switch (base->getType()) + { + case ESM::Creature::sRecordId: + case ESM::NPC::sRecordId: + case ESM::CreatureLevList::sRecordId: + { + MWWorld::Ptr ptr(base, this); + if (ptr.mRef->isDeleted()) + continue; + // Remove actors that have been dead a while, but don't belong here and didn't get hit by the + // logic above + if (ptr.getClass().isActor()) + clearCorpse(ptr, mStore); + else // Respawn lists in their new position + ptr.getClass().respawn(ptr); + break; + } + default: + break; + } + } } } From f45053ad25f2fb13d15e11022378cb2d95e763b1 Mon Sep 17 00:00:00 2001 From: Andy Lanzone Date: Thu, 17 Jul 2025 07:20:13 -0700 Subject: [PATCH 243/330] Bump libsdl to 2.0.20 --- CMakeLists.txt | 2 +- apps/openmw/mwinput/controllermanager.cpp | 4 ---- components/sdlutil/events.hpp | 2 -- components/sdlutil/sdlinputwrapper.cpp | 2 -- 4 files changed, 1 insertion(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a00dafc7ef..902f89ec27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -466,7 +466,7 @@ find_package(Boost 1.70.0 CONFIG REQUIRED COMPONENTS ${BOOST_COMPONENTS} OPTIONA if(OPENMW_USE_SYSTEM_MYGUI) find_package(MyGUI 3.4.3 REQUIRED) endif() -find_package(SDL2 2.0.10 REQUIRED) +find_package(SDL2 2.0.20 REQUIRED) find_package(OpenAL REQUIRED) find_package(ZLIB REQUIRED) diff --git a/apps/openmw/mwinput/controllermanager.cpp b/apps/openmw/mwinput/controllermanager.cpp index 1a8490d8b7..0bba8bfa32 100644 --- a/apps/openmw/mwinput/controllermanager.cpp +++ b/apps/openmw/mwinput/controllermanager.cpp @@ -349,7 +349,6 @@ namespace MWInput void ControllerManager::enableGyroSensor() { mGyroAvailable = false; -#if SDL_VERSION_ATLEAST(2, 0, 14) SDL_GameController* cntrl = mBindingsManager->getControllerOrNull(); if (!cntrl) return; @@ -361,7 +360,6 @@ namespace MWInput return; } mGyroAvailable = true; -#endif } bool ControllerManager::isGyroAvailable() const @@ -372,7 +370,6 @@ namespace MWInput std::array ControllerManager::getGyroValues() const { float gyro[3] = { 0.f }; -#if SDL_VERSION_ATLEAST(2, 0, 14) SDL_GameController* cntrl = mBindingsManager->getControllerOrNull(); if (cntrl && mGyroAvailable) { @@ -380,7 +377,6 @@ namespace MWInput if (result < 0) Log(Debug::Error) << "Failed to get game controller sensor data: " << SDL_GetError(); } -#endif return std::array({ gyro[0], gyro[1], gyro[2] }); } diff --git a/components/sdlutil/events.hpp b/components/sdlutil/events.hpp index 3ae15e448c..410ee68440 100644 --- a/components/sdlutil/events.hpp +++ b/components/sdlutil/events.hpp @@ -28,7 +28,6 @@ namespace SDLUtil float mY; float mPressure; -#if SDL_VERSION_ATLEAST(2, 0, 14) explicit TouchEvent(const SDL_ControllerTouchpadEvent& arg) : mDevice(arg.touchpad) , mFinger(arg.finger) @@ -37,7 +36,6 @@ namespace SDLUtil , mPressure(arg.pressure) { } -#endif }; /////////////// diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index 41a4f13818..104f83fc6d 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -173,7 +173,6 @@ namespace SDLUtil if (mConListener) mConListener->axisMoved(1, evt.caxis); break; -#if SDL_VERSION_ATLEAST(2, 0, 14) case SDL_CONTROLLERSENSORUPDATE: // controller sensor data is received on demand break; @@ -186,7 +185,6 @@ namespace SDLUtil case SDL_CONTROLLERTOUCHPADUP: mConListener->touchpadReleased(1, TouchEvent(evt.ctouchpad)); break; -#endif case SDL_WINDOWEVENT: handleWindowEvent(evt); break; From b61d8fb585aa7140ccfadcedc1fb58916d3649ac Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Thu, 17 Jul 2025 16:42:24 +0200 Subject: [PATCH 244/330] Use Context::initializeOnce --- apps/openmw/mwlua/cellbindings.cpp | 56 ++++++++++++++---------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwlua/cellbindings.cpp b/apps/openmw/mwlua/cellbindings.cpp index 202186d119..ec64a3cddd 100644 --- a/apps/openmw/mwlua/cellbindings.cpp +++ b/apps/openmw/mwlua/cellbindings.cpp @@ -299,35 +299,33 @@ namespace MWLua }; } - if (view["openmw_cellbindings"] != sol::nil) - return; // Only add the usertype once - - auto pathGridT = view.new_usertype("ESM3_PathGrid"); - pathGridT[sol::meta_function::to_string] = [](const ESM::Pathgrid& rec) -> std::string { - return "ESM3_PathGrid[" + rec.mCell.toDebugString() + "]"; - }; - pathGridT["getPoints"] = [](sol::this_state lua, const ESM::Pathgrid& rec) -> sol::table { - sol::table points(lua, sol::create); - for (const ESM::Pathgrid::Point& point : rec.mPoints) - { - sol::table table(lua, sol::create); - table["autoGenerated"] = point.mAutogenerated == 0; - table["relativePosition"] = osg::Vec3f(point.mX, point.mY, point.mZ); - sol::table edges(lua, sol::create); - table["connections"] = edges; - points.add(table); - } - for (const ESM::Pathgrid::Edge& edge : rec.mEdges) - { - sol::table p1 = points[edge.mV0 + 1]; - sol::table p2 = points[edge.mV1 + 1]; - p1.get("connections").add(p2); - p2.get("connections").add(p1); - } - return points; - }; - - view["openmw_cellbindings"] = true; + if (context.initializeOnce("openmw_cellbindings")) + { + auto pathGridT = view.new_usertype("ESM3_PathGrid"); + pathGridT[sol::meta_function::to_string] = [](const ESM::Pathgrid& rec) -> std::string { + return "ESM3_PathGrid[" + rec.mCell.toDebugString() + "]"; + }; + pathGridT["getPoints"] = [](sol::this_state lua, const ESM::Pathgrid& rec) -> sol::table { + sol::table points(lua, sol::create); + for (const ESM::Pathgrid::Point& point : rec.mPoints) + { + sol::table table(lua, sol::create); + table["autoGenerated"] = point.mAutogenerated == 0; + table["relativePosition"] = osg::Vec3f(point.mX, point.mY, point.mZ); + sol::table edges(lua, sol::create); + table["connections"] = edges; + points.add(table); + } + for (const ESM::Pathgrid::Edge& edge : rec.mEdges) + { + sol::table p1 = points[edge.mV0 + 1]; + sol::table p2 = points[edge.mV1 + 1]; + p1.get("connections").add(p2); + p2.get("connections").add(p1); + } + return points; + }; + } } void initCellBindingsForLocalScripts(const Context& context) From 67961213055070f31abb01d1b3a3b264b34aa73b Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Thu, 17 Jul 2025 20:18:57 +0300 Subject: [PATCH 245/330] Use zlib directly for BSA file decompression (#8569) --- components/bsa/ba2dx10file.cpp | 49 ++++++++++------------------ components/bsa/ba2gnrlfile.cpp | 32 +++++------------- components/bsa/compressedbsafile.cpp | 39 +++++++++------------- 3 files changed, 42 insertions(+), 78 deletions(-) diff --git a/components/bsa/ba2dx10file.cpp b/components/bsa/ba2dx10file.cpp index a438121d5b..afb2c0a4aa 100644 --- a/components/bsa/ba2dx10file.cpp +++ b/components/bsa/ba2dx10file.cpp @@ -1,29 +1,12 @@ #include "ba2dx10file.hpp" +#include #include +#include #include #include -#include - -#if defined(_MSC_VER) -// why is this necessary? These are included with /external:I -#pragma warning(push) -#pragma warning(disable : 4706) -#pragma warning(disable : 4702) -#include -#include -#include -#include -#pragma warning(pop) -#else -#include -#include -#include -#include -#endif - -#include +#include #include #include @@ -644,11 +627,16 @@ namespace Bsa size_t headerSize = (header.ddspf.fourCC == ESM::fourCC("DX10") ? sizeof(DDSHeaderDX10) : sizeof(DDSHeader)); size_t textureSize = sizeof(uint32_t) + headerSize; //"DDS " + header + uint32_t maxPackedChunkSize = 0; for (const auto& textureChunk : fileRecord.texturesChunks) + { textureSize += textureChunk.size; + maxPackedChunkSize = std::max(textureChunk.packedSize, maxPackedChunkSize); + } auto memoryStreamPtr = std::make_unique(textureSize); char* buff = memoryStreamPtr->getRawData(); + std::vector inputBuffer(maxPackedChunkSize); uint32_t dds = ESM::fourCC("DDS "); buff = (char*)std::memcpy(buff, &dds, sizeof(uint32_t)) + sizeof(uint32_t); @@ -658,25 +646,22 @@ namespace Bsa // append chunks for (const auto& c : fileRecord.texturesChunks) { + const uint32_t inputSize = c.packedSize != 0 ? c.packedSize : c.size; + Files::IStreamPtr streamPtr = Files::openConstrainedFileStream(mFilepath, c.offset, inputSize); if (c.packedSize != 0) { - Files::IStreamPtr streamPtr = Files::openConstrainedFileStream(mFilepath, c.offset, c.packedSize); - std::istream* fileStream = streamPtr.get(); + streamPtr->read(inputBuffer.data(), c.packedSize); + uLongf destSize = static_cast(c.size); + int ec = ::uncompress(reinterpret_cast(memoryStreamPtr->getRawData() + offset), &destSize, + reinterpret_cast(inputBuffer.data()), static_cast(c.packedSize)); - boost::iostreams::filtering_streambuf inputStreamBuf; - inputStreamBuf.push(boost::iostreams::zlib_decompressor()); - inputStreamBuf.push(*fileStream); - - boost::iostreams::basic_array_sink sr(memoryStreamPtr->getRawData() + offset, c.size); - boost::iostreams::copy(inputStreamBuf, sr); + if (ec != Z_OK) + fail("zlib uncompress failed: " + std::string(::zError(ec))); } // uncompressed chunk else { - Files::IStreamPtr streamPtr = Files::openConstrainedFileStream(mFilepath, c.offset, c.size); - std::istream* fileStream = streamPtr.get(); - - fileStream->read(memoryStreamPtr->getRawData() + offset, c.size); + streamPtr->read(memoryStreamPtr->getRawData() + offset, c.size); } offset += c.size; } diff --git a/components/bsa/ba2gnrlfile.cpp b/components/bsa/ba2gnrlfile.cpp index 75e7305245..f169440208 100644 --- a/components/bsa/ba2gnrlfile.cpp +++ b/components/bsa/ba2gnrlfile.cpp @@ -1,27 +1,11 @@ #include "ba2gnrlfile.hpp" +#include #include #include #include -#include - -#if defined(_MSC_VER) -// why is this necessary? These are included with /external:I -#pragma warning(push) -#pragma warning(disable : 4706) -#pragma warning(disable : 4702) -#include -#include -#include -#pragma warning(pop) -#else -#include -#include -#include -#endif - -#include +#include #include #include @@ -223,12 +207,14 @@ namespace Bsa auto memoryStreamPtr = std::make_unique(fileRecord.size); if (fileRecord.packedSize) { - boost::iostreams::filtering_streambuf inputStreamBuf; - inputStreamBuf.push(boost::iostreams::zlib_decompressor()); - inputStreamBuf.push(*streamPtr); + std::vector buffer(inputSize); + streamPtr->read(buffer.data(), inputSize); + uLongf destSize = static_cast(fileRecord.size); + int ec = ::uncompress(reinterpret_cast(memoryStreamPtr->getRawData()), &destSize, + reinterpret_cast(buffer.data()), static_cast(buffer.size())); - boost::iostreams::basic_array_sink sr(memoryStreamPtr->getRawData(), fileRecord.size); - boost::iostreams::copy(inputStreamBuf, sr); + if (ec != Z_OK) + fail("zlib uncompress failed: " + std::string(::zError(ec))); } else { diff --git a/components/bsa/compressedbsafile.cpp b/components/bsa/compressedbsafile.cpp index 8426c5965c..655a4d2844 100644 --- a/components/bsa/compressedbsafile.cpp +++ b/components/bsa/compressedbsafile.cpp @@ -24,27 +24,13 @@ */ #include "compressedbsafile.hpp" +#include #include #include #include #include - -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable : 4706) -#pragma warning(disable : 4702) -#include -#include -#include -#pragma warning(pop) -#else -#include -#include -#include -#endif - -#include +#include #include #include @@ -292,19 +278,26 @@ namespace Bsa if (compressed) { + std::vector buffer(size); + streamPtr->read(buffer.data(), size); + if (mHeader.mVersion != Version_SSE) { - boost::iostreams::filtering_streambuf inputStreamBuf; - inputStreamBuf.push(boost::iostreams::zlib_decompressor()); - inputStreamBuf.push(*streamPtr); + uLongf destSize = static_cast(resultSize); + int ec = ::uncompress(reinterpret_cast(memoryStreamPtr->getRawData()), &destSize, + reinterpret_cast(buffer.data()), static_cast(buffer.size())); - boost::iostreams::basic_array_sink sr(memoryStreamPtr->getRawData(), resultSize); - boost::iostreams::copy(inputStreamBuf, sr); + if (ec != Z_OK) + { + std::string message = "zlib uncompress failed for file "; + message.append(fileRecord.mName.begin(), fileRecord.mName.end()); + message += ": "; + message += ::zError(ec); + fail(message); + } } else { - auto buffer = std::vector(size); - streamPtr->read(buffer.data(), size); LZ4F_decompressionContext_t context = nullptr; LZ4F_createDecompressionContext(&context, LZ4F_VERSION); LZ4F_decompressOptions_t options = {}; From 93cb69b0127fc7d36ca91fa14d1a1b47ab9a5499 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Tue, 8 Jul 2025 22:36:43 +0300 Subject: [PATCH 246/330] Assume NIF controller data is already sorted (#8545) --- components/nif/data.cpp | 11 +++-------- components/nif/data.hpp | 4 ++-- components/nif/nifkey.hpp | 24 ++++++++++++++++-------- components/nif/particle.cpp | 12 ++++++++---- components/nifosg/controller.cpp | 3 ++- components/nifosg/controller.hpp | 11 ++++++----- 6 files changed, 37 insertions(+), 28 deletions(-) diff --git a/components/nif/data.cpp b/components/nif/data.cpp index 29b11bd806..a134749bdc 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -247,16 +247,11 @@ namespace Nif void NiVisData::read(NIFStream* nif) { - mKeys = std::make_shared>(); - uint32_t numKeys; - nif->read(numKeys); - for (size_t i = 0; i < numKeys; i++) + mKeys = std::make_shared>>(nif->get()); + for (auto& [time, value] : *mKeys) { - float time; - char value; nif->read(time); - nif->read(value); - (*mKeys)[time] = (value != 0); + value = nif->get() != 0; } } diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 1ccd2919b7..4000055e8c 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -193,8 +193,8 @@ namespace Nif struct NiVisData : public Record { - // TODO: investigate possible use of BoolKeyMap - std::shared_ptr> mKeys; + // This is theoretically a "flat map" sorted by time + std::shared_ptr>> mKeys; void read(NIFStream* nif) override; }; diff --git a/components/nif/nifkey.hpp b/components/nif/nifkey.hpp index 5a755c8d0d..e32ef76d95 100644 --- a/components/nif/nifkey.hpp +++ b/components/nif/nifkey.hpp @@ -3,7 +3,7 @@ #ifndef OPENMW_COMPONENTS_NIF_NIFKEY_HPP #define OPENMW_COMPONENTS_NIF_NIFKEY_HPP -#include +#include #include #include "exception.hpp" @@ -46,7 +46,8 @@ namespace Nif template struct KeyMapT { - using MapType = std::map>; + // This is theoretically a "flat map" sorted by time + using MapType = std::vector>>; using ValueType = T; using KeyType = KeyT; @@ -78,8 +79,12 @@ namespace Nif uint32_t count; nif->read(count); - if (count != 0 || morph) - nif->read(mInterpolationType); + if (count == 0 && !morph) + return; + + nif->read(mInterpolationType); + + mKeys.reserve(count); KeyType key = {}; @@ -90,7 +95,7 @@ namespace Nif float time; nif->read(time); readValue(*nif, key); - mKeys[time] = key; + mKeys.emplace_back(time, key); } } else if (mInterpolationType == InterpolationType_Quadratic) @@ -100,7 +105,7 @@ namespace Nif float time; nif->read(time); readQuadratic(*nif, key); - mKeys[time] = key; + mKeys.emplace_back(time, key); } } else if (mInterpolationType == InterpolationType_TCB) @@ -115,8 +120,9 @@ namespace Nif nif->read(tcbKey.mBias); } generateTCBTangents(tcbKeys); - for (TCBKey& key : tcbKeys) - mKeys[key.mTime] = KeyType{ std::move(key.mValue), std::move(key.mInTan), std::move(key.mOutTan) }; + for (TCBKey& tcbKey : tcbKeys) + mKeys.emplace_back(std::move(tcbKey.mTime), + KeyType{ std::move(tcbKey.mValue), std::move(tcbKey.mInTan), std::move(tcbKey.mOutTan) }); } else if (mInterpolationType == InterpolationType_XYZ) { @@ -132,6 +138,8 @@ namespace Nif throw Nif::Exception("Unhandled interpolation type: " + std::to_string(mInterpolationType), nif->getFile().getFilename()); } + + // Note: NetImmerse does NOT sort keys or remove duplicates } private: diff --git a/components/nif/particle.cpp b/components/nif/particle.cpp index d81d423fb6..9249541717 100644 --- a/components/nif/particle.cpp +++ b/components/nif/particle.cpp @@ -676,12 +676,16 @@ namespace Nif void NiPSysEmitterCtlrData::read(NIFStream* nif) { + // TODO: this is not used in the official files and needs verification mFloatKeyList = std::make_shared(); + mFloatKeyList->read(nif); mVisKeyList = std::make_shared(); - uint32_t numVisKeys; - nif->read(numVisKeys); - for (size_t i = 0; i < numVisKeys; i++) - mVisKeyList->mKeys[nif->get()].mValue = nif->get() != 0; + mVisKeyList->mKeys.resize(nif->get()); + for (auto& [time, key] : mVisKeyList->mKeys) + { + nif->read(time); + key.mValue = nif->get() != 0; + } } void NiPSysCollider::read(NIFStream* nif) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 7e4c5da7a0..ee3d0dd45e 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -374,7 +374,8 @@ namespace NifOsg if (mData->empty()) return true; - auto iter = mData->upper_bound(time); + auto iter = std::upper_bound(mData->begin(), mData->end(), time, + [](float time, const std::pair& key) { return time < key.first; }); if (iter != mData->begin()) --iter; return iter->second; diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 468668ce76..41c8027eea 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -54,7 +54,8 @@ namespace NifOsg return mLastHighKey; } - return mKeys->mKeys.lower_bound(time); + return std::lower_bound(mKeys->mKeys.begin(), mKeys->mKeys.end(), time, + [](const typename MapT::MapType::value_type& key, float t) { return key.first < t; }); } public: @@ -99,8 +100,8 @@ namespace NifOsg const typename MapT::MapType& keys = mKeys->mKeys; - if (time <= keys.begin()->first) - return keys.begin()->second.mValue; + if (time <= keys.front().first) + return keys.front().second.mValue; typename MapT::MapType::const_iterator it = retrieveKey(time); @@ -116,7 +117,7 @@ namespace NifOsg return interpolate(mLastLowKey->second, mLastHighKey->second, a, mKeys->mInterpolationType); } - return keys.rbegin()->second.mValue; + return keys.back().second.mValue; } bool empty() const { return !mKeys || mKeys->mKeys.empty(); } @@ -283,7 +284,7 @@ namespace NifOsg class VisController : public SceneUtil::NodeCallback, public SceneUtil::Controller { private: - std::shared_ptr> mData; + std::shared_ptr>> mData; BoolInterpolator mInterpolator; unsigned int mMask{ 0u }; From 4a0c998f53426ffff26bc1dd210fac803dc1499a Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Fri, 18 Jul 2025 00:13:01 +0300 Subject: [PATCH 247/330] Avoid zero division during animation interpolation --- components/nifosg/controller.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 41c8027eea..cceec279b2 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -112,7 +112,12 @@ namespace NifOsg mLastHighKey = it; mLastLowKey = --it; - float a = (time - mLastLowKey->first) / (mLastHighKey->first - mLastLowKey->first); + const float highTime = mLastHighKey->first; + const float lowTime = mLastLowKey->first; + if (highTime == lowTime) + return mLastLowKey->second.mValue; + + const float a = (time - lowTime) / (highTime - lowTime); return interpolate(mLastLowKey->second, mLastHighKey->second, a, mKeys->mInterpolationType); } From 7f28b33cf1d2a98b5903afbf71623506b2da9492 Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Sat, 27 May 2023 21:02:29 +0200 Subject: [PATCH 248/330] Object paging in ESM4 worldspaces --- apps/openmw/mwclass/esm4base.hpp | 17 +++-- apps/openmw/mwrender/objectpaging.cpp | 93 +++++++++++++++++++++++++-- apps/openmw/mwworld/scene.cpp | 11 +++- apps/openmw/mwworld/scene.hpp | 6 +- apps/openmw/mwworld/worldimp.cpp | 7 -- 5 files changed, 113 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwclass/esm4base.hpp b/apps/openmw/mwclass/esm4base.hpp index f13d6007cd..0e7888317e 100644 --- a/apps/openmw/mwclass/esm4base.hpp +++ b/apps/openmw/mwclass/esm4base.hpp @@ -55,6 +55,16 @@ namespace MWClass } return res; } + + // TODO: Figure out a better way to find markers and LOD meshes + inline bool isMarkerModel(std::string_view model) + { + return Misc::StringUtils::ciStartsWith(model, "marker"); + } + inline bool isLodModel(std::string_view model) + { + return Misc::StringUtils::ciEndsWith(model, "lod.nif"); + } } // Base for many ESM4 Classes @@ -100,11 +110,8 @@ namespace MWClass { std::string_view model = getClassModel(ptr); - // Hide meshes meshes/marker/* and *LOD.nif in ESM4 cells. It is a temporarty hack. - // Needed because otherwise LOD meshes are rendered on top of normal meshes. - // TODO: Figure out a better way find markers and LOD meshes; show LOD only outside of active grid. - if (model.empty() || Misc::StringUtils::ciStartsWith(model, "marker") - || Misc::StringUtils::ciEndsWith(model, "lod.nif")) + // TODO: There should be a better way to hide markers + if (ESM4Impl::isMarkerModel(model) || ESM4Impl::isLodModel(model)) return {}; return model; diff --git a/apps/openmw/mwrender/objectpaging.cpp b/apps/openmw/mwrender/objectpaging.cpp index f45247398f..9f8b1ed86c 100644 --- a/apps/openmw/mwrender/objectpaging.cpp +++ b/apps/openmw/mwrender/objectpaging.cpp @@ -20,6 +20,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include #include #include @@ -36,12 +42,14 @@ #include "apps/openmw/mwbase/environment.hpp" #include "apps/openmw/mwbase/world.hpp" +#include "apps/openmw/mwclass/esm4base.hpp" #include "apps/openmw/mwworld/esmstore.hpp" #include "vismask.hpp" namespace MWRender { + namespace { bool typeFilter(int type, bool far) @@ -51,8 +59,14 @@ namespace MWRender case ESM::REC_STAT: case ESM::REC_ACTI: case ESM::REC_DOOR: + case ESM::REC_STAT4: + case ESM::REC_DOOR4: + case ESM::REC_TREE4: return true; case ESM::REC_CONT: + case ESM::REC_ACTI4: + case ESM::REC_CONT4: + case ESM::REC_FURN4: return !far; default: @@ -60,7 +74,16 @@ namespace MWRender } } - std::string getModel(int type, ESM::RefId id, const MWWorld::ESMStore& store) + template + std::string_view getEsm4Model(const Record& record) + { + if (MWClass::ESM4Impl::isMarkerModel(record->mModel)) + return {}; + else + return record->mModel; + } + + std::string_view getModel(int type, ESM::RefId id, const MWWorld::ESMStore& store) { switch (type) { @@ -72,6 +95,18 @@ namespace MWRender return store.get().searchStatic(id)->mModel; case ESM::REC_CONT: return store.get().searchStatic(id)->mModel; + case ESM::REC_STAT4: + return getEsm4Model(store.get().searchStatic(id)); + case ESM::REC_DOOR4: + return getEsm4Model(store.get().searchStatic(id)); + case ESM::REC_TREE4: + return getEsm4Model(store.get().searchStatic(id)); + case ESM::REC_ACTI4: + return getEsm4Model(store.get().searchStatic(id)); + case ESM::REC_CONT4: + return getEsm4Model(store.get().searchStatic(id)); + case ESM::REC_FURN4: + return getEsm4Model(store.get().searchStatic(id)); default: return {}; } @@ -494,6 +529,17 @@ namespace MWRender }; } + PagedCellRef makePagedCellRef(const ESM4::Reference& value) + { + return PagedCellRef{ + .mRefId = value.mBaseObj, + .mRefNum = value.mId, + .mPosition = value.mPos.asVec3(), + .mRotation = value.mPos.asRotationVec3(), + .mScale = value.mScale, + }; + } + std::map collectESM3References( float size, const osg::Vec2i& startCell, const MWWorld::ESMStore& store) { @@ -561,6 +607,45 @@ namespace MWRender } return refs; } + + std::map collectESM4References( + float size, const osg::Vec2i& startCell, ESM::RefId worldspace) + { + std::map refs; + const auto& store = MWBase::Environment::get().getWorld()->getStore(); + for (int cellX = startCell.x(); cellX < startCell.x() + size; ++cellX) + { + for (int cellY = startCell.y(); cellY < startCell.y() + size; ++cellY) + { + const ESM4::Cell* cell + = store.get().searchExterior(ESM::ExteriorCellLocation(cellX, cellY, worldspace)); + if (!cell) + continue; + for (const ESM4::Reference* ref4 : store.get().getByCell(cell->mId)) + { + if (ref4->mFlags & ESM4::Rec_Disabled) + continue; + int type = store.findStatic(ref4->mBaseObj); + if (!typeFilter(type, size >= 2)) + continue; + if (!ref4->mEsp.parent.isZeroOrUnset()) + { + const ESM4::Reference* parentRef + = store.get().searchStatic(ref4->mEsp.parent); + if (parentRef) + { + bool parentDisabled = parentRef->mFlags & ESM4::Rec_Disabled; + bool inversed = ref4->mEsp.flags & ESM4::EnableParent::Flag_Inversed; + if (parentDisabled != inversed) + continue; + } + } + refs.insert_or_assign(ref4->mId, makePagedCellRef(*ref4)); + } + } + } + return refs; + } } osg::ref_ptr ObjectPaging::createChunk(float size, const osg::Vec2f& center, bool activeGrid, @@ -578,7 +663,7 @@ namespace MWRender } else { - // TODO + refs = collectESM4References(size, startCell, mWorldspace); } if (activeGrid && !refs.empty()) @@ -648,12 +733,12 @@ namespace MWRender continue; const int type = store.findStatic(ref.mRefId); - VFS::Path::Normalized model = getModel(type, ref.mRefId, store); + VFS::Path::Normalized model(getModel(type, ref.mRefId, store)); if (model.empty()) continue; model = Misc::ResourceHelpers::correctMeshPath(model); - if (activeGrid && type != ESM::REC_STAT) + if (activeGrid && type != ESM::REC_STAT && type != ESM::REC_STAT4) { model = Misc::ResourceHelpers::correctActorModelPath(model, mSceneManager->getVFS()); if (Misc::getFileExtension(model) == "nif") diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 478bdb5bb8..0c9a13bc47 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "../mwbase/environment.hpp" @@ -511,7 +512,7 @@ namespace MWWorld if (cellVariant.isExterior()) { - if (const auto heightField = mPhysics->getHeightField(cellX, cellY)) + if (mPhysics->getHeightField(cellX, cellY) != nullptr) mNavigator.addWater( osg::Vec2i(cellX, cellY), ESM::Land::REAL_SIZE, waterLevel, navigatorUpdateGuard); } @@ -645,8 +646,11 @@ namespace MWWorld mHalfGridSize = halfGridSize; mCurrentGridCenter = osg::Vec2i(playerCellX, playerCellY); osg::Vec4i newGrid = gridCenterToBounds(mCurrentGridCenter); - mRendering.setActiveGrid(newGrid); + + // NOTE: setActiveGrid must be after enableTerrain, otherwise we set the grid in the old exterior worldspace mRendering.enableTerrain(true, playerCellIndex.mWorldspace); + mRendering.setActiveGrid(newGrid); + mPreloader->setTerrain(mRendering.getTerrain()); if (mRendering.pagingUnlockCache()) mPreloader->abortTerrainPreloadExcept(nullptr); @@ -1292,6 +1296,9 @@ namespace MWWorld void Scene::preloadTerrain(const osg::Vec3f& pos, ESM::RefId worldspace, bool sync) { + if (mRendering.getTerrain()->getWorldspace() != worldspace) + throw std::runtime_error("preloadTerrain can only work with the current exterior worldspace"); + ESM::ExteriorCellLocation cellPos = ESM::positionToExteriorCellLocation(pos.x(), pos.y(), worldspace); const PositionCellGrid position{ pos, gridCenterToBounds({ cellPos.mX, cellPos.mY }) }; mPreloader->abortTerrainPreloadExcept(&position); diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 116e52e535..1fa7779e51 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -129,6 +129,9 @@ namespace MWWorld void preloadExteriorGrid(const osg::Vec3f& playerPos, const osg::Vec3f& predictedPos); void preloadFastTravelDestinations( const osg::Vec3f& playerPos, std::vector& exteriorPositions); + void preloadCellWithSurroundings(MWWorld::CellStore& cell); + void preloadCell(MWWorld::CellStore& cell); + void preloadTerrain(const osg::Vec3f& pos, ESM::RefId worldspace, bool sync = false); osg::Vec4i gridCenterToBounds(const osg::Vec2i& centerCell) const; osg::Vec2i getNewGridCenter(const osg::Vec3f& pos, const osg::Vec2i* currentGridCenter = nullptr) const; @@ -143,9 +146,6 @@ namespace MWWorld ~Scene(); - void preloadCellWithSurroundings(MWWorld::CellStore& cell); - void preloadCell(MWWorld::CellStore& cell); - void preloadTerrain(const osg::Vec3f& pos, ESM::RefId worldspace, bool sync = false); void reloadTerrain(); void playerMoved(const osg::Vec3f& pos); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f608b8c781..97788669d5 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -517,13 +517,6 @@ namespace MWWorld mStore.checkPlayer(); mPlayer->readRecord(reader, type); - if (getPlayerPtr().isInCell()) - { - if (getPlayerPtr().getCell()->isExterior()) - mWorldScene->preloadTerrain(getPlayerPtr().getRefData().getPosition().asVec3(), - getPlayerPtr().getCell()->getCell()->getWorldSpace()); - mWorldScene->preloadCellWithSurroundings(*getPlayerPtr().getCell()); - } break; case ESM::REC_CSTA: // We need to rebuild the ESMStore index in order to be able to lookup dynamic records while loading the From 614062d3876a310520069527a9c4bfb3bd6f6c71 Mon Sep 17 00:00:00 2001 From: Kuyondo Date: Tue, 15 Jul 2025 01:47:48 +0800 Subject: [PATCH 249/330] prevent item flickering on drag use and dont stop drag on denied lua itemusage --- AUTHORS.md | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 67 +++++++++++---------------- apps/openmw/mwgui/inventorywindow.hpp | 1 - 3 files changed, 27 insertions(+), 43 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index 51910dedaa..c2e71aa85d 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -197,7 +197,7 @@ Programmers Qlonever Radu-Marius Popovici (rpopovici) Rafael Moura (dhustkoder) - Randy Davin (Kindi) + Randy Davin (Kuyondo) rdimesio rexelion riothamus diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index c558f1bad9..e5f6b7dc1e 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -573,24 +573,37 @@ namespace MWGui } std::unique_ptr action = ptr.getClass().use(ptr, force); + + MWWorld::InventoryStore& invStore = mPtr.getClass().getInventoryStore(mPtr); + auto [eqSlots, canStack] = ptr.getClass().getEquipmentSlots(ptr); + bool isFromDragAndDrop = mDragAndDrop->mItem.mBase == ptr; + int useCount = isFromDragAndDrop ? mDragAndDrop->mDraggedCount : ptr.getCellRef().getCount(); + + if (!eqSlots.empty()) + { + MWWorld::ContainerStoreIterator it = invStore.getSlot(eqSlots.front()); + if (it != invStore.end() && it->getCellRef().getRefId() == ptr.getCellRef().getRefId()) + useCount += it->getCellRef().getCount(); + } + action->execute(player, !canEquip); - // Handles partial equipping (final part) - if (mEquippedStackableCount.has_value()) - { - // the count to unequip - int count = ptr.getCellRef().getCount() - mDragAndDrop->mDraggedCount - mEquippedStackableCount.value(); - if (count > 0) - { - MWWorld::InventoryStore& invStore = mPtr.getClass().getInventoryStore(mPtr); - invStore.unequipItemQuantity(ptr, count); - updateItemView(); - } - mEquippedStackableCount.reset(); - } + // Partial equipping + int excess = ptr.getCellRef().getCount() - useCount; + if (excess > 0 && canStack) + invStore.unequipItemQuantity(ptr, excess); if (isVisible()) { + if (isFromDragAndDrop) + { + // Feature: Don't stop draganddrop if potion or ingredient was used + if (ptr.getType() != ESM::Potion::sRecordId && ptr.getType() != ESM::Ingredient::sRecordId) + mDragAndDrop->finish(); + else + mDragAndDrop->update(); + } + mItemView->update(); notifyContentChanged(); @@ -612,8 +625,6 @@ namespace MWGui return; } - mDragAndDrop->finish(); - if (mDragAndDrop->mSourceModel != mTradeModel) { // Move item to the player's inventory @@ -621,33 +632,7 @@ namespace MWGui mDragAndDrop->mItem, mDragAndDrop->mDraggedCount, mTradeModel); } - // Handles partial equipping - mEquippedStackableCount.reset(); - const auto slots = ptr.getClass().getEquipmentSlots(ptr); - if (!slots.first.empty() && slots.second) - { - MWWorld::InventoryStore& invStore = mPtr.getClass().getInventoryStore(mPtr); - MWWorld::ConstContainerStoreIterator slotIt = invStore.getSlot(slots.first.front()); - - // Save the currently equipped count before useItem() - if (slotIt != invStore.end() && slotIt->getCellRef().getRefId() == ptr.getCellRef().getRefId()) - mEquippedStackableCount = slotIt->getCellRef().getCount(); - else - mEquippedStackableCount = 0; - } - MWBase::Environment::get().getLuaManager()->useItem(ptr, MWMechanics::getPlayer(), false); - - // If item is ingredient or potion don't stop drag and drop to simplify action of taking more than one 1 - // item - if ((ptr.getType() == ESM::Potion::sRecordId || ptr.getType() == ESM::Ingredient::sRecordId) - && mDragAndDrop->mDraggedCount > 1) - { - // Item can be provided from other window for example container. - // But after DragAndDrop::startDrag item automaticly always gets to player inventory. - mSelectedItem = getModel()->getIndex(mDragAndDrop->mItem); - dragItem(nullptr, mDragAndDrop->mDraggedCount - 1); - } } else { diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 2dc25144d5..e245fe46ca 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -85,7 +85,6 @@ namespace MWGui Misc::NotNullPtr mItemTransfer; int mSelectedItem; - std::optional mEquippedStackableCount; MWWorld::Ptr mPtr; From c098f2ccde424ea399034e43fa621ca0b70e8ace Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Wed, 6 Nov 2024 19:46:45 +0100 Subject: [PATCH 250/330] Prevent iterator invalidation during actor traversal --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/actor.hpp | 6 +- apps/openmw/mwmechanics/actors.cpp | 58 ++++++++++++++----- .../mwmechanics/mechanicsmanagerimp.cpp | 2 + 4 files changed, 53 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5435835606..b4617936dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -80,6 +80,7 @@ Bug #4754: Stack of ammunition cannot be equipped partially Bug #4816: GetWeaponDrawn returns 1 before weapon is attached Bug #4822: Non-weapon equipment and body parts can't inherit time from parent animation + Bug #4885: Disable in dialogue result script causes a crash Bug #4898: Odd/Incorrect lighting on meshes Bug #5057: Weapon swing sound plays at same pitch whether it hits or misses Bug #5062: Root bone rotations for NPC animation don't work the same as for creature animation diff --git a/apps/openmw/mwmechanics/actor.hpp b/apps/openmw/mwmechanics/actor.hpp index d7438712d9..1cafbe8253 100644 --- a/apps/openmw/mwmechanics/actor.hpp +++ b/apps/openmw/mwmechanics/actor.hpp @@ -62,14 +62,18 @@ namespace MWMechanics void setPositionAdjusted(bool adjusted) { mPositionAdjusted = adjusted; } bool getPositionAdjusted() const { return mPositionAdjusted; } + void invalidate() { mInvalid = true; } + bool isInvalid() const { return mInvalid; } + private: CharacterController mCharacterController; int mGreetingTimer{ 0 }; float mTargetAngleRadians{ 0.f }; GreetingState mGreetingState{ Greet_None }; - bool mIsTurningToPlayer{ false }; Misc::DeviatingPeriodicTimer mEngageCombat{ 1.0f, 0.25f, Misc::Rng::deviate(0, 0.25f, MWBase::Environment::get().getWorld()->getPrng()) }; + bool mIsTurningToPlayer{ false }; + bool mInvalid{ false }; bool mPositionAdjusted; }; diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 65eb71232f..8491cdcb7b 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1247,7 +1247,7 @@ namespace MWMechanics { if (!keepActive) removeTemporaryEffects(iter->second->getPtr()); - mActors.erase(iter->second); + iter->second->invalidate(); mIndex.erase(iter); } } @@ -1299,16 +1299,15 @@ namespace MWMechanics void Actors::dropActors(const MWWorld::CellStore* cellStore, const MWWorld::Ptr& ignore) { - for (auto iter = mActors.begin(); iter != mActors.end();) + for (Actor& actor : mActors) { - if ((iter->getPtr().isInCell() && iter->getPtr().getCell() == cellStore) && iter->getPtr() != ignore) + if (!actor.isInvalid() && actor.getPtr().isInCell() && actor.getPtr().getCell() == cellStore + && actor.getPtr() != ignore) { - removeTemporaryEffects(iter->getPtr()); - mIndex.erase(iter->getPtr().mRef); - iter = mActors.erase(iter); + removeTemporaryEffects(actor.getPtr()); + mIndex.erase(actor.getPtr().mRef); + actor.invalidate(); } - else - ++iter; } } @@ -1327,6 +1326,8 @@ namespace MWMechanics const MWBase::World* const world = MWBase::Environment::get().getWorld(); for (const Actor& actor : mActors) { + if (actor.isInvalid()) + continue; const MWWorld::Ptr& ptr = actor.getPtr(); if (ptr == player) continue; // Don't interfere with player controls. @@ -1391,6 +1392,8 @@ namespace MWMechanics // Iterate through all other actors and predict collisions. for (const Actor& otherActor : mActors) { + if (otherActor.isInvalid()) + continue; const MWWorld::Ptr& otherPtr = otherActor.getPtr(); if (otherPtr == ptr || otherPtr == currentTarget) continue; @@ -1509,6 +1512,8 @@ namespace MWMechanics // AI and magic effects update for (Actor& actor : mActors) { + if (actor.isInvalid()) + continue; const bool isPlayer = actor.getPtr() == player; CharacterController& ctrl = actor.getCharacterController(); MWBase::LuaManager::ActorControls* luaControls @@ -1570,6 +1575,8 @@ namespace MWMechanics for (const Actor& otherActor : mActors) { + if (otherActor.isInvalid()) + continue; if (otherActor.getPtr() == actor.getPtr() || isPlayer) // player is not AI-controlled continue; engageCombat( @@ -1627,6 +1634,8 @@ namespace MWMechanics CharacterController* playerCharacter = nullptr; for (Actor& actor : mActors) { + if (actor.isInvalid()) + continue; const float dist = (playerPos - actor.getPtr().getRefData().getPosition().asVec3()).length(); const bool isPlayer = actor.getPtr() == player; CreatureStats& stats = actor.getPtr().getClass().getCreatureStats(actor.getPtr()); @@ -1692,8 +1701,15 @@ namespace MWMechanics luaControls->mJump = false; } - for (const Actor& actor : mActors) + for (auto it = mActors.begin(); it != mActors.end();) { + if (it->isInvalid()) + { + it = mActors.erase(it); + continue; + } + const Actor& actor = *it; + it++; const MWWorld::Class& cls = actor.getPtr().getClass(); CreatureStats& stats = cls.getCreatureStats(actor.getPtr()); @@ -1743,6 +1759,8 @@ namespace MWMechanics { for (Actor& actor : mActors) { + if (actor.isInvalid()) + continue; const MWWorld::Class& cls = actor.getPtr().getClass(); CreatureStats& stats = cls.getCreatureStats(actor.getPtr()); @@ -1830,6 +1848,8 @@ namespace MWMechanics { for (const Actor& actor : mActors) { + if (actor.isInvalid()) + continue; MWMechanics::ActiveSpells& spells = actor.getPtr().getClass().getCreatureStats(actor.getPtr()).getActiveSpells(); spells.purge(actor.getPtr(), casterActorId); @@ -1849,6 +1869,8 @@ namespace MWMechanics for (const Actor& actor : mActors) { + if (actor.isInvalid()) + continue; if (actor.getPtr().getClass().getCreatureStats(actor.getPtr()).isDead()) { adjustMagicEffects(actor.getPtr(), duration); @@ -2046,7 +2068,10 @@ namespace MWMechanics void Actors::persistAnimationStates() const { for (const Actor& actor : mActors) - actor.getCharacterController().persistAnimationState(); + { + if (!actor.isInvalid()) + actor.getCharacterController().persistAnimationState(); + } } void Actors::clearAnimationQueue(const MWWorld::Ptr& ptr, bool clearScripted) @@ -2060,6 +2085,8 @@ namespace MWMechanics { for (const Actor& actor : mActors) { + if (actor.isInvalid()) + continue; if ((actor.getPtr().getRefData().getPosition().asVec3() - position).length2() <= radius * radius) out.push_back(actor.getPtr()); } @@ -2069,6 +2096,8 @@ namespace MWMechanics { for (const Actor& actor : mActors) { + if (actor.isInvalid()) + continue; if ((actor.getPtr().getRefData().getPosition().asVec3() - position).length2() <= radius * radius) return true; } @@ -2082,6 +2111,8 @@ namespace MWMechanics list.push_back(actorPtr); for (const Actor& actor : mActors) { + if (actor.isInvalid()) + continue; const MWWorld::Ptr& iteratedActor = actor.getPtr(); if (iteratedActor == getPlayer()) continue; @@ -2352,10 +2383,11 @@ namespace MWMechanics if (!MWBase::Environment::get().getMechanicsManager()->isAIActive()) return; - for (auto it = mActors.begin(); it != mActors.end();) + for (const Actor& actor : mActors) { - const MWWorld::Ptr ptr = it->getPtr(); - ++it; + if (actor.isInvalid()) + continue; + const MWWorld::Ptr ptr = actor.getPtr(); if (ptr == getPlayer() || !isConscious(ptr) || ptr.getClass().getCreatureStats(ptr).isParalyzed()) continue; MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence(); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 384c25953b..f0ba99b0ca 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1725,6 +1725,8 @@ namespace MWMechanics .getActorId()); // Stops guard from ending combat if player is unreachable for (const Actor& actor : mActors) { + if (actor.isInvalid()) + continue; if (actor.getPtr().getClass().isClass(actor.getPtr(), "Guard")) { MWMechanics::AiSequence& aiSeq From b2bb12cd1930029f8ba8ad97a9709229bcdcc83b Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Wed, 6 Nov 2024 21:33:58 +0100 Subject: [PATCH 251/330] Run ~CharacterController when invalidating an Actor --- apps/openmw/mwmechanics/actor.hpp | 21 +++++++++++++-------- apps/openmw/mwmechanics/actors.cpp | 4 +++- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/actor.hpp b/apps/openmw/mwmechanics/actor.hpp index 1cafbe8253..6deaba3a95 100644 --- a/apps/openmw/mwmechanics/actor.hpp +++ b/apps/openmw/mwmechanics/actor.hpp @@ -2,6 +2,7 @@ #define OPENMW_MECHANICS_ACTOR_H #include +#include #include "character.hpp" #include "creaturestats.hpp" @@ -29,18 +30,18 @@ namespace MWMechanics { public: Actor(const MWWorld::Ptr& ptr, MWRender::Animation* animation) - : mCharacterController(ptr, animation) - , mPositionAdjusted(ptr.getClass().getCreatureStats(ptr).getFallHeight() > 0) + : mPositionAdjusted(ptr.getClass().getCreatureStats(ptr).getFallHeight() > 0) { + mCharacterController.emplace(ptr, animation); } - const MWWorld::Ptr& getPtr() const { return mCharacterController.getPtr(); } + const MWWorld::Ptr& getPtr() const { return mCharacterController->getPtr(); } /// Notify this actor of its new base object Ptr, use when the object changed cells - void updatePtr(const MWWorld::Ptr& newPtr) { mCharacterController.updatePtr(newPtr); } + void updatePtr(const MWWorld::Ptr& newPtr) { mCharacterController->updatePtr(newPtr); } - CharacterController& getCharacterController() { return mCharacterController; } - const CharacterController& getCharacterController() const { return mCharacterController; } + CharacterController& getCharacterController() { return *mCharacterController; } + const CharacterController& getCharacterController() const { return *mCharacterController; } int getGreetingTimer() const { return mGreetingTimer; } void setGreetingTimer(int timer) { mGreetingTimer = timer; } @@ -62,11 +63,15 @@ namespace MWMechanics void setPositionAdjusted(bool adjusted) { mPositionAdjusted = adjusted; } bool getPositionAdjusted() const { return mPositionAdjusted; } - void invalidate() { mInvalid = true; } + void invalidate() + { + mInvalid = true; + mCharacterController.reset(); + } bool isInvalid() const { return mInvalid; } private: - CharacterController mCharacterController; + std::optional mCharacterController; int mGreetingTimer{ 0 }; float mTargetAngleRadians{ 0.f }; GreetingState mGreetingState{ Greet_None }; diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 8491cdcb7b..6d1cdfcb3d 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -122,6 +122,8 @@ namespace { for (const MWMechanics::Actor& actor : actors) { + if (actor.isInvalid()) + continue; const MWWorld::Ptr& iteratedActor = actor.getPtr(); if (iteratedActor == player || iteratedActor == actorPtr) continue; @@ -345,7 +347,7 @@ namespace MWMechanics // Find something nearby. for (const Actor& otherActor : actors) { - if (otherActor.getPtr() == ptr) + if (otherActor.isInvalid() || otherActor.getPtr() == ptr) continue; updateHeadTracking( From d34aee6257499b2a015ce0d2be4792794f3baa49 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Thu, 7 Nov 2024 16:37:28 +0100 Subject: [PATCH 252/330] Allow unsetting a character controller's animation --- apps/openmw/mwmechanics/actor.hpp | 19 ++++--- apps/openmw/mwmechanics/actors.cpp | 2 +- apps/openmw/mwmechanics/character.cpp | 72 +++++++++++++++------------ apps/openmw/mwmechanics/character.hpp | 15 +++--- apps/openmw/mwmechanics/objects.cpp | 2 +- 5 files changed, 61 insertions(+), 49 deletions(-) diff --git a/apps/openmw/mwmechanics/actor.hpp b/apps/openmw/mwmechanics/actor.hpp index 6deaba3a95..69e370ec86 100644 --- a/apps/openmw/mwmechanics/actor.hpp +++ b/apps/openmw/mwmechanics/actor.hpp @@ -2,7 +2,6 @@ #define OPENMW_MECHANICS_ACTOR_H #include -#include #include "character.hpp" #include "creaturestats.hpp" @@ -29,19 +28,19 @@ namespace MWMechanics class Actor { public: - Actor(const MWWorld::Ptr& ptr, MWRender::Animation* animation) - : mPositionAdjusted(ptr.getClass().getCreatureStats(ptr).getFallHeight() > 0) + Actor(const MWWorld::Ptr& ptr, MWRender::Animation& animation) + : mCharacterController(ptr, animation) + , mPositionAdjusted(ptr.getClass().getCreatureStats(ptr).getFallHeight() > 0) { - mCharacterController.emplace(ptr, animation); } - const MWWorld::Ptr& getPtr() const { return mCharacterController->getPtr(); } + const MWWorld::Ptr& getPtr() const { return mCharacterController.getPtr(); } /// Notify this actor of its new base object Ptr, use when the object changed cells - void updatePtr(const MWWorld::Ptr& newPtr) { mCharacterController->updatePtr(newPtr); } + void updatePtr(const MWWorld::Ptr& newPtr) { mCharacterController.updatePtr(newPtr); } - CharacterController& getCharacterController() { return *mCharacterController; } - const CharacterController& getCharacterController() const { return *mCharacterController; } + CharacterController& getCharacterController() { return mCharacterController; } + const CharacterController& getCharacterController() const { return mCharacterController; } int getGreetingTimer() const { return mGreetingTimer; } void setGreetingTimer(int timer) { mGreetingTimer = timer; } @@ -66,12 +65,12 @@ namespace MWMechanics void invalidate() { mInvalid = true; - mCharacterController.reset(); + mCharacterController.detachAnimation(); } bool isInvalid() const { return mInvalid; } private: - std::optional mCharacterController; + CharacterController mCharacterController; int mGreetingTimer{ 0 }; float mTargetAngleRadians{ 0.f }; GreetingState mGreetingState{ Greet_None }; diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 6d1cdfcb3d..0df37875f6 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1197,7 +1197,7 @@ namespace MWMechanics MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); if (!anim) return; - const auto it = mActors.emplace(mActors.end(), ptr, anim); + const auto it = mActors.emplace(mActors.end(), ptr, *anim); mIndex.emplace(ptr.mRef, it); if (updateImmediately) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 87cc469eb4..651bff3999 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -535,7 +535,7 @@ namespace MWMechanics bool CharacterController::onOpen() const { - if (mPtr.getType() == ESM::Container::sRecordId) + if (mPtr.getType() == ESM::Container::sRecordId && mAnimation) { if (!mAnimation->hasAnimation("containeropen")) return true; @@ -559,7 +559,7 @@ namespace MWMechanics { if (mPtr.getType() == ESM::Container::sRecordId) { - if (!mAnimation->hasAnimation("containerclose")) + if (!mAnimation || !mAnimation->hasAnimation("containerclose")) return; float complete, startPoint = 0.f; @@ -883,14 +883,16 @@ namespace MWMechanics } mDeathState = hitStateToDeathState(mHitState); - if (mDeathState == CharState_None && MWBase::Environment::get().getWorld()->isSwimming(mPtr)) - mDeathState = CharState_SwimDeath; - - if (mDeathState == CharState_None || !mAnimation->hasAnimation(deathStateToAnimGroup(mDeathState))) - mDeathState = chooseRandomDeathState(); + if (mDeathState == CharState_None) + { + if (MWBase::Environment::get().getWorld()->isSwimming(mPtr)) + mDeathState = CharState_SwimDeath; + else if (mAnimation && !mAnimation->hasAnimation(deathStateToAnimGroup(mDeathState))) + mDeathState = chooseRandomDeathState(); + } // Do not interrupt scripted animation by death - if (isScriptedAnimPlaying()) + if (!mAnimation || isScriptedAnimPlaying()) return; playDeath(startpoint, mDeathState); @@ -910,13 +912,10 @@ namespace MWMechanics return result; } - CharacterController::CharacterController(const MWWorld::Ptr& ptr, MWRender::Animation* anim) + CharacterController::CharacterController(const MWWorld::Ptr& ptr, MWRender::Animation& anim) : mPtr(ptr) - , mAnimation(anim) + , mAnimation(&anim) { - if (!mAnimation) - return; - mAnimation->setTextKeyListener(this); const MWWorld::Class& cls = mPtr.getClass(); @@ -992,11 +991,17 @@ namespace MWMechanics } CharacterController::~CharacterController() + { + detachAnimation(); + } + + void CharacterController::detachAnimation() { if (mAnimation) { persistAnimationState(); mAnimation->setTextKeyListener(nullptr); + mAnimation = nullptr; } } @@ -1066,7 +1071,7 @@ namespace MWMechanics std::string_view action = evt.substr(groupname.size() + 2); if (action == "equip attach") { - if (mUpperBodyState == UpperBodyState::Equipping) + if (mUpperBodyState == UpperBodyState::Equipping && mAnimation) { if (groupname == "shield") mAnimation->showCarriedLeft(true); @@ -1076,7 +1081,7 @@ namespace MWMechanics } else if (action == "unequip detach") { - if (mUpperBodyState == UpperBodyState::Unequipping) + if (mUpperBodyState == UpperBodyState::Unequipping && mAnimation) { if (groupname == "shield") mAnimation->showCarriedLeft(false); @@ -1148,18 +1153,18 @@ namespace MWMechanics mPtr, mAttackStrength, ESM::Weapon::AT_Thrust, mAttackVictim, mAttackHitPos, mAttackSuccess); } } - else if (action == "shoot attach") + else if (action == "shoot attach" && mAnimation) mAnimation->attachArrow(); else if (action == "shoot release") { // See notes for melee release above - if (mReadyToHit) + if (mReadyToHit && mAnimation) { mAnimation->releaseArrow(mAttackStrength); mReadyToHit = false; } } - else if (action == "shoot follow attach") + else if (action == "shoot follow attach" && mAnimation) mAnimation->attachArrow(); // Make sure this key is actually for the RangeType we are casting. The flame atronach has // the same animation for all range types, so there are 3 "release" keys on the same time, one for each range @@ -1232,7 +1237,8 @@ namespace MWMechanics float CharacterController::calculateWindUp() const { - if (mCurrentWeapon.empty() || mWeaponType == ESM::Weapon::PickProbe || isRandomAttackAnimation(mCurrentWeapon)) + if (mCurrentWeapon.empty() || mWeaponType == ESM::Weapon::PickProbe || isRandomAttackAnimation(mCurrentWeapon) + || !mAnimation) return -1.f; float minAttackTime = mAnimation->getTextKeyTime(mCurrentWeapon + ": " + mAttackType + " min attack"); @@ -1950,6 +1956,8 @@ namespace MWMechanics void CharacterController::update(float duration) { + if (!mAnimation) + return; MWBase::World* world = MWBase::Environment::get().getWorld(); MWBase::SoundManager* sndMgr = MWBase::Environment::get().getSoundManager(); const MWWorld::Class& cls = mPtr.getClass(); @@ -2528,7 +2536,7 @@ namespace MWMechanics ESM::AnimationState::ScriptedAnimation anim; anim.mGroup = iter->mGroup; - if (iter == mAnimQueue.begin()) + if (iter == mAnimQueue.begin() && mAnimation) { float complete; size_t loopcount; @@ -2741,23 +2749,18 @@ namespace MWMechanics void CharacterController::clearAnimQueue(bool clearScriptedAnims) { // Do not interrupt scripted animations, if we want to keep them - if ((!isScriptedAnimPlaying() || clearScriptedAnims) && !mAnimQueue.empty()) + if (mAnimation && (!isScriptedAnimPlaying() || clearScriptedAnims) && !mAnimQueue.empty()) mAnimation->disable(mAnimQueue.front().mGroup); if (clearScriptedAnims) { - mAnimation->setPlayScriptedOnly(false); + if (mAnimation) + mAnimation->setPlayScriptedOnly(false); mAnimQueue.clear(); return; } - for (AnimationQueue::iterator it = mAnimQueue.begin(); it != mAnimQueue.end();) - { - if (!it->mScripted) - it = mAnimQueue.erase(it); - else - ++it; - } + std::erase_if(mAnimQueue, [](const AnimationQueueEntry& entry) { return !entry.mScripted; }); } void CharacterController::forceStateUpdate() @@ -2866,6 +2869,8 @@ namespace MWMechanics void CharacterController::setVisibility(float visibility) const { + if (!mAnimation) + return; // We should take actor's invisibility in account if (mPtr.getClass().isActor()) { @@ -2926,7 +2931,7 @@ namespace MWMechanics bool CharacterController::isReadyToBlock() const { - return updateCarriedLeftVisible(mWeaponType); + return mAnimation && updateCarriedLeftVisible(mWeaponType); } bool CharacterController::isKnockedDown() const @@ -3030,7 +3035,8 @@ namespace MWMechanics void CharacterController::setActive(int active) const { - mAnimation->setActive(active); + if (mAnimation) + mAnimation->setActive(active); } void CharacterController::setHeadTrackTarget(const MWWorld::ConstPtr& target) @@ -3061,6 +3067,8 @@ namespace MWMechanics float CharacterController::getAnimationMovementDirection() const { + if (!mAnimation) + return 0.f; switch (mMovementState) { case CharState_RunLeft: @@ -3155,6 +3163,8 @@ namespace MWMechanics MWWorld::MovementDirectionFlags CharacterController::getSupportedMovementDirections() const { + if (!mAnimation) + return 0; using namespace std::string_view_literals; // There are fallbacks in the CharacterController::refreshMovementAnims for certain animations. Arrays below // represent them. diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index d5c642c883..2a1982c664 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -252,13 +252,21 @@ namespace MWMechanics void prepareHit(); + void unpersistAnimationState(); + + void playBlendedAnimation(const std::string& groupname, const MWRender::AnimPriority& priority, int blendMask, + bool autodisable, float speedmult, std::string_view start, std::string_view stop, float startpoint, + uint32_t loops, bool loopfallback = false) const; + public: - CharacterController(const MWWorld::Ptr& ptr, MWRender::Animation* anim); + CharacterController(const MWWorld::Ptr& ptr, MWRender::Animation& anim); virtual ~CharacterController(); CharacterController(const CharacterController&) = delete; CharacterController(CharacterController&&) = delete; + void detachAnimation(); + const MWWorld::Ptr& getPtr() const { return mPtr; } void handleTextKey(std::string_view groupname, SceneUtil::TextKeyMap::ConstIterator key, @@ -275,11 +283,6 @@ namespace MWMechanics void onClose() const; void persistAnimationState() const; - void unpersistAnimationState(); - - void playBlendedAnimation(const std::string& groupname, const MWRender::AnimPriority& priority, int blendMask, - bool autodisable, float speedmult, std::string_view start, std::string_view stop, float startpoint, - uint32_t loops, bool loopfallback = false) const; bool playGroup(std::string_view groupname, int mode, uint32_t count, bool scripted = false); bool playGroupLua(std::string_view groupname, float speed, std::string_view startKey, std::string_view stopKey, uint32_t loops, bool forceLoop); diff --git a/apps/openmw/mwmechanics/objects.cpp b/apps/openmw/mwmechanics/objects.cpp index 12d342666b..62f0df556d 100644 --- a/apps/openmw/mwmechanics/objects.cpp +++ b/apps/openmw/mwmechanics/objects.cpp @@ -20,7 +20,7 @@ namespace MWMechanics if (anim == nullptr) return; - const auto it = mObjects.emplace(mObjects.end(), ptr, anim); + const auto it = mObjects.emplace(mObjects.end(), ptr, *anim); mIndex.emplace(ptr.mRef, it); } From 35eed6826940fa25256fbfcdba2427a3d25ddfb0 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Mon, 18 Nov 2024 17:26:43 +0100 Subject: [PATCH 253/330] Move null checks to address feedback --- apps/openmw/mwmechanics/character.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 651bff3999..cfe076184d 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1008,6 +1008,8 @@ namespace MWMechanics void CharacterController::handleTextKey( std::string_view groupname, SceneUtil::TextKeyMap::ConstIterator key, const SceneUtil::TextKeyMap& map) { + if (!mAnimation) + return; std::string_view evt = key->second; MWBase::Environment::get().getLuaManager()->animationTextKey(mPtr, key->second); @@ -1153,18 +1155,18 @@ namespace MWMechanics mPtr, mAttackStrength, ESM::Weapon::AT_Thrust, mAttackVictim, mAttackHitPos, mAttackSuccess); } } - else if (action == "shoot attach" && mAnimation) + else if (action == "shoot attach") mAnimation->attachArrow(); else if (action == "shoot release") { // See notes for melee release above - if (mReadyToHit && mAnimation) + if (mAttackStrength != -1.f && mAnimation) { mAnimation->releaseArrow(mAttackStrength); mReadyToHit = false; } } - else if (action == "shoot follow attach" && mAnimation) + else if (action == "shoot follow attach") mAnimation->attachArrow(); // Make sure this key is actually for the RangeType we are casting. The flame atronach has // the same animation for all range types, so there are 3 "release" keys on the same time, one for each range @@ -1237,8 +1239,8 @@ namespace MWMechanics float CharacterController::calculateWindUp() const { - if (mCurrentWeapon.empty() || mWeaponType == ESM::Weapon::PickProbe || isRandomAttackAnimation(mCurrentWeapon) - || !mAnimation) + if (!mAnimation || mCurrentWeapon.empty() || mWeaponType == ESM::Weapon::PickProbe + || isRandomAttackAnimation(mCurrentWeapon)) return -1.f; float minAttackTime = mAnimation->getTextKeyTime(mCurrentWeapon + ": " + mAttackType + " min attack"); From 1dfa2629f020ea04b45f5144768f43f482a27982 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Mon, 18 Nov 2024 19:57:57 +0100 Subject: [PATCH 254/330] Remove more redundant checks --- apps/openmw/mwmechanics/character.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index cfe076184d..a22220bcda 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1073,7 +1073,7 @@ namespace MWMechanics std::string_view action = evt.substr(groupname.size() + 2); if (action == "equip attach") { - if (mUpperBodyState == UpperBodyState::Equipping && mAnimation) + if (mUpperBodyState == UpperBodyState::Equipping) { if (groupname == "shield") mAnimation->showCarriedLeft(true); @@ -1083,7 +1083,7 @@ namespace MWMechanics } else if (action == "unequip detach") { - if (mUpperBodyState == UpperBodyState::Unequipping && mAnimation) + if (mUpperBodyState == UpperBodyState::Unequipping) { if (groupname == "shield") mAnimation->showCarriedLeft(false); From 39cc8936396772d1424f07ddf095091e9559050d Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sat, 19 Jul 2025 09:38:44 +0200 Subject: [PATCH 255/330] Unbreak swimdeath fallback --- CHANGELOG.md | 1 - apps/openmw/mwmechanics/character.cpp | 15 +++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4617936dd..5435835606 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -80,7 +80,6 @@ Bug #4754: Stack of ammunition cannot be equipped partially Bug #4816: GetWeaponDrawn returns 1 before weapon is attached Bug #4822: Non-weapon equipment and body parts can't inherit time from parent animation - Bug #4885: Disable in dialogue result script causes a crash Bug #4898: Odd/Incorrect lighting on meshes Bug #5057: Weapon swing sound plays at same pitch whether it hits or misses Bug #5062: Root bone rotations for NPC animation don't work the same as for creature animation diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index a22220bcda..77f1ef6d15 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -883,13 +883,12 @@ namespace MWMechanics } mDeathState = hitStateToDeathState(mHitState); - if (mDeathState == CharState_None) - { - if (MWBase::Environment::get().getWorld()->isSwimming(mPtr)) - mDeathState = CharState_SwimDeath; - else if (mAnimation && !mAnimation->hasAnimation(deathStateToAnimGroup(mDeathState))) - mDeathState = chooseRandomDeathState(); - } + if (mDeathState == CharState_None && MWBase::Environment::get().getWorld()->isSwimming(mPtr)) + mDeathState = CharState_SwimDeath; + + if (mDeathState == CharState_None + || (mAnimation && !mAnimation->hasAnimation(deathStateToAnimGroup(mDeathState)))) + mDeathState = chooseRandomDeathState(); // Do not interrupt scripted animation by death if (!mAnimation || isScriptedAnimPlaying()) @@ -1160,7 +1159,7 @@ namespace MWMechanics else if (action == "shoot release") { // See notes for melee release above - if (mAttackStrength != -1.f && mAnimation) + if (mAttackStrength != -1.f && mAnimation) { mAnimation->releaseArrow(mAttackStrength); mReadyToHit = false; From 10602a0412dab88bb5734e5f9d47c5418dde5662 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sat, 19 Jul 2025 12:03:06 +0300 Subject: [PATCH 256/330] Don't run some non-essential jobs on upstream branch pushes --- .gitlab-ci.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 42074a0667..119126de64 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -46,6 +46,9 @@ Ubuntu_GCC_preprocess: - pip3 install --user click termtables script: - CI/ubuntu_gcc_preprocess.sh + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + - if: $CI_PIPELINE_SOURCE == "push" && $CI_PROJECT_ID != "7107382" .Ubuntu: extends: .Ubuntu_Image @@ -268,6 +271,9 @@ Ubuntu_GCC_tests_asan: when: always reports: junit: build/*-tests.xml + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + - if: $CI_PIPELINE_SOURCE == "push" && $CI_PROJECT_ID != "7107382" Ubuntu_GCC_tests_ubsan: extends: Ubuntu_GCC @@ -285,6 +291,9 @@ Ubuntu_GCC_tests_ubsan: when: always reports: junit: build/*-tests.xml + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + - if: $CI_PIPELINE_SOURCE == "push" && $CI_PROJECT_ID != "7107382" .Ubuntu_GCC_tests_tsan: extends: Ubuntu_GCC @@ -322,6 +331,9 @@ Ubuntu_GCC_tests_coverage: coverage_format: cobertura path: coverage.xml junit: build/*-tests.xml + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + - if: $CI_PIPELINE_SOURCE == "push" && $CI_PROJECT_ID != "7107382" .Ubuntu_Static_Deps: extends: Ubuntu_Clang @@ -402,6 +414,9 @@ Ubuntu_Clang: - build/ expire_in: 12h timeout: 3h + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + - if: $CI_PIPELINE_SOURCE == "push" && $CI_PROJECT_ID != "7107382" Ubuntu_Clang_Tidy_components: extends: .Ubuntu_Clang_Tidy_Base From 01fa3cc4e61b2fcc86cf4230502f56f9890d190b Mon Sep 17 00:00:00 2001 From: Aussiemon <1407091-Aussiemon@users.noreply.gitlab.com> Date: Sun, 20 Jul 2025 10:05:24 -0600 Subject: [PATCH 257/330] Subtract Charm from permanent disposition clamp range --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 9f3bb0b26f..ab92300804 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -448,12 +449,14 @@ namespace MWDialogue { updateOriginalDisposition(); MWMechanics::NpcStats& npcStats = mActor.getClass().getNpcStats(mActor); - // Clamp permanent disposition change so that final disposition doesn't go below 0 (could happen with - // intimidate) - npcStats.setBaseDisposition(0); - int zero = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor, false); - int disposition = std::clamp(mOriginalDisposition + mPermanentDispositionChange, -zero, 100 - zero); + // Get the sum of disposition effects minus charm (shouldn't be made permanent) + npcStats.setBaseDisposition(0); + int zero = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor, false) + - npcStats.getMagicEffects().getOrDefault(ESM::MagicEffect::Charm).getMagnitude(); + + // Clamp new permanent disposition to avoid negative derived disposition (can be caused by intimidate) + int disposition = std::clamp(mOriginalDisposition + mPermanentDispositionChange, -zero, 100 - zero); npcStats.setBaseDisposition(disposition); } mPermanentDispositionChange = 0; From 28851411a321c5eace03d5a52f8a210dd137110e Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 20 Jul 2025 11:00:19 +0200 Subject: [PATCH 258/330] Fix and enforce namespace naming --- .clang-tidy | 4 ++ apps/components_tests/fx/lexer.cpp | 2 +- apps/components_tests/fx/technique.cpp | 2 +- apps/components_tests/lua/testl10n.cpp | 2 +- apps/launcher/main.cpp | 2 +- apps/openmw/engine.cpp | 2 +- apps/openmw/engine.hpp | 4 +- apps/openmw/mwbase/environment.hpp | 8 ++-- apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwgui/loadingscreen.cpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 13 +++--- apps/openmw/mwgui/postprocessorhud.cpp | 42 +++++++++---------- apps/openmw/mwgui/race.cpp | 2 +- apps/openmw/mwgui/savegamedialog.cpp | 2 +- apps/openmw/mwgui/videowidget.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 8 ++-- apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- apps/openmw/mwlua/postprocessingbindings.cpp | 4 +- apps/openmw/mwrender/pingpongcanvas.cpp | 6 +-- apps/openmw/mwrender/pingpongcanvas.hpp | 12 +++--- apps/openmw/mwrender/postprocessor.cpp | 42 +++++++++---------- apps/openmw/mwrender/postprocessor.hpp | 22 +++++----- apps/wizard/main.cpp | 2 +- components/fallback/validate.hpp | 2 + components/files/configurationmanager.hpp | 2 + components/fontloader/fontloader.cpp | 6 +-- components/fx/lexer.cpp | 2 +- components/fx/lexer.hpp | 2 +- components/fx/lexertypes.hpp | 2 +- components/fx/parseconstants.hpp | 6 +-- components/fx/pass.cpp | 2 +- components/fx/pass.hpp | 2 +- components/fx/stateupdater.cpp | 2 +- components/fx/stateupdater.hpp | 2 +- components/fx/technique.cpp | 34 +++++++-------- components/fx/technique.hpp | 4 +- components/fx/types.hpp | 2 +- components/fx/widgets.cpp | 8 ++-- components/fx/widgets.hpp | 8 ++-- components/l10n/manager.cpp | 2 +- components/l10n/manager.hpp | 2 +- components/l10n/messagebundles.cpp | 2 +- components/l10n/messagebundles.hpp | 2 +- components/l10n/qttranslations.cpp | 2 +- components/l10n/qttranslations.hpp | 2 +- components/lua/l10n.cpp | 4 +- components/lua/l10n.hpp | 4 +- components/lua/luastate.cpp | 2 +- components/lua/luastate.hpp | 4 +- components/myguiplatform/additivelayer.cpp | 2 +- components/myguiplatform/additivelayer.hpp | 2 +- components/myguiplatform/myguidatamanager.cpp | 2 +- components/myguiplatform/myguidatamanager.hpp | 2 +- components/myguiplatform/myguiloglistener.cpp | 2 +- components/myguiplatform/myguiloglistener.hpp | 2 +- components/myguiplatform/myguiplatform.cpp | 2 +- components/myguiplatform/myguiplatform.hpp | 2 +- .../myguiplatform/myguirendermanager.cpp | 14 +++---- .../myguiplatform/myguirendermanager.hpp | 2 +- components/myguiplatform/myguitexture.cpp | 2 +- components/myguiplatform/myguitexture.hpp | 2 +- components/myguiplatform/scalinglayer.cpp | 2 +- components/myguiplatform/scalinglayer.hpp | 2 +- 63 files changed, 175 insertions(+), 166 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 92500ad04d..90c72765ca 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -13,3 +13,7 @@ HeaderFilterRegex: '(apps|components)/' CheckOptions: - key: readability-identifier-naming.ConceptCase value: CamelCase +- key: readability-identifier-naming.NamespaceCase + value: CamelCase +- key: readability-identifier-naming.NamespaceIgnoredRegexp + value: 'osg(DB|FX|Particle|Shadow|Viewer|Util)?' diff --git a/apps/components_tests/fx/lexer.cpp b/apps/components_tests/fx/lexer.cpp index 9c095a1f64..976f88d7a3 100644 --- a/apps/components_tests/fx/lexer.cpp +++ b/apps/components_tests/fx/lexer.cpp @@ -5,7 +5,7 @@ namespace { using namespace testing; - using namespace fx::Lexer; + using namespace Fx::Lexer; struct LexerTest : Test { diff --git a/apps/components_tests/fx/technique.cpp b/apps/components_tests/fx/technique.cpp index 2becf4da5b..b04ff5c52a 100644 --- a/apps/components_tests/fx/technique.cpp +++ b/apps/components_tests/fx/technique.cpp @@ -91,7 +91,7 @@ namespace )" }; using namespace testing; - using namespace fx; + using namespace Fx; struct TechniqueTest : Test { diff --git a/apps/components_tests/lua/testl10n.cpp b/apps/components_tests/lua/testl10n.cpp index 5528c0520a..7446822f7f 100644 --- a/apps/components_tests/lua/testl10n.cpp +++ b/apps/components_tests/lua/testl10n.cpp @@ -105,7 +105,7 @@ speed: "Speed" lua.protectedCall([&](LuaUtil::LuaView& view) { sol::state_view& l = view.sol(); internal::CaptureStdout(); - l10n::Manager l10nManager(mVFS.get()); + L10n::Manager l10nManager(mVFS.get()); l10nManager.setPreferredLocales({ "de", "en" }); EXPECT_THAT(internal::GetCapturedStdout(), "Preferred locales: gmst de en\n"); diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index 2ea152305f..ff85154289 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -42,7 +42,7 @@ int runLauncher(int argc, char* argv[]) resourcesPath = Files::pathToQString(variables["resources"].as().u8string()); } - l10n::installQtTranslations(app, "launcher", resourcesPath); + L10n::installQtTranslations(app, "launcher", resourcesPath); Launcher::MainDialog mainWin(configurationManager); diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 5807ef222b..244c458f46 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -755,7 +755,7 @@ void OMW::Engine::prepareEngine() mViewer->addEventHandler(mScreenCaptureHandler); - mL10nManager = std::make_unique(mVFS.get()); + mL10nManager = std::make_unique(mVFS.get()); mL10nManager->setPreferredLocales(Settings::general().mPreferredLocales, Settings::general().mGmstOverridesL10n); mEnvironment.setL10nManager(*mL10nManager); diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 38e95ea7c8..97b6a78ee9 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -113,7 +113,7 @@ namespace MWDialogue class Journal; } -namespace l10n +namespace L10n { class Manager; } @@ -141,7 +141,7 @@ namespace OMW std::unique_ptr mStateManager; std::unique_ptr mLuaManager; std::unique_ptr mLuaWorker; - std::unique_ptr mL10nManager; + std::unique_ptr mL10nManager; MWBase::Environment mEnvironment; ToUTF8::FromType mEncoding; std::unique_ptr mEncoder; diff --git a/apps/openmw/mwbase/environment.hpp b/apps/openmw/mwbase/environment.hpp index aa8a41b7c1..94f918a60b 100644 --- a/apps/openmw/mwbase/environment.hpp +++ b/apps/openmw/mwbase/environment.hpp @@ -10,7 +10,7 @@ namespace Resource class ResourceSystem; } -namespace l10n +namespace L10n { class Manager; } @@ -57,7 +57,7 @@ namespace MWBase StateManager* mStateManager = nullptr; LuaManager* mLuaManager = nullptr; Resource::ResourceSystem* mResourceSystem = nullptr; - l10n::Manager* mL10nManager = nullptr; + L10n::Manager* mL10nManager = nullptr; float mFrameRateLimit = 0; float mFrameDuration = 0; @@ -95,7 +95,7 @@ namespace MWBase void setResourceSystem(Resource::ResourceSystem& value) { mResourceSystem = &value; } - void setL10nManager(l10n::Manager& value) { mL10nManager = &value; } + void setL10nManager(L10n::Manager& value) { mL10nManager = &value; } Misc::NotNullPtr getWorld() const { return mWorld; } Misc::NotNullPtr getWorldModel() const { return mWorldModel; } @@ -122,7 +122,7 @@ namespace MWBase Misc::NotNullPtr getResourceSystem() const { return mResourceSystem; } - Misc::NotNullPtr getL10nManager() const { return mL10nManager; } + Misc::NotNullPtr getL10nManager() const { return mL10nManager; } float getFrameRateLimit() const { return mFrameRateLimit; } diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index c558f1bad9..e45388b2e0 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -91,7 +91,7 @@ namespace MWGui , mUpdateNextFrame(false) { mPreviewTexture - = std::make_unique(mPreview->getTexture(), mPreview->getTextureStateSet()); + = std::make_unique(mPreview->getTexture(), mPreview->getTextureStateSet()); mPreview->rebuild(); mMainWidget->castType()->eventWindowChangeCoord diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 263e676e15..8322ae9073 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -294,7 +294,7 @@ namespace MWGui if (!mGuiTexture.get()) { - mGuiTexture = std::make_unique(mTexture); + mGuiTexture = std::make_unique(mTexture); } if (!mCopyFramebufferToTextureCallback) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index bf4bd7644c..59d21886dc 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -599,27 +599,27 @@ namespace MWGui osg::ref_ptr texture = mLocalMapRender->getMapTexture(entry.mCellX, entry.mCellY); if (texture) { - entry.mMapTexture = std::make_unique(texture); + entry.mMapTexture = std::make_unique(texture); entry.mMapWidget->setRenderItemTexture(entry.mMapTexture.get()); entry.mMapWidget->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); needRedraw = true; } else - entry.mMapTexture = std::make_unique(std::string(), nullptr); + entry.mMapTexture = std::make_unique(std::string(), nullptr); } if (!entry.mFogTexture && mFogOfWarToggled && mFogOfWarEnabled) { osg::ref_ptr tex = mLocalMapRender->getFogOfWarTexture(entry.mCellX, entry.mCellY); if (tex) { - entry.mFogTexture = std::make_unique(tex); + entry.mFogTexture = std::make_unique(tex); entry.mFogWidget->setRenderItemTexture(entry.mFogTexture.get()); entry.mFogWidget->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); } else { entry.mFogWidget->setImageTexture("black"); - entry.mFogTexture = std::make_unique(std::string(), nullptr); + entry.mFogTexture = std::make_unique(std::string(), nullptr); } needRedraw = true; } @@ -1280,11 +1280,12 @@ namespace MWGui { if (!mGlobalMapTexture.get()) { - mGlobalMapTexture = std::make_unique(mGlobalMapRender->getBaseTexture()); + mGlobalMapTexture = std::make_unique(mGlobalMapRender->getBaseTexture()); mGlobalMapImage->setRenderItemTexture(mGlobalMapTexture.get()); mGlobalMapImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); - mGlobalMapOverlayTexture = std::make_unique(mGlobalMapRender->getOverlayTexture()); + mGlobalMapOverlayTexture + = std::make_unique(mGlobalMapRender->getOverlayTexture()); mGlobalMapOverlay->setRenderItemTexture(mGlobalMapOverlayTexture.get()); mGlobalMapOverlay->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); diff --git a/apps/openmw/mwgui/postprocessorhud.cpp b/apps/openmw/mwgui/postprocessorhud.cpp index cc95203a0f..68be9a7d4a 100644 --- a/apps/openmw/mwgui/postprocessorhud.cpp +++ b/apps/openmw/mwgui/postprocessorhud.cpp @@ -35,9 +35,9 @@ namespace MWGui { namespace { - std::shared_ptr& getTechnique(const MyGUI::ListBox& list, size_t selected) + std::shared_ptr& getTechnique(const MyGUI::ListBox& list, size_t selected) { - return *list.getItemDataAt>(selected); + return *list.getItemDataAt>(selected); } } @@ -110,7 +110,7 @@ namespace MWGui { for (size_t i = 1; i < mConfigArea->getChildCount(); ++i) { - if (auto* child = dynamic_cast(mConfigArea->getChildAt(i))) + if (auto* child = dynamic_cast(mConfigArea->getChildAt(i))) child->toDefault(); } } @@ -309,7 +309,7 @@ namespace MWGui auto technique = processor->loadTechnique(path); - if (technique->getStatus() == fx::Technique::Status::File_Not_exists) + if (technique->getStatus() == Fx::Technique::Status::File_Not_exists) return; while (mConfigArea->getChildCount() > 0) @@ -330,15 +330,15 @@ namespace MWGui const auto flags = technique->getFlags(); - const auto flag_interior = serializeBool(!(flags & fx::Technique::Flag_Disable_Interiors)); - const auto flag_exterior = serializeBool(!(flags & fx::Technique::Flag_Disable_Exteriors)); - const auto flag_underwater = serializeBool(!(flags & fx::Technique::Flag_Disable_Underwater)); - const auto flag_abovewater = serializeBool(!(flags & fx::Technique::Flag_Disable_Abovewater)); + const auto flag_interior = serializeBool(!(flags & Fx::Technique::Flag_Disable_Interiors)); + const auto flag_exterior = serializeBool(!(flags & Fx::Technique::Flag_Disable_Exteriors)); + const auto flag_underwater = serializeBool(!(flags & Fx::Technique::Flag_Disable_Underwater)); + const auto flag_abovewater = serializeBool(!(flags & Fx::Technique::Flag_Disable_Abovewater)); switch (technique->getStatus()) { - case fx::Technique::Status::Success: - case fx::Technique::Status::Uncompiled: + case Fx::Technique::Status::Success: + case Fx::Technique::Status::Uncompiled: { if (technique->getDynamic()) ss << "#{fontcolourhtml=header}#{OMWShaders:ShaderLocked}: #{fontcolourhtml=normal} " @@ -360,13 +360,13 @@ namespace MWGui << flag_abovewater; break; } - case fx::Technique::Status::Parse_Error: + case Fx::Technique::Status::Parse_Error: ss << "#{fontcolourhtml=negative}Shader Compile Error: #{fontcolourhtml=normal} <" << std::string(technique->getName()) << "> failed to compile." << endl << endl << technique->getLastError(); break; - case fx::Technique::Status::File_Not_exists: + case Fx::Technique::Status::File_Not_exists: break; } @@ -398,7 +398,7 @@ namespace MWGui divider->setCaptionWithReplacing(uniform->mHeader); } - fx::Widgets::UniformBase* uwidget = mConfigArea->createWidget( + Fx::Widgets::UniformBase* uwidget = mConfigArea->createWidget( "MW_UniformEdit", { 0, 0, 0, 22 }, MyGUI::Align::Default); uwidget->init(uniform); uwidget->getLabel()->eventMouseWheel += MyGUI::newDelegate(this, &PostProcessorHud::notifyMouseWheel); @@ -489,14 +489,14 @@ namespace MWGui void PostProcessorHud::registerMyGUIComponents() { MyGUI::FactoryManager& factory = MyGUI::FactoryManager::getInstance(); - factory.registerFactory("Widget"); - factory.registerFactory("Widget"); - factory.registerFactory("Widget"); - factory.registerFactory("Widget"); - factory.registerFactory("Widget"); - factory.registerFactory("Widget"); - factory.registerFactory("Widget"); - factory.registerFactory("Widget"); + factory.registerFactory("Widget"); + factory.registerFactory("Widget"); + factory.registerFactory("Widget"); + factory.registerFactory("Widget"); + factory.registerFactory("Widget"); + factory.registerFactory("Widget"); + factory.registerFactory("Widget"); + factory.registerFactory("Widget"); factory.registerFactory("Widget"); } } diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 7b445d419f..c7de8f4125 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -154,7 +154,7 @@ namespace MWGui mPreview->setAngle(mCurrentAngle); mPreviewTexture - = std::make_unique(mPreview->getTexture(), mPreview->getTextureStateSet()); + = std::make_unique(mPreview->getTexture(), mPreview->getTextureStateSet()); mPreviewImage->setRenderItemTexture(mPreviewTexture.get()); mPreviewImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 4957789ffd..eec3b7bfe6 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -488,7 +488,7 @@ namespace MWGui texture->setResizeNonPowerOfTwoHint(false); texture->setUnRefImageDataAfterApply(true); - mScreenshotTexture = std::make_unique(texture); + mScreenshotTexture = std::make_unique(texture); mScreenshot->setRenderItemTexture(mScreenshotTexture.get()); } } diff --git a/apps/openmw/mwgui/videowidget.cpp b/apps/openmw/mwgui/videowidget.cpp index a82d8ce67f..0fc555ab27 100644 --- a/apps/openmw/mwgui/videowidget.cpp +++ b/apps/openmw/mwgui/videowidget.cpp @@ -50,7 +50,7 @@ namespace MWGui if (!texture) return; - mTexture = std::make_unique(texture); + mTexture = std::make_unique(texture); setRenderItemTexture(mTexture.get()); getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index c7c4b575a5..358816221d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -205,7 +205,7 @@ namespace MWGui SDL_GL_GetDrawableSize(window, &dw, &dh); mScalingFactor = Settings::gui().mScalingFactor * (dw / w); - mGuiPlatform = std::make_unique(viewer, guiRoot, resourceSystem->getImageManager(), + mGuiPlatform = std::make_unique(viewer, guiRoot, resourceSystem->getImageManager(), resourceSystem->getVFS(), mScalingFactor, "mygui", logpath / "MyGUI.log"); mGui = std::make_unique(); @@ -229,8 +229,8 @@ namespace MWGui MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Layer"); - MyGUI::FactoryManager::getInstance().registerFactory("Layer"); + MyGUI::FactoryManager::getInstance().registerFactory("Layer"); + MyGUI::FactoryManager::getInstance().registerFactory("Layer"); BookPage::registerMyGUIComponents(); PostProcessorHud::registerMyGUIComponents(); ItemView::registerComponents(); @@ -1127,7 +1127,7 @@ namespace MWGui std::vector split; Misc::StringUtils::split(tag, split, ":"); - l10n::Manager& l10nManager = *MWBase::Environment::get().getL10nManager(); + L10n::Manager& l10nManager = *MWBase::Environment::get().getL10nManager(); // If a key has a "Context:KeyName" format, use YAML to translate data if (split.size() == 2) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index b04c648986..c231718db6 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -402,7 +402,7 @@ namespace MWGui Resource::ResourceSystem* mResourceSystem; osg::ref_ptr mWorkQueue; - std::unique_ptr mGuiPlatform; + std::unique_ptr mGuiPlatform; osgViewer::Viewer* mViewer; std::unique_ptr mFontLoader; diff --git a/apps/openmw/mwlua/postprocessingbindings.cpp b/apps/openmw/mwlua/postprocessingbindings.cpp index 6127cb4b27..f12bda8650 100644 --- a/apps/openmw/mwlua/postprocessingbindings.cpp +++ b/apps/openmw/mwlua/postprocessingbindings.cpp @@ -35,9 +35,9 @@ namespace MWLua { struct Shader { - std::shared_ptr mShader; + std::shared_ptr mShader; - Shader(std::shared_ptr shader) + Shader(std::shared_ptr shader) : mShader(std::move(shader)) { } diff --git a/apps/openmw/mwrender/pingpongcanvas.cpp b/apps/openmw/mwrender/pingpongcanvas.cpp index 5a37e09d84..a289272d1b 100644 --- a/apps/openmw/mwrender/pingpongcanvas.cpp +++ b/apps/openmw/mwrender/pingpongcanvas.cpp @@ -46,7 +46,7 @@ namespace MWRender mMultiviewResolveStateSet->addUniform(new osg::Uniform("lastShader", 0)); } - void PingPongCanvas::setPasses(fx::DispatchArray&& passes) + void PingPongCanvas::setPasses(Fx::DispatchArray&& passes) { mPasses = std::move(passes); } @@ -54,8 +54,8 @@ namespace MWRender void PingPongCanvas::setMask(bool underwater, bool exterior) { mMask = 0; - mMask |= underwater ? fx::Technique::Flag_Disable_Underwater : fx::Technique::Flag_Disable_Abovewater; - mMask |= exterior ? fx::Technique::Flag_Disable_Exteriors : fx::Technique::Flag_Disable_Interiors; + mMask |= underwater ? Fx::Technique::Flag_Disable_Underwater : Fx::Technique::Flag_Disable_Abovewater; + mMask |= exterior ? Fx::Technique::Flag_Disable_Exteriors : Fx::Technique::Flag_Disable_Interiors; } void PingPongCanvas::drawGeometry(osg::RenderInfo& renderInfo) const diff --git a/apps/openmw/mwrender/pingpongcanvas.hpp b/apps/openmw/mwrender/pingpongcanvas.hpp index 5a37b7fbc9..f5bfcb6ffe 100644 --- a/apps/openmw/mwrender/pingpongcanvas.hpp +++ b/apps/openmw/mwrender/pingpongcanvas.hpp @@ -31,14 +31,14 @@ namespace MWRender void dirty() { mDirty = true; } - void setDirtyAttachments(const std::vector& attachments) + void setDirtyAttachments(const std::vector& attachments) { mDirtyAttachments = attachments; } - const fx::DispatchArray& getPasses() { return mPasses; } + const Fx::DispatchArray& getPasses() { return mPasses; } - void setPasses(fx::DispatchArray&& passes); + void setPasses(Fx::DispatchArray&& passes); void setMask(bool underwater, bool exterior); @@ -60,8 +60,8 @@ namespace MWRender bool mAvgLum = false; bool mPostprocessing = false; - fx::DispatchArray mPasses; - fx::FlagsType mMask = 0; + Fx::DispatchArray mPasses; + Fx::FlagsType mMask = 0; osg::ref_ptr mFallbackProgram; osg::ref_ptr mMultiviewResolveProgram; @@ -74,7 +74,7 @@ namespace MWRender osg::ref_ptr mTextureDistortion; mutable bool mDirty = false; - mutable std::vector mDirtyAttachments; + mutable std::vector mDirtyAttachments; mutable osg::ref_ptr mRenderViewport; mutable osg::ref_ptr mMultiviewResolveFramebuffer; mutable osg::ref_ptr mDestinationFBO; diff --git a/apps/openmw/mwrender/postprocessor.cpp b/apps/openmw/mwrender/postprocessor.cpp index d941e5daff..365429a4a8 100644 --- a/apps/openmw/mwrender/postprocessor.cpp +++ b/apps/openmw/mwrender/postprocessor.cpp @@ -207,7 +207,7 @@ namespace MWRender mGLSLVersion = ext->glslLanguageVersion * 100; mUBO = ext->isUniformBufferObjectSupported && mGLSLVersion >= 330; - mStateUpdater = new fx::StateUpdater(mUBO); + mStateUpdater = new Fx::StateUpdater(mUBO); addChild(mHUDCamera); addChild(mRootNode); @@ -251,10 +251,10 @@ namespace MWRender void PostProcessor::populateTechniqueFiles() { - for (const auto& path : mVFS->getRecursiveDirectoryIterator(fx::Technique::sSubdir)) + for (const auto& path : mVFS->getRecursiveDirectoryIterator(Fx::Technique::sSubdir)) { std::string_view fileExt = Misc::getFileExtension(path); - if (path.parent().parent().empty() && fileExt == fx::Technique::sExt) + if (path.parent().parent().empty() && fileExt == Fx::Technique::sExt) { mTechniqueFiles.emplace(path); } @@ -347,7 +347,7 @@ namespace MWRender for (auto& technique : mTechniques) { - if (technique->getStatus() == fx::Technique::Status::File_Not_exists) + if (technique->getStatus() == Fx::Technique::Status::File_Not_exists) continue; const auto lastWriteTime = mVFS->getLastModified(technique->getFileName()); @@ -400,7 +400,7 @@ namespace MWRender createObjectsForFrame(frameId); mDirty = false; - mCanvases[frameId]->setPasses(fx::DispatchArray(mTemplateData)); + mCanvases[frameId]->setPasses(Fx::DispatchArray(mTemplateData)); } if ((mNormalsSupported && mNormals != mPrevNormals) || (mPassLights != mPrevPassLights)) @@ -565,7 +565,7 @@ namespace MWRender mNormals = false; mPassLights = false; - std::vector attachmentsToDirty; + std::vector attachmentsToDirty; for (const auto& technique : mTechniques) { @@ -579,7 +579,7 @@ namespace MWRender continue; } - fx::DispatchNode node; + Fx::DispatchNode node; node.mFlags = technique->getFlags(); @@ -592,7 +592,7 @@ namespace MWRender if (technique->getLights()) mPassLights = true; - if (node.mFlags & fx::Technique::Flag_Disable_SunGlare) + if (node.mFlags & Fx::Technique::Flag_Disable_SunGlare) sunglare = false; // required default samplers available to every shader pass @@ -638,7 +638,7 @@ namespace MWRender for (const auto& pass : technique->getPasses()) { int subTexUnit = texUnit; - fx::DispatchNode::SubPass subPass; + Fx::DispatchNode::SubPass subPass; pass->prepareStateSet(subPass.mStateSet, technique->getName()); @@ -673,7 +673,7 @@ namespace MWRender [renderTarget](const auto& rt) { return renderTarget.mTarget == rt.mTarget; }) == attachmentsToDirty.cend()) { - attachmentsToDirty.push_back(fx::Types::RenderTarget(renderTarget)); + attachmentsToDirty.push_back(Fx::Types::RenderTarget(renderTarget)); } } @@ -692,7 +692,7 @@ namespace MWRender [renderTarget](const auto& rt) { return renderTarget.mTarget == rt.mTarget; }) == attachmentsToDirty.cend()) { - attachmentsToDirty.push_back(fx::Types::RenderTarget(renderTarget)); + attachmentsToDirty.push_back(Fx::Types::RenderTarget(renderTarget)); } subTexUnit++; } @@ -705,7 +705,7 @@ namespace MWRender mTemplateData.emplace_back(std::move(node)); } - mCanvases[frameId]->setPasses(fx::DispatchArray(mTemplateData)); + mCanvases[frameId]->setPasses(Fx::DispatchArray(mTemplateData)); if (auto hud = MWBase::Environment::get().getWindowManager()->getPostProcessorHud()) hud->updateTechniques(); @@ -717,7 +717,7 @@ namespace MWRender } PostProcessor::Status PostProcessor::enableTechnique( - std::shared_ptr technique, std::optional location) + std::shared_ptr technique, std::optional location) { if (technique->getLocked() || (location.has_value() && location.value() < 0)) return Status_Error; @@ -732,7 +732,7 @@ namespace MWRender return Status_Toggled; } - PostProcessor::Status PostProcessor::disableTechnique(std::shared_ptr technique, bool dirty) + PostProcessor::Status PostProcessor::disableTechnique(std::shared_ptr technique, bool dirty) { if (technique->getLocked()) return Status_Error; @@ -748,7 +748,7 @@ namespace MWRender return Status_Toggled; } - bool PostProcessor::isTechniqueEnabled(const std::shared_ptr& technique) const + bool PostProcessor::isTechniqueEnabled(const std::shared_ptr& technique) const { if (auto it = std::find(mTechniques.begin(), mTechniques.end(), technique); it == mTechniques.end()) return false; @@ -756,13 +756,13 @@ namespace MWRender return technique->isValid(); } - std::shared_ptr PostProcessor::loadTechnique(std::string_view name, bool loadNextFrame) + std::shared_ptr PostProcessor::loadTechnique(std::string_view name, bool loadNextFrame) { - VFS::Path::Normalized path = fx::Technique::makeFileName(name); + VFS::Path::Normalized path = Fx::Technique::makeFileName(name); return loadTechnique(VFS::Path::NormalizedView(path), loadNextFrame); } - std::shared_ptr PostProcessor::loadTechnique(VFS::Path::NormalizedView path, bool loadNextFrame) + std::shared_ptr PostProcessor::loadTechnique(VFS::Path::NormalizedView path, bool loadNextFrame) { for (const auto& technique : mTemplates) if (technique->getFileName() == path) @@ -778,12 +778,12 @@ namespace MWRender else name = path.stem(); - auto technique = std::make_shared(*mVFS, *mRendering.getResourceSystem()->getImageManager(), + auto technique = std::make_shared(*mVFS, *mRendering.getResourceSystem()->getImageManager(), path, std::move(name), renderWidth(), renderHeight(), mUBO, mNormalsSupported); technique->compile(); - if (technique->getStatus() != fx::Technique::Status::File_Not_exists) + if (technique->getStatus() != Fx::Technique::Status::File_Not_exists) technique->setLastModificationTime(mVFS->getLastModified(path)); if (loadNextFrame) @@ -840,7 +840,7 @@ namespace MWRender { for (auto& technique : mTemplates) { - if (technique->getStatus() == fx::Technique::Status::File_Not_exists) + if (technique->getStatus() == Fx::Technique::Status::File_Not_exists) continue; technique->compile(); } diff --git a/apps/openmw/mwrender/postprocessor.hpp b/apps/openmw/mwrender/postprocessor.hpp index eb9bc6347c..f81a50e9d6 100644 --- a/apps/openmw/mwrender/postprocessor.hpp +++ b/apps/openmw/mwrender/postprocessor.hpp @@ -58,7 +58,7 @@ namespace MWRender public: using FBOArray = std::array, 6>; using TextureArray = std::array, 6>; - using TechniqueList = std::vector>; + using TechniqueList = std::vector>; enum TextureIndex { @@ -122,7 +122,7 @@ namespace MWRender osg::ref_ptr getHUDCamera() { return mHUDCamera; } - osg::ref_ptr getStateUpdater() { return mStateUpdater; } + osg::ref_ptr getStateUpdater() { return mStateUpdater; } const TechniqueList& getTechniques() { return mTechniques; } @@ -132,14 +132,14 @@ namespace MWRender void resize(); - Status enableTechnique(std::shared_ptr technique, std::optional location = std::nullopt); + Status enableTechnique(std::shared_ptr technique, std::optional location = std::nullopt); - Status disableTechnique(std::shared_ptr technique, bool dirty = true); + Status disableTechnique(std::shared_ptr technique, bool dirty = true); bool getSupportsNormalsRT() const { return mNormalsSupported; } template - void setUniform(std::shared_ptr technique, const std::string& name, const T& value) + void setUniform(std::shared_ptr technique, const std::string& name, const T& value) { if (!isEnabled()) return; @@ -158,7 +158,7 @@ namespace MWRender (*it)->setValue(value); } - std::optional getUniformSize(std::shared_ptr technique, const std::string& name) + std::optional getUniformSize(std::shared_ptr technique, const std::string& name) { auto it = technique->findUniform(name); @@ -168,7 +168,7 @@ namespace MWRender return (*it)->getNumElements(); } - bool isTechniqueEnabled(const std::shared_ptr& technique) const; + bool isTechniqueEnabled(const std::shared_ptr& technique) const; void setExteriorFlag(bool exterior) { mExteriorFlag = exterior; } @@ -176,8 +176,8 @@ namespace MWRender void toggleMode(); - std::shared_ptr loadTechnique(VFS::Path::NormalizedView path, bool loadNextFrame = false); - std::shared_ptr loadTechnique(std::string_view name, bool loadNextFrame = false); + std::shared_ptr loadTechnique(VFS::Path::NormalizedView path, bool loadNextFrame = false); + std::shared_ptr loadTechnique(std::string_view name, bool loadNextFrame = false); TechniqueList getChain(); @@ -263,13 +263,13 @@ namespace MWRender int mHeight; int mSamples; - osg::ref_ptr mStateUpdater; + osg::ref_ptr mStateUpdater; osg::ref_ptr mPingPongCull; std::array, 2> mCanvases; osg::ref_ptr mTransparentDepthPostPass; osg::ref_ptr mDistortionCallback; - fx::DispatchArray mTemplateData; + Fx::DispatchArray mTemplateData; }; } diff --git a/apps/wizard/main.cpp b/apps/wizard/main.cpp index 09a34994e4..bfade9bf68 100644 --- a/apps/wizard/main.cpp +++ b/apps/wizard/main.cpp @@ -45,7 +45,7 @@ int main(int argc, char* argv[]) resourcesPath = Files::pathToQString(variables["resources"].as().u8string()); } - l10n::installQtTranslations(app, "wizard", resourcesPath); + L10n::installQtTranslations(app, "wizard", resourcesPath); Wizard::MainWizard wizard(std::move(configurationManager)); diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp index 9540c85654..f5dfff9e26 100644 --- a/components/fallback/validate.hpp +++ b/components/fallback/validate.hpp @@ -5,10 +5,12 @@ #include #include +// NOLINTBEGIN(readability-identifier-naming) namespace boost { class any; } +// NOLINTEND(readability-identifier-naming) namespace Fallback { diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index 306ea38fe1..2e10f21252 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -9,11 +9,13 @@ #include #include +// NOLINTBEGIN(readability-identifier-naming) namespace boost::program_options { class options_description; class variables_map; } +// NOLINTEND(readability-identifier-naming) /** * \namespace Files diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index c9003f3aa8..f43c78bfd3 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -276,8 +276,8 @@ namespace Gui { Log(Debug::Info) << "Loading font file " << fileName; - osgMyGUI::DataManager* dataManager - = dynamic_cast(&osgMyGUI::DataManager::getInstance()); + MyGUIPlatform::DataManager* dataManager + = dynamic_cast(&MyGUIPlatform::DataManager::getInstance()); if (!dataManager) { Log(Debug::Error) << "Can not load TrueType font " << fontId << ": osgMyGUI::DataManager is not available."; @@ -287,7 +287,7 @@ namespace Gui // TODO: it may be worth to take in account resolution change, but it is not safe to replace used assets std::unique_ptr layersStream(dataManager->getData("openmw_layers.xml")); MyGUI::IntSize bookSize = getBookSize(layersStream.get()); - float bookScale = osgMyGUI::ScalingLayer::getScaleFactor(bookSize); + float bookScale = MyGUIPlatform::ScalingLayer::getScaleFactor(bookSize); const auto oldDataPath = dataManager->getDataPath({}); dataManager->setResourcePath("fonts"); diff --git a/components/fx/lexer.cpp b/components/fx/lexer.cpp index 2fc25e44f1..cab59df314 100644 --- a/components/fx/lexer.cpp +++ b/components/fx/lexer.cpp @@ -8,7 +8,7 @@ #include -namespace fx +namespace Fx { namespace Lexer { diff --git a/components/fx/lexer.hpp b/components/fx/lexer.hpp index dda6b3a0f6..1b32298608 100644 --- a/components/fx/lexer.hpp +++ b/components/fx/lexer.hpp @@ -9,7 +9,7 @@ #include "lexertypes.hpp" -namespace fx +namespace Fx { namespace Lexer { diff --git a/components/fx/lexertypes.hpp b/components/fx/lexertypes.hpp index 2a56a84a1a..327d6832c8 100644 --- a/components/fx/lexertypes.hpp +++ b/components/fx/lexertypes.hpp @@ -4,7 +4,7 @@ #include #include -namespace fx +namespace Fx { namespace Lexer { diff --git a/components/fx/parseconstants.hpp b/components/fx/parseconstants.hpp index 3ad9abd959..eec315042b 100644 --- a/components/fx/parseconstants.hpp +++ b/components/fx/parseconstants.hpp @@ -13,11 +13,11 @@ #include "technique.hpp" -namespace fx +namespace Fx { - namespace constants + namespace Constants { - constexpr std::array, 6> TechniqueFlag = { { + constexpr std::array, 6> TechniqueFlag = { { { "disable_interiors", Technique::Flag_Disable_Interiors }, { "disable_exteriors", Technique::Flag_Disable_Exteriors }, { "disable_underwater", Technique::Flag_Disable_Underwater }, diff --git a/components/fx/pass.cpp b/components/fx/pass.cpp index c55bee76e3..85b420f4fd 100644 --- a/components/fx/pass.cpp +++ b/components/fx/pass.cpp @@ -49,7 +49,7 @@ void main() } -namespace fx +namespace Fx { Pass::Pass(Pass::Type type, Pass::Order order, bool ubo) : mCompiled(false) diff --git a/components/fx/pass.hpp b/components/fx/pass.hpp index 1c417ac8cf..2e68bddcc5 100644 --- a/components/fx/pass.hpp +++ b/components/fx/pass.hpp @@ -18,7 +18,7 @@ namespace osg class StateSet; } -namespace fx +namespace Fx { class Technique; diff --git a/components/fx/stateupdater.cpp b/components/fx/stateupdater.cpp index 9e86f25b9c..8dd6bce994 100644 --- a/components/fx/stateupdater.cpp +++ b/components/fx/stateupdater.cpp @@ -5,7 +5,7 @@ #include -namespace fx +namespace Fx { std::string StateUpdater::sDefinition = UniformData::getDefinition("_omw_data"); diff --git a/components/fx/stateupdater.hpp b/components/fx/stateupdater.hpp index 33a7a09fe6..f5921faadf 100644 --- a/components/fx/stateupdater.hpp +++ b/components/fx/stateupdater.hpp @@ -7,7 +7,7 @@ #include #include -namespace fx +namespace Fx { class StateUpdater : public SceneUtil::StateSetUpdater { diff --git a/components/fx/technique.cpp b/components/fx/technique.cpp index 58ea55b2f6..5865298fe5 100644 --- a/components/fx/technique.cpp +++ b/components/fx/technique.cpp @@ -35,7 +35,7 @@ namespace }; } -namespace fx +namespace Fx { VFS::Path::Normalized Technique::makeFileName(std::string_view name) { @@ -280,7 +280,7 @@ namespace fx if (mRenderTargets.count(mBlockName)) error(Misc::StringUtils::format("redeclaration of render target '%s'", std::string(mBlockName))); - fx::Types::RenderTarget rt; + Fx::Types::RenderTarget rt; rt.mTarget->setTextureSize(mWidth, mHeight); rt.mTarget->setSourceFormat(GL_RGB); rt.mTarget->setInternalFormat(GL_RGB); @@ -341,7 +341,7 @@ namespace fx auto& pass = mPassMap[mBlockName]; if (!pass) - pass = std::make_shared(); + pass = std::make_shared(); pass->mName = mBlockName; @@ -364,7 +364,7 @@ namespace fx auto& pass = mPassMap[mBlockName]; if (!pass) - pass = std::make_shared(); + pass = std::make_shared(); pass->mUBO = mUBO; pass->mName = mBlockName; @@ -388,7 +388,7 @@ namespace fx auto& pass = mPassMap[mBlockName]; if (!pass) - pass = std::make_shared(); + pass = std::make_shared(); pass->mName = mBlockName; @@ -810,7 +810,7 @@ namespace fx auto& pass = mPassMap[mBlockName]; if (!pass) - pass = std::make_shared(); + pass = std::make_shared(); while (!isNext()) { @@ -883,7 +883,7 @@ namespace fx FlagsType Technique::parseFlags() { auto parseBit = [this](std::string_view term) { - for (const auto& [identifer, bit] : constants::TechniqueFlag) + for (const auto& [identifer, bit] : Constants::TechniqueFlag) { if (Misc::StringUtils::ciEqual(term, identifer)) return bit; @@ -902,7 +902,7 @@ namespace fx { expect(); - for (const auto& [identifer, mode] : constants::FilterMode) + for (const auto& [identifer, mode] : Constants::FilterMode) { if (asLiteral() == identifer) return mode; @@ -915,7 +915,7 @@ namespace fx { expect(); - for (const auto& [identifer, mode] : constants::WrapMode) + for (const auto& [identifer, mode] : Constants::WrapMode) { if (asLiteral() == identifer) return mode; @@ -933,7 +933,7 @@ namespace fx { expect(); - for (const auto& [identifer, mode] : constants::Compression) + for (const auto& [identifer, mode] : Constants::Compression) { if (asLiteral() == identifer) return mode; @@ -946,7 +946,7 @@ namespace fx { expect(); - for (const auto& [identifer, mode] : constants::InternalFormat) + for (const auto& [identifer, mode] : Constants::InternalFormat) { if (asLiteral() == identifer) return mode; @@ -959,7 +959,7 @@ namespace fx { expect(); - for (const auto& [identifer, mode] : constants::SourceType) + for (const auto& [identifer, mode] : Constants::SourceType) { if (asLiteral() == identifer) return mode; @@ -972,7 +972,7 @@ namespace fx { expect(); - for (const auto& [identifer, mode] : constants::SourceFormat) + for (const auto& [identifer, mode] : Constants::SourceFormat) { if (asLiteral() == identifer) return mode; @@ -985,7 +985,7 @@ namespace fx { expect(); - for (const auto& [identifer, mode] : constants::BlendEquation) + for (const auto& [identifer, mode] : Constants::BlendEquation) { if (asLiteral() == identifer) return mode; @@ -998,7 +998,7 @@ namespace fx { expect(); - for (const auto& [identifer, mode] : constants::BlendFunc) + for (const auto& [identifer, mode] : Constants::BlendFunc) { if (asLiteral() == identifer) return mode; @@ -1025,11 +1025,11 @@ namespace fx */ expect(); - std::vector> choices; + std::vector> choices; while (!isNext()) { - fx::Types::Choice choice; + Fx::Types::Choice choice; choice.mLabel = parseString(); expect(); choice.mValue = getUniformValue(); diff --git a/components/fx/technique.hpp b/components/fx/technique.hpp index 00b87a86e2..ebf3fe30f5 100644 --- a/components/fx/technique.hpp +++ b/components/fx/technique.hpp @@ -29,7 +29,7 @@ namespace VFS class Manager; } -namespace fx +namespace Fx { using FlagsType = size_t; @@ -85,7 +85,7 @@ namespace fx } // not safe to read/write in draw thread - std::shared_ptr mHandle = nullptr; + std::shared_ptr mHandle = nullptr; FlagsType mFlags = 0; diff --git a/components/fx/types.hpp b/components/fx/types.hpp index 1536cda115..ddfa966010 100644 --- a/components/fx/types.hpp +++ b/components/fx/types.hpp @@ -12,7 +12,7 @@ #include #include -namespace fx +namespace Fx { namespace Types { diff --git a/components/fx/widgets.cpp b/components/fx/widgets.cpp index 8382ca2d56..087e071b96 100644 --- a/components/fx/widgets.cpp +++ b/components/fx/widgets.cpp @@ -6,7 +6,7 @@ namespace { template void createVectorWidget( - const std::shared_ptr& uniform, MyGUI::Widget* client, fx::Widgets::UniformBase* base) + const std::shared_ptr& uniform, MyGUI::Widget* client, Fx::Widgets::UniformBase* base) { int height = client->getHeight(); base->setSize(base->getSize().width, (base->getSize().height - height) + (height * T::num_components)); @@ -16,13 +16,13 @@ namespace { auto* widget = client->createWidget( "MW_ValueEditNumber", { 0, height * i, client->getWidth(), height }, MyGUI::Align::Default); - widget->setData(uniform, static_cast(i)); + widget->setData(uniform, static_cast(i)); base->addItem(widget); } } } -namespace fx +namespace Fx { namespace Widgets { @@ -127,7 +127,7 @@ namespace fx mChoices->eventComboChangePosition += MyGUI::newDelegate(this, &EditChoice::notifyComboBoxChanged); } - void UniformBase::init(const std::shared_ptr& uniform) + void UniformBase::init(const std::shared_ptr& uniform) { if (uniform->mDisplayName.empty()) mLabel->setCaption(uniform->mName); diff --git a/components/fx/widgets.hpp b/components/fx/widgets.hpp index 59787ed9aa..c91fa01c4e 100644 --- a/components/fx/widgets.hpp +++ b/components/fx/widgets.hpp @@ -28,7 +28,7 @@ namespace Gui class AutoSizedButton; } -namespace fx +namespace Fx { namespace Widgets { @@ -46,7 +46,7 @@ namespace fx public: virtual ~EditBase() = default; - void setData(const std::shared_ptr& uniform, Index index = None) + void setData(const std::shared_ptr& uniform, Index index = None) { mUniform = uniform; mIndex = index; @@ -57,7 +57,7 @@ namespace fx virtual void toDefault() = 0; protected: - std::shared_ptr mUniform; + std::shared_ptr mUniform; Index mIndex; }; @@ -268,7 +268,7 @@ namespace fx MYGUI_RTTI_DERIVED(UniformBase) public: - void init(const std::shared_ptr& uniform); + void init(const std::shared_ptr& uniform); void toDefault(); diff --git a/components/l10n/manager.cpp b/components/l10n/manager.cpp index f6f4bb4f05..27a4d603d4 100644 --- a/components/l10n/manager.cpp +++ b/components/l10n/manager.cpp @@ -6,7 +6,7 @@ #include #include -namespace l10n +namespace L10n { void Manager::setPreferredLocales(const std::vector& langs, bool gmstHasPriority) diff --git a/components/l10n/manager.hpp b/components/l10n/manager.hpp index 2ee54921b3..4b047fa9d7 100644 --- a/components/l10n/manager.hpp +++ b/components/l10n/manager.hpp @@ -10,7 +10,7 @@ namespace VFS class Manager; } -namespace l10n +namespace L10n { class Manager diff --git a/components/l10n/messagebundles.cpp b/components/l10n/messagebundles.cpp index 2948ff155e..e8a56a9bb3 100644 --- a/components/l10n/messagebundles.cpp +++ b/components/l10n/messagebundles.cpp @@ -7,7 +7,7 @@ #include -namespace l10n +namespace L10n { MessageBundles::MessageBundles(const std::vector& preferredLocales, icu::Locale& fallbackLocale) : mFallbackLocale(fallbackLocale) diff --git a/components/l10n/messagebundles.hpp b/components/l10n/messagebundles.hpp index 0ea92e93fe..f142d3f2ac 100644 --- a/components/l10n/messagebundles.hpp +++ b/components/l10n/messagebundles.hpp @@ -10,7 +10,7 @@ #include #include -namespace l10n +namespace L10n { /** * @brief A collection of Message Bundles diff --git a/components/l10n/qttranslations.cpp b/components/l10n/qttranslations.cpp index 9bc146699e..1051b3dd2d 100644 --- a/components/l10n/qttranslations.cpp +++ b/components/l10n/qttranslations.cpp @@ -3,7 +3,7 @@ #include #include -namespace l10n +namespace L10n { QTranslator AppTranslator{}; QTranslator ComponentsTranslator{}; diff --git a/components/l10n/qttranslations.hpp b/components/l10n/qttranslations.hpp index 3ce87f0837..6a2bf9d903 100644 --- a/components/l10n/qttranslations.hpp +++ b/components/l10n/qttranslations.hpp @@ -4,7 +4,7 @@ #include #include -namespace l10n +namespace L10n { extern QTranslator AppTranslator; extern QTranslator ComponentsTranslator; diff --git a/components/lua/l10n.cpp b/components/lua/l10n.cpp index ec42992ebb..8153efd5b5 100644 --- a/components/lua/l10n.cpp +++ b/components/lua/l10n.cpp @@ -8,7 +8,7 @@ namespace { struct L10nContext { - std::shared_ptr mData; + std::shared_ptr mData; }; void getICUArgs(std::string_view messageId, const sol::table& table, std::vector& argNames, @@ -52,7 +52,7 @@ namespace sol namespace LuaUtil { - sol::function initL10nLoader(lua_State* L, l10n::Manager* manager) + sol::function initL10nLoader(lua_State* L, L10n::Manager* manager) { sol::state_view lua(L); sol::usertype ctxDef = lua.new_usertype("L10nContext"); diff --git a/components/lua/l10n.hpp b/components/lua/l10n.hpp index 1fc3e17747..2abe7f56f2 100644 --- a/components/lua/l10n.hpp +++ b/components/lua/l10n.hpp @@ -3,14 +3,14 @@ #include -namespace l10n +namespace L10n { class Manager; } namespace LuaUtil { - sol::function initL10nLoader(lua_State*, l10n::Manager* manager); + sol::function initL10nLoader(lua_State*, L10n::Manager* manager); } #endif // COMPONENTS_LUA_L10N_H diff --git a/components/lua/luastate.cpp b/components/lua/luastate.cpp index f959263153..b83415e58d 100644 --- a/components/lua/luastate.cpp +++ b/components/lua/luastate.cpp @@ -453,7 +453,7 @@ namespace LuaUtil return call(sol::state_view(obj.lua_state())["tostring"], obj); } - std::string internal::formatCastingError(const sol::object& obj, const std::type_info& t) + std::string Internal::formatCastingError(const sol::object& obj, const std::type_info& t) { const char* typeName = t.name(); if (t == typeid(int)) diff --git a/components/lua/luastate.hpp b/components/lua/luastate.hpp index d842478cb1..7ce9a0ec94 100644 --- a/components/lua/luastate.hpp +++ b/components/lua/luastate.hpp @@ -325,7 +325,7 @@ namespace LuaUtil // String representation of a Lua object. Should be used for debugging/logging purposes only. std::string toString(const sol::object&); - namespace internal + namespace Internal { std::string formatCastingError(const sol::object& obj, const std::type_info&); } @@ -334,7 +334,7 @@ namespace LuaUtil decltype(auto) cast(const sol::object& obj) { if (!obj.is()) - throw std::runtime_error(internal::formatCastingError(obj, typeid(T))); + throw std::runtime_error(Internal::formatCastingError(obj, typeid(T))); return obj.as(); } diff --git a/components/myguiplatform/additivelayer.cpp b/components/myguiplatform/additivelayer.cpp index d170c831a6..9ffdc9b84e 100644 --- a/components/myguiplatform/additivelayer.cpp +++ b/components/myguiplatform/additivelayer.cpp @@ -5,7 +5,7 @@ #include "myguirendermanager.hpp" -namespace osgMyGUI +namespace MyGUIPlatform { AdditiveLayer::AdditiveLayer() diff --git a/components/myguiplatform/additivelayer.hpp b/components/myguiplatform/additivelayer.hpp index cfd5c82058..4b5185f97f 100644 --- a/components/myguiplatform/additivelayer.hpp +++ b/components/myguiplatform/additivelayer.hpp @@ -10,7 +10,7 @@ namespace osg class StateSet; } -namespace osgMyGUI +namespace MyGUIPlatform { /// @brief A Layer rendering with additive blend mode. diff --git a/components/myguiplatform/myguidatamanager.cpp b/components/myguiplatform/myguidatamanager.cpp index 49dba3634b..41a2d84e80 100644 --- a/components/myguiplatform/myguidatamanager.cpp +++ b/components/myguiplatform/myguidatamanager.cpp @@ -24,7 +24,7 @@ namespace }; } -namespace osgMyGUI +namespace MyGUIPlatform { void DataManager::setResourcePath(const std::filesystem::path& path) diff --git a/components/myguiplatform/myguidatamanager.hpp b/components/myguiplatform/myguidatamanager.hpp index 5b392177b7..f7489f8b65 100644 --- a/components/myguiplatform/myguidatamanager.hpp +++ b/components/myguiplatform/myguidatamanager.hpp @@ -11,7 +11,7 @@ namespace VFS class Manager; } -namespace osgMyGUI +namespace MyGUIPlatform { class DataManager : public MyGUI::DataManager diff --git a/components/myguiplatform/myguiloglistener.cpp b/components/myguiplatform/myguiloglistener.cpp index 3e52e75ad2..66b35e0961 100644 --- a/components/myguiplatform/myguiloglistener.cpp +++ b/components/myguiplatform/myguiloglistener.cpp @@ -4,7 +4,7 @@ #include -namespace osgMyGUI +namespace MyGUIPlatform { void CustomLogListener::open() { diff --git a/components/myguiplatform/myguiloglistener.hpp b/components/myguiplatform/myguiloglistener.hpp index 15cea0effd..3557f56540 100644 --- a/components/myguiplatform/myguiloglistener.hpp +++ b/components/myguiplatform/myguiloglistener.hpp @@ -10,7 +10,7 @@ #include #include -namespace osgMyGUI +namespace MyGUIPlatform { /// \brief Custom MyGUI::ILogListener interface implementation diff --git a/components/myguiplatform/myguiplatform.cpp b/components/myguiplatform/myguiplatform.cpp index 20fdaa7e7c..9d24e13ca1 100644 --- a/components/myguiplatform/myguiplatform.cpp +++ b/components/myguiplatform/myguiplatform.cpp @@ -6,7 +6,7 @@ #include "components/files/conversion.hpp" -namespace osgMyGUI +namespace MyGUIPlatform { Platform::Platform(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ImageManager* imageManager, diff --git a/components/myguiplatform/myguiplatform.hpp b/components/myguiplatform/myguiplatform.hpp index 66b02cd8ba..ff7e4a339f 100644 --- a/components/myguiplatform/myguiplatform.hpp +++ b/components/myguiplatform/myguiplatform.hpp @@ -26,7 +26,7 @@ namespace VFS class Manager; } -namespace osgMyGUI +namespace MyGUIPlatform { class RenderManager; diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 5d32641b6d..a17e387ed6 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -40,12 +40,12 @@ } \ } while (0) -namespace osgMyGUI +namespace MyGUIPlatform { class Drawable : public osg::Drawable { - osgMyGUI::RenderManager* mParent; + MyGUIPlatform::RenderManager* mParent; osg::ref_ptr mStateSet; public: @@ -58,12 +58,12 @@ namespace osgMyGUI { } - void setRenderManager(osgMyGUI::RenderManager* renderManager) { mRenderManager = renderManager; } + void setRenderManager(MyGUIPlatform::RenderManager* renderManager) { mRenderManager = renderManager; } void operator()(osg::Node*, osg::NodeVisitor*) { mRenderManager->update(); } private: - osgMyGUI::RenderManager* mRenderManager; + MyGUIPlatform::RenderManager* mRenderManager; }; // Stage 1: collect draw calls. Run during the Cull traversal. @@ -75,12 +75,12 @@ namespace osgMyGUI { } - void setRenderManager(osgMyGUI::RenderManager* renderManager) { mRenderManager = renderManager; } + void setRenderManager(MyGUIPlatform::RenderManager* renderManager) { mRenderManager = renderManager; } void operator()(osg::Node*, osg::NodeVisitor*) { mRenderManager->collectDrawCalls(); } private: - osgMyGUI::RenderManager* mRenderManager; + MyGUIPlatform::RenderManager* mRenderManager; }; // Stage 2: execute the draw calls. Run during the Draw traversal. May run in parallel with the update traversal @@ -162,7 +162,7 @@ namespace osgMyGUI } public: - Drawable(osgMyGUI::RenderManager* parent = nullptr) + Drawable(MyGUIPlatform::RenderManager* parent = nullptr) : mParent(parent) , mWriteTo(0) , mReadFrom(0) diff --git a/components/myguiplatform/myguirendermanager.hpp b/components/myguiplatform/myguirendermanager.hpp index 7f1582203a..737a0eb21e 100644 --- a/components/myguiplatform/myguirendermanager.hpp +++ b/components/myguiplatform/myguirendermanager.hpp @@ -28,7 +28,7 @@ namespace osg class StateSet; } -namespace osgMyGUI +namespace MyGUIPlatform { class Drawable; diff --git a/components/myguiplatform/myguitexture.cpp b/components/myguiplatform/myguitexture.cpp index 9d865e1296..529488beb1 100644 --- a/components/myguiplatform/myguitexture.cpp +++ b/components/myguiplatform/myguitexture.cpp @@ -8,7 +8,7 @@ #include #include -namespace osgMyGUI +namespace MyGUIPlatform { OSGTexture::OSGTexture(const std::string& name, Resource::ImageManager* imageManager) diff --git a/components/myguiplatform/myguitexture.hpp b/components/myguiplatform/myguitexture.hpp index 7139a81dba..3e34820069 100644 --- a/components/myguiplatform/myguitexture.hpp +++ b/components/myguiplatform/myguitexture.hpp @@ -17,7 +17,7 @@ namespace Resource class ImageManager; } -namespace osgMyGUI +namespace MyGUIPlatform { class OSGTexture final : public MyGUI::ITexture diff --git a/components/myguiplatform/scalinglayer.cpp b/components/myguiplatform/scalinglayer.cpp index c04134bfad..1660e4f0ca 100644 --- a/components/myguiplatform/scalinglayer.cpp +++ b/components/myguiplatform/scalinglayer.cpp @@ -3,7 +3,7 @@ #include #include -namespace osgMyGUI +namespace MyGUIPlatform { /// @brief the ProxyRenderTarget allows to adjust the pixel scale and offset for a "source" render target. diff --git a/components/myguiplatform/scalinglayer.hpp b/components/myguiplatform/scalinglayer.hpp index 4f04ce917a..512bb0109e 100644 --- a/components/myguiplatform/scalinglayer.hpp +++ b/components/myguiplatform/scalinglayer.hpp @@ -3,7 +3,7 @@ #include -namespace osgMyGUI +namespace MyGUIPlatform { ///@brief A Layer that lays out and renders widgets in screen-relative coordinates. The "Size" property determines From 30cfb42ed1e21716ace66c44b47c0f9d09fc0365 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Mon, 21 Jul 2025 17:57:51 +0200 Subject: [PATCH 259/330] Fix rebase fallout --- apps/openmw/mwmechanics/character.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 77f1ef6d15..1aac063ce3 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1159,7 +1159,7 @@ namespace MWMechanics else if (action == "shoot release") { // See notes for melee release above - if (mAttackStrength != -1.f && mAnimation) + if (mReadyToHit) { mAnimation->releaseArrow(mAttackStrength); mReadyToHit = false; From 93cde36b09732f2dd06b8882fab7e9952e6f1ee2 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Mon, 9 Jun 2025 12:05:01 +0300 Subject: [PATCH 260/330] Deduplicate GetPCRunning logic --- apps/openmw/mwclass/creature.cpp | 4 +-- apps/openmw/mwclass/npc.cpp | 25 ++++++------------- .../mwmechanics/mechanicsmanagerimp.cpp | 21 ++++++++++++---- apps/openmw/mwscript/controlextensions.cpp | 9 +------ 4 files changed, 26 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index b85bb9e996..a1c632dab9 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -530,10 +530,11 @@ namespace MWClass const MWBase::World* world = MWBase::Environment::get().getWorld(); const MWMechanics::MagicEffects& mageffects = stats.getMagicEffects(); + const float normalizedEncumbrance = getNormalizedEncumbrance(ptr); float moveSpeed; - if (getEncumbrance(ptr) > getCapacity(ptr)) + if (normalizedEncumbrance > 1.0f) moveSpeed = 0.0f; else if (canFly(ptr) || (mageffects.getOrDefault(ESM::MagicEffect::Levitate).getMagnitude() > 0 && world->isLevitationEnabled())) @@ -543,7 +544,6 @@ namespace MWClass + mageffects.getOrDefault(ESM::MagicEffect::Levitate).getMagnitude()); flySpeed = gmst.fMinFlySpeed->mValue.getFloat() + flySpeed * (gmst.fMaxFlySpeed->mValue.getFloat() - gmst.fMinFlySpeed->mValue.getFloat()); - const float normalizedEncumbrance = getNormalizedEncumbrance(ptr); flySpeed *= 1.0f - gmst.fEncumberedMoveEffect->mValue.getFloat() * normalizedEncumbrance; flySpeed = std::max(0.0f, flySpeed); moveSpeed = flySpeed; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index c03d132503..693caeb5ae 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -990,15 +990,10 @@ namespace MWClass const MWMechanics::MagicEffects& mageffects = stats.getMagicEffects(); const float normalizedEncumbrance = getNormalizedEncumbrance(ptr); - - bool swimming = world->isSwimming(ptr); - bool sneaking = MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr); - bool running = stats.getStance(MWMechanics::CreatureStats::Stance_Run); - bool inair = !world->isOnGround(ptr) && !swimming && !world->isFlying(ptr); - running = running && (inair || MWBase::Environment::get().getMechanicsManager()->isRunning(ptr)); + const bool running = MWBase::Environment::get().getMechanicsManager()->isRunning(ptr); float moveSpeed; - if (getEncumbrance(ptr) > getCapacity(ptr)) + if (normalizedEncumbrance > 1.0f) moveSpeed = 0.0f; else if (mageffects.getOrDefault(ESM::MagicEffect::Levitate).getMagnitude() > 0 && world->isLevitationEnabled()) { @@ -1011,9 +1006,9 @@ namespace MWClass flySpeed = std::max(0.0f, flySpeed); moveSpeed = flySpeed; } - else if (swimming) + else if (world->isSwimming(ptr)) moveSpeed = getSwimSpeed(ptr); - else if (running && !sneaking) + else if (running && !MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr)) moveSpeed = getRunSpeed(ptr); else moveSpeed = getWalkSpeed(ptr); @@ -1509,14 +1504,8 @@ namespace MWClass float Npc::getSwimSpeed(const MWWorld::Ptr& ptr) const { - const MWBase::World* world = MWBase::Environment::get().getWorld(); - const MWMechanics::NpcStats& stats = getNpcStats(ptr); - const MWMechanics::MagicEffects& mageffects = stats.getMagicEffects(); - const bool swimming = world->isSwimming(ptr); - const bool inair = !world->isOnGround(ptr) && !swimming && !world->isFlying(ptr); - const bool running = stats.getStance(MWMechanics::CreatureStats::Stance_Run) - && (inair || MWBase::Environment::get().getMechanicsManager()->isRunning(ptr)); - - return getSwimSpeedImpl(ptr, getGmst(), mageffects, running ? getRunSpeed(ptr) : getWalkSpeed(ptr)); + const MWMechanics::MagicEffects& effects = getNpcStats(ptr).getMagicEffects(); + const bool running = MWBase::Environment::get().getMechanicsManager()->isRunning(ptr); + return getSwimSpeedImpl(ptr, getGmst(), effects, running ? getRunSpeed(ptr) : getWalkSpeed(ptr)); } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 384c25953b..d09b5b3f9b 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -368,17 +368,28 @@ namespace MWMechanics bool MechanicsManager::isRunning(const MWWorld::Ptr& ptr) { - return mActors.isRunning(ptr); + CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); + if (!stats.getStance(MWMechanics::CreatureStats::Stance_Run)) + return false; + + if (mActors.isRunning(ptr)) + return true; + + MWBase::World* world = MWBase::Environment::get().getWorld(); + return !world->isOnGround(ptr) && !world->isSwimming(ptr) && !world->isFlying(ptr); } bool MechanicsManager::isSneaking(const MWWorld::Ptr& ptr) { CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); + if (!stats.getStance(MWMechanics::CreatureStats::Stance_Sneak)) + return false; + + if (mActors.isSneaking(ptr)) + return true; + MWBase::World* world = MWBase::Environment::get().getWorld(); - bool animActive = mActors.isSneaking(ptr); - bool stanceOn = stats.getStance(MWMechanics::CreatureStats::Stance_Sneak); - bool inair = !world->isOnGround(ptr) && !world->isSwimming(ptr) && !world->isFlying(ptr); - return stanceOn && (animActive || inair); + return !world->isOnGround(ptr) && !world->isSwimming(ptr) && !world->isFlying(ptr); } void MechanicsManager::rest(double hours, bool sleep) diff --git a/apps/openmw/mwscript/controlextensions.cpp b/apps/openmw/mwscript/controlextensions.cpp index b9e8f8965a..3a70ec5142 100644 --- a/apps/openmw/mwscript/controlextensions.cpp +++ b/apps/openmw/mwscript/controlextensions.cpp @@ -164,14 +164,7 @@ namespace MWScript void execute(Interpreter::Runtime& runtime) override { MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); - MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); - MWBase::World* world = MWBase::Environment::get().getWorld(); - - bool stanceOn = stats.getStance(MWMechanics::CreatureStats::Stance_Run); - bool running = MWBase::Environment::get().getMechanicsManager()->isRunning(ptr); - bool inair = !world->isOnGround(ptr) && !world->isSwimming(ptr) && !world->isFlying(ptr); - - runtime.push(stanceOn && (running || inair)); + runtime.push(MWBase::Environment::get().getMechanicsManager()->isRunning(ptr)); } }; From d899454f3618b85608cba374e5f50373c4fd10ff Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Fri, 11 Apr 2025 06:08:42 +0300 Subject: [PATCH 261/330] Remove completion threshold-based turning for the player (#8447) --- apps/openmw/mwmechanics/character.cpp | 48 ++++++++------------------- 1 file changed, 14 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 1aac063ce3..3f4f6c6956 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2310,17 +2310,13 @@ namespace MWMechanics } else { - // Do not play turning animation for player if rotation speed is very slow. - // Actual threshold should take framerate in account. - float rotationThreshold = (isPlayer ? 0.015f : 0.001f) * 60 * duration; - // It seems only bipedal actors use turning animations. // Also do not use turning animations in the first-person view and when sneaking. if (!sneak && !isFirstPersonPlayer && isBiped) { - if (effectiveRotation > rotationThreshold) + if (effectiveRotation > 0.f) movestate = inwater ? CharState_SwimTurnRight : CharState_TurnRight; - else if (effectiveRotation < -rotationThreshold) + else if (effectiveRotation < 0.f) movestate = inwater ? CharState_SwimTurnLeft : CharState_TurnLeft; } } @@ -2346,34 +2342,19 @@ namespace MWMechanics vec.y() *= std::sqrt(1.0f - swimUpwardCoef * swimUpwardCoef); } - // Player can not use smooth turning as NPCs, so we play turning animation a bit to avoid jittering - if (isPlayer) + if (isBiped) { - float threshold = mCurrentMovement.find("swim") == std::string::npos ? 0.4f : 0.8f; - float complete; - bool animPlaying = mAnimation->getInfo(mCurrentMovement, &complete); - if (movestate == CharState_None && jumpstate == JumpState_None && isTurning()) - { - if (animPlaying && complete < threshold) - movestate = mMovementState; - } - } - else - { - if (isBiped) - { - if (mTurnAnimationThreshold > 0) - mTurnAnimationThreshold -= duration; + if (mTurnAnimationThreshold > 0) + mTurnAnimationThreshold -= duration; - if (movestate == CharState_TurnRight || movestate == CharState_TurnLeft - || movestate == CharState_SwimTurnRight || movestate == CharState_SwimTurnLeft) - { - mTurnAnimationThreshold = 0.05f; - } - else if (movestate == CharState_None && isTurning() && mTurnAnimationThreshold > 0) - { - movestate = mMovementState; - } + if (movestate == CharState_TurnRight || movestate == CharState_TurnLeft + || movestate == CharState_SwimTurnRight || movestate == CharState_SwimTurnLeft) + { + mTurnAnimationThreshold = 0.05f; + } + else if (movestate == CharState_None && isTurning() && mTurnAnimationThreshold > 0) + { + movestate = mMovementState; } } @@ -2402,11 +2383,10 @@ namespace MWMechanics if (isTurning()) { - // Adjust animation speed from 1.0 to 1.5 multiplier if (duration > 0) { float turnSpeed = std::min(1.5f, std::abs(rot.z()) / duration / static_cast(osg::PI)); - mAnimation->adjustSpeedMult(mCurrentMovement, std::max(turnSpeed, 1.0f)); + mAnimation->adjustSpeedMult(mCurrentMovement, turnSpeed); } } else if (mMovementState != CharState_None && mAdjustMovementAnimSpeed) From 896d6fd01ef1b305f76e1e1fdbad7716b112c332 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sat, 22 Mar 2025 21:11:33 +0300 Subject: [PATCH 262/330] Put combat actions on hold when the actor is incapacitated (#7979) --- apps/openmw/mwmechanics/aicombat.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index a6f9935194..7b7148f1de 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -178,11 +178,16 @@ namespace MWMechanics currentCell = actor.getCell(); } + const MWWorld::Class& actorClass = actor.getClass(); + MWMechanics::CreatureStats& stats = actorClass.getCreatureStats(actor); + if (stats.isParalyzed() || stats.getKnockedDown()) + return false; + bool forceFlee = false; if (!canFight(actor, target)) { storage.stopAttack(); - actor.getClass().getCreatureStats(actor).setAttackingOrSpell(false); + stats.setAttackingOrSpell(false); storage.mActionCooldown = 0.f; // Continue combat if target is player or player follower/escorter and an attack has been attempted const auto& playerFollowersAndEscorters @@ -191,18 +196,14 @@ namespace MWMechanics = (std::find(playerFollowersAndEscorters.begin(), playerFollowersAndEscorters.end(), target) != playerFollowersAndEscorters.end()); if ((target == MWMechanics::getPlayer() || targetSidesWithPlayer) - && ((actor.getClass().getCreatureStats(actor).getHitAttemptActorId() - == target.getClass().getCreatureStats(target).getActorId()) - || (target.getClass().getCreatureStats(target).getHitAttemptActorId() - == actor.getClass().getCreatureStats(actor).getActorId()))) + && ((stats.getHitAttemptActorId() == target.getClass().getCreatureStats(target).getActorId()) + || (target.getClass().getCreatureStats(target).getHitAttemptActorId() == stats.getActorId()))) forceFlee = true; else // Otherwise end combat return true; } - const MWWorld::Class& actorClass = actor.getClass(); - actorClass.getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true); - + stats.setMovementFlag(CreatureStats::Flag_Run, true); float& actionCooldown = storage.mActionCooldown; std::unique_ptr& currentAction = storage.mCurrentAction; @@ -330,7 +331,7 @@ namespace MWMechanics { storage.mUseCustomDestination = false; storage.stopAttack(); - actor.getClass().getCreatureStats(actor).setAttackingOrSpell(false); + stats.setAttackingOrSpell(false); currentAction = std::make_unique(); actionCooldown = currentAction->getActionCooldown(); storage.startFleeing(); From 044c556f0eeeae8e297bfb1dc35b137dd6814a67 Mon Sep 17 00:00:00 2001 From: Aussiemon <1407091-Aussiemon@users.noreply.gitlab.com> Date: Wed, 23 Jul 2025 03:31:38 -0600 Subject: [PATCH 263/330] Fix precision issue with container capacity check --- apps/openmw/mwgui/containeritemmodel.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/containeritemmodel.cpp b/apps/openmw/mwgui/containeritemmodel.cpp index 09b66672ba..ff50431d86 100644 --- a/apps/openmw/mwgui/containeritemmodel.cpp +++ b/apps/openmw/mwgui/containeritemmodel.cpp @@ -224,7 +224,7 @@ namespace MWGui if (target.getType() != ESM::Container::sRecordId) return true; - // check container organic flag + // Check container organic flag MWWorld::LiveCellRef* ref = target.get(); if (ref->mBase->mFlags & ESM::Container::Organic) { @@ -232,9 +232,18 @@ namespace MWGui return false; } - // check that we don't exceed container capacity - float weight = item.getClass().getWeight(item) * count; - if (target.getClass().getCapacity(target) < target.getClass().getEncumbrance(target) + weight) + // Check for container without capacity + float capacity = target.getClass().getCapacity(target); + if (capacity <= 0.0f) + { + MWBase::Environment::get().getWindowManager()->messageBox("#{sContentsMessage3}"); + return false; + } + + // Check the container capacity plus one increment so the expected total weight can + // fit in the container with floating-point imprecision + float newEncumbrance = target.getClass().getEncumbrance(target) + (item.getClass().getWeight(item) * count); + if (std::nextafterf(capacity, std::numeric_limits::max()) < newEncumbrance) { MWBase::Environment::get().getWindowManager()->messageBox("#{sContentsMessage3}"); return false; From 324bdf8f7ad7133672c3bc34b513473bd2c3161f Mon Sep 17 00:00:00 2001 From: Jared Davenport Date: Wed, 23 Jul 2025 09:32:04 +0000 Subject: [PATCH 264/330] Save user settings when closing windows --- apps/openmw/mwbase/inputmanager.hpp | 2 ++ apps/openmw/mwbase/luamanager.hpp | 2 ++ apps/openmw/mwgui/postprocessorhud.cpp | 6 +++- apps/openmw/mwgui/postprocessorhud.hpp | 5 +++- apps/openmw/mwgui/settingswindow.cpp | 13 ++++++++- apps/openmw/mwgui/settingswindow.hpp | 6 +++- apps/openmw/mwgui/windowmanagerimp.cpp | 4 +-- apps/openmw/mwinput/bindingsmanager.cpp | 39 ++++++++++++++----------- apps/openmw/mwinput/bindingsmanager.hpp | 2 ++ apps/openmw/mwinput/inputmanagerimp.cpp | 5 ++++ apps/openmw/mwinput/inputmanagerimp.hpp | 2 ++ apps/openmw/mwlua/luamanagerimp.hpp | 2 +- 12 files changed, 64 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index 5ee20476b3..de6cf91f4e 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -88,6 +88,8 @@ namespace MWBase virtual void executeAction(int action) = 0; virtual bool controlsDisabled() = 0; + + virtual void saveBindings() = 0; }; } diff --git a/apps/openmw/mwbase/luamanager.hpp b/apps/openmw/mwbase/luamanager.hpp index a5d6fe1114..bbdb843199 100644 --- a/apps/openmw/mwbase/luamanager.hpp +++ b/apps/openmw/mwbase/luamanager.hpp @@ -1,6 +1,7 @@ #ifndef GAME_MWBASE_LUAMANAGER_H #define GAME_MWBASE_LUAMANAGER_H +#include #include #include #include @@ -75,6 +76,7 @@ namespace MWBase virtual void questUpdated(const ESM::RefId& questId, int stage) = 0; // `arg` is either forwarded from MWGui::pushGuiMode or empty virtual void uiModeChanged(const MWWorld::Ptr& arg) = 0; + virtual void savePermanentStorage(const std::filesystem::path& userConfigPath) = 0; // TODO: notify LuaManager about other events // virtual void objectOnHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, diff --git a/apps/openmw/mwgui/postprocessorhud.cpp b/apps/openmw/mwgui/postprocessorhud.cpp index cc95203a0f..3d13988937 100644 --- a/apps/openmw/mwgui/postprocessorhud.cpp +++ b/apps/openmw/mwgui/postprocessorhud.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -50,8 +51,9 @@ namespace MWGui MyGUI::ListBox::onKeyButtonPressed(key, ch); } - PostProcessorHud::PostProcessorHud() + PostProcessorHud::PostProcessorHud(Files::ConfigurationManager& cfgMgr) : WindowBase("openmw_postprocessor_hud.layout") + , mCfgMgr(cfgMgr) { getWidget(mActiveList, "ActiveList"); getWidget(mInactiveList, "InactiveList"); @@ -243,6 +245,8 @@ namespace MWGui void PostProcessorHud::onClose() { + Settings::ShaderManager::get().save(); + Settings::Manager::saveUser(mCfgMgr.getUserConfigPath() / "settings.cfg"); toggleMode(Settings::ShaderManager::Mode::Normal); } diff --git a/apps/openmw/mwgui/postprocessorhud.hpp b/apps/openmw/mwgui/postprocessorhud.hpp index 0028999966..b5cf2495a6 100644 --- a/apps/openmw/mwgui/postprocessorhud.hpp +++ b/apps/openmw/mwgui/postprocessorhud.hpp @@ -5,6 +5,7 @@ #include +#include #include #include @@ -32,7 +33,7 @@ namespace MWGui }; public: - PostProcessorHud(); + PostProcessorHud(Files::ConfigurationManager& cfgMgr); void onOpen() override; @@ -99,6 +100,8 @@ namespace MWGui std::string mOverrideHint; int mOffset = 0; + + Files::ConfigurationManager& mCfgMgr; }; } diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 02353c5d41..77032623d2 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -39,6 +40,7 @@ #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" +#include "../mwlua/luamanagerimp.hpp" #include "confirmationdialog.hpp" @@ -247,10 +249,11 @@ namespace MWGui } } - SettingsWindow::SettingsWindow() + SettingsWindow::SettingsWindow(Files::ConfigurationManager& cfgMgr) : WindowBase("openmw_settings_window.layout") , mKeyboardMode(true) , mCurrentPage(-1) + , mCfgMgr(cfgMgr) { const bool terrain = Settings::terrain().mDistantTerrain; const std::string_view widgetName = terrain ? "RenderingDistanceSlider" : "LargeRenderingDistanceSlider"; @@ -1092,6 +1095,14 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mOkButton); } + void SettingsWindow::onClose() + { + // Save user settings + Settings::Manager::saveUser(mCfgMgr.getUserConfigPath() / "settings.cfg"); + MWBase::Environment::get().getLuaManager()->savePermanentStorage(mCfgMgr.getUserConfigPath()); + MWBase::Environment::get().getInputManager()->saveBindings(); + } + void SettingsWindow::onWindowResize(MyGUI::Window* _sender) { layoutControlsBox(); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index dc4e09f8ac..22a15eab97 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -1,6 +1,7 @@ #ifndef MWGUI_SETTINGS_H #define MWGUI_SETTINGS_H +#include #include #include "windowbase.hpp" @@ -10,10 +11,12 @@ namespace MWGui class SettingsWindow : public WindowBase { public: - SettingsWindow(); + SettingsWindow(Files::ConfigurationManager& cfgMgr); void onOpen() override; + void onClose() override; + void onFrame(float duration) override; void updateControlsBox(); @@ -120,6 +123,7 @@ namespace MWGui private: void resetScrollbars(); + Files::ConfigurationManager& mCfgMgr; }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index c7c4b575a5..cc0d493a26 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -409,7 +409,7 @@ namespace MWGui mCountDialog = countDialog.get(); mWindows.push_back(std::move(countDialog)); - auto settingsWindow = std::make_unique(); + auto settingsWindow = std::make_unique(mCfgMgr); mSettingsWindow = settingsWindow.get(); mWindows.push_back(std::move(settingsWindow)); trackWindow(mSettingsWindow, makeSettingsWindowSettingValues()); @@ -503,7 +503,7 @@ namespace MWGui mWindows.push_back(std::move(debugWindow)); trackWindow(mDebugWindow, makeDebugWindowSettingValues()); - auto postProcessorHud = std::make_unique(); + auto postProcessorHud = std::make_unique(mCfgMgr); mPostProcessorHud = postProcessorHud.get(); mWindows.push_back(std::move(postProcessorHud)); trackWindow(mPostProcessorHud, makePostprocessorWindowSettingValues()); diff --git a/apps/openmw/mwinput/bindingsmanager.cpp b/apps/openmw/mwinput/bindingsmanager.cpp index 339ebf4276..22322014d4 100644 --- a/apps/openmw/mwinput/bindingsmanager.cpp +++ b/apps/openmw/mwinput/bindingsmanager.cpp @@ -196,23 +196,7 @@ namespace MWInput BindingsManager::~BindingsManager() { - const std::string newFileName = Files::pathToUnicodeString(mUserFile) + ".new"; - try - { - if (mInputBinder->save(newFileName)) - { - std::filesystem::rename(Files::pathFromUnicodeString(newFileName), mUserFile); - Log(Debug::Info) << "Saved input bindings: " << mUserFile; - } - else - { - Log(Debug::Error) << "Failed to save input bindings to " << newFileName; - } - } - catch (const std::exception& e) - { - Log(Debug::Error) << "Failed to save input bindings to " << newFileName << ": " << e.what(); - } + saveBindings(); } void BindingsManager::update(float dt) @@ -715,4 +699,25 @@ namespace MWInput if (previousValue <= 0.6 && currentValue > 0.6) manager->executeAction(action); } + + void BindingsManager::saveBindings() + { + const std::string newFileName = Files::pathToUnicodeString(mUserFile) + ".new"; + try + { + if (mInputBinder->save(newFileName)) + { + std::filesystem::rename(Files::pathFromUnicodeString(newFileName), mUserFile); + Log(Debug::Info) << "Saved input bindings: " << mUserFile; + } + else + { + Log(Debug::Error) << "Failed to save input bindings to " << newFileName; + } + } + catch (const std::exception& e) + { + Log(Debug::Error) << "Failed to save input bindings to " << newFileName << ": " << e.what(); + } + } } diff --git a/apps/openmw/mwinput/bindingsmanager.hpp b/apps/openmw/mwinput/bindingsmanager.hpp index bee9e07cf7..40c2076d3c 100644 --- a/apps/openmw/mwinput/bindingsmanager.hpp +++ b/apps/openmw/mwinput/bindingsmanager.hpp @@ -65,6 +65,8 @@ namespace MWInput void actionValueChanged(int action, float currentValue, float previousValue); + void saveBindings(); + private: void setupSDLKeyMappings(); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 328757a954..d81d720b21 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -246,4 +246,9 @@ namespace MWInput { mActionManager->executeAction(action); } + + void InputManager::saveBindings() + { + mBindingsManager->saveBindings(); + } } diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 39a1133db5..46e4774b6b 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -106,6 +106,8 @@ namespace MWInput private: bool mControlsDisabled; + void saveBindings() override; + std::unique_ptr mInputWrapper; std::unique_ptr mBindingsManager; std::unique_ptr mControlSwitch; diff --git a/apps/openmw/mwlua/luamanagerimp.hpp b/apps/openmw/mwlua/luamanagerimp.hpp index 3f2135e9c9..9877c98fb9 100644 --- a/apps/openmw/mwlua/luamanagerimp.hpp +++ b/apps/openmw/mwlua/luamanagerimp.hpp @@ -43,7 +43,7 @@ namespace MWLua void init(); void loadPermanentStorage(const std::filesystem::path& userConfigPath); - void savePermanentStorage(const std::filesystem::path& userConfigPath); + void savePermanentStorage(const std::filesystem::path& userConfigPath) override; // \brief Executes lua handlers. Defaults to running in parallel with OSG Cull. // From 362c1a7ebe63792e2799e042414ab8441174d061 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Wed, 23 Jul 2025 17:35:35 +0200 Subject: [PATCH 265/330] Update sol --- extern/sol3/README.md | 7 +- extern/sol3/sol/abort.hpp | 47 + extern/sol3/sol/as_args.hpp | 2 +- extern/sol3/sol/as_returns.hpp | 2 +- extern/sol3/sol/assert.hpp | 198 +- extern/sol3/sol/base_traits.hpp | 279 +-- extern/sol3/sol/bind_traits.hpp | 10 +- extern/sol3/sol/bytecode.hpp | 242 +-- extern/sol3/sol/call.hpp | 32 +- extern/sol3/sol/compatibility.hpp | 26 +- extern/sol3/sol/compatibility/compat-5.3.c.h | 1800 ++++++++--------- extern/sol3/sol/compatibility/compat-5.3.h | 854 ++++---- extern/sol3/sol/compatibility/compat-5.4.h | 54 +- extern/sol3/sol/compatibility/lua_version.hpp | 99 +- extern/sol3/sol/config.hpp | 50 + extern/sol3/sol/coroutine.hpp | 12 +- extern/sol3/sol/debug.hpp | 115 +- extern/sol3/sol/demangle.hpp | 8 +- extern/sol3/sol/deprecate.hpp | 88 +- extern/sol3/sol/detail/build_version.hpp | 464 ++--- extern/sol3/sol/dump_handler.hpp | 154 +- extern/sol3/sol/ebco.hpp | 321 +-- extern/sol3/sol/environment.hpp | 23 +- extern/sol3/sol/epilogue.hpp | 78 +- extern/sol3/sol/error.hpp | 191 +- extern/sol3/sol/error_handler.hpp | 27 +- extern/sol3/sol/forward.hpp | 14 +- extern/sol3/sol/forward_as.hpp | 44 + extern/sol3/sol/forward_detail.hpp | 4 +- extern/sol3/sol/function.hpp | 284 +-- extern/sol3/sol/function_result.hpp | 2 +- extern/sol3/sol/function_types.hpp | 14 +- extern/sol3/sol/function_types_core.hpp | 2 +- extern/sol3/sol/function_types_overloaded.hpp | 4 +- extern/sol3/sol/function_types_stateful.hpp | 6 +- extern/sol3/sol/function_types_stateless.hpp | 44 +- extern/sol3/sol/function_types_templated.hpp | 4 +- extern/sol3/sol/in_place.hpp | 2 +- extern/sol3/sol/inheritance.hpp | 390 ++-- extern/sol3/sol/load_result.hpp | 16 +- extern/sol3/sol/lua_table.hpp | 190 +- extern/sol3/sol/lua_value.hpp | 324 +-- extern/sol3/sol/make_reference.hpp | 2 +- extern/sol3/sol/metatable.hpp | 10 +- extern/sol3/sol/object.hpp | 2 +- extern/sol3/sol/object_base.hpp | 2 +- extern/sol3/sol/optional.hpp | 12 +- extern/sol3/sol/optional_implementation.hpp | 21 +- extern/sol3/sol/overload.hpp | 4 +- extern/sol3/sol/packaged_coroutine.hpp | 524 ++--- extern/sol3/sol/pairs_iterator.hpp | 550 ++--- extern/sol3/sol/pointer_like.hpp | 205 +- extern/sol3/sol/policies.hpp | 2 +- extern/sol3/sol/prologue.hpp | 94 +- extern/sol3/sol/property.hpp | 2 +- extern/sol3/sol/protect.hpp | 2 +- extern/sol3/sol/protected_function.hpp | 20 +- extern/sol3/sol/protected_function_result.hpp | 27 +- extern/sol3/sol/protected_handler.hpp | 4 +- extern/sol3/sol/proxy_base.hpp | 2 +- extern/sol3/sol/raii.hpp | 2 +- extern/sol3/sol/reference.hpp | 26 +- extern/sol3/sol/resolve.hpp | 2 +- extern/sol3/sol/sol.hpp | 18 +- extern/sol3/sol/stack.hpp | 735 +++---- extern/sol3/sol/stack/detail/pairs.hpp | 196 +- extern/sol3/sol/stack_check.hpp | 2 +- extern/sol3/sol/stack_check_get.hpp | 2 +- extern/sol3/sol/stack_check_get_qualified.hpp | 21 +- .../sol3/sol/stack_check_get_unqualified.hpp | 8 +- extern/sol3/sol/stack_check_qualified.hpp | 4 +- extern/sol3/sol/stack_check_unqualified.hpp | 135 +- extern/sol3/sol/stack_core.hpp | 51 +- extern/sol3/sol/stack_field.hpp | 14 +- extern/sol3/sol/stack_get.hpp | 2 +- extern/sol3/sol/stack_get_qualified.hpp | 2 +- extern/sol3/sol/stack_get_unqualified.hpp | 99 +- extern/sol3/sol/stack_guard.hpp | 4 +- extern/sol3/sol/stack_iterator.hpp | 2 +- extern/sol3/sol/stack_pop.hpp | 2 +- extern/sol3/sol/stack_probe.hpp | 4 +- extern/sol3/sol/stack_proxy.hpp | 2 +- extern/sol3/sol/stack_proxy_base.hpp | 2 +- extern/sol3/sol/stack_push.hpp | 107 +- extern/sol3/sol/stack_reference.hpp | 6 +- extern/sol3/sol/state.hpp | 2 +- extern/sol3/sol/state_handling.hpp | 18 +- extern/sol3/sol/state_view.hpp | 18 +- extern/sol3/sol/string_view.hpp | 2 +- extern/sol3/sol/table.hpp | 232 +-- extern/sol3/sol/table_core.hpp | 12 +- extern/sol3/sol/table_iterator.hpp | 2 +- extern/sol3/sol/table_proxy.hpp | 22 +- extern/sol3/sol/thread.hpp | 12 +- extern/sol3/sol/tie.hpp | 2 +- extern/sol3/sol/traits.hpp | 39 +- extern/sol3/sol/trampoline.hpp | 25 +- extern/sol3/sol/tuple.hpp | 186 +- extern/sol3/sol/types.hpp | 97 +- extern/sol3/sol/unicode.hpp | 616 +++--- extern/sol3/sol/unique_usertype_traits.hpp | 480 ++--- extern/sol3/sol/unreachable.hpp | 37 + extern/sol3/sol/unsafe_function.hpp | 10 +- extern/sol3/sol/unsafe_function_result.hpp | 8 +- extern/sol3/sol/userdata.hpp | 18 +- extern/sol3/sol/usertype.hpp | 2 +- extern/sol3/sol/usertype_container.hpp | 90 +- extern/sol3/sol/usertype_container_launch.hpp | 2 +- extern/sol3/sol/usertype_core.hpp | 4 +- extern/sol3/sol/usertype_proxy.hpp | 2 +- extern/sol3/sol/usertype_storage.hpp | 14 +- extern/sol3/sol/usertype_traits.hpp | 122 +- extern/sol3/sol/utility/is_integer.hpp | 43 + extern/sol3/sol/utility/to_string.hpp | 59 + extern/sol3/sol/variadic_args.hpp | 2 +- extern/sol3/sol/variadic_results.hpp | 4 +- extern/sol3/sol/version.hpp | 202 +- extern/sol3/sol/wrapper.hpp | 4 +- 118 files changed, 6291 insertions(+), 5557 deletions(-) create mode 100644 extern/sol3/sol/abort.hpp create mode 100644 extern/sol3/sol/config.hpp create mode 100644 extern/sol3/sol/forward_as.hpp create mode 100644 extern/sol3/sol/unreachable.hpp create mode 100644 extern/sol3/sol/utility/is_integer.hpp create mode 100644 extern/sol3/sol/utility/to_string.hpp diff --git a/extern/sol3/README.md b/extern/sol3/README.md index 202b2ca08b..fe249704c4 100644 --- a/extern/sol3/README.md +++ b/extern/sol3/README.md @@ -1,5 +1,8 @@ -The code in this directory is copied from https://github.com/ThePhD/sol2.git (64096348465b980e2f1d0e5ba9cbeea8782e8f27) +The code in this directory is copied from https://github.com/ThePhD/sol2.git (c1f95a773c6f8f4fde8ca3efe872e7286afe4444) and has been patched to include -Additional changes include cherry-picking upstream commit d805d027e0a0a7222e936926139f06e23828ce9f to fix compilation under Clang 19. +https://github.com/ThePhD/sol2/pull/1674 (71d85143ad69164f5f52c3bdab91fb503c676eb4) +https://github.com/ThePhD/sol2/pull/1676 (a6872ef46b08704b9069ebf83161f4637459ce63) +https://github.com/ThePhD/sol2/pull/1716 (5b6881ed94c795298eae72b6848308e9a37e42c5) +https://github.com/ThePhD/sol2/pull/1722 (ab874eb0e8ef8aea4c10074a89efa25f62a29d9a) License: MIT diff --git a/extern/sol3/sol/abort.hpp b/extern/sol3/sol/abort.hpp new file mode 100644 index 0000000000..692244daa7 --- /dev/null +++ b/extern/sol3/sol/abort.hpp @@ -0,0 +1,47 @@ +// sol2 + +// The MIT License (MIT) + +// Copyright (c) 2013-2022 Rapptz, ThePhD and contributors + +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#ifndef SOL_ABORT_HPP +#define SOL_ABORT_HPP + +#include + +#include + +#include + +// clang-format off +#if SOL_IS_ON(SOL_DEBUG_BUILD) + #if SOL_IS_ON(SOL_COMPILER_VCXX) + #define SOL_DEBUG_ABORT() \ + if (true) { ::std::abort(); } \ + static_assert(true, "") + #else + #define SOL_DEBUG_ABORT() ::std::abort() + #endif +#else + #define SOL_DEBUG_ABORT() static_assert(true, "") +#endif +// clang-format on + +#endif // SOL_ABORT_HPP diff --git a/extern/sol3/sol/as_args.hpp b/extern/sol3/sol/as_args.hpp index 5afe78b0e4..719a3cdc99 100644 --- a/extern/sol3/sol/as_args.hpp +++ b/extern/sol3/sol/as_args.hpp @@ -2,7 +2,7 @@ // The MIT License (MIT) -// Copyright (c) 2013-2021 Rapptz, ThePhD and contributors +// Copyright (c) 2013-2022 Rapptz, ThePhD and contributors // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in diff --git a/extern/sol3/sol/as_returns.hpp b/extern/sol3/sol/as_returns.hpp index 0ac499e67d..982f408b71 100644 --- a/extern/sol3/sol/as_returns.hpp +++ b/extern/sol3/sol/as_returns.hpp @@ -2,7 +2,7 @@ // The MIT License (MIT) -// Copyright (c) 2013-2021 Rapptz, ThePhD and contributors +// Copyright (c) 2013-2022 Rapptz, ThePhD and contributors // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in diff --git a/extern/sol3/sol/assert.hpp b/extern/sol3/sol/assert.hpp index e46b9f122a..7f27905dc4 100644 --- a/extern/sol3/sol/assert.hpp +++ b/extern/sol3/sol/assert.hpp @@ -1,99 +1,99 @@ -// sol2 - -// The MIT License (MIT) - -// Copyright (c) 2013-2021 Rapptz, ThePhD and contributors - -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -#pragma once - -#ifndef SOL_ASSERT_HPP -#define SOL_ASSERT_HPP - -#include - -#if SOL_IS_ON(SOL2_CI_I_) - -struct pre_main { - pre_main() { -#ifdef _MSC_VER - _set_abort_behavior(0, _WRITE_ABORT_MSG); -#endif - } -} inline sol2_ci_dont_lock_ci_please = {}; - -#endif // Prevent lockup when doing Continuous Integration - - -// clang-format off - -#if SOL_IS_ON(SOL_USER_C_ASSERT_I_) - #define sol_c_assert(...) SOL_C_ASSERT(__VA_ARGS__) -#else - #if SOL_IS_ON(SOL_DEBUG_BUILD_I_) - #include - #include - #include - - #define sol_c_assert(...) \ - do { \ - if (!(__VA_ARGS__)) { \ - std::cerr << "Assertion `" #__VA_ARGS__ "` failed in " << __FILE__ << " line " << __LINE__ << std::endl; \ - std::terminate(); \ - } \ - } while (false) - #else - #define sol_c_assert(...) \ - do { \ - if (false) { \ - (void)(__VA_ARGS__); \ - } \ - } while (false) - #endif -#endif - -#if SOL_IS_ON(SOL_USER_M_ASSERT_I_) - #define sol_m_assert(message, ...) SOL_M_ASSERT(message, __VA_ARGS__) -#else - #if SOL_IS_ON(SOL_DEBUG_BUILD_I_) - #include - #include - #include - - #define sol_m_assert(message, ...) \ - do { \ - if (!(__VA_ARGS__)) { \ - std::cerr << "Assertion `" #__VA_ARGS__ "` failed in " << __FILE__ << " line " << __LINE__ << ": " << message << std::endl; \ - std::terminate(); \ - } \ - } while (false) - #else - #define sol_m_assert(message, ...) \ - do { \ - if (false) { \ - (void)(__VA_ARGS__); \ - (void)sizeof(message); \ - } \ - } while (false) - #endif -#endif - -// clang-format on - -#endif // SOL_ASSERT_HPP +// sol2 + +// The MIT License (MIT) + +// Copyright (c) 2013-2022 Rapptz, ThePhD and contributors + +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +#ifndef SOL_ASSERT_HPP +#define SOL_ASSERT_HPP + +#include + +#if SOL_IS_ON(SOL2_CI) + +struct pre_main { + pre_main() { +#ifdef _MSC_VER + _set_abort_behavior(0, _WRITE_ABORT_MSG); +#endif + } +} inline sol2_ci_dont_lock_ci_please = {}; + +#endif // Prevent lockup when doing Continuous Integration + + +// clang-format off + +#if SOL_IS_ON(SOL_USER_ASSERT) + #define SOL_ASSERT(...) SOL_C_ASSERT(__VA_ARGS__) +#else + #if SOL_IS_ON(SOL_DEBUG_BUILD) + #include + #include + #include + + #define SOL_ASSERT(...) \ + do { \ + if (!(__VA_ARGS__)) { \ + std::cerr << "Assertion `" #__VA_ARGS__ "` failed in " << __FILE__ << " line " << __LINE__ << std::endl; \ + std::terminate(); \ + } \ + } while (false) + #else + #define SOL_ASSERT(...) \ + do { \ + if (false) { \ + (void)(__VA_ARGS__); \ + } \ + } while (false) + #endif +#endif + +#if SOL_IS_ON(SOL_USER_ASSERT_MSG) + #define SOL_ASSERT_MSG(message, ...) SOL_ASSERT_MSG(message, __VA_ARGS__) +#else + #if SOL_IS_ON(SOL_DEBUG_BUILD) + #include + #include + #include + + #define SOL_ASSERT_MSG(message, ...) \ + do { \ + if (!(__VA_ARGS__)) { \ + std::cerr << "Assertion `" #__VA_ARGS__ "` failed in " << __FILE__ << " line " << __LINE__ << ": " << message << std::endl; \ + std::terminate(); \ + } \ + } while (false) + #else + #define SOL_ASSERT_MSG(message, ...) \ + do { \ + if (false) { \ + (void)(__VA_ARGS__); \ + (void)sizeof(message); \ + } \ + } while (false) + #endif +#endif + +// clang-format on + +#endif // SOL_ASSERT_HPP diff --git a/extern/sol3/sol/base_traits.hpp b/extern/sol3/sol/base_traits.hpp index a28f23a74c..204afc276f 100644 --- a/extern/sol3/sol/base_traits.hpp +++ b/extern/sol3/sol/base_traits.hpp @@ -1,123 +1,156 @@ -// sol2 - -// The MIT License (MIT) - -// Copyright (c) 2013-2021 Rapptz, ThePhD and contributors - -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -#ifndef SOL_BASE_TRAITS_HPP -#define SOL_BASE_TRAITS_HPP - -#include - -namespace sol { - namespace detail { - struct unchecked_t { }; - const unchecked_t unchecked = unchecked_t {}; - } // namespace detail - - namespace meta { - using sfinae_yes_t = std::true_type; - using sfinae_no_t = std::false_type; - - template - using void_t = void; - - template - using unqualified = std::remove_cv>; - - template - using unqualified_t = typename unqualified::type; - - namespace meta_detail { - template - struct unqualified_non_alias : unqualified { }; - - template