diff --git a/src/HUDHandler.cpp b/src/HUDHandler.cpp index b6864c3..fdf016d 100644 --- a/src/HUDHandler.cpp +++ b/src/HUDHandler.cpp @@ -25,8 +25,8 @@ HUDHandler::EventResult HUDHandler::ProcessEvent(const RE::TESCombatEvent* a_eve { using WidgetRemovalMode = TRUEHUD_API::WidgetRemovalMode; - bool bInfoBarsEnabled = Settings::bEnableActorInfoBars && - (Settings::uInfoBarDisplayHostiles > InfoBarsDisplayMode::kNever || + bool bInfoBarsEnabled = Settings::bEnableActorInfoBars && + (Settings::uInfoBarDisplayHostiles > InfoBarsDisplayMode::kNever || Settings::uInfoBarDisplayTeammates > InfoBarsDisplayMode::kNever || Settings::uInfoBarDisplayOthers > InfoBarsDisplayMode::kNever); @@ -300,7 +300,6 @@ RE::GPtr HUDHandler::GetTrueHUDMenu() void HUDHandler::Update() { - } RE::ObjectRefHandle HUDHandler::GetTarget() const @@ -638,6 +637,13 @@ void HUDHandler::DrawHalfCircle(const RE::NiPoint3& a_center, const RE::NiPoint3 }); } +void HUDHandler::DrawArc(const RE::NiPoint3& a_origin, float a_radius, float a_startRadian, float a_endRadian, const RE::NiMatrix3& a_matrix, uint32_t a_segments, float a_duration, uint32_t a_color, float a_thickness) +{ + AddHUDTask([a_origin, a_radius, a_startRadian, a_endRadian, a_matrix, a_segments, a_duration, a_color, a_thickness](TrueHUDMenu& a_menu) { + a_menu.DrawArc(a_origin, a_radius, a_startRadian, a_endRadian, a_matrix, a_segments, a_duration, a_color, a_thickness); + }); +} + void HUDHandler::DrawSphere(const RE::NiPoint3& a_origin, float a_radius, uint32_t a_segments, float a_duration, uint32_t a_color, float a_thickness) { AddHUDTask([a_origin, a_radius, a_segments, a_duration, a_color, a_thickness](TrueHUDMenu& a_menu) { @@ -763,7 +769,6 @@ void HUDHandler::OnSettingsUpdated() void HUDHandler::Initialize() { - } void HUDHandler::Process(TrueHUDMenu& a_menu, float a_deltaTime) diff --git a/src/HUDHandler.h b/src/HUDHandler.h index 1ac9828..86a06b9 100644 --- a/src/HUDHandler.h +++ b/src/HUDHandler.h @@ -1,11 +1,11 @@ #pragma once -#include #include +#include +#include "Scaleform/TrueHUDMenu.h" #include "TrueHUDAPI.h" #include "Widgets/ActorInfoBar.h" #include "Widgets/BossInfoBar.h" -#include "Scaleform/TrueHUDMenu.h" class HUDHandler : public RE::BSTEventSink, @@ -50,7 +50,7 @@ class HUDHandler : RE::ObjectRefHandle GetTarget() const; RE::ObjectRefHandle GetSoftTarget() const; void SetTarget(RE::ObjectRefHandle a_actorHandle); - void SetSoftTarget(RE::ObjectRefHandle a_actorHandle); + void SetSoftTarget(RE::ObjectRefHandle a_actorHandle); bool HasActorInfoBar(RE::ObjectRefHandle a_actorHandle); void AddActorInfoBar(RE::ObjectRefHandle a_actorHandle); @@ -94,6 +94,7 @@ class HUDHandler : void DrawBox(const RE::NiPoint3& a_center, const RE::NiPoint3& a_extent, const RE::NiQuaternion& a_rotation, float a_duration, uint32_t a_color, float a_thickness); void DrawCircle(const RE::NiPoint3& a_center, const RE::NiPoint3& a_x, const RE::NiPoint3& a_y, float a_radius, uint32_t a_segments, float a_duration, uint32_t a_color, float a_thickness); void DrawHalfCircle(const RE::NiPoint3& a_center, const RE::NiPoint3& a_x, const RE::NiPoint3& a_y, float a_radius, uint32_t a_segments, float a_duration, uint32_t a_color, float a_thickness); + void DrawArc(const RE::NiPoint3& a_origin, float a_radius, float a_startRadian, float a_endRadian, const RE::NiMatrix3& a_matrix, uint32_t a_segments, float a_duration, uint32_t a_color, float a_thickness); void DrawSphere(const RE::NiPoint3& a_origin, float a_radius, uint32_t a_segments, float a_duration, uint32_t a_color, float a_thickness); void DrawCylinder(const RE::NiPoint3& a_start, const RE::NiPoint3& a_end, float a_radius, uint32_t a_segments, float a_duration, uint32_t a_color, float a_thickness); void DrawCone(const RE::NiPoint3& a_origin, const RE::NiPoint3& a_direction, float a_length, float a_angleWidth, float a_angleHeight, uint32_t a_segments, float a_duration, uint32_t a_color, float a_thickness); diff --git a/src/ModAPI.cpp b/src/ModAPI.cpp index e9d2e74..7f24174 100644 --- a/src/ModAPI.cpp +++ b/src/ModAPI.cpp @@ -325,6 +325,12 @@ namespace Messaging hudHandler->DrawCapsule(a_vertexA, a_vertexB, a_radius, a_duration, a_color, a_thickness); } + void TrueHUDInterface::DrawArc(const RE::NiPoint3& a_origin, float a_radius, float a_startRadian, float a_endRadian, const RE::NiMatrix3& a_matrix, uint32_t a_segments, float a_duration, uint32_t a_color, float a_thickness) noexcept + { + auto hudHandler = HUDHandler::GetSingleton(); + hudHandler->DrawArc(a_origin, a_radius, a_startRadian, a_endRadian, a_matrix, a_segments, a_duration, a_color, a_thickness); + } + bool TrueHUDInterface::HasInfoBar(RE::ActorHandle a_actorHandle, bool a_bFloatingOnly /*= false*/) const noexcept { auto hudHandler = HUDHandler::GetSingleton(); diff --git a/src/ModAPI.h b/src/ModAPI.h index 1e0fec0..8062971 100644 --- a/src/ModAPI.h +++ b/src/ModAPI.h @@ -10,6 +10,7 @@ namespace Messaging using InterfaceVersion2 = ::TRUEHUD_API::IVTrueHUD2; using InterfaceVersion3 = ::TRUEHUD_API::IVTrueHUD3; using InterfaceVersion4 = ::TRUEHUD_API::IVTrueHUD4; + using InterfaceVersion5 = ::TRUEHUD_API::IVTrueHUD5; using PlayerWidgetBarType = ::TRUEHUD_API::PlayerWidgetBarType; using BarColorType = ::TRUEHUD_API::BarColorType; using WidgetRemovalMode = ::TRUEHUD_API::WidgetRemovalMode; @@ -19,7 +20,7 @@ namespace Messaging using WidgetBase = ::TRUEHUD_API::WidgetBase; - class TrueHUDInterface : public InterfaceVersion4 + class TrueHUDInterface : public InterfaceVersion5 { private: TrueHUDInterface() noexcept; @@ -78,6 +79,9 @@ namespace Messaging // InterfaceVersion4 virtual void DrawCapsule(const RE::NiPoint3& a_vertexA, const RE::NiPoint3& a_vertexB, float a_radius, float a_duration, uint32_t a_color, float a_thickness) noexcept override; + //InterfaceVersion5 + virtual void DrawArc(const RE::NiPoint3& a_origin, float a_radius, float a_startRadian, float a_endRadian, const RE::NiMatrix3& a_matrix, uint32_t a_segments, float a_duration, uint32_t a_color, float a_thickness) noexcept override; + // Does a mod have control over the current target? bool IsTargetControlTaken() const noexcept; // Does a mod have control over the special resource bars? diff --git a/src/Scaleform/TrueHUDMenu.cpp b/src/Scaleform/TrueHUDMenu.cpp index 937ceba..3b518c9 100644 --- a/src/Scaleform/TrueHUDMenu.cpp +++ b/src/Scaleform/TrueHUDMenu.cpp @@ -1,11 +1,11 @@ #include "Scaleform/TrueHUDMenu.h" -#include "Settings.h" -#include "Offsets.h" #include "HUDHandler.h" +#include "Offsets.h" +#include "Settings.h" +#include "Utils.h" #include "Widgets/ActorInfoBar.h" #include "Widgets/FloatingText.h" -#include "Utils.h" namespace Scaleform { @@ -36,7 +36,7 @@ namespace Scaleform if (a_actorHandle) { AddActorInfoBar(a_actorHandle); } - } + } } void TrueHUDMenu::SetSoftTarget(RE::ObjectRefHandle a_actorHandle) @@ -47,7 +47,7 @@ namespace Scaleform if (a_actorHandle) { AddActorInfoBar(a_actorHandle); } - } + } } RE::ObjectRefHandle TrueHUDMenu::GetTarget() const @@ -68,7 +68,7 @@ namespace Scaleform } bool TrueHUDMenu::AddActorInfoBar(RE::ObjectRefHandle a_actorHandle) - { + { using WidgetStateMode = InfoBarBase::WidgetStateMode; if (_view && !HasActorInfoBar(a_actorHandle) && !HasBossInfoBar(a_actorHandle)) { @@ -105,8 +105,7 @@ namespace Scaleform if (it != _actorInfoBarMap.end()) { auto& widget = it->second; - switch (a_removalMode) - { + switch (a_removalMode) { case WidgetRemovalMode::Immediate: if (widget->_object.IsDisplayObject()) { RE::GFxValue arg; @@ -154,7 +153,7 @@ namespace Scaleform } else { // Maximum count of boss bars, add to queue _bossQueue.emplace_back(a_actorHandle); - } + } } return false; @@ -447,7 +446,7 @@ namespace Scaleform RE::GFxValue args[2]; args[0].SetNumber(a_myPluginHandle); args[1].SetNumber(a_widgetType); - + _view->Invoke("_root.TrueHUD.RegisterNewWidgetType", nullptr, args, 2); } @@ -522,7 +521,7 @@ namespace Scaleform return true; } - } + } } } @@ -678,7 +677,7 @@ namespace Scaleform barType = BarType::kStamina; break; } - + auto it = _colorOverrides.find(a_actorHandle); if (it != _colorOverrides.end()) { auto& bars = it->second; @@ -894,6 +893,47 @@ namespace Scaleform } } + void TrueHUDMenu::DrawArc(const RE::NiPoint3& a_origin, float a_radius, float a_startRadian, float a_endRadian, const RE::NiMatrix3& a_matrix, uint32_t a_segments, float a_duration, uint32_t a_color, float a_thickness) + { + if (std::abs(a_radius) < 1e-6) + return; + + float radian = a_startRadian < a_endRadian ? a_endRadian - a_startRadian : a_endRadian - a_startRadian + 2.0f * PI; + + auto GetPointOnArc = [](const RE::NiPoint3& origin, float radius, float startAngle, float radian, float i, float maxI, const RE::NiMatrix3& matrix) -> RE::NiPoint3 { + auto currentAngle = startAngle + radian * (i / maxI); + return origin + matrix * RE::NiPoint3(radius * std::sinf(currentAngle), radius * std::cosf(currentAngle), 0.f); + }; + + auto currentPoint = GetPointOnArc(a_origin, a_radius, a_startRadian, radian, 0, a_segments, a_matrix); + DrawLine( + currentPoint, + a_origin, + a_duration, + a_color, + a_thickness); + + for (int i = 1; i <= a_segments; i++) { + auto nextPoint = GetPointOnArc(a_origin, a_radius, a_startRadian, radian, i, a_segments, a_matrix); + + DrawLine( + currentPoint, + nextPoint, + a_duration, + a_color, + a_thickness); + + currentPoint = nextPoint; + } + + DrawLine( + currentPoint, + a_origin, + a_duration, + a_color, + a_thickness); + } + void TrueHUDMenu::DrawSphere(const RE::NiPoint3& a_origin, float a_radius, uint32_t a_segments /*= 16*/, float a_duration /*= 0.f*/, uint32_t a_color /*= 0xFF0000FF*/, float a_thickness /*= 1.f*/) { a_segments = max(a_segments, 4); @@ -903,7 +943,7 @@ namespace Scaleform uint32_t numSegmentsY = a_segments, numSegmentsX; float latitude = angleInc, longitude; float sinY1 = 0.f, cosY1 = 1.f, sinY2, cosY2, sinX, cosX; - + while (numSegmentsY--) { sinY2 = sinf(latitude); cosY2 = cosf(latitude); @@ -957,8 +997,7 @@ namespace Scaleform p1 = segment + a_start; p3 = segment + a_end; - while (a_segments--) - { + while (a_segments--) { segment = Utils::RotateAngleAxis(perpendicular, angle, axis) * a_radius; p2 = segment + a_start; p4 = segment + a_end; @@ -976,9 +1015,11 @@ namespace Scaleform void TrueHUDMenu::DrawCone(const RE::NiPoint3& a_origin, const RE::NiPoint3& a_direction, float a_length, float a_angleWidth, float a_angleHeight, uint32_t a_segments, float a_duration /*= 0.f*/, uint32_t a_color /*= 0xFF0000FF*/, float a_thickness /*= 1.f*/) { a_segments = max(a_segments, 4); - - const float angle1 = a_angleHeight < 1e-4f ? 1e-4f : a_angleHeight < PI - 1e-4f ? a_angleHeight : PI - 1e-4f; - const float angle2 = a_angleWidth < 1e-4f ? 1e-4f : a_angleWidth < PI - 1e-4f ? a_angleWidth : PI - 1e-4f; + + const float angle1 = a_angleHeight < 1e-4f ? 1e-4f : a_angleHeight < PI - 1e-4f ? a_angleHeight : + PI - 1e-4f; + const float angle2 = a_angleWidth < 1e-4f ? 1e-4f : a_angleWidth < PI - 1e-4f ? a_angleWidth : + PI - 1e-4f; const float sinX2 = sinf(0.5f * angle1); const float sinY2 = sinf(0.5f * angle2); @@ -1228,8 +1269,7 @@ namespace Scaleform { Locker locker(_lock); - for (auto& entry : _actorInfoBarMap) - { + for (auto& entry : _actorInfoBarMap) { auto& widget = entry.second; if (widget->_object.IsDisplayObject()) { RE::GFxValue arg; @@ -1303,7 +1343,7 @@ namespace Scaleform if (_bSubtitleYSaved) { auto hud = RE::UI::GetSingleton()->GetMenu(RE::HUDMenu::MENU_NAME); hud.get()->uiMovie->SetVariable("HUDMovieBaseInstance.SubtitleTextHolder._y", _savedSubtitleY); - } + } if (_bCompassAlphaSaved) { auto hud = RE::UI::GetSingleton()->GetMenu(RE::HUDMenu::MENU_NAME); @@ -1340,7 +1380,7 @@ namespace Scaleform hud->uiMovie->SetVariable("HUDMovieBaseInstance.EnemyHealth_mc._alpha", 0.f); _bVanillaEnemyHealthHidden = true; - } + } } } else if (_bVanillaEnemyHealthHidden) { auto hudPtr = RE::UI::GetSingleton()->GetMenu(RE::HUDMenu::MENU_NAME); @@ -1349,7 +1389,7 @@ namespace Scaleform if (hud && hud->uiMovie) { hud->uiMovie->SetVariable("HUDMovieBaseInstance.EnemyHealth_mc._alpha", _savedVanillaEnemyHealthAlpha); _bVanillaEnemyHealthHidden = false; - } + } } } @@ -1371,10 +1411,10 @@ namespace Scaleform // actor info bars for (auto widget_it = _actorInfoBarMap.begin(), next_widget_it = widget_it; widget_it != _actorInfoBarMap.end(); widget_it = next_widget_it) { ++next_widget_it; - + auto& entry = *widget_it; auto& widget = entry.second; - + widget->ProcessDelegates(); widget->Update(a_deltaTime); @@ -1387,14 +1427,14 @@ namespace Scaleform // add to depths array AddToDepthsArray(widget, static_cast(TrueHUDWidgetType::kInfoBar), depthArray); } - + // boss bars for (auto widget_it = _bossInfoBarMap.begin(), next_widget_it = widget_it; widget_it != _bossInfoBarMap.end(); widget_it = next_widget_it) { ++next_widget_it; - + auto& entry = *widget_it; auto& widget = entry.second; - + widget->ProcessDelegates(); widget->Update(a_deltaTime); @@ -1407,7 +1447,7 @@ namespace Scaleform // add to depths array AddToDepthsArray(widget, static_cast(TrueHUDWidgetType::kBossBar), depthArray); } - + if (_shoutIndicator) { _shoutIndicator->ProcessDelegates(); _shoutIndicator->Update(a_deltaTime); @@ -1649,8 +1689,7 @@ namespace Scaleform void TrueHUDMenu::UpdateBossQueue() { - if (_bossQueue.size() > 0 && _bossInfoBarMap.size() < Settings::uBossBarMaxCount) - { + if (_bossQueue.size() > 0 && _bossInfoBarMap.size() < Settings::uBossBarMaxCount) { auto boss = _bossQueue.begin(); bool bSuccess = AddBossInfoBarWidget(*boss); @@ -1737,7 +1776,6 @@ namespace Scaleform _view->Invoke("lineTo", nullptr, argsEndPos, 2); _view->Invoke("endFill", nullptr, nullptr, 0); - } // https://www.oreilly.com/library/view/actionscript-cookbook/0596004907/ch04s06.html diff --git a/src/Scaleform/TrueHUDMenu.h b/src/Scaleform/TrueHUDMenu.h index df19357..0ee532f 100644 --- a/src/Scaleform/TrueHUDMenu.h +++ b/src/Scaleform/TrueHUDMenu.h @@ -1,13 +1,13 @@ #pragma once +#include "Offsets.h" #include "TrueHUDAPI.h" #include "Widgets/ActorInfoBar.h" #include "Widgets/BossInfoBar.h" -#include "Widgets/ShoutIndicator.h" -#include "Widgets/PlayerWidget.h" #include "Widgets/FloatingText.h" +#include "Widgets/PlayerWidget.h" #include "Widgets/RecentLoot.h" -#include "Offsets.h" +#include "Widgets/ShoutIndicator.h" #include #include @@ -128,7 +128,7 @@ namespace Scaleform void SetSoftTarget(RE::ObjectRefHandle a_actorHandle); RE::ObjectRefHandle GetTarget() const; RE::ObjectRefHandle GetSoftTarget() const; - + bool HasActorInfoBar(RE::ObjectRefHandle a_actorHandle); bool AddActorInfoBar(RE::ObjectRefHandle a_actorHandle); bool RemoveActorInfoBar(RE::ObjectRefHandle a_actorHandle, WidgetRemovalMode a_removalMode); @@ -173,6 +173,7 @@ namespace Scaleform void DrawBox(const RE::NiPoint3& a_center, const RE::NiPoint3& a_extent, const RE::NiQuaternion& a_rotation, float a_duration = 0.f, uint32_t a_color = 0xFF0000FF, float a_thickness = 1.f); void DrawCircle(const RE::NiPoint3& a_center, const RE::NiPoint3& a_x, const RE::NiPoint3& a_y, float a_radius, uint32_t a_segments, float a_duration = 0.f, uint32_t a_color = 0xFF0000FF, float a_thickness = 1.f); void DrawHalfCircle(const RE::NiPoint3& a_center, const RE::NiPoint3& a_x, const RE::NiPoint3& a_y, float a_radius, uint32_t a_segments, float a_duration = 0.f, uint32_t a_color = 0xFF0000FF, float a_thickness = 1.f); + void DrawArc(const RE::NiPoint3& a_origin, float a_radius, float a_startRadian, float a_endRadian, const RE::NiMatrix3& a_matrix, uint32_t a_segments, float a_duration = 0.f, uint32_t a_color = 0xFF0000FF, float a_thickness = 1.f); void DrawSphere(const RE::NiPoint3& a_origin, float a_radius, uint32_t a_segments = 16, float a_duration = 0.f, uint32_t a_color = 0xFF0000FF, float a_thickness = 1.f); void DrawCylinder(const RE::NiPoint3& a_start, const RE::NiPoint3& a_end, float a_radius, uint32_t a_segments, float a_duration = 0.f, uint32_t a_color = 0xFF0000FF, float a_thickness = 1.f); void DrawCone(const RE::NiPoint3& a_origin, const RE::NiPoint3& a_direction, float a_length, float a_angleWidth, float a_angleHeight, uint32_t a_segments, float a_duration = 0.f, uint32_t a_color = 0xFF0000FF, float a_thickness = 1.f); @@ -222,7 +223,7 @@ namespace Scaleform menu->inputContext = Context::kNone; _view = menu->uiMovie; - _view->SetMouseCursorCount(0); // disable input + _view->SetMouseCursorCount(0); // disable input } TrueHUDMenu(const TrueHUDMenu&) = default; @@ -236,12 +237,14 @@ namespace Scaleform static RE::stl::owner Creator() { return new TrueHUDMenu(); } // IMenu - void PostCreate() { + void PostCreate() + { OnOpen(); Super::PostCreate(); } - UIResult ProcessMessage(RE::UIMessage& a_message) override { + UIResult ProcessMessage(RE::UIMessage& a_message) override + { using Type = RE::UI_MESSAGE_TYPE; switch (*a_message.type) { @@ -339,7 +342,7 @@ namespace Scaleform MenuVisibilityMode _menuVisibilityMode = MenuVisibilityMode::kVisible; bool _bCartMode = false; - + std::unordered_map> _actorInfoBarMap; std::unordered_map> _bossInfoBarMap; std::shared_ptr _shoutIndicator; diff --git a/src/TrueHUDAPI.h b/src/TrueHUDAPI.h index 2ad5590..7e29af8 100644 --- a/src/TrueHUDAPI.h +++ b/src/TrueHUDAPI.h @@ -16,7 +16,8 @@ namespace TRUEHUD_API V1, V2, V3, - V4 + V4, + V5 }; // Error types that may be returned by the True HUD @@ -383,6 +384,13 @@ namespace TRUEHUD_API virtual void DrawCapsule(const RE::NiPoint3& a_vertexA, const RE::NiPoint3& a_vertexB, float a_radius, float a_duration = 0.f, uint32_t a_color = 0xFF0000FF, float a_thickness = 1.f) noexcept = 0; }; + class IVTrueHUD5 : public IVTrueHUD4 + { + public: + // Debug drawing API functions + virtual void DrawArc(const RE::NiPoint3& a_origin, float a_radius, float a_startRadian, float a_endRadian, const RE::NiMatrix3& a_matrix, uint32_t a_segments, float a_duration = 0.f, uint32_t a_color = 0xFF0000FF, float a_thickness = 1.f) noexcept = 0; + }; + typedef void* (*_RequestPluginAPI)(const InterfaceVersion interfaceVersion); /// @@ -391,7 +399,7 @@ namespace TRUEHUD_API /// /// The interface version to request /// The pointer to the API singleton, or nullptr if request failed - [[nodiscard]] inline void* RequestPluginAPI(const InterfaceVersion a_interfaceVersion = InterfaceVersion::V4) + [[nodiscard]] inline void* RequestPluginAPI(const InterfaceVersion a_interfaceVersion = InterfaceVersion::V5) { auto pluginHandle = GetModuleHandle("TrueHUD.dll"); _RequestPluginAPI requestAPIFunction = (_RequestPluginAPI)GetProcAddress(pluginHandle, "RequestPluginAPI"); diff --git a/src/main.cpp b/src/main.cpp index d858eac..bb6680a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -135,6 +135,8 @@ extern "C" DLLEXPORT void* SKSEAPI RequestPluginAPI(const TRUEHUD_API::Interface case TRUEHUD_API::InterfaceVersion::V3: [[fallthrough]]; case TRUEHUD_API::InterfaceVersion::V4: + [[fallthrough]]; + case TRUEHUD_API::InterfaceVersion::V5: logger::info("TrueHUD::RequestPluginAPI returned the API singleton"); return static_cast(api); }